diff --git a/.gitmodules b/.gitmodules index 8eb1526cb..3fa5f9f56 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,12 +8,6 @@ [submodule "External/imgui"] path = External/imgui url = https://github.com/Sonicadvance1/imgui.git -[submodule "External/json-maker"] - path = External/json-maker - url = https://github.com/Sonicadvance1/json-maker.git -[submodule "External/tiny-json"] - path = External/tiny-json - url = https://github.com/Sonicadvance1/tiny-json.git [submodule "External/xbyak"] shallow = true path = External/xbyak diff --git a/External/json-maker b/External/json-maker deleted file mode 160000 index 8ecb8ecc3..000000000 --- a/External/json-maker +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8ecb8ecc348bf88c592fac808c03efb342f69e0a diff --git a/External/json-maker/CMakeLists.txt b/External/json-maker/CMakeLists.txt new file mode 100644 index 000000000..0e86f131c --- /dev/null +++ b/External/json-maker/CMakeLists.txt @@ -0,0 +1,3 @@ +set(NAME json-maker) +set(SRCS json-maker.c) +add_library(${NAME} ${SRCS}) diff --git a/External/json-maker/LICENSE b/External/json-maker/LICENSE new file mode 100644 index 000000000..ab602974d --- /dev/null +++ b/External/json-maker/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/External/json-maker/json-maker.c b/External/json-maker/json-maker.c new file mode 100644 index 000000000..70bbedc51 --- /dev/null +++ b/External/json-maker/json-maker.c @@ -0,0 +1,277 @@ + +/* + + + Licensed under the MIT License . + SPDX-License-Identifier: MIT + Copyright (c) 2018 Rafa Garcia . + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +#include // For NULL +#include "json-maker.h" + +/** Add a character at the end of a string. + * @param dest Pointer to the null character of the string + * @param ch Value to be added. + * @return Pointer to the null character of the destination string. */ +static char* chtoa( char* dest, char ch ) { + *dest = ch; + *++dest = '\0'; + return dest; +} + +/** Copy a null-terminated string. + * @param dest Destination memory block. + * @param src Source string. + * @return Pointer to the null character of the destination string. */ +static char* atoa( char* dest, char const* src ) { + for( ; *src != '\0'; ++dest, ++src ) + *dest = *src; + *dest = '\0'; + return dest; +} + +/* Open a JSON object in a JSON string. */ +char* json_objOpen( char* dest, char const* name ) { + if ( NULL == name ) + dest = chtoa( dest, '{' ); + else { + dest = chtoa( dest, '\"' ); + dest = atoa( dest, name ); + dest = atoa( dest, "\":{" ); + } + return dest; +} + +/* Close a JSON object in a JSON string. */ +char* json_objClose( char* dest ) { + if ( dest[-1] == ',' ) + --dest; + return atoa( dest, "}," ); +} + +/* Open an array in a JSON string. */ +char* json_arrOpen( char* dest, char const* name ) { + if ( NULL == name ) + dest = chtoa( dest, '[' ); + else { + dest = chtoa( dest, '\"' ); + dest = atoa( dest, name ); + dest = atoa( dest, "\":[" ); + } + return dest; +} + +/* Close an array in a JSON string. */ +char* json_arrClose( char* dest ) { + if ( dest[-1] == ',' ) + --dest; + return atoa( dest, "]," ); +} + +/** Add the name of a text property. + * @param dest Destination memory. + * @param name The name of the property. + * @return Pointer to the next char. */ +static char* strname( char* dest, char const* name ) { + dest = chtoa( dest, '\"' ); + if ( NULL != name ) { + dest = atoa( dest, name ); + dest = atoa( dest, "\":\"" ); + } + return dest; +} + +/** Get the hexadecimal digit of the least significant nibble of a integer. */ +static int nibbletoch( int nibble ) { + return "0123456789ABCDEF"[ nibble % 16u ]; +} + +/** Get the escape character of a non-printable. + * @param ch Character source. + * @return The escape character or null character if error. */ +static int escape( int ch ) { + static struct { char code; char ch; } const pair[] = { + { '\"', '\"' }, { '\\', '\\' }, { '/', '/' }, { 'b', '\b' }, + { 'f', '\f' }, { 'n', '\n' }, { 'r', '\r' }, { 't', '\t' }, + }; + for( int i = 0; i < sizeof pair / sizeof *pair; ++i ) + if ( ch == pair[i].ch ) + return pair[i].code; + return '\0'; +} + +/** Copy a null-terminated string inserting escape characters if needed. + * @param dest Destination memory block. + * @param src Source string. + * @return Pointer to the null character of the destination string. */ +static char* atoesc( char* dest, char const* src ) { + for( ; *src != '\0'; ++dest, ++src ) { + if ( *src >= ' ' && *src != '\"' && *src != '\\' && *src != '/' ) + *dest = *src; + else { + *dest++ = '\\'; + int const esc = escape( *src ); + if ( esc ) + *dest = esc; + else { + *dest++ = 'u'; + *dest++ = '0'; + *dest++ = '0'; + *dest++ = nibbletoch( *src / 16 ); + *dest++ = nibbletoch( *src ); + } + } + } + *dest = '\0'; + return dest; +} + +/* Add a text property in a JSON string. */ +char* json_str( char* dest, char const* name, char const* value ) { + dest = strname( dest, name ); + dest = atoesc( dest, value ); + dest = atoa( dest, "\"," ); + return dest; +} + +/** Add the name of a primitive property. + * @param dest Destination memory. + * @param name The name of the property. + * @return Pointer to the next char. */ +static char* primitivename( char* dest, char const* name ) { + if( NULL == name ) + return dest; + dest = chtoa( dest, '\"' ); + dest = atoa( dest, name ); + dest = atoa( dest, "\":" ); + return dest; +} + +/* Add a boolean property in a JSON string. */ +char* json_bool( char* dest, char const* name, int value ) { + dest = primitivename( dest, name ); + dest = atoa( dest, value ? "true," : "false," ); + return dest; +} + +/* Add a null property in a JSON string. */ +char* json_null( char* dest, char const* name ) { + dest = primitivename( dest, name ); + dest = atoa( dest, "null," ); + return dest; +} + +/* Used to finish the root JSON object. After call json_objClose(). */ +char* json_end( char* dest ) { + if ( ',' == dest[-1] ) { + dest[-1] = '\0'; + --dest; + } + return dest; +} + +#ifdef NO_SPRINTF + +static char* format( char* dest, int len, int isnegative ) { + if ( isnegative ) + dest[ len++ ] = '-'; + dest[ len ] = '\0'; + int head = 0; + int tail = len - 1; + while( head < tail ) { + char tmp = dest[ head ]; + dest[ head ] = dest[ tail ]; + dest[ tail ] = tmp; + ++head; + --tail; + } + return dest + len; +} + +#define numtoa( func, type, utype ) \ +static char* func( char* dest, type val ) { \ + enum { base = 10 }; \ + if ( 0 == val ) \ + return chtoa( dest, '0' ); \ + int const isnegative = 0 > val; \ + utype num = isnegative ? -val : val; \ + int len = 0; \ + while( 0 != num ) { \ + int rem = num % base; \ + dest[ len++ ] = rem + '0'; \ + num = num / base; \ + } \ + return format( dest, len, isnegative ); \ +} \ + +#define json_num( func, func2, type ) \ +char* func( char* dest, char const* name, type value ) { \ + dest = primitivename( dest, name ); \ + dest = func2( dest, value ); \ + dest = chtoa( dest, ',' ); \ + return dest; \ +} \ + +#define ALL_TYPES \ + X( int, int, unsigned int ) \ + X( long, long, unsigned long ) \ + X( uint, unsigned int, unsigned int ) \ + X( ulong, unsigned long, unsigned long ) \ + X( verylong, long long, unsigned long long ) \ + +#define X( name, type, utype ) numtoa( name##toa, type, utype ) +ALL_TYPES +#undef X + +#define X( name, type, utype ) json_num( json_##name, name##toa, type ) +ALL_TYPES +#undef X + +char* json_double( char* dest, char const* name, double value ) { + return json_verylong( dest, name, value ); +} + +#else + +#include + +#define ALL_TYPES \ + X( json_int, int, "%d" ) \ + X( json_long, long, "%ld" ) \ + X( json_uint, unsigned int, "%u" ) \ + X( json_ulong, unsigned long, "%lu" ) \ + X( json_verylong, long long, "%lld" ) \ + X( json_double, double, "%g" ) \ + + +#define json_num( funcname, type, fmt ) \ +char* funcname( char* dest, char const* name, type value ) { \ + dest = primitivename( dest, name ); \ + dest += sprintf( dest, fmt, value ); \ + dest = chtoa( dest, ',' ); \ + return dest; \ +} + +#define X( name, type, fmt ) json_num( name, type, fmt ) +ALL_TYPES +#undef X + + +#endif \ No newline at end of file diff --git a/External/json-maker/json-maker.h b/External/json-maker/json-maker.h new file mode 100644 index 000000000..3adea1633 --- /dev/null +++ b/External/json-maker/json-maker.h @@ -0,0 +1,133 @@ + +/* + + + Licensed under the MIT License . + SPDX-License-Identifier: MIT + Copyright (c) 2018 Rafa Garcia . + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +#ifndef MAKE_JSON_H +#define MAKE_JSON_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup makejoson Make JSON. + * @{ */ + +/** Open a JSON object in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @return Pointer to the new end of JSON under construction. */ +char* json_objOpen( char* dest, char const* name ); + +/** Close a JSON object in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @return Pointer to the new end of JSON under construction. */ +char* json_objClose( char* dest ); + +/** Used to finish the root JSON object. After call json_objClose(). + * @param dest Pointer to the end of JSON under construction. + * @return Pointer to the new end of JSON under construction. */ +char* json_end( char* dest ); + +/** Open an array in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @return Pointer to the new end of JSON under construction. */ +char* json_arrOpen( char* dest, char const* name ); + +/** Close an array in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @return Pointer to the new end of JSON under construction. */ +char* json_arrClose( char* dest ); + +/** Add a text property in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @param value A valid null-terminated string with the value. + * Backslash escapes will be added for special characters. + * @return Pointer to the new end of JSON under construction. */ +char* json_str( char* dest, char const* name, char const* value ); + +/** Add a boolean property in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @param value Zero for false. Non zero for true. + * @return Pointer to the new end of JSON under construction. */ +char* json_bool( char* dest, char const* name, int value ); + +/** Add a null property in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @return Pointer to the new end of JSON under construction. */ +char* json_null( char* dest, char const* name ); + +/** Add an integer property in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @param value Value of the property. + * @return Pointer to the new end of JSON under construction. */ +char* json_int( char* dest, char const* name, int value ); + +/** Add an unsigned integer property in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @param value Value of the property. + * @return Pointer to the new end of JSON under construction. */ +char* json_uint( char* dest, char const* name, unsigned int value ); + +/** Add a long integer property in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @param value Value of the property. + * @return Pointer to the new end of JSON under construction. */ +char* json_long( char* dest, char const* name, long int value ); + +/** Add an unsigned long integer property in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @param value Value of the property. + * @return Pointer to the new end of JSON under construction. */ +char* json_ulong( char* dest, char const* name, unsigned long int value ); + +/** Add a long long integer property in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @param value Value of the property. + * @return Pointer to the new end of JSON under construction. */ +char* json_verylong( char* dest, char const* name, long long int value ); + +/** Add a double precision number property in a JSON string. + * @param dest Pointer to the end of JSON under construction. + * @param name Pointer to null-terminated string or null for unnamed. + * @param value Value of the property. + * @return Pointer to the new end of JSON under construction. */ +char* json_double( char* dest, char const* name, double value ); + +/** @ } */ + +#ifdef __cplusplus +} +#endif + +#endif /* MAKE_JSON_H */ + diff --git a/External/tiny-json b/External/tiny-json deleted file mode 160000 index 9d09127f8..000000000 --- a/External/tiny-json +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9d09127f87ea6a128fb17d1ffd0b444517343f1c diff --git a/External/tiny-json/CMakeLists.txt b/External/tiny-json/CMakeLists.txt new file mode 100644 index 000000000..8cf0054ee --- /dev/null +++ b/External/tiny-json/CMakeLists.txt @@ -0,0 +1,3 @@ +set(NAME tiny-json) +set(SRCS tiny-json.c) +add_library(${NAME} ${SRCS}) diff --git a/External/tiny-json/LICENSE b/External/tiny-json/LICENSE new file mode 100644 index 000000000..0fccdb29f --- /dev/null +++ b/External/tiny-json/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Rafa Garcia + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/External/tiny-json/tiny-json.c b/External/tiny-json/tiny-json.c new file mode 100644 index 000000000..b8566904a --- /dev/null +++ b/External/tiny-json/tiny-json.c @@ -0,0 +1,463 @@ + +/* + + + + Licensed under the MIT License . + SPDX-License-Identifier: MIT + Copyright (c) 2016-2018 Rafa Garcia . + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +#include +#include +#include "tiny-json.h" + +/** Structure to handle a heap of JSON properties. */ +typedef struct jsonStaticPool_s { + json_t* const mem; /**< Pointer to array of json properties. */ + unsigned int const qty; /**< Length of the array of json properties. */ + unsigned int nextFree; /**< The index of the next free json property. */ + jsonPool_t pool; +} jsonStaticPool_t; + +/* Search a property by its name in a JSON object. */ +json_t const* json_getProperty( json_t const* obj, char const* property ) { + json_t const* sibling; + for( sibling = obj->u.c.child; sibling; sibling = sibling->sibling ) + if ( sibling->name && !strcmp( sibling->name, property ) ) + return sibling; + return 0; +} + +/* Search a property by its name in a JSON object and return its value. */ +char const* json_getPropertyValue( json_t const* obj, char const* property ) { + json_t const* field = json_getProperty( obj, property ); + if ( !field ) return 0; + jsonType_t type = json_getType( field ); + if ( JSON_ARRAY >= type ) return 0; + return json_getValue( field ); +} + +/* Internal prototypes: */ +static char* goBlank( char* str ); +static char* goNum( char* str ); +static json_t* poolInit( jsonPool_t* pool ); +static json_t* poolAlloc( jsonPool_t* pool ); +static char* objValue( char* ptr, json_t* obj, jsonPool_t* pool ); +static char* setToNull( char* ch ); +static bool isEndOfPrimitive( char ch ); + +/* Parse a string to get a json. */ +json_t const* json_createWithPool( char *str, jsonPool_t *pool ) { + char* ptr = goBlank( str ); + if ( !ptr || *ptr != '{' ) return 0; + json_t* obj = pool->init( pool ); + obj->name = 0; + obj->sibling = 0; + obj->u.c.child = 0; + ptr = objValue( ptr, obj, pool ); + if ( !ptr ) return 0; + return obj; +} + +/* Parse a string to get a json. */ +json_t const* json_create( char* str, json_t mem[], unsigned int qty ) { + jsonStaticPool_t spool = { + .mem = mem, + .qty = qty, + .pool = { + .init = poolInit, + .alloc = poolAlloc + } + }; + return json_createWithPool( str, &spool.pool ); +} + +/** Get a special character with its escape character. Examples: + * 'b' -> '\b', 'n' -> '\n', 't' -> '\t' + * @param ch The escape character. + * @return The character code. */ +static char getEscape( char ch ) { + static struct { char ch; char code; } const pair[] = { + { '\"', '\"' }, { '\\', '\\' }, + { '/', '/' }, { 'b', '\b' }, + { 'f', '\f' }, { 'n', '\n' }, + { 'r', '\r' }, { 't', '\t' }, + }; + unsigned int i; + for( i = 0; i < sizeof pair / sizeof *pair; ++i ) + if ( pair[i].ch == ch ) + return pair[i].code; + return '\0'; +} + +/** Parse 4 characters. + * @Param str Pointer to first digit. + * @retval '?' If the four characters are hexadecimal digits. + * @retcal '\0' In other cases. */ +static unsigned char getCharFromUnicode( unsigned char const* str ) { + unsigned int i; + for( i = 0; i < 4; ++i ) + if ( !isxdigit( str[i] ) ) + return '\0'; + return '?'; +} + +/** Parse a string and replace the scape characters by their meaning characters. + * This parser stops when finds the character '\"'. Then replaces '\"' by '\0'. + * @param str Pointer to first character. + * @retval Pointer to first non white space after the string. If success. + * @retval Null pointer if any error occur. */ +static char* parseString( char* str ) { + unsigned char* head = (unsigned char*)str; + unsigned char* tail = (unsigned char*)str; + for( ; *head >= ' '; ++head, ++tail ) { + if ( *head == '\"' ) { + *tail = '\0'; + return (char*)++head; + } + if ( *head == '\\' ) { + if ( *++head == 'u' ) { + char const ch = getCharFromUnicode( ++head ); + if ( ch == '\0' ) return 0; + *tail = ch; + head += 3; + } + else { + char const esc = getEscape( *head ); + if ( esc == '\0' ) return 0; + *tail = esc; + } + } + else *tail = *head; + } + return 0; +} + +/** Parse a string to get the name of a property. + * @param str Pointer to first character. + * @param property The property to assign the name. + * @retval Pointer to first of property value. If success. + * @retval Null pointer if any error occur. */ +static char* propertyName( char* ptr, json_t* property ) { + property->name = ++ptr; + ptr = parseString( ptr ); + if ( !ptr ) return 0; + ptr = goBlank( ptr ); + if ( !ptr ) return 0; + if ( *ptr++ != ':' ) return 0; + return goBlank( ptr ); +} + +/** Parse a string to get the value of a property when its type is JSON_TEXT. + * @param str Pointer to first character ('\"'). + * @param property The property to assign the name. + * @retval Pointer to first non white space after the string. If success. + * @retval Null pointer if any error occur. */ +static char* textValue( char* ptr, json_t* property ) { + ++property->u.value; + ptr = parseString( ++ptr ); + if ( !ptr ) return 0; + property->type = JSON_TEXT; + return ptr; +} + +/** Compare two strings until get the null character in the second one. + * @param ptr sub string + * @param str main string + * @retval Pointer to next character. + * @retval Null pointer if any error occur. */ +static char* checkStr( char* ptr, char const* str ) { + while( *str ) + if ( *ptr++ != *str++ ) + return 0; + return ptr; +} + +/** Parser a string to get a primitive value. + * If the first character after the value is different of '}' or ']' is set to '\0'. + * @param str Pointer to first character. + * @param property Property handler to set the value and the type, (true, false or null). + * @param value String with the primitive literal. + * @param type The code of the type. ( JSON_BOOLEAN or JSON_NULL ) + * @retval Pointer to first non white space after the string. If success. + * @retval Null pointer if any error occur. */ +static char* primitiveValue( char* ptr, json_t* property, char const* value, jsonType_t type ) { + ptr = checkStr( ptr, value ); + if ( !ptr || !isEndOfPrimitive( *ptr ) ) return 0; + ptr = setToNull( ptr ); + property->type = type; + return ptr; +} + +/** Parser a string to get a true value. + * If the first character after the value is different of '}' or ']' is set to '\0'. + * @param str Pointer to first character. + * @param property Property handler to set the value and the type, (true, false or null). + * @retval Pointer to first non white space after the string. If success. + * @retval Null pointer if any error occur. */ +static char* trueValue( char* ptr, json_t* property ) { + return primitiveValue( ptr, property, "true", JSON_BOOLEAN ); +} + +/** Parser a string to get a false value. + * If the first character after the value is different of '}' or ']' is set to '\0'. + * @param str Pointer to first character. + * @param property Property handler to set the value and the type, (true, false or null). + * @retval Pointer to first non white space after the string. If success. + * @retval Null pointer if any error occur. */ +static char* falseValue( char* ptr, json_t* property ) { + return primitiveValue( ptr, property, "false", JSON_BOOLEAN ); +} + +/** Parser a string to get a null value. + * If the first character after the value is different of '}' or ']' is set to '\0'. + * @param str Pointer to first character. + * @param property Property handler to set the value and the type, (true, false or null). + * @retval Pointer to first non white space after the string. If success. + * @retval Null pointer if any error occur. */ +static char* nullValue( char* ptr, json_t* property ) { + return primitiveValue( ptr, property, "null", JSON_NULL ); +} + +/** Analyze the exponential part of a real number. + * @param str Pointer to first character. + * @retval Pointer to first non numerical after the string. If success. + * @retval Null pointer if any error occur. */ +static char* expValue( char* ptr ) { + if ( *ptr == '-' || *ptr == '+' ) ++ptr; + if ( !isdigit( *ptr ) ) return 0; + ptr = goNum( ++ptr ); + return ptr; +} + +/** Analyze the decimal part of a real number. + * @param str Pointer to first character. + * @retval Pointer to first non numerical after the string. If success. + * @retval Null pointer if any error occur. */ +static char* fraqValue( char* ptr ) { + if ( !isdigit( *ptr ) ) return 0; + ptr = goNum( ++ptr ); + if ( !ptr ) return 0; + return ptr; +} + +/** Parser a string to get a numerical value. + * If the first character after the value is different of '}' or ']' is set to '\0'. + * @param str Pointer to first character. + * @param property Property handler to set the value and the type: JSON_REAL or JSON_INTEGER. + * @retval Pointer to first non white space after the string. If success. + * @retval Null pointer if any error occur. */ +static char* numValue( char* ptr, json_t* property ) { + if ( *ptr == '-' ) ++ptr; + if ( !isdigit( *ptr ) ) return 0; + if ( *ptr != '0' ) { + ptr = goNum( ptr ); + if ( !ptr ) return 0; + } + else if ( isdigit( *++ptr ) ) return 0; + property->type = JSON_INTEGER; + if ( *ptr == '.' ) { + ptr = fraqValue( ++ptr ); + if ( !ptr ) return 0; + property->type = JSON_REAL; + } + if ( *ptr == 'e' || *ptr == 'E' ) { + ptr = expValue( ++ptr ); + if ( !ptr ) return 0; + property->type = JSON_REAL; + } + if ( !isEndOfPrimitive( *ptr ) ) return 0; + if ( JSON_INTEGER == property->type ) { + char const* value = property->u.value; + bool const negative = *value == '-'; + static char const min[] = "-9223372036854775808"; + static char const max[] = "9223372036854775807"; + unsigned int const maxdigits = ( negative? sizeof min: sizeof max ) - 1; + unsigned int const len = ptr - value; + if ( len > maxdigits ) return 0; + if ( len == maxdigits ) { + char const tmp = *ptr; + *ptr = '\0'; + char const* const threshold = negative ? min: max; + if ( 0 > strcmp( threshold, value ) ) return 0; + *ptr = tmp; + } + } + ptr = setToNull( ptr ); + return ptr; +} + +/** Add a property to a JSON object or array. + * @param obj The handler of the JSON object or array. + * @param property The handler of the property to be added. */ +static void add( json_t* obj, json_t* property ) { + property->sibling = 0; + if ( !obj->u.c.child ){ + obj->u.c.child = property; + obj->u.c.last_child = property; + } else { + obj->u.c.last_child->sibling = property; + obj->u.c.last_child = property; + } +} + +/** Parser a string to get a json object value. + * @param str Pointer to first character. + * @param pool The handler of a json pool for creating json instances. + * @retval Pointer to first character after the value. If success. + * @retval Null pointer if any error occur. */ +static char* objValue( char* ptr, json_t* obj, jsonPool_t* pool ) { + obj->type = JSON_OBJ; + obj->u.c.child = 0; + obj->sibling = 0; + ptr++; + for(;;) { + ptr = goBlank( ptr ); + if ( !ptr ) return 0; + if ( *ptr == ',' ) { + ++ptr; + continue; + } + char const endchar = ( obj->type == JSON_OBJ )? '}': ']'; + if ( *ptr == endchar ) { + *ptr = '\0'; + json_t* parentObj = obj->sibling; + if ( !parentObj ) return ++ptr; + obj->sibling = 0; + obj = parentObj; + ++ptr; + continue; + } + json_t* property = pool->alloc( pool ); + if ( !property ) return 0; + if( obj->type != JSON_ARRAY ) { + if ( *ptr != '\"' ) return 0; + ptr = propertyName( ptr, property ); + if ( !ptr ) return 0; + } + else property->name = 0; + add( obj, property ); + property->u.value = ptr; + switch( *ptr ) { + case '{': + property->type = JSON_OBJ; + property->u.c.child = 0; + property->sibling = obj; + obj = property; + ++ptr; + break; + case '[': + property->type = JSON_ARRAY; + property->u.c.child = 0; + property->sibling = obj; + obj = property; + ++ptr; + break; + case '\"': ptr = textValue( ptr, property ); break; + case 't': ptr = trueValue( ptr, property ); break; + case 'f': ptr = falseValue( ptr, property ); break; + case 'n': ptr = nullValue( ptr, property ); break; + default: ptr = numValue( ptr, property ); break; + } + if ( !ptr ) return 0; + } +} + +/** Initialize a json pool. + * @param pool The handler of the pool. + * @return a instance of a json. */ +static json_t* poolInit( jsonPool_t* pool ) { + jsonStaticPool_t *spool = json_containerOf( pool, jsonStaticPool_t, pool ); + spool->nextFree = 1; + return spool->mem; +} + +/** Create an instance of a json from a pool. + * @param pool The handler of the pool. + * @retval The handler of the new instance if success. + * @retval Null pointer if the pool was empty. */ +static json_t* poolAlloc( jsonPool_t* pool ) { + jsonStaticPool_t *spool = json_containerOf( pool, jsonStaticPool_t, pool ); + if ( spool->nextFree >= spool->qty ) return 0; + return spool->mem + spool->nextFree++; +} + +/** Checks whether an character belongs to set. + * @param ch Character value to be checked. + * @param set Set of characters. It is just a null-terminated string. + * @return true or false there is membership or not. */ +static bool isOneOfThem( char ch, char const* set ) { + while( *set != '\0' ) + if ( ch == *set++ ) + return true; + return false; +} + +/** Increases a pointer while it points to a character that belongs to a set. + * @param str The initial pointer value. + * @param set Set of characters. It is just a null-terminated string. + * @return The final pointer value or null pointer if the null character was found. */ +static char* goWhile( char* str, char const* set ) { + for(; *str != '\0'; ++str ) { + if ( !isOneOfThem( *str, set ) ) + return str; + } + return 0; +} + +/** Set of characters that defines a blank. */ +static char const* const blank = " \n\r\t\f"; + +/** Increases a pointer while it points to a white space character. + * @param str The initial pointer value. + * @return The final pointer value or null pointer if the null character was found. */ +static char* goBlank( char* str ) { + return goWhile( str, blank ); +} + +/** Increases a pointer while it points to a decimal digit character. + * @param str The initial pointer value. + * @return The final pointer value or null pointer if the null character was found. */ +static char* goNum( char* str ) { + for( ; *str != '\0'; ++str ) { + if ( !isdigit( *str ) ) + return str; + } + return 0; +} + +/** Set of characters that defines the end of an array or a JSON object. */ +static char const* const endofblock = "}]"; + +/** Set a char to '\0' and increase its pointer if the char is different to '}' or ']'. + * @param ch Pointer to character. + * @return Final value pointer. */ +static char* setToNull( char* ch ) { + if ( !isOneOfThem( *ch, endofblock ) ) *ch++ = '\0'; + return ch; +} + +/** Indicate if a character is the end of a primitive value. */ +static bool isEndOfPrimitive( char ch ) { + return ch == ',' || isOneOfThem( ch, blank ) || isOneOfThem( ch, endofblock ); +} diff --git a/External/tiny-json/tiny-json.h b/External/tiny-json/tiny-json.h new file mode 100644 index 000000000..d592a4aaa --- /dev/null +++ b/External/tiny-json/tiny-json.h @@ -0,0 +1,176 @@ + +/* + + + + Licensed under the MIT License . + SPDX-License-Identifier: MIT + Copyright (c) 2016-2018 Rafa Garcia . + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +#ifndef _TINY_JSON_H_ +#define _TINY_JSON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#define json_containerOf( ptr, type, member ) \ + ((type*)( (char*)ptr - offsetof( type, member ) )) + +/** @defgroup tinyJson Tiny JSON parser. + * @{ */ + +/** Enumeration of codes of supported JSON properties types. */ +typedef enum { + JSON_OBJ, JSON_ARRAY, JSON_TEXT, JSON_BOOLEAN, + JSON_INTEGER, JSON_REAL, JSON_NULL +} jsonType_t; + +/** Structure to handle JSON properties. */ +typedef struct json_s { + struct json_s* sibling; + char const* name; + union { + char const* value; + struct { + struct json_s* child; + struct json_s* last_child; + } c; + } u; + jsonType_t type; +} json_t; + +/** Parse a string to get a json. + * @param str String pointer with a JSON object. It will be modified. + * @param mem Array of json properties to allocate. + * @param qty Number of elements of mem. + * @retval Null pointer if any was wrong in the parse process. + * @retval If the parser process was successfully a valid handler of a json. + * This property is always unnamed and its type is JSON_OBJ. */ +json_t const* json_create( char* str, json_t mem[], unsigned int qty ); + +/** Get the name of a json property. + * @param json A valid handler of a json property. + * @retval Pointer to null-terminated if property has name. + * @retval Null pointer if the property is unnamed. */ +static inline char const* json_getName( json_t const* json ) { + return json->name; +} + +/** Get the value of a json property. + * The type of property cannot be JSON_OBJ or JSON_ARRAY. + * @param json A valid handler of a json property. + * @return Pointer to null-terminated string with the value. */ +static inline char const* json_getValue( json_t const* property ) { + return property->u.value; +} + +/** Get the type of a json property. + * @param json A valid handler of a json property. + * @return The code of type.*/ +static inline jsonType_t json_getType( json_t const* json ) { + return json->type; +} + +/** Get the next sibling of a JSON property that is within a JSON object or array. + * @param json A valid handler of a json property. + * @retval The handler of the next sibling if found. + * @retval Null pointer if the json property is the last one. */ +static inline json_t const* json_getSibling( json_t const* json ) { + return json->sibling; +} + +/** Search a property by its name in a JSON object. + * @param obj A valid handler of a json object. Its type must be JSON_OBJ. + * @param property The name of property to get. + * @retval The handler of the json property if found. + * @retval Null pointer if not found. */ +json_t const* json_getProperty( json_t const* obj, char const* property ); + + +/** Search a property by its name in a JSON object and return its value. + * @param obj A valid handler of a json object. Its type must be JSON_OBJ. + * @param property The name of property to get. + * @retval If found a pointer to null-terminated string with the value. + * @retval Null pointer if not found or it is an array or an object. */ +char const* json_getPropertyValue( json_t const* obj, char const* property ); + +/** Get the first property of a JSON object or array. + * @param json A valid handler of a json property. + * Its type must be JSON_OBJ or JSON_ARRAY. + * @retval The handler of the first property if there is. + * @retval Null pointer if the json object has not properties. */ +static inline json_t const* json_getChild( json_t const* json ) { + return json->u.c.child; +} + +/** Get the value of a json boolean property. + * @param property A valid handler of a json object. Its type must be JSON_BOOLEAN. + * @return The value stdbool. */ +static inline bool json_getBoolean( json_t const* property ) { + return *property->u.value == 't'; +} + +/** Get the value of a json integer property. + * @param property A valid handler of a json object. Its type must be JSON_INTEGER. + * @return The value stdint. */ +static inline int64_t json_getInteger( json_t const* property ) { + return atoll( property->u.value ); +} + +/** Get the value of a json real property. + * @param property A valid handler of a json object. Its type must be JSON_REAL. + * @return The value. */ +static inline double json_getReal( json_t const* property ) { + return atof( property->u.value ); +} + + + +/** Structure to handle a heap of JSON properties. */ +typedef struct jsonPool_s jsonPool_t; +struct jsonPool_s { + json_t* (*init)( jsonPool_t* pool ); + json_t* (*alloc)( jsonPool_t* pool ); +}; + +/** Parse a string to get a json. + * @param str String pointer with a JSON object. It will be modified. + * @param pool Custom json pool pointer. + * @retval Null pointer if any was wrong in the parse process. + * @retval If the parser process was successfully a valid handler of a json. + * This property is always unnamed and its type is JSON_OBJ. */ +json_t const* json_createWithPool( char* str, jsonPool_t* pool ); + +/** @ } */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TINY_JSON_H_ */