//file name: JsonParserGeneratorRK.cpp
#include "Particle.h"
#include "JsonParserGeneratorRK.h"
JsonBuffer::JsonBuffer() : buffer(0), bufferLen(0), offset(0), staticBuffers(false) {
}
JsonBuffer::~JsonBuffer() {
if (!staticBuffers && buffer) {
free(buffer);
}
}
JsonBuffer::JsonBuffer(char *buffer, size_t bufferLen) : buffer(buffer), bufferLen(bufferLen), offset(0), staticBuffers(true) {
}
bool JsonBuffer::allocate(size_t len) {
if (!staticBuffers) {
char *newBuffer;
if (buffer) {
newBuffer = (char *) realloc(buffer, len);
}
else {
newBuffer = (char *) malloc(len);
}
if (newBuffer) {
buffer = newBuffer;
bufferLen = len;
return true;
}
else {
return false;
}
}
else {
return false;
}
}
bool JsonBuffer::addData(const char *data, size_t dataLen) {
if (!buffer || (offset + dataLen) > bufferLen) {
// Need to allocate more space for data
if (!allocate(offset + dataLen)) {
return false;
}
}
memcpy(&buffer[offset], data, dataLen);
offset += dataLen;
return true;
}
void JsonBuffer::clear() {
offset = 0;
}
//
JsonParser::JsonParser() : JsonBuffer(), tokens(0), maxTokens(0) {
}
JsonParser::JsonParser(char *buffer, size_t bufferLen, JsonParserGeneratorRK::jsmntok_t *tokens, size_t maxTokens) :
JsonBuffer(buffer, bufferLen), tokens(tokens), maxTokens(maxTokens) {
}
JsonParser::~JsonParser() {
if (!staticBuffers && tokens) {
free(tokens);
}
}
bool JsonParser::allocateTokens(size_t maxTokens) {
if (!staticBuffers) {
JsonParserGeneratorRK::jsmntok_t *newTokens;
if (tokens) {
newTokens = (JsonParserGeneratorRK::jsmntok_t *)realloc(buffer, sizeof(JsonParserGeneratorRK::jsmntok_t) * maxTokens);
}
else {
newTokens = (JsonParserGeneratorRK::jsmntok_t *)malloc(sizeof(JsonParserGeneratorRK::jsmntok_t) * maxTokens);
}
if (newTokens) {
tokens = newTokens;
this->maxTokens = maxTokens;
return true;
}
else {
return false;
}
}
else {
return false;
}
}
bool JsonParser::parse() {
if (tokens) {
// Try to use the existing token buffer if possible
JsonParserGeneratorRK::jsmn_init(&parser);
int result = JsonParserGeneratorRK::jsmn_parse(&parser, buffer, offset, tokens, maxTokens);
if (result == JsonParserGeneratorRK::JSMN_ERROR_NOMEM) {
if (staticBuffers) {
// If using static buffers and there is not enough space, fail
return false;
}
free(tokens);
tokens = 0;
maxTokens = 0;
}
else
if (result < 0) {
// Failed to parse: JSMN_ERROR_INVAL or JSMN_ERROR_PART
return false;
}
else {
tokensEnd = &tokens[result];
return true;
}
}
// Pass 1: determine now many tokens we need
JsonParserGeneratorRK::jsmn_init(&parser);
int result = JsonParserGeneratorRK::jsmn_parse(&parser, buffer, offset, 0, 0);
if (result < 0) {
// Failed to parse: JSMN_ERROR_INVAL or JSMN_ERROR_PART
return false;
}
// If we get here, tokens will always be == 0; it would have been freed if it was
// too small, and this code is never executed for staticBuffers == true
maxTokens = (size_t) result;
if (maxTokens > 0) {
tokens = (JsonParserGeneratorRK::jsmntok_t *)malloc(sizeof(JsonParserGeneratorRK::jsmntok_t) * maxTokens);
JsonParserGeneratorRK::jsmn_init(&parser);
int result = JsonParserGeneratorRK::jsmn_parse(&parser, buffer, offset, tokens, maxTokens);
tokensEnd = &tokens[result];
}
else {
tokensEnd = tokens;
}
/*
for(const JsonParserGeneratorRK::jsmntok_t *token = tokens; token < tokensEnd; token++) {
printf("%d, %d, %d, %d\n", token->type, token->start, token->end, token->size);
}
*/
return true;
}
JsonReference JsonParser::getReference() const {
if (tokens < tokensEnd) {
return JsonReference(this, &tokens[0]);
}
else {
return JsonReference(this);
}
}
const JsonParserGeneratorRK::jsmntok_t *JsonParser::getOuterArray() const {
for(const JsonParserGeneratorRK::jsmntok_t *token = tokens; token < tokensEnd; token++) {
if (token->type == JsonParserGeneratorRK::JSMN_ARRAY) {
return token;
}
}
return 0;
}
const JsonParserGeneratorRK::jsmntok_t *JsonParser::getTokenByIndex(const JsonParserGeneratorRK::jsmntok_t *container, size_t desiredIndex) const {
size_t index = 0;
const JsonParserGeneratorRK::jsmntok_t *token = container + 1;
while(token < tokensEnd && token->end < container->end) {
if (desiredIndex == index) {
return token;
}
index++;
skipObject(container, token);
}
return 0;
}
const JsonParserGeneratorRK::jsmntok_t *JsonParser::getOuterObject() const {
if (tokens < tokensEnd && tokens[0].type == JsonParserGeneratorRK::JSMN_OBJECT) {
return &tokens[0];
}
else {
return 0;
}
}
const JsonParserGeneratorRK::jsmntok_t *JsonParser::getOuterToken() const {
for(const JsonParserGeneratorRK::jsmntok_t *token = tokens; token < tokensEnd; token++) {
if (token->type == JsonParserGeneratorRK::JSMN_OBJECT || token->type == JsonParserGeneratorRK::JSMN_ARRAY) {
return token;
}
}
return 0;
}
bool JsonParser::skipObject(const JsonParserGeneratorRK::jsmntok_t *container, const JsonParserGeneratorRK::jsmntok_t *&obj) const {
int curObjectEnd = obj->end;
while(++obj < tokensEnd && obj->end < container->end && obj->end <= curObjectEnd) {
}
if (obj >= tokensEnd || obj->end > container->end) {
// No object after index
return false;
}
return true;
}
bool JsonParser::getKeyValueTokenByIndex(const JsonParserGeneratorRK::jsmntok_t *container, const JsonParserGeneratorRK::jsmntok_t *&key, const JsonParserGeneratorRK::jsmntok_t *&value, size_t desiredIndex) const {
size_t index = 0;
const JsonParserGeneratorRK::jsmntok_t *token = container + 1;
while(token < tokensEnd && token->end < container->end) {
if (desiredIndex == index) {
key = token;
if (skipObject(container, token)) {
value = token;
return true;
}
}
index++;
skipObject(container, token);
skipObject(container, token);
}
return false;
}
bool JsonParser::getValueTokenByKey(const JsonParserGeneratorRK::jsmntok_t *container, const char *name, const JsonParserGeneratorRK::jsmntok_t *&value) const {
const JsonParserGeneratorRK::jsmntok_t *key;
String keyName;
for(size_t ii = 0; getKeyValueTokenByIndex(container, key, value, ii); ii++) {
if (getTokenValue(key, keyName) && keyName == name) {
return true;
}
}
return false;
}
bool JsonParser::getValueTokenByIndex(const JsonParserGeneratorRK::jsmntok_t *container, size_t desiredIndex, const JsonParserGeneratorRK::jsmntok_t *&value) const {
size_t index = 0;
const JsonParserGeneratorRK::jsmntok_t *token = container + 1;
while(token < tokensEnd && token->end < container->end) {
if (desiredIndex == index) {
value = token;
return true;
}
index++;
skipObject(container, token);
}
return false;
}
bool JsonParser::getValueTokenByColRow(const JsonParserGeneratorRK::jsmntok_t *container, size_t col, size_t row, const JsonParserGeneratorRK::jsmntok_t *&value) const {
const JsonParserGeneratorRK::jsmntok_t *columnContainer;
if (getValueTokenByIndex(container, col, columnContainer)) {
return getValueTokenByIndex(columnContainer, row, value);
}
else {
return false;
}
}
size_t JsonParser::getArraySize(const JsonParserGeneratorRK::jsmntok_t *arrayContainer) const {
size_t index = 0;
const JsonParserGeneratorRK::jsmntok_t *token = arrayContainer + 1;
while(token < tokensEnd && token->end < arrayContainer->end) {
index++;
skipObject(arrayContainer, token);
}
return index;
}
void JsonParser::copyTokenValue(const JsonParserGeneratorRK::jsmntok_t *token, char *dst, size_t dstLen) const {
int ii;
for(ii = 0; ii < (token->end - token->start) && ii < ((int)dstLen - 1); ii++) {
dst[ii] = buffer[token->start + ii];
}
dst[ii] = 0;
}
bool JsonParser::getTokenValue(const JsonParserGeneratorRK::jsmntok_t *token, bool &result) const {
if (token->end > token->start) {
switch(buffer[token->start]) {
case 't': // should be this
case 'T':
case 'y':
case 'Y':
case '1':
result = true;
break;
default:
result = false;
break;
}
return true;
}
else {
return false;
}
}
bool JsonParser::getTokenValue(const JsonParserGeneratorRK::jsmntok_t *token, int &result) const {
// Copy data here, because tokens are not null terminated
char tmp[16];
copyTokenValue(token, tmp, sizeof(tmp));
if (sscanf(tmp, "%d", &result) == 1) {
return true;
}
else {
return false;
}
}
bool JsonParser::getTokenValue(const JsonParserGeneratorRK::jsmntok_t *token, unsigned long &result) const {
// Copy data here, because tokens are not null terminated
char tmp[16];
copyTokenValue(token, tmp, sizeof(tmp));
if (sscanf(tmp, "%lu", &result) == 1) {
return true;
}
else {
return false;
}
}
bool JsonParser::getTokenValue(const JsonParserGeneratorRK::jsmntok_t *token, float &result) const {
// Copy data here, because tokens are not null terminated
char tmp[16];
copyTokenValue(token, tmp, sizeof(tmp));
result = strtof(tmp, 0);
return true;
}
bool JsonParser::getTokenValue(const JsonParserGeneratorRK::jsmntok_t *token, double &result) const {
// Copy data here, because tokens are not null terminated
char tmp[16];
copyTokenValue(token, tmp, sizeof(tmp));
result = strtod(tmp, 0);
return true;
}
bool JsonParser::getTokenValue(const JsonParserGeneratorRK::jsmntok_t *token, String &result) const {
result = "";
result.reserve(token->end - token->start + 1);
JsonParserString strWrapper(&result);
return getTokenValue(token, strWrapper);
}
bool JsonParser::getTokenValue(const JsonParserGeneratorRK::jsmntok_t *token, char *str, size_t &bufLen) const {
JsonParserString strWrapper(str, bufLen);
bool result = getTokenValue(token, strWrapper);
bufLen = strWrapper.getLength() + 1;
return result;
}
bool JsonParser::getTokenValue(const JsonParserGeneratorRK::jsmntok_t *token, JsonParserString &str) const {
int unicode;
bool escape = false;
for(int ii = token->start; ii < token->end; ii++) {
if (escape) {
escape = false;
switch(buffer[ii]) {
case 'b':
str.append('\b');
break;
case 'f':
str.append('\f');
break;
case 'n':
str.append('\n');
break;
case 'r':
str.append('\r');
break;
case 't':
str.append('\t');
break;
case 'u':
if ((ii + 4) < token->end) {
// Copy data here because buffer is not null terminated and this could
// read past the end otherwise
char tmp[5];
for(size_t jj = 0; jj < 4; jj++) {
tmp[jj] = buffer[ii + jj + 1];
}
tmp[4] = 0;
if (sscanf(tmp, "%04x", &unicode) == 1) {
appendUtf8((uint16_t)unicode, str);
ii += 5; // also increments in loop
}
}
break;
default:
str.append(buffer[ii]);
break;
}
}
else
if (buffer[ii] == '\\') {
escape = true;
}
else {
str.append(buffer[ii]);
}
}
return true;
}
// [static]
void JsonParser::appendUtf8(uint16_t unicode, JsonParserString &str) {
unsigned char value;
if (unicode <= 0x007f) {
// 0x00000000 - 0x0000007F:
str.append((char)unicode);
}
else
if (unicode <= 0x7ff) {
// 0x00000080 - 0x000007FF:
// 110xxxxx 10xxxxxx
value = (0b11000000 | ((unicode >> 6) & 0b11111));
str.append((char)value);
value = (0b10000000 | (unicode & 0b111111));
str.append((char)value);
}
else {
// 0x00000800 - 0x0000FFFF:
// 1110xxxx 10xxxxxx 10xxxxxx
value = 0b11100000 | ((unicode >> 12) & 0b1111);
str.append((char)value);
value = 0b10000000 | ((unicode >> 6) & 0b111111);
str.append((char)value);
value = 0b10000000 | (unicode & 0b111111);
str.append((char)value);
}
}
//
//
//
JsonReference::JsonReference(const JsonParser *parser) : parser(parser), token(0) {
}
JsonReference::~JsonReference() {
}
JsonReference::JsonReference(const JsonParser *parser, const JsonParserGeneratorRK::jsmntok_t *token) : parser(parser), token(token) {
}
JsonReference JsonReference::key(const char *name) const {
const JsonParserGeneratorRK::jsmntok_t *newToken;
if (token && parser->getValueTokenByKey(token, name, newToken)) {
return JsonReference(parser, newToken);
}
else {
return JsonReference(parser);
}
}
JsonReference JsonReference::index(size_t index) const {
const JsonParserGeneratorRK::jsmntok_t *newToken;
if (token && parser->getValueTokenByIndex(token, index, newToken)) {
return JsonReference(parser, newToken);
}
else {
return JsonReference(parser);
}
}
size_t JsonReference::size() const {
if (token) {
return parser->getArraySize(token);
}
else {
return 0;
}
}
bool JsonReference::valueBool(bool result) const {
(void) value(result);
return result;
}
int JsonReference::valueInt(int result) const {
(void) value(result);
return result;
}
unsigned long JsonReference::valueUnsignedLong(unsigned long result) const {
(void) value(result);
return result;
}
float JsonReference::valueFloat(float result) const {
(void) value(result);
return result;
}
double JsonReference::valueDouble(double result) const {
(void) value(result);
return result;
}
String JsonReference::valueString() const {
String result;
(void) value(result);
return result;
}
//
//
//
JsonParserString::JsonParserString(String *str) : str(str), buf(0), bufLen(0), length(0){
}
JsonParserString::JsonParserString(char *buf, size_t bufLen) : str(0), buf(buf), bufLen(bufLen), length(0){
if (buf && bufLen) {
memset(buf, 0, bufLen);
}
}
void JsonParserString::append(char ch) {
if (str) {
str->concat(ch);
length++;
}
else {
if (buf && length < (bufLen - 1)) {
buf[length] = ch;
}
length++;
}
}
//
//
//
JsonWriter::JsonWriter() : JsonBuffer(), floatPlaces(-1) {
init();
}
JsonWriter::~JsonWriter() {
}
JsonWriter::JsonWriter(char *buffer, size_t bufferLen) : JsonBuffer(buffer, bufferLen), floatPlaces(-1) {
init();
}
void JsonWriter::init() {
// Save start of insertion point for later
offset = 0;
contextIndex = 0;
context[contextIndex].isFirst = false;
context[contextIndex].terminator = 0;
truncated = false;
}
bool JsonWriter::startObjectOrArray(char startChar, char endChar) {
if ((contextIndex + 1) >= MAX_NESTED_CONTEXT) {
return false;
}
contextIndex++;
context[contextIndex].isFirst = true;
context[contextIndex].terminator = endChar;
insertChar(startChar);
return true;
}
void JsonWriter::finishObjectOrArray() {
if (contextIndex > 0) {
if (context[contextIndex].terminator != 0) {
insertChar(context[contextIndex].terminator);
}
contextIndex--;
}
}
void JsonWriter::insertChar(char ch) {
if (offset < bufferLen) {
buffer[offset++] = ch;
}
else {
truncated = true;
}
}
void JsonWriter::insertString(const char *s, bool quoted) {
// 0x00000000 - 0x0000007F:
// 0x00000080 - 0x000007FF:
// 110xxxxx 10xxxxxx
// 0x00000800 - 0x0000FFFF:
// 1110xxxx 10xxxxxx 10xxxxxx
if (quoted) {
insertChar('"');
}
for(size_t ii = 0; s[ii] && offset < bufferLen; ii++) {
if (s[ii] & 0x80) {
// High bit set: convert UTF-8 to JSON Unicode escape
if (((s[ii] & 0b11110000) == 0b11100000) && ((s[ii+1] & 0b11000000) == 0b10000000) && ((s[ii+2] & 0b11000000) == 0b10000000)) {
// 3-byte
uint16_t utf16 = ((s[ii] & 0b1111) << 12) | ((s[ii+1] & 0b111111) << 6) | (s[ii+2] & 0b111111);
insertsprintf("\\u%04X", utf16);
ii += 2; // plus one more in loop increment
}
else
if (((s[ii] & 0b11100000) == 0b11000000) && ((s[ii+1] & 0b11000000) == 0b10000000)) {
// 2-byte
uint16_t utf16 = ((s[ii] & 0b11111) << 6) | (s[ii+1] & 0b111111);
insertsprintf("\\u%04X", utf16);
ii++; // plus one more in loop increment
}
else {
// Not valid unicode, just pass characters through
insertChar(s[ii]);
}
}
else {
switch(s[ii]) {
case '\b':
insertChar('\\');
insertChar('b');
break;
case '\f':
insertChar('\\');
insertChar('f');
break;
case '\n':
insertChar('\\');
insertChar('n');
break;
case '\r':
insertChar('\\');
insertChar('r');
break;
case '\t':
insertChar('\\');
insertChar('t');
break;
case '"':
case '\\':
insertChar('\\');
insertChar(s[ii]);
break;
default:
insertChar(s[ii]);
break;
}
}
}
if (quoted) {
insertChar('"');
}
}
void JsonWriter::insertsprintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
insertvsprintf(fmt, ap);
va_end(ap);
}
void JsonWriter::insertvsprintf(const char *fmt, va_list ap) {
size_t spaceAvailable = bufferLen - offset;
size_t count = vsnprintf(&buffer[offset], spaceAvailable, fmt, ap);
if (count <= spaceAvailable) {
offset += count;
}
else {
// Truncated, no more space left
offset = bufferLen;
truncated = true;
}
}
void JsonWriter::insertCheckSeparator() {
if (context[contextIndex].isFirst) {
context[contextIndex].isFirst = false;
}
else {
insertChar(',');
}
}
void JsonWriter::insertValue(bool value) {
if (value) {
insertString("true");
}
else {
insertString("false");
}
}
void JsonWriter::insertValue(float value) {
if (floatPlaces >= 0) {
insertsprintf("%.*f", floatPlaces, value);
}
else {
insertsprintf("%f", value);
}
}
void JsonWriter::insertValue(double value) {
if (floatPlaces >= 0) {
insertsprintf("%.*lf", floatPlaces, value);
}
else {
insertsprintf("%lf", value);
}
}
void JsonWriter::insertKeyObject(const char *key) {
insertCheckSeparator();
insertValue(key);
insertChar(':');
startObject();
}
void JsonWriter::insertKeyArray(const char *key) {
insertCheckSeparator();
insertValue(key);
insertChar(':');
startArray();
}
// begin jsmn.cpp
// https://github.com/zserge/jsmn
namespace JsonParserGeneratorRK {
/**
* Allocates a fresh unused token from the token pull.
*/
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *tok;
if (parser->toknext >= num_tokens) {
return NULL;
}
tok = &tokens[parser->toknext++];
tok->start = tok->end = -1;
tok->size = 0;
#ifdef JSMN_PARENT_LINKS
tok->parent = -1;
#endif
return tok;
}
/**
* Fills token type and boundaries.
*/
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
int start, int end) {
token->type = type;
token->start = start;
token->end = end;
token->size = 0;
}
/**
* Fills next available token with JSON primitive.
*/
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
size_t len, jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *token;
int start;
start = parser->pos;
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
switch (js[parser->pos]) {
#ifndef JSMN_STRICT
/* In strict mode primitive must be followed by "," or "}" or "]" */
case ':':
#endif
case '\t' : case '\r' : case '\n' : case ' ' :
case ',' : case ']' : case '}' :
goto found;
}
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
parser->pos = start;
return JSMN_ERROR_INVAL;
}
}
#ifdef JSMN_STRICT
/* In strict mode primitive must be followed by a comma/object/array */
parser->pos = start;
return JSMN_ERROR_PART;
#endif
found:
if (tokens == NULL) {
parser->pos--;
return 0;
}
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
parser->pos--;
return 0;
}
/**
* Fills next token with JSON string.
*/
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
size_t len, jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *token;
int start = parser->pos;
parser->pos++;
/* Skip starting quote */
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
char c = js[parser->pos];
/* Quote: end of string */
if (c == '\"') {
if (tokens == NULL) {
return 0;
}
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
return 0;
}
/* Backslash: Quoted symbol expected */
if (c == '\\' && parser->pos + 1 < len) {
int i;
parser->pos++;
switch (js[parser->pos]) {
/* Allowed escaped symbols */
case '\"': case '/' : case '\\' : case 'b' :
case 'f' : case 'r' : case 'n' : case 't' :
break;
/* Allows escaped symbol \uXXXX */
case 'u':
parser->pos++;
for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
/* If it isn't a hex character we have an error */
if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
parser->pos = start;
return JSMN_ERROR_INVAL;
}
parser->pos++;
}
parser->pos--;
break;
/* Unexpected symbol */
default:
parser->pos = start;
return JSMN_ERROR_INVAL;
}
}
}
parser->pos = start;
return JSMN_ERROR_PART;
}
/**
* Parse JSON string and fill tokens.
*/
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
jsmntok_t *tokens, unsigned int num_tokens) {
int r;
int i;
jsmntok_t *token;
int count = parser->toknext;
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
char c;
jsmntype_t type;
c = js[parser->pos];
switch (c) {
case '{': case '[':
count++;
if (tokens == NULL) {
break;
}
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL)
return JSMN_ERROR_NOMEM;
if (parser->toksuper != -1) {
tokens[parser->toksuper].size++;
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
}
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
token->start = parser->pos;
parser->toksuper = parser->toknext - 1;
break;
case '}': case ']':
if (tokens == NULL)
break;
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
#ifdef JSMN_PARENT_LINKS
if (parser->toknext < 1) {
return JSMN_ERROR_INVAL;
}
token = &tokens[parser->toknext - 1];
for (;;) {
if (token->start != -1 && token->end == -1) {
if (token->type != type) {
return JSMN_ERROR_INVAL;
}
token->end = parser->pos + 1;
parser->toksuper = token->parent;
break;
}
if (token->parent == -1) {
if(token->type != type || parser->toksuper == -1) {
return JSMN_ERROR_INVAL;
}
break;
}
token = &tokens[token->parent];
}
#else
for (i = parser->toknext - 1; i >= 0; i--) {
token = &tokens[i];
if (token->start != -1 && token->end == -1) {
if (token->type != type) {
return JSMN_ERROR_INVAL;
}
parser->toksuper = -1;
token->end = parser->pos + 1;
break;
}
}
/* Error if unmatched closing bracket */
if (i == -1) return JSMN_ERROR_INVAL;
for (; i >= 0; i--) {
token = &tokens[i];
if (token->start != -1 && token->end == -1) {
parser->toksuper = i;
break;
}
}
#endif
break;
case '\"':
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
if (r < 0) return r;
count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
case '\t' : case '\r' : case '\n' : case ' ':
break;
case ':':
parser->toksuper = parser->toknext - 1;
break;
case ',':
if (tokens != NULL && parser->toksuper != -1 &&
tokens[parser->toksuper].type != JSMN_ARRAY &&
tokens[parser->toksuper].type != JSMN_OBJECT) {
#ifdef JSMN_PARENT_LINKS
parser->toksuper = tokens[parser->toksuper].parent;
#else
for (i = parser->toknext - 1; i >= 0; i--) {
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
if (tokens[i].start != -1 && tokens[i].end == -1) {
parser->toksuper = i;
break;
}
}
}
#endif
}
break;
#ifdef JSMN_STRICT
/* In strict mode 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' :
/* And they must not be keys of the object */
if (tokens != NULL && parser->toksuper != -1) {
jsmntok_t *t = &tokens[parser->toksuper];
if (t->type == JSMN_OBJECT ||
(t->type == JSMN_STRING && t->size != 0)) {
return JSMN_ERROR_INVAL;
}
}
#else
/* In non-strict mode every unquoted value is a primitive */
default:
#endif
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
if (r < 0) return r;
count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
#ifdef JSMN_STRICT
/* Unexpected char in strict mode */
default:
return JSMN_ERROR_INVAL;
#endif
}
}
if (tokens != NULL) {
for (i = parser->toknext - 1; i >= 0; i--) {
/* Unmatched opened object or array */
if (tokens[i].start != -1 && tokens[i].end == -1) {
return JSMN_ERROR_PART;
}
}
}
return count;
}
/**
* Creates a new parser based over a given buffer with an array of tokens
* available.
*/
void jsmn_init(jsmn_parser *parser) {
parser->pos = 0;
parser->toknext = 0;
parser->toksuper = -1;
}
}
// end jsmn.cpp
Click to Expand
Content Rating
Is this a good/useful/informative piece of content to include in the project? Have your say!
You must login before you can post a comment. .