mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Replace JSMN with SAJSON.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
e685b3ffe0
commit
d79f292729
@ -133,7 +133,7 @@ if(WIN32 OR MINGW)
|
|||||||
target_link_libraries(SqModule wsock32 ws2_32 shlwapi)
|
target_link_libraries(SqModule wsock32 ws2_32 shlwapi)
|
||||||
endif()
|
endif()
|
||||||
# Link to base libraries
|
# Link to base libraries
|
||||||
target_link_libraries(SqModule Squirrel fmt::fmt SimpleINI TinyDir ConcurrentQueue JSMN CPR PUGIXML maxminddb libzmq-static)
|
target_link_libraries(SqModule Squirrel fmt::fmt SimpleINI TinyDir ConcurrentQueue SAJSON CPR PUGIXML maxminddb libzmq-static)
|
||||||
# Link to POCO libraries
|
# Link to POCO libraries
|
||||||
target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net Poco::JSON Poco::XML)
|
target_link_libraries(SqModule Poco::Foundation Poco::Crypto Poco::Data Poco::Net Poco::JSON Poco::XML)
|
||||||
# Does POCO have SQLite support?
|
# Does POCO have SQLite support?
|
||||||
|
@ -17,90 +17,76 @@ static SQInteger SqToJSON(HSQUIRRELVM vm) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
static SQInteger SqFromJson_Push(HSQUIRRELVM vm, const char * str, jsmntok * t, size_t count) noexcept
|
static SQInteger SqFromJson_Push(HSQUIRRELVM vm, const sajson::value & node) noexcept
|
||||||
{
|
{
|
||||||
// Are there any elements to process?
|
// Operation result
|
||||||
if (count == 0)
|
SQInteger r = SQ_OK;
|
||||||
|
// Identify element type
|
||||||
|
switch (node.get_type())
|
||||||
{
|
{
|
||||||
// We still need something on the stack
|
case sajson::TYPE_INTEGER: {
|
||||||
sq_pushnull(vm);
|
sq_pushinteger(vm, static_cast< SQInteger >(node.get_integer_value()));
|
||||||
// No token consumed
|
} break;
|
||||||
return 0;
|
case sajson::TYPE_DOUBLE: {
|
||||||
}
|
sq_pushfloat(vm, static_cast< SQFloat >(node.get_double_value()));
|
||||||
// Is this a primitive type?
|
} break;
|
||||||
else if (t->type & JSMN_PRIMITIVE)
|
case sajson::TYPE_NULL: {
|
||||||
{
|
|
||||||
// Primitive length (in characters)
|
|
||||||
const jsmnint l = (t->end - t->start);
|
|
||||||
// Primitive start (character offset)
|
|
||||||
const char * v = (str + t->start);
|
|
||||||
// Is this a floating point?
|
|
||||||
if (memchr(v, '.', l) || memchr(v, 'e', l) || memchr(v, 'E', l))
|
|
||||||
{
|
|
||||||
sq_pushfloat(vm, ConvNum< SQFloat >::FromStr(v));
|
|
||||||
}
|
|
||||||
// Is this an integer?
|
|
||||||
else if (((v[0] >= '0') && (v[0] <= '9')) || (v[0] == '-') || (v[0] == '+'))
|
|
||||||
{
|
|
||||||
sq_pushinteger(vm, ConvNum< SQInteger >::FromStr(v));
|
|
||||||
}
|
|
||||||
// Is this a boolean true?
|
|
||||||
else if (v[0] == 't')
|
|
||||||
{
|
|
||||||
sq_pushbool(vm, SQTrue);
|
|
||||||
}
|
|
||||||
// Is this a boolean false?
|
|
||||||
else if (v[0] == 'f')
|
|
||||||
{
|
|
||||||
sq_pushbool(vm, SQFalse);
|
|
||||||
}
|
|
||||||
// Is this null?
|
|
||||||
else if (v[0] == 'n')
|
|
||||||
{
|
|
||||||
sq_pushnull(vm);
|
sq_pushnull(vm);
|
||||||
}
|
} break;
|
||||||
// Should never really get here because it should be sanitized by the JSON parser
|
case sajson::TYPE_FALSE: {
|
||||||
// But doesn't hurt to have it here in case something out of our scope goes wrong
|
sq_pushbool(vm, SQFalse);
|
||||||
else
|
} break;
|
||||||
{
|
case sajson::TYPE_TRUE: {
|
||||||
return sq_throwerrorf(vm, _SC("Unrecognized JSON primitive: '%.*s'"), l, v);
|
sq_pushbool(vm, SQTrue);
|
||||||
}
|
} break;
|
||||||
// One token was consumed
|
case sajson::TYPE_STRING: {
|
||||||
return 1;
|
sq_pushstring(vm, node.as_cstring(), static_cast< SQInteger >(node.get_string_length()));
|
||||||
}
|
} break;
|
||||||
// Is this a string?
|
case sajson::TYPE_ARRAY: {
|
||||||
else if (t->type & JSMN_STRING)
|
// Array length
|
||||||
{
|
const size_t n = node.get_length();
|
||||||
sq_pushstring(vm, (str + t->start), static_cast< SQInteger >(t->end - t->start));
|
// Create a new array on the stack
|
||||||
// One token was consumed
|
sq_newarrayex(vm, static_cast< SQInteger >(n));
|
||||||
return 1;
|
// Process array elements
|
||||||
}
|
for (size_t i = 0; i < n; ++i)
|
||||||
// Is this an object?
|
|
||||||
else if (t->type & JSMN_OBJECT)
|
|
||||||
{
|
|
||||||
// Number of tokens consumed by this object
|
|
||||||
SQInteger c = 0, r = SQ_OK;
|
|
||||||
// Create a new table on the stack
|
|
||||||
sq_newtableex(vm, static_cast< SQInteger >(t->size));
|
|
||||||
// Process object elements
|
|
||||||
for (jsmnint i = 0; i < t->size; i++)
|
|
||||||
{
|
|
||||||
// Locate key token relative to the current token
|
|
||||||
jsmntok * k = (t + 1 + c);
|
|
||||||
// Transform the key into a script object on the stack
|
|
||||||
r = SqFromJson_Push(vm, str, k, count - c);
|
|
||||||
// Did we fail?
|
|
||||||
if (SQ_FAILED(r))
|
|
||||||
{
|
|
||||||
break; // Abort
|
|
||||||
}
|
|
||||||
// Update consumed tokens
|
|
||||||
c += r;
|
|
||||||
// Does the key have an associated value?
|
|
||||||
if (k->size > 0)
|
|
||||||
{
|
{
|
||||||
// Transform the value into a script object on the stack
|
// Transform the value into a script object on the stack
|
||||||
r = SqFromJson_Push(vm, str, (t + 1 + c), count - c);
|
r = SqFromJson_Push(vm, node.get_array_element(i));
|
||||||
|
// Did we fail?
|
||||||
|
if (SQ_FAILED(r))
|
||||||
|
{
|
||||||
|
break; // Abort
|
||||||
|
}
|
||||||
|
// At this point we have a value on the stack
|
||||||
|
r = sq_arrayappend(vm, -2);
|
||||||
|
// Did we fail?
|
||||||
|
if (SQ_FAILED(r))
|
||||||
|
{
|
||||||
|
// Discard the value
|
||||||
|
sq_poptop(vm);
|
||||||
|
// Abort
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Anything bad happened?
|
||||||
|
if (SQ_FAILED(r))
|
||||||
|
{
|
||||||
|
sq_poptop(vm); // Discard the array
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case sajson::TYPE_OBJECT: {
|
||||||
|
// Object length
|
||||||
|
const size_t n = node.get_length();
|
||||||
|
// Create a new table on the stack
|
||||||
|
sq_newtableex(vm, static_cast< SQInteger >(n));
|
||||||
|
//
|
||||||
|
for (size_t i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
const auto k = node.get_object_key(i);
|
||||||
|
// Transform the key into a script object on the stack
|
||||||
|
sq_pushstring(vm, k.data(), static_cast< SQInteger >(k.length()));
|
||||||
|
// Transform the value into a script object on the stack
|
||||||
|
r = SqFromJson_Push(vm, node.get_object_value(i));
|
||||||
// Did we fail?
|
// Did we fail?
|
||||||
if (SQ_FAILED(r))
|
if (SQ_FAILED(r))
|
||||||
{
|
{
|
||||||
@ -109,79 +95,30 @@ static SQInteger SqFromJson_Push(HSQUIRRELVM vm, const char * str, jsmntok * t,
|
|||||||
// Abort
|
// Abort
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Update consumed tokens
|
// At this point we have a key and a value on the stack
|
||||||
c += r;
|
r = sq_newslot(vm, -3, SQFalse);
|
||||||
|
// Did we fail?
|
||||||
|
if (SQ_FAILED(r))
|
||||||
|
{
|
||||||
|
// Discard the key/value pair
|
||||||
|
sq_pop(vm, 2);
|
||||||
|
// Abort
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
// Anything bad happened?
|
||||||
{
|
|
||||||
sq_pushnull(vm); // Default to null because a value must exist
|
|
||||||
}
|
|
||||||
// At this point we have a key and a value on the stack
|
|
||||||
r = sq_newslot(vm, -3, SQFalse);
|
|
||||||
// Did we fail?
|
|
||||||
if (SQ_FAILED(r))
|
if (SQ_FAILED(r))
|
||||||
{
|
{
|
||||||
// Discard the key/value pair
|
sq_poptop(vm); // Discard the table
|
||||||
sq_pop(vm, 2);
|
|
||||||
// Abort
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
// Anything bad happened?
|
default:
|
||||||
if (SQ_FAILED(r))
|
// Should never really get here because it should be sanitized by the JSON parser
|
||||||
{
|
// But doesn't hurt to have it here in case something out of our scope goes wrong
|
||||||
// Discard the table
|
r = sq_throwerror(vm, _SC("Unrecognized JSON type"));
|
||||||
sq_poptop(vm);
|
|
||||||
// Propagate the error
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
// Return consumed tokens
|
|
||||||
return c + 1;
|
|
||||||
}
|
}
|
||||||
// Is this an array?
|
// Return the result
|
||||||
else if (t->type & JSMN_ARRAY)
|
return r;
|
||||||
{
|
|
||||||
// Number of tokens consumed by this array
|
|
||||||
SQInteger c = 0, r = SQ_OK;
|
|
||||||
// Create a new array on the stack
|
|
||||||
sq_newarrayex(vm, static_cast< SQInteger >(t->size));
|
|
||||||
// Process array elements
|
|
||||||
for (jsmnint i = 0; i < t->size; i++)
|
|
||||||
{
|
|
||||||
// Transform the value into a script object on the stack
|
|
||||||
r = SqFromJson_Push(vm, str, (t + 1 + c), count - c);
|
|
||||||
// Did we fail?
|
|
||||||
if (SQ_FAILED(r))
|
|
||||||
{
|
|
||||||
break; // Abort
|
|
||||||
}
|
|
||||||
// Update consumed tokens
|
|
||||||
c += r;
|
|
||||||
// At this point we have a value on the stack
|
|
||||||
r = sq_arrayappend(vm, -2);
|
|
||||||
// Did we fail?
|
|
||||||
if (SQ_FAILED(r))
|
|
||||||
{
|
|
||||||
// Discard the value
|
|
||||||
sq_poptop(vm);
|
|
||||||
// Abort
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Anything bad happened?
|
|
||||||
if (SQ_FAILED(r))
|
|
||||||
{
|
|
||||||
// Discard the array
|
|
||||||
sq_poptop(vm);
|
|
||||||
// Propagate the error
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
// Return consumed tokens
|
|
||||||
return c + 1;
|
|
||||||
}
|
|
||||||
// Should never really get here because it should be sanitized by the JSON parser
|
|
||||||
// But doesn't hurt to have it here in case something out of our scope goes wrong
|
|
||||||
return sq_throwerror(vm, _SC("Unrecognized JSON type"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@ -201,45 +138,17 @@ static SQInteger SqFromJSON(HSQUIRRELVM vm) noexcept
|
|||||||
{
|
{
|
||||||
return s.mRes; // Propagate the error
|
return s.mRes; // Propagate the error
|
||||||
}
|
}
|
||||||
// Parser context
|
|
||||||
jsmnparser p;
|
|
||||||
// Initialize parser
|
|
||||||
jsmn_init(&p);
|
|
||||||
// Estimate the number of tokens necessary to parse the specified JSON string
|
|
||||||
jsmnint r = jsmn_parse(&p, s.mPtr, static_cast< size_t >(s.mLen), nullptr, 0);
|
|
||||||
// Is there anything to parse?
|
|
||||||
if (r == 0)
|
|
||||||
{
|
|
||||||
// Default to null
|
|
||||||
sq_pushnull(vm);
|
|
||||||
// A value was returned
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// See if there was an error
|
|
||||||
switch (r)
|
|
||||||
{
|
|
||||||
case jsmnint(JSMN_ERROR_NOMEM):
|
|
||||||
return sq_throwerror(vm, _SC("Not enough token memory was provided"));
|
|
||||||
case jsmnint(JSMN_ERROR_LEN):
|
|
||||||
return sq_throwerror(vm, _SC("Input data too long"));
|
|
||||||
case jsmnint(JSMN_ERROR_INVAL):
|
|
||||||
return sq_throwerror(vm, _SC("Invalid character inside JSON string"));
|
|
||||||
case jsmnint(JSMN_ERROR_PART):
|
|
||||||
return sq_throwerror(vm, _SC("The string is not a full JSON packet, more bytes expected"));
|
|
||||||
case jsmnint(JSMN_ERROR_UNMATCHED_BRACKETS):
|
|
||||||
return sq_throwerror(vm, _SC("The JSON string has unmatched brackets"));
|
|
||||||
default: break; // Nothing bad happened
|
|
||||||
}
|
|
||||||
// Initialize the token array
|
|
||||||
std::vector< jsmntok > tks(static_cast< size_t >(r) + 16);
|
|
||||||
// Initialize parser
|
|
||||||
jsmn_init(&p);
|
|
||||||
// Attempt to parse the specified JSON string
|
// Attempt to parse the specified JSON string
|
||||||
r = jsmn_parse(&p, s.mPtr, static_cast< size_t >(s.mLen), tks.data(), tks.size());
|
const sajson::document & document = sajson::parse(sajson::dynamic_allocation(), sajson::string(s.mPtr, static_cast<size_t>(s.mLen)));
|
||||||
// Process the tokens that were parsed from the string
|
// See if there was an error
|
||||||
SQInteger res = SqFromJson_Push(vm, s.mPtr, tks.data(), p.toknext);
|
if (!document.is_valid())
|
||||||
|
{
|
||||||
|
return sq_throwerror(vm, document.get_error_message_as_cstring());
|
||||||
|
}
|
||||||
|
// Process the nodes that were parsed from the string
|
||||||
|
SQInteger r = SqFromJson_Push(vm, document.get_root());
|
||||||
// We either have a value to return or we propagate some error
|
// We either have a value to return or we propagate some error
|
||||||
return SQ_SUCCEEDED(res) ? 1 : res;
|
return SQ_SUCCEEDED(r) ? 1 : r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================================================================================================
|
// ================================================================================================
|
||||||
|
@ -5,9 +5,7 @@
|
|||||||
#include "Library/IO/Buffer.hpp"
|
#include "Library/IO/Buffer.hpp"
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
extern "C" {
|
#include <sajson.h>
|
||||||
#include <jsmn.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
namespace SqMod {
|
namespace SqMod {
|
||||||
|
2
vendor/CMakeLists.txt
vendored
2
vendor/CMakeLists.txt
vendored
@ -3,7 +3,7 @@ add_subdirectory(Fmt)
|
|||||||
add_subdirectory(Squirrel)
|
add_subdirectory(Squirrel)
|
||||||
add_subdirectory(SimpleIni)
|
add_subdirectory(SimpleIni)
|
||||||
add_subdirectory(TinyDir)
|
add_subdirectory(TinyDir)
|
||||||
add_subdirectory(JSMN)
|
add_subdirectory(SAJSON)
|
||||||
add_subdirectory(CPR)
|
add_subdirectory(CPR)
|
||||||
add_subdirectory(PUGIXML)
|
add_subdirectory(PUGIXML)
|
||||||
set(BUILD_TESTING OFF CACHE INTERNAL "" FORCE)
|
set(BUILD_TESTING OFF CACHE INTERNAL "" FORCE)
|
||||||
|
7
vendor/JSMN/CMakeLists.txt
vendored
7
vendor/JSMN/CMakeLists.txt
vendored
@ -1,7 +0,0 @@
|
|||||||
# Create the JSMN library
|
|
||||||
add_library(JSMN STATIC include/jsmn.h jsmn.c)
|
|
||||||
# Library includes
|
|
||||||
target_include_directories(JSMN PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
|
||||||
target_include_directories(JSMN PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
|
||||||
# Compile time options
|
|
||||||
target_compile_definitions(JSMN PUBLIC JSMN_UTF8=1)
|
|
202
vendor/JSMN/include/jsmn.h
vendored
202
vendor/JSMN/include/jsmn.h
vendored
@ -1,202 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010 Serge Zaitsev
|
|
||||||
*
|
|
||||||
* 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 JSMN_H
|
|
||||||
#define JSMN_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "jsmn_defines.h"
|
|
||||||
|
|
||||||
#ifdef JSMN_SHORT_TOKENS
|
|
||||||
typedef unsigned short jsmnint;
|
|
||||||
#else
|
|
||||||
typedef unsigned int jsmnint;
|
|
||||||
#endif
|
|
||||||
#define JSMN_NEG ((jsmnint)-1)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON type identifier. Basic types are:
|
|
||||||
*/
|
|
||||||
typedef enum jsmntype {
|
|
||||||
JSMN_UNDEFINED = 0x0000,
|
|
||||||
JSMN_OBJECT = 0x0001, /*!< Object */
|
|
||||||
JSMN_ARRAY = 0x0002, /*!< Array */
|
|
||||||
JSMN_STRING = 0x0004, /*!< String */
|
|
||||||
JSMN_PRIMITIVE =
|
|
||||||
0x0008, /*!< Other primitive: number, boolean (true/false) or null */
|
|
||||||
|
|
||||||
JSMN_KEY = 0x0010, /*!< is a key */
|
|
||||||
JSMN_VALUE = 0x0020, /*!< is a value */
|
|
||||||
|
|
||||||
/* Complex elements */
|
|
||||||
JSMN_CONTAINER = JSMN_OBJECT | JSMN_ARRAY,
|
|
||||||
#ifndef JSMN_PERMISSIVE_KEY
|
|
||||||
JSMN_KEY_TYPE = JSMN_STRING,
|
|
||||||
#else
|
|
||||||
JSMN_KEY_TYPE = JSMN_STRING | JSMN_PRIMITIVE,
|
|
||||||
#endif
|
|
||||||
JSMN_ANY_TYPE = JSMN_OBJECT | JSMN_ARRAY | JSMN_STRING | JSMN_PRIMITIVE,
|
|
||||||
|
|
||||||
JSMN_OBJ_VAL = JSMN_OBJECT | JSMN_VALUE,
|
|
||||||
JSMN_ARR_VAL = JSMN_ARRAY | JSMN_VALUE,
|
|
||||||
JSMN_STR_KEY = JSMN_STRING | JSMN_KEY,
|
|
||||||
JSMN_STR_VAL = JSMN_STRING | JSMN_VALUE,
|
|
||||||
JSMN_PRI_VAL = JSMN_PRIMITIVE | JSMN_VALUE,
|
|
||||||
#ifdef JSMN_PERMISSIVE_KEY
|
|
||||||
JSMN_OBJ_KEY = JSMN_OBJECT | JSMN_KEY,
|
|
||||||
JSMN_ARR_KEY = JSMN_ARRAY | JSMN_KEY,
|
|
||||||
JSMN_PRI_KEY = JSMN_PRIMITIVE | JSMN_KEY,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Primitive extension */
|
|
||||||
JSMN_PRI_LITERAL = 0x0040, /*!< true, false, null */
|
|
||||||
JSMN_PRI_INTEGER = 0x0080, /*!< 0, 1 - 9 */
|
|
||||||
JSMN_PRI_SIGN = 0x0100, /*!< minus sign, '-' or plus sign, '+' */
|
|
||||||
JSMN_PRI_DECIMAL = 0x0200, /*!< deminal point '.' */
|
|
||||||
JSMN_PRI_EXPONENT = 0x0400, /*!< exponent, 'e' or 'E' */
|
|
||||||
|
|
||||||
JSMN_PRI_MINUS = JSMN_PRI_SIGN,
|
|
||||||
|
|
||||||
/* Parsing validation, expectations, and state information */
|
|
||||||
JSMN_PRI_CONTINUE = 0x0800, /*!< Allow a continuation of a PRIMITIVE */
|
|
||||||
JSMN_CLOSE = 0x1000, /*!< Close OBJECT '}' or ARRAY ']' */
|
|
||||||
JSMN_COLON = 0x2000, /*!< Colon ':' expected after KEY */
|
|
||||||
JSMN_COMMA = 0x4000, /*!< Comma ',' expected after VALUE */
|
|
||||||
JSMN_INSD_OBJ = 0x8000, /*!< Inside an OBJECT */
|
|
||||||
|
|
||||||
/* Parsing rules */
|
|
||||||
JSMN_ROOT_INIT = JSMN_ANY_TYPE | JSMN_VALUE,
|
|
||||||
#ifndef JSMN_PERMISSIVE
|
|
||||||
#ifndef JSMN_MULTIPLE_JSON
|
|
||||||
JSMN_ROOT = JSMN_UNDEFINED,
|
|
||||||
#else
|
|
||||||
JSMN_ROOT = JSMN_ANY_TYPE | JSMN_VALUE,
|
|
||||||
#endif
|
|
||||||
JSMN_OPEN_OBJECT = JSMN_KEY_TYPE | JSMN_KEY | JSMN_CLOSE | JSMN_INSD_OBJ,
|
|
||||||
JSMN_AFTR_OBJ_KEY = JSMN_VALUE | JSMN_INSD_OBJ | JSMN_COLON,
|
|
||||||
JSMN_AFTR_OBJ_VAL = JSMN_KEY | JSMN_CLOSE | JSMN_INSD_OBJ | JSMN_COMMA,
|
|
||||||
JSMN_OPEN_ARRAY = JSMN_ANY_TYPE | JSMN_VALUE | JSMN_CLOSE,
|
|
||||||
JSMN_AFTR_ARR_VAL = JSMN_VALUE | JSMN_CLOSE | JSMN_COMMA,
|
|
||||||
JSMN_AFTR_CLOSE = JSMN_CLOSE | JSMN_COMMA,
|
|
||||||
JSMN_AFTR_COLON = JSMN_ANY_TYPE | JSMN_VALUE | JSMN_INSD_OBJ,
|
|
||||||
JSMN_AFTR_COMMA_O = JSMN_KEY_TYPE | JSMN_KEY | JSMN_INSD_OBJ,
|
|
||||||
JSMN_AFTR_COMMA_A = JSMN_ANY_TYPE | JSMN_VALUE,
|
|
||||||
#else
|
|
||||||
JSMN_ROOT = JSMN_ANY_TYPE | JSMN_COLON | JSMN_COMMA,
|
|
||||||
JSMN_ROOT_AFTR_O = JSMN_ANY_TYPE | JSMN_COMMA,
|
|
||||||
JSMN_OPEN_OBJECT = JSMN_KEY_TYPE | JSMN_KEY | JSMN_CLOSE | JSMN_INSD_OBJ,
|
|
||||||
JSMN_AFTR_OBJ_KEY = JSMN_VALUE | JSMN_INSD_OBJ | JSMN_COLON,
|
|
||||||
JSMN_AFTR_OBJ_VAL = JSMN_ANY_TYPE | JSMN_CLOSE | JSMN_INSD_OBJ | JSMN_COMMA,
|
|
||||||
JSMN_OPEN_ARRAY = JSMN_ANY_TYPE | JSMN_VALUE | JSMN_CLOSE,
|
|
||||||
JSMN_AFTR_ARR_VAL = JSMN_ANY_TYPE | JSMN_CLOSE | JSMN_COMMA,
|
|
||||||
JSMN_AFTR_CLOSE = JSMN_ANY_TYPE | JSMN_CLOSE | JSMN_COMMA,
|
|
||||||
JSMN_AFTR_COLON = JSMN_ANY_TYPE | JSMN_VALUE | JSMN_INSD_OBJ,
|
|
||||||
JSMN_AFTR_COLON_R = JSMN_ANY_TYPE | JSMN_VALUE,
|
|
||||||
JSMN_AFTR_COMMA_O = JSMN_KEY_TYPE | JSMN_KEY | JSMN_INSD_OBJ,
|
|
||||||
JSMN_AFTR_COMMA_A = JSMN_ANY_TYPE | JSMN_VALUE,
|
|
||||||
JSMN_AFTR_COMMA_R = JSMN_ANY_TYPE,
|
|
||||||
#endif
|
|
||||||
} jsmntype;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* JSMN Error Codes
|
|
||||||
*/
|
|
||||||
typedef enum jsmnerr {
|
|
||||||
JSMN_SUCCESS = 0,
|
|
||||||
JSMN_ERROR_NOMEM = -1, /*!< Not enough tokens were provided */
|
|
||||||
JSMN_ERROR_LEN = -2, /*!< Input data too long */
|
|
||||||
JSMN_ERROR_INVAL = -3, /*!< Invalid character inside JSON string */
|
|
||||||
JSMN_ERROR_PART =
|
|
||||||
-4, /*!< The string is not a full JSON packet, more bytes expected */
|
|
||||||
JSMN_ERROR_UNMATCHED_BRACKETS =
|
|
||||||
-5, /*!< The JSON string has unmatched brackets */
|
|
||||||
} jsmnerr;
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* JSMN Boolean
|
|
||||||
*/
|
|
||||||
typedef enum jsmnbool {
|
|
||||||
JSMN_FALSE = 0,
|
|
||||||
JSMN_TRUE = 1,
|
|
||||||
} jsmnbool;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON token description.
|
|
||||||
*/
|
|
||||||
typedef struct jsmntok {
|
|
||||||
jsmntype type; /*!< type (object, array, string etc.) */
|
|
||||||
jsmnint start; /*!< start position in JSON data string */
|
|
||||||
jsmnint end; /*!< end position in JSON data string */
|
|
||||||
jsmnint size; /*!< number of children */
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
jsmnint parent; /*!< parent id */
|
|
||||||
#endif
|
|
||||||
#ifdef JSMN_NEXT_SIBLING
|
|
||||||
jsmnint next_sibling; /*!< next sibling id */
|
|
||||||
#endif
|
|
||||||
} jsmntok;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON parser
|
|
||||||
*
|
|
||||||
* Contains an array of token blocks available. Also stores
|
|
||||||
* the string being parsed now and current position in that string.
|
|
||||||
*/
|
|
||||||
typedef struct jsmnparser {
|
|
||||||
jsmnint pos; /*!< offset in the JSON string */
|
|
||||||
jsmnint toknext; /*!< next token to allocate */
|
|
||||||
/*!< when tokens == NULL, keeps track of container types to a depth of
|
|
||||||
* (sizeof(jsmnint) * 8) */
|
|
||||||
jsmnint toksuper; /*!< superior token node, e.g. parent object or array */
|
|
||||||
/*!< when tokens == NULL, toksuper represents container depth */
|
|
||||||
jsmntype expected; /*!< Expected jsmn type(s) */
|
|
||||||
} jsmnparser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create JSON parser over an array of tokens
|
|
||||||
*
|
|
||||||
* @param[out] parser jsmn parser
|
|
||||||
*/
|
|
||||||
JSMN_API
|
|
||||||
void jsmn_init(jsmnparser *parser);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Run JSON parser
|
|
||||||
*
|
|
||||||
* It parses a JSON data string into and array of tokens, each
|
|
||||||
* describing a single JSON object.
|
|
||||||
*
|
|
||||||
* @param[in,out] parser jsmn parser
|
|
||||||
* @param[in] js JSON data string
|
|
||||||
* @param[in] len JSON data string length
|
|
||||||
* @param[in,out] tokens pointer to memory allocated for tokens or NULL
|
|
||||||
* @param[in] num_tokens number of tokens allocated
|
|
||||||
* @return jsmnint number of tokens found or ERRNO
|
|
||||||
*/
|
|
||||||
JSMN_API
|
|
||||||
jsmnint jsmn_parse(jsmnparser *parser, const char *js, const size_t len,
|
|
||||||
jsmntok *tokens, const size_t num_tokens);
|
|
||||||
|
|
||||||
#endif /* JSMN_H */
|
|
137
vendor/JSMN/include/jsmn_defines.h
vendored
137
vendor/JSMN/include/jsmn_defines.h
vendored
@ -1,137 +0,0 @@
|
|||||||
#ifndef JSMN_DEFINES
|
|
||||||
#define JSMN_DEFINES
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* If nothing is defined, the default definitions are JSMN_PARENT_LINKS and *
|
|
||||||
* JSMN_NEXT_SIBLING with a jsmntok field size of 4 bytes (unsigned int). *
|
|
||||||
* This will parse one json object in a buffer at a time and return after a *
|
|
||||||
* successful json object parse. To check if there is more data in the *
|
|
||||||
* buffer that hasn't been parsed, run jsmn_eof. !*/
|
|
||||||
|
|
||||||
/*! @def JSMN_PARENT_LINKS
|
|
||||||
* @brief Adds a parent field to the token
|
|
||||||
*
|
|
||||||
* This decreases the initial time required to parse a json buffer and
|
|
||||||
* simplifies the post-processing of token array by adding a link to the id of
|
|
||||||
* a token's parent.
|
|
||||||
* This is enabled by default and highly recommended.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! @def JSMN_NEXT_SIBLING
|
|
||||||
* @brief Adds a next_sibling field to the token
|
|
||||||
*
|
|
||||||
* This simplifies the post-processing of token array by adding a link to the id
|
|
||||||
* of a token's next sibling.
|
|
||||||
* This is enabled by default and highly recommended.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! @def JSMN_UTF8
|
|
||||||
* @brief Add UTF-8 functionality
|
|
||||||
*
|
|
||||||
* This allows for stricter parsing of json strings and also allows for the
|
|
||||||
* conversion of escaped characters (\uXXXX) to UTF-8 and back.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! @def JSMN_LOW_MEMORY
|
|
||||||
* @brief Enables defintions that reduce jsmn's memory footprint for small
|
|
||||||
* devices and doesn't enable definitions that increase it's footprint.
|
|
||||||
*
|
|
||||||
* This enables definitions that reduce jsmn's memory footprint at the cost of
|
|
||||||
* CPU usage. This is useful for small devices that don't parse json objects
|
|
||||||
* often and have restrictive memory requirements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! @def JSMN_SHORT_TOKENS
|
|
||||||
* @brief Changes the tokens field size from a uint32_t to a uint16_t
|
|
||||||
*
|
|
||||||
* This reduces the jsmntok size by half by changing jsmntok field sizes
|
|
||||||
* from an unsigned int to an unsigned short. NOTE: This reduces the maximum
|
|
||||||
* possible json string length from 4,294,967,295 to 65,535 minus the size of
|
|
||||||
* jsmnerr.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! @def JSMN_PERMISSIVE
|
|
||||||
* @brief Enables all PERMISSIVE definitions
|
|
||||||
*
|
|
||||||
* Enables JSMN_PERMISSIVE_KEY, JSMN_PERMISSIVE_PRIMITIVE, and
|
|
||||||
* JSMN_MULTIPLE_JSON
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! @def JSMN_PERMISSIVE_KEY
|
|
||||||
* @brief Allows PRIMITIVEs to be OBJECT KEYs
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! @def JSMN_PERMISSIVE_PRIMITIVE
|
|
||||||
* @brief Allows PRIMITIVEs to be any contiguous value
|
|
||||||
*
|
|
||||||
* This allows PRIMIVITEs to be any contiguous value that does not contain a
|
|
||||||
* character that has a special meaning to json (`{}[]",:`). NOTE: There is no
|
|
||||||
* validation of JSMN_PRI_MINUS, JSNM_PRI_DECIMAL, or JSMN_PRI_EXPONENT;
|
|
||||||
* everything is the base type JSMN_PRIMITIVE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! @def JSMN_MULTIPLE_JSON
|
|
||||||
* @brief Allows multiple json objects in a complete buffer
|
|
||||||
*
|
|
||||||
* This allows jsmn to parse multiple json objects in a single buffer.
|
|
||||||
* NOTE: If a single json object is malformed jsmn_parse will return with
|
|
||||||
* an error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! @def JSMN_MULTIPLE_JSON_FAIL
|
|
||||||
* @brief Fails if there is more than one json object in a buffer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef JSMN_API
|
|
||||||
# ifdef JSMN_STATIC
|
|
||||||
# define JSMN_API static
|
|
||||||
# else
|
|
||||||
# define JSMN_API extern
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef JSMN_LOW_MEMORY
|
|
||||||
|
|
||||||
# ifndef JSMN_PARENT_LINKS
|
|
||||||
# define JSMN_PARENT_LINKS
|
|
||||||
# endif
|
|
||||||
# ifndef JSMN_NEXT_SIBLING
|
|
||||||
# define JSMN_NEXT_SIBLING
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
# ifndef JSMN_SHORT_TOKENS
|
|
||||||
# define JSMN_SHORT_TOKENS
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
# ifndef JSMN_PERMISSIVE_KEY
|
|
||||||
# define JSMN_PERMISSIVE_KEY
|
|
||||||
# endif
|
|
||||||
# ifndef JSMN_PERMISSIVE_PRIMITIVE
|
|
||||||
# define JSMN_PERMISSIVE_PRIMITIVE
|
|
||||||
# endif
|
|
||||||
# ifndef JSMN_MULTIPLE_JSON
|
|
||||||
# define JSMN_MULTIPLE_JSON
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JSMN_MULTIPLE_JSON_FAIL
|
|
||||||
# undef JSMN_MULTIPLE_JSON
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (defined(__linux__) || defined(__APPLE__) || defined(ARDUINO))
|
|
||||||
# define JSMN_EXPORT __attribute__((visibility("default")))
|
|
||||||
# define JSMN_LOCAL __attribute__((visibility("hidden")))
|
|
||||||
#elif (defined(_WIN32))
|
|
||||||
# define JSMN_EXPORT __declspec(dllexport)
|
|
||||||
# define JSMN_LOCAL
|
|
||||||
#else
|
|
||||||
# define JSMN_EXPORT
|
|
||||||
# define JSMN_LOCAL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* JSMN_DEFINES */
|
|
857
vendor/JSMN/jsmn.c
vendored
857
vendor/JSMN/jsmn.c
vendored
@ -1,857 +0,0 @@
|
|||||||
/*
|
|
||||||
* MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2010 Serge Zaitsev
|
|
||||||
*
|
|
||||||
* 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 "jsmn.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocates a fresh unused token from the token pool.
|
|
||||||
*/
|
|
||||||
static jsmntok *jsmn_alloc_token(jsmnparser *parser, jsmntok *tokens,
|
|
||||||
const size_t num_tokens) {
|
|
||||||
if (parser->toknext >= num_tokens) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsmntok *tok;
|
|
||||||
tok = &tokens[parser->toknext++];
|
|
||||||
tok->start = tok->end = JSMN_NEG;
|
|
||||||
tok->size = 0;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
tok->parent = JSMN_NEG;
|
|
||||||
#endif
|
|
||||||
#ifdef JSMN_NEXT_SIBLING
|
|
||||||
tok->next_sibling = JSMN_NEG;
|
|
||||||
#endif
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills token type and boundaries.
|
|
||||||
*/
|
|
||||||
static void jsmn_fill_token(jsmntok *token, const jsmntype type,
|
|
||||||
const jsmnint start, const jsmnint end) {
|
|
||||||
token->type = type;
|
|
||||||
token->start = start;
|
|
||||||
token->end = end;
|
|
||||||
token->size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JSMN_NEXT_SIBLING
|
|
||||||
/**
|
|
||||||
* Set previous child's next_sibling to current token
|
|
||||||
*/
|
|
||||||
static void jsmn_next_sibling(jsmnparser *parser, jsmntok *tokens) {
|
|
||||||
jsmnint sibling;
|
|
||||||
|
|
||||||
/* Start with parent's first child */
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
sibling = parser->toksuper + 1;
|
|
||||||
} else {
|
|
||||||
sibling = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the first child is the current token */
|
|
||||||
if (sibling == parser->toknext - 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loop until we find previous sibling */
|
|
||||||
while (tokens[sibling].next_sibling != JSMN_NEG) {
|
|
||||||
sibling = tokens[sibling].next_sibling;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set previous sibling's next_sibling to current token */
|
|
||||||
tokens[sibling].next_sibling = parser->toknext - 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static jsmnbool is_whitespace(const char c) {
|
|
||||||
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
|
|
||||||
return JSMN_TRUE;
|
|
||||||
}
|
|
||||||
return JSMN_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static jsmnbool is_hexadecimal(const char c) {
|
|
||||||
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
|
|
||||||
(c >= 'a' && c <= 'f')) {
|
|
||||||
return JSMN_TRUE;
|
|
||||||
}
|
|
||||||
return JSMN_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: Confusing function name */
|
|
||||||
static jsmnbool is_character(const char c) {
|
|
||||||
if ((c >= 0x20 && c <= 0x21) || (c >= 0x23 && c <= 0x5B) || (c >= 0x5D)) {
|
|
||||||
return JSMN_TRUE;
|
|
||||||
}
|
|
||||||
return JSMN_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static jsmnbool is_special(const char c) {
|
|
||||||
if (c == '{' || c == '}' || c == '[' || c == ']' || c == '"' || c == ':' ||
|
|
||||||
c == ',') {
|
|
||||||
return JSMN_TRUE;
|
|
||||||
}
|
|
||||||
return JSMN_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills next available token with JSON primitive.
|
|
||||||
*/
|
|
||||||
static jsmnint jsmn_parse_primitive(jsmnparser *parser, const char *js,
|
|
||||||
const size_t len, jsmntok *tokens,
|
|
||||||
const size_t num_tokens) {
|
|
||||||
/* If a PRIMITIVE wasn't expected */
|
|
||||||
if (!(parser->expected & (JSMN_PRIMITIVE | JSMN_PRI_CONTINUE))) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsmnint pos;
|
|
||||||
jsmntype type;
|
|
||||||
jsmntype expected = JSMN_CLOSE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find beginning of the primitive
|
|
||||||
* TODO: See if it is really necessary.
|
|
||||||
* Shouldn't parser stay at the last valid state in case of an error?
|
|
||||||
* In this case it should be right before primitive is parsed.
|
|
||||||
*/
|
|
||||||
if (!(parser->expected & JSMN_PRI_CONTINUE)) {
|
|
||||||
pos = parser->pos;
|
|
||||||
} else {
|
|
||||||
if (tokens != NULL) {
|
|
||||||
pos = tokens[parser->toknext - 1].start;
|
|
||||||
} else {
|
|
||||||
pos = parser->pos;
|
|
||||||
while (pos != JSMN_NEG && !is_whitespace(js[pos]) &&
|
|
||||||
!is_special(js[pos]) && is_character(js[pos])) {
|
|
||||||
pos--;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type = JSMN_PRIMITIVE;
|
|
||||||
|
|
||||||
#ifndef JSMN_PERMISSIVE_PRIMITIVE
|
|
||||||
if (js[pos] == 't' || js[pos] == 'f' || js[pos] == 'n') {
|
|
||||||
char *literal = NULL;
|
|
||||||
jsmnint size = 0;
|
|
||||||
if (js[pos] == 't') {
|
|
||||||
literal = "true";
|
|
||||||
size = 4;
|
|
||||||
} else if (js[pos] == 'f') {
|
|
||||||
literal = "false";
|
|
||||||
size = 5;
|
|
||||||
} else if (js[pos] == 'n') {
|
|
||||||
literal = "null";
|
|
||||||
size = 4;
|
|
||||||
}
|
|
||||||
jsmnint i;
|
|
||||||
for (i = 1, pos++; i < size; i++, pos++) {
|
|
||||||
if (pos == len || js[pos] == '\0') {
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
} else if (js[pos] != literal[i]) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type |= JSMN_PRI_LITERAL;
|
|
||||||
if (pos == len || js[pos] == '\0') {
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
expected = JSMN_PRI_MINUS | JSMN_PRI_INTEGER;
|
|
||||||
for (; pos < len && js[pos] != '\0'; pos++) {
|
|
||||||
switch (js[pos]) {
|
|
||||||
case '0':
|
|
||||||
if (!(expected & JSMN_PRI_INTEGER)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
if (type & JSMN_PRI_EXPONENT) {
|
|
||||||
expected = JSMN_PRI_INTEGER | JSMN_CLOSE;
|
|
||||||
} else if (type & JSMN_PRI_DECIMAL) {
|
|
||||||
expected = JSMN_PRI_INTEGER | JSMN_PRI_EXPONENT | JSMN_CLOSE;
|
|
||||||
} else if (parser->pos == pos ||
|
|
||||||
(parser->pos + 1 == pos && (type & JSMN_PRI_MINUS))) {
|
|
||||||
expected = JSMN_PRI_DECIMAL | JSMN_PRI_EXPONENT | JSMN_CLOSE;
|
|
||||||
} else {
|
|
||||||
expected = JSMN_PRI_INTEGER | JSMN_PRI_DECIMAL | JSMN_PRI_EXPONENT |
|
|
||||||
JSMN_CLOSE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
case '8':
|
|
||||||
case '9':
|
|
||||||
if (!(expected & JSMN_PRI_INTEGER)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
if (type & JSMN_PRI_EXPONENT) {
|
|
||||||
expected = JSMN_PRI_INTEGER | JSMN_CLOSE;
|
|
||||||
} else if (type & JSMN_PRI_DECIMAL) {
|
|
||||||
expected = JSMN_PRI_INTEGER | JSMN_PRI_EXPONENT | JSMN_CLOSE;
|
|
||||||
} else {
|
|
||||||
expected = JSMN_PRI_INTEGER | JSMN_PRI_DECIMAL | JSMN_PRI_EXPONENT |
|
|
||||||
JSMN_CLOSE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
if (!(expected & JSMN_PRI_MINUS)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
expected = JSMN_PRI_INTEGER;
|
|
||||||
if (parser->pos == pos) {
|
|
||||||
type |= JSMN_PRI_MINUS;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
if (!(expected & JSMN_PRI_SIGN)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
expected = JSMN_PRI_INTEGER;
|
|
||||||
break;
|
|
||||||
case '.':
|
|
||||||
if (!(expected & JSMN_PRI_DECIMAL)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
type |= JSMN_PRI_DECIMAL;
|
|
||||||
expected = JSMN_PRI_INTEGER;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
case 'E':
|
|
||||||
if (!(expected & JSMN_PRI_EXPONENT)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
type |= JSMN_PRI_EXPONENT;
|
|
||||||
expected = JSMN_PRI_SIGN | JSMN_PRI_INTEGER;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!(expected & JSMN_CLOSE)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
goto check_primitive_border;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!(expected & JSMN_CLOSE)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
} else {
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
check_primitive_border:
|
|
||||||
switch (js[pos]) {
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
case ',':
|
|
||||||
case '}':
|
|
||||||
case ']':
|
|
||||||
goto found;
|
|
||||||
case '"':
|
|
||||||
case ':':
|
|
||||||
case '{':
|
|
||||||
case '[':
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
case '\0':
|
|
||||||
goto found;
|
|
||||||
default:
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for (; pos < len && js[pos] != '\0'; pos++) {
|
|
||||||
switch (js[pos]) {
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
case ',':
|
|
||||||
case '}':
|
|
||||||
case ']':
|
|
||||||
case ':':
|
|
||||||
|
|
||||||
case '{':
|
|
||||||
case '[':
|
|
||||||
case '"':
|
|
||||||
goto found;
|
|
||||||
default: /* to quiet a warning from gcc */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!is_character(js[pos])) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
found:
|
|
||||||
expected = parser->expected;
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
/* OBJECT KEY, strict query */
|
|
||||||
if ((parser->expected & (JSMN_KEY | JSMN_INSD_OBJ)) ==
|
|
||||||
(JSMN_KEY | JSMN_INSD_OBJ)) {
|
|
||||||
parser->expected = JSMN_AFTR_OBJ_KEY;
|
|
||||||
type |= JSMN_KEY | JSMN_INSD_OBJ;
|
|
||||||
/* OBJECT VALUE, VALUE is implicit */
|
|
||||||
} else if (parser->expected & JSMN_INSD_OBJ) {
|
|
||||||
parser->expected = JSMN_AFTR_OBJ_VAL;
|
|
||||||
type |= JSMN_VALUE | JSMN_INSD_OBJ;
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
/* OBJECT VALUE at the ROOT level */
|
|
||||||
} else if (parser->toksuper == JSMN_NEG) {
|
|
||||||
parser->expected = JSMN_ROOT_AFTR_O;
|
|
||||||
type |= JSMN_VALUE;
|
|
||||||
#endif
|
|
||||||
/* ARRAY VALUE, VALUE is implicit */
|
|
||||||
} else {
|
|
||||||
parser->expected = JSMN_AFTR_ARR_VAL;
|
|
||||||
type |= JSMN_VALUE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parser->expected = JSMN_ROOT;
|
|
||||||
type |= JSMN_VALUE;
|
|
||||||
}
|
|
||||||
if (pos == len || js[pos] == '\0') {
|
|
||||||
parser->expected |= JSMN_PRI_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens == NULL) {
|
|
||||||
parser->pos = pos - 1;
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsmntok *token;
|
|
||||||
if (!(expected & JSMN_PRI_CONTINUE)) {
|
|
||||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
|
||||||
if (token == NULL) {
|
|
||||||
parser->expected = expected;
|
|
||||||
return JSMN_ERROR_NOMEM;
|
|
||||||
}
|
|
||||||
jsmn_fill_token(token, type, parser->pos, pos);
|
|
||||||
} else {
|
|
||||||
token = &tokens[parser->toknext - 1];
|
|
||||||
jsmn_fill_token(token, type, token->start, pos);
|
|
||||||
}
|
|
||||||
parser->pos = pos;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
token->parent = parser->toksuper;
|
|
||||||
#endif
|
|
||||||
#ifdef JSMN_NEXT_SIBLING
|
|
||||||
jsmn_next_sibling(parser, tokens);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
if (!(expected & JSMN_PRI_CONTINUE)) {
|
|
||||||
tokens[parser->toksuper].size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(tokens[parser->toksuper].type & JSMN_CONTAINER)) {
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
parser->toksuper = tokens[parser->toksuper].parent;
|
|
||||||
#else
|
|
||||||
jsmnint i;
|
|
||||||
for (i = parser->toksuper; i != JSMN_NEG; i--) {
|
|
||||||
if (tokens[i].type & JSMN_CONTAINER && tokens[i].end == JSMN_NEG) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
if (i == JSMN_NEG) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parser->pos--;
|
|
||||||
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills next token with JSON string.
|
|
||||||
*/
|
|
||||||
static jsmnint jsmn_parse_string(jsmnparser *parser, const char *js,
|
|
||||||
const size_t len, jsmntok *tokens,
|
|
||||||
const size_t num_tokens) {
|
|
||||||
/* If a STRING wasn't expected */
|
|
||||||
if (!(parser->expected & JSMN_STRING)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len >= JSMN_NEG) {
|
|
||||||
return JSMN_ERROR_LEN;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsmnint pos;
|
|
||||||
pos = parser->pos;
|
|
||||||
|
|
||||||
/* Skip starting quote */
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
char c;
|
|
||||||
for (; pos < len && js[pos] != '\0'; pos++) {
|
|
||||||
c = js[pos];
|
|
||||||
|
|
||||||
/* Quote: end of string */
|
|
||||||
if (c == '\"') {
|
|
||||||
jsmntype expected = parser->expected;
|
|
||||||
jsmntype type;
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
/* OBJECT KEY, strict query */
|
|
||||||
if ((parser->expected & (JSMN_INSD_OBJ | JSMN_KEY)) ==
|
|
||||||
(JSMN_INSD_OBJ | JSMN_KEY)) {
|
|
||||||
parser->expected = JSMN_AFTR_OBJ_KEY;
|
|
||||||
type = JSMN_STRING | JSMN_KEY | JSMN_INSD_OBJ;
|
|
||||||
/* OBJECT VALUE, VALUE is implicit */
|
|
||||||
} else if (parser->expected & JSMN_INSD_OBJ) {
|
|
||||||
parser->expected = JSMN_AFTR_OBJ_VAL;
|
|
||||||
type = JSMN_STRING | JSMN_VALUE | JSMN_INSD_OBJ;
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
/* OBJECT VALUE at the ROOT level */
|
|
||||||
} else if (parser->toksuper == JSMN_NEG) {
|
|
||||||
parser->expected = JSMN_ROOT_AFTR_O;
|
|
||||||
type = JSMN_STRING | JSMN_VALUE;
|
|
||||||
#endif
|
|
||||||
/* ARRAY VALUE, VALUE is implicit */
|
|
||||||
} else {
|
|
||||||
parser->expected = JSMN_AFTR_ARR_VAL;
|
|
||||||
type = JSMN_STRING | JSMN_VALUE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parser->expected = JSMN_ROOT;
|
|
||||||
type = JSMN_STRING | JSMN_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens == NULL) {
|
|
||||||
parser->pos = pos;
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsmntok *token;
|
|
||||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
|
||||||
if (token == NULL) {
|
|
||||||
parser->expected = expected;
|
|
||||||
return JSMN_ERROR_NOMEM;
|
|
||||||
}
|
|
||||||
jsmn_fill_token(token, type, parser->pos + 1, pos);
|
|
||||||
parser->pos = pos;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
token->parent = parser->toksuper;
|
|
||||||
#endif
|
|
||||||
#ifdef JSMN_NEXT_SIBLING
|
|
||||||
jsmn_next_sibling(parser, tokens);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
tokens[parser->toksuper].size++;
|
|
||||||
|
|
||||||
if (!(tokens[parser->toksuper].type & JSMN_CONTAINER)) {
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
parser->toksuper = tokens[parser->toksuper].parent;
|
|
||||||
#else
|
|
||||||
jsmnint i;
|
|
||||||
for (i = parser->toksuper; i != JSMN_NEG; i--) {
|
|
||||||
if (tokens[i].type & JSMN_CONTAINER && tokens[i].end == JSMN_NEG) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
if (i == JSMN_NEG) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Backslash: Quoted symbol expected */
|
|
||||||
if (c == '\\' && pos + 1 < len) {
|
|
||||||
pos++;
|
|
||||||
switch (js[pos]) {
|
|
||||||
/* Allowed escaped symbols */
|
|
||||||
case '\"':
|
|
||||||
case '\\':
|
|
||||||
case '/':
|
|
||||||
case 'b':
|
|
||||||
case 'f':
|
|
||||||
case 'n':
|
|
||||||
case 'r':
|
|
||||||
case 't':
|
|
||||||
break;
|
|
||||||
/* Allows escaped symbol \uXXXX */
|
|
||||||
case 'u':
|
|
||||||
pos++;
|
|
||||||
jsmnint i;
|
|
||||||
for (i = pos + 4; pos < i; pos++) {
|
|
||||||
if (pos == len || js[pos] == '\0') {
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
}
|
|
||||||
/* If it isn't a hex character we have an error */
|
|
||||||
if (!is_hexadecimal(js[pos])) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pos--;
|
|
||||||
break;
|
|
||||||
/* Unexpected symbol */
|
|
||||||
default:
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* form feed, new line, carraige return, tab, and vertical tab not allowed
|
|
||||||
*/
|
|
||||||
else if (c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
}
|
|
||||||
|
|
||||||
static jsmnint jsmn_parse_container_open(jsmnparser *parser, const char c,
|
|
||||||
jsmntok *tokens,
|
|
||||||
const size_t num_tokens) {
|
|
||||||
/* If an OBJECT or ARRAY wasn't expected */
|
|
||||||
if (!(parser->expected & JSMN_CONTAINER)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsmntype type;
|
|
||||||
if (c == '{') {
|
|
||||||
parser->expected = JSMN_OPEN_OBJECT;
|
|
||||||
type = JSMN_OBJECT | JSMN_VALUE;
|
|
||||||
} else {
|
|
||||||
parser->expected = JSMN_OPEN_ARRAY;
|
|
||||||
type = JSMN_ARRAY | JSMN_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens == NULL) {
|
|
||||||
parser->toksuper++;
|
|
||||||
if (parser->toksuper < (sizeof(jsmnint) * 8) &&
|
|
||||||
parser->expected & JSMN_INSD_OBJ) {
|
|
||||||
parser->toknext |= (1 << parser->toksuper);
|
|
||||||
}
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser->toksuper != JSMN_NEG &&
|
|
||||||
tokens[parser->toksuper].type & JSMN_INSD_OBJ) {
|
|
||||||
type |= JSMN_INSD_OBJ;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsmntok *token;
|
|
||||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
|
||||||
if (token == NULL) {
|
|
||||||
return JSMN_ERROR_NOMEM;
|
|
||||||
}
|
|
||||||
jsmn_fill_token(token, type, parser->pos, JSMN_NEG);
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
token->parent = parser->toksuper;
|
|
||||||
#endif
|
|
||||||
#ifdef JSMN_NEXT_SIBLING
|
|
||||||
jsmn_next_sibling(parser, tokens);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
tokens[parser->toksuper].size++;
|
|
||||||
}
|
|
||||||
parser->toksuper = parser->toknext - 1;
|
|
||||||
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static jsmnint jsmn_parse_container_close(jsmnparser *parser, const char c,
|
|
||||||
jsmntok *tokens) {
|
|
||||||
/* If an OBJECT or ARRAY CLOSE wasn't expected */
|
|
||||||
if (!(parser->expected & JSMN_CLOSE)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens == NULL) {
|
|
||||||
if (parser->toksuper < (sizeof(jsmnint) * 8)) {
|
|
||||||
jsmntype type;
|
|
||||||
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
|
||||||
if ((((parser->toknext & (1 << parser->toksuper)) == 1) &&
|
|
||||||
!(type & JSMN_OBJECT)) ||
|
|
||||||
(((parser->toknext & (1 << parser->toksuper)) == 0) &&
|
|
||||||
!(type & JSMN_ARRAY))) {
|
|
||||||
return JSMN_ERROR_UNMATCHED_BRACKETS;
|
|
||||||
}
|
|
||||||
parser->toknext &= ~(1 << parser->toksuper);
|
|
||||||
}
|
|
||||||
parser->toksuper--;
|
|
||||||
} else {
|
|
||||||
jsmntype type;
|
|
||||||
jsmntok *token;
|
|
||||||
|
|
||||||
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
if (parser->toksuper == JSMN_NEG) {
|
|
||||||
return JSMN_ERROR_UNMATCHED_BRACKETS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
token = &tokens[parser->toksuper];
|
|
||||||
if (!(token->type & type) || token->end != JSMN_NEG) {
|
|
||||||
return JSMN_ERROR_UNMATCHED_BRACKETS;
|
|
||||||
}
|
|
||||||
token->end = parser->pos + 1;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
if (token->type & JSMN_INSD_OBJ) {
|
|
||||||
if (tokens[token->parent].type & JSMN_CONTAINER) {
|
|
||||||
parser->toksuper = token->parent;
|
|
||||||
} else {
|
|
||||||
parser->toksuper = tokens[token->parent].parent;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parser->toksuper = token->parent;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
jsmnint i;
|
|
||||||
for (i = parser->toksuper - 1; i != JSMN_NEG; i--) {
|
|
||||||
if (tokens[i].type & JSMN_CONTAINER && tokens[i].end == JSMN_NEG) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i == JSMN_NEG) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
parser->expected = JSMN_AFTR_CLOSE;
|
|
||||||
} else {
|
|
||||||
parser->expected = JSMN_ROOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static jsmnint jsmn_parse_colon(jsmnparser *parser, jsmntok *tokens) {
|
|
||||||
/* If a COLON wasn't expected; strict check because it is a complex enum */
|
|
||||||
if (!((parser->expected & JSMN_COLON) == JSMN_COLON)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
parser->expected = JSMN_AFTR_COLON;
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
} else {
|
|
||||||
parser->expected = JSMN_AFTR_COLON_R;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens == NULL) {
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
tokens[parser->toknext - 1].type &= ~JSMN_VALUE;
|
|
||||||
tokens[parser->toknext - 1].type |= JSMN_KEY;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
parser->toksuper = parser->toknext - 1;
|
|
||||||
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static jsmnint jsmn_parse_comma(jsmnparser *parser, jsmntok *tokens) {
|
|
||||||
/* If a COMMA wasn't expected; strict check because it is a complex enum */
|
|
||||||
if (!((parser->expected & JSMN_COMMA) == JSMN_COMMA)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsmntype type = JSMN_UNDEFINED;
|
|
||||||
if (tokens == NULL) {
|
|
||||||
if (parser->toksuper < (sizeof(jsmnint) * 8) &&
|
|
||||||
parser->toknext & (1 << parser->toksuper)) {
|
|
||||||
type = JSMN_INSD_OBJ;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
type = tokens[parser->toksuper].type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
if (type & (JSMN_OBJECT | JSMN_INSD_OBJ)) {
|
|
||||||
parser->expected = JSMN_AFTR_COMMA_O;
|
|
||||||
} else {
|
|
||||||
parser->expected = JSMN_AFTR_COMMA_A;
|
|
||||||
}
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
} else {
|
|
||||||
parser->expected = JSMN_AFTR_COMMA_R;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens == NULL) {
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JSMN_PERMISSIVE
|
|
||||||
tokens[parser->toknext - 1].type |= JSMN_VALUE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return JSMN_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse JSON string and fill tokens.
|
|
||||||
*/
|
|
||||||
JSMN_API
|
|
||||||
jsmnint jsmn_parse(jsmnparser *parser, const char *js, const size_t len,
|
|
||||||
jsmntok *tokens, const size_t num_tokens) {
|
|
||||||
jsmnint r;
|
|
||||||
jsmnint count = parser->toknext;
|
|
||||||
|
|
||||||
char c;
|
|
||||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
|
||||||
#ifndef JSMN_MULTIPLE_JSON_FAIL
|
|
||||||
if (parser->expected == JSMN_UNDEFINED) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
c = js[parser->pos];
|
|
||||||
switch (c) {
|
|
||||||
case '{':
|
|
||||||
case '[':
|
|
||||||
r = jsmn_parse_container_open(parser, c, tokens, num_tokens);
|
|
||||||
if (r != JSMN_SUCCESS) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
break;
|
|
||||||
case '}':
|
|
||||||
case ']':
|
|
||||||
r = jsmn_parse_container_close(parser, c, tokens);
|
|
||||||
if (r != JSMN_SUCCESS) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '\"':
|
|
||||||
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
|
|
||||||
if (r != JSMN_SUCCESS) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
break;
|
|
||||||
case ':':
|
|
||||||
r = jsmn_parse_colon(parser, tokens);
|
|
||||||
if (r != JSMN_SUCCESS) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ',':
|
|
||||||
r = jsmn_parse_comma(parser, tokens);
|
|
||||||
if (r != JSMN_SUCCESS) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
/* Valid whitespace */
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
case '\n':
|
|
||||||
case '\r':
|
|
||||||
break;
|
|
||||||
#ifndef JSMN_PERMISSIVE_PRIMITIVE
|
|
||||||
/* rfc8259: PRIMITIVEs are numbers and booleans */
|
|
||||||
case '-':
|
|
||||||
case '0':
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
case '8':
|
|
||||||
case '9':
|
|
||||||
case 't':
|
|
||||||
case 'f':
|
|
||||||
case 'n':
|
|
||||||
#else
|
|
||||||
/* In permissive mode every unquoted value is a PRIMITIVE */
|
|
||||||
default:
|
|
||||||
#endif
|
|
||||||
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
|
|
||||||
if (r != JSMN_SUCCESS) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifndef JSMN_PERMISSIVE
|
|
||||||
/* Unexpected char */
|
|
||||||
default:
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parser->toksuper != JSMN_NEG) {
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 0) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (parser->pos < len && is_whitespace(js[parser->pos])) {
|
|
||||||
parser->pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new parser based over a given buffer with an array of tokens
|
|
||||||
* available.
|
|
||||||
*/
|
|
||||||
JSMN_API
|
|
||||||
void jsmn_init(jsmnparser *parser) {
|
|
||||||
parser->pos = 0;
|
|
||||||
parser->toknext = 0;
|
|
||||||
parser->toksuper = JSMN_NEG;
|
|
||||||
parser->expected = JSMN_ROOT_INIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
5
vendor/SAJSON/CMakeLists.txt
vendored
Normal file
5
vendor/SAJSON/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Create the SAJSON library
|
||||||
|
add_library(SAJSON STATIC include/sajson.h sajson.cpp)
|
||||||
|
# Library includes
|
||||||
|
target_include_directories(SAJSON PRIVATE ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
target_include_directories(SAJSON PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
2600
vendor/SAJSON/include/sajson.h
vendored
Normal file
2600
vendor/SAJSON/include/sajson.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
vendor/SAJSON/sajson.cpp
vendored
Normal file
1
vendor/SAJSON/sajson.cpp
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include <sajson.h>
|
Loading…
Reference in New Issue
Block a user