inline json_error_t* allocate_object_by_type( json_t **objectPtr, jsmntok_t *token, jsmntok_t tokens[TOKENS_COUNT], size_t tokensCount, size_t *tokenIndex, char* js) { json_error_t* parseError = NULL; json_t* jsonObject = NULL; json_type type = decode_jsmn_type(token->type); switch (type) { case JSON_STRING: jsonObject = json_alloc(JSON_STRING, token->size); if(jsonObject == NULL) { parseError = parsingError( JSON_MEMORY_ALLOC_FAILED, "Error: Unable to allocate string object.", token, js ); } break; case JSON_PRIMITIVE: { char *firstCharacter = js + token->start; switch(*firstCharacter) { case '-': {}; case '0': {}; case '1': {}; case '2': {}; case '3': {}; case '4': {}; case '5': {}; case '6': {}; case '7': {}; case '8': {}; case '9': {}; jsonObject = json_alloc(JSON_NUMBER, token->size); break; case 't': jsonObject = json_alloc(JSON_TRUE, token->size); break; case 'f': jsonObject = json_alloc(JSON_FALSE, token->size); break; case 'n' : jsonObject = json_alloc(JSON_NULL, token->size); break; default: parseError = parsingError( JSON_INVALID_OBJECT_TYPE, "Error: Unable to allocate primitive object by first character. Wrong character at -->", token, js ); break; } } break; case JSON_OBJECT: case JSON_ARRAY: parseError = createJsonObject(&jsonObject, js, tokens, tokensCount, tokenIndex); break; default: parseError = parsingError( JSON_INVALID_OBJECT_TYPE, "Error: Unable to allocate object by type. Wrong type.", token, js ); break; } if(parseError == NULL) { add_value_from_token(jsonObject, js, token); // /* assign returned object */ // if(objectPtr != NULL) { // json_free(objectPtr); // } // objectPtr = (json_t*) json_malloc(sizeof(json_t)); // memcpy(objectPtr, jsonObject, sizeof(json_t)); // // json_free(jsonObject); *objectPtr = jsonObject; } return parseError; }
json_value *json_parse(char *source, char **error_pos, int *error_line, block_allocator *allocator) { json_value *root = 0; json_value *top = 0; char *name = 0; char *it = source; int escaped_newlines = 0; while (*it) { switch (*it) { case '{': case '[': { // create new value json_value *object = json_alloc(allocator); // name object->name = name; name = 0; // type object->type = (*it == '{') ? JSON_OBJECT : JSON_ARRAY; // skip open character ++it; // set top and root if (top) { json_append(top, object); } else if (!root) { root = object; } else { ERROR(it, "Second root. Only one root allowed"); } top = object; } break; case '}': case ']': { if (!top || top->type != ((*it == '}') ? JSON_OBJECT : JSON_ARRAY)) { ERROR(it, "Mismatch closing brace/bracket"); } // skip close character ++it; // set top top = top->parent; } break; case ':': if (!top || top->type != JSON_OBJECT) { ERROR(it, "Unexpected character"); } ++it; break; case ',': CHECK_TOP(); ++it; break; case '"': { CHECK_TOP(); // skip '"' character ++it; char *first = it; char *last = it; while (*it) { if ((unsigned char)*it < '\x20') { ERROR(first, "Control characters not allowed in strings"); } else if (*it == '\\') { switch (it[1]) { case '"': *last = '"'; break; case '\\': *last = '\\'; break; case '/': *last = '/'; break; case 'b': *last = '\b'; break; case 'f': *last = '\f'; break; case 'n': *last = '\n'; ++escaped_newlines; break; case 'r': *last = '\r'; break; case 't': *last = '\t'; break; case 'u': { unsigned int codepoint; if (hatoui(it + 2, it + 6, &codepoint) != it + 6) { ERROR(it, "Bad unicode codepoint"); } if (codepoint <= 0x7F) { *last = (char)codepoint; } else if (codepoint <= 0x7FF) { *last++ = (char)(0xC0 | (codepoint >> 6)); *last = (char)(0x80 | (codepoint & 0x3F)); } else if (codepoint <= 0xFFFF) { *last++ = (char)(0xE0 | (codepoint >> 12)); *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F)); *last = (char)(0x80 | (codepoint & 0x3F)); } } it += 4; break; default: ERROR(first, "Unrecognized escape sequence"); } ++last; it += 2; } else if (*it == '"') { *last = 0; ++it; break; } else { *last++ = *it++; } }
json_error_t* createJsonObject( json_t **json_root, char *js, jsmntok_t tokens[TOKENS_COUNT], size_t tokensCount, size_t *tokenIndex ) { typedef enum { START, KEY, PRINT, VALUE, ARRAY, STOP } parse_state; parse_state state = START; json_error_t* error = NULL; //static char msgBuffer[MSG_BUFFER_SIZE]; //size_t tokenIndex = 0; // strbuffer_t *tokenStr = NULL; size_t object_tokens = 0; json_t *root = NULL; json_t *key = NULL; json_t *value = NULL; for (; *tokenIndex < tokensCount; *tokenIndex += 1 ) { jsmntok_t *token = &tokens[*tokenIndex]; // size_t heapSize = xPortGetFreeHeapSize(); // sprintf(msgBuffer, "HEAP SIZE: %d\n", heapSize); // log_d(msgBuffer); if(token->start > strlen(js) || token->end > strlen(js) || token->end > strlen(js) || (token->end - token->start) > strlen(js) ) { continue; } // tokenStr = json_token_tostr(js, token); switch (state) { case START: if (token->type != JSMN_OBJECT && token->type != JSMN_ARRAY) { return parsingError( JSON_INVALID_OBJECT_TYPE, "Error: Root object is not object or array.", token, js ); } switch(token->type) { case JSMN_OBJECT: root = json_alloc(JSON_OBJECT, token->size); if(root == NULL) { freeResources(root, key, value); return parsingError( JSON_MEMORY_ALLOC_FAILED, "Error: Unable to allocate root object.", token, js ); } state = KEY; break; case JSMN_ARRAY: state = ARRAY; root = json_alloc(JSON_ARRAY, token->size); if(root == NULL) { freeResources(root, key, value); return parsingError( JSON_MEMORY_ALLOC_FAILED, "Error: Unable to allocate root array.", token, js ); } break; default: freeResources(root, key, value); return parsingError( JSON_INVALID_OBJECT_TYPE, "Error: Root object is not object or array.", token, js ); } object_tokens = token->size; if (object_tokens == 0) { *json_root = root; return NULL; /* exit with no errors */ } // if (object_tokens % 2 != 0) // log_die("Invalid response: object must have even number of children. %d\n", tokenIndex); break; case KEY: if (token->type != JSMN_STRING) { freeResources(root, key, value); return parsingError( JSON_INVALID_OBJECT_TYPE, "Error: Object key is not string.", token, js ); } key = json_alloc(JSON_KEY, token->size); if(key == NULL) { freeResources(root, key, value); return parsingError( JSON_MEMORY_ALLOC_FAILED, "Error: Unable to allocate memory for json key object.", token, js ); } add_value_from_token(key, js, token); if(key->value == NULL) { freeResources(root, key, value); return parsingError( JSON_MEMORY_ALLOC_FAILED, "Error: Unable to allocate memory for json key string.", token, js ); } error = json_append_child(root, key); if( error != NULL) { freeResources(root, key, value); return error; } object_tokens--; state = VALUE; break; case VALUE: // if (token->type != JSMN_STRING && token->type != JSMN_PRIMITIVE) // printf("failed: not string and not primitive skip %d\n", tokenIndex); error = allocate_object_by_type( &value, token, tokens, tokensCount, tokenIndex, js); if(error != NULL) { freeResources(root, key, value); return error; } error = json_append_child(key, value); if(error != NULL) { freeResources(root, key, value); return error; } object_tokens--; state = KEY; if (object_tokens == 0) { *json_root = root; return NULL; /* exit with no errors */ } break; case ARRAY: if(root->type != JSON_ARRAY) { freeResources(root, key, value); return parsingError( JSON_INVALID_OBJECT_TYPE, "Error: In state ARRAY. Parent element is not array", token, js ); } error = allocate_object_by_type( &value, token, tokens, tokensCount, tokenIndex, js); if(error != NULL) { freeResources(root, key, value); return error; } error = json_append_child(root, value); if(error != NULL) { freeResources(root, key, value); return error; } object_tokens--; state = ARRAY; if (object_tokens == 0) { *json_root = root; return NULL; /* exit with no errors */ } break; case STOP: // Just consume the tokens return NULL; /* exit with no errors */ break; default: return parsingError( JSON_INLLEGAL_STATE_EXCEPTION, "Error: Invalid parsing state. Program should not get here!", NULL, NULL ); } } return parsingError( JSON_INLLEGAL_STATE_EXCEPTION, "Error: Program should not get here!", NULL, NULL ); //json_object_free(root); // for (tokenIndex = 0, tokensLeft = 1; tokensLeft > 0; // tokenIndex++, tokensLeft--) { // // jsmntok_t *t = &tokens[tokenIndex]; // // // Should never reach uninitialized tokens // log_assert(t->start != -1 && t->end != -1); // // if (t->type == JSMN_ARRAY || t->type == JSMN_OBJECT) // tokensLeft += t->size; // // switch (state) { // case START: // if (t->type != JSMN_OBJECT) // printf("failed NOt object: %d\n", tokenIndex); // // state = KEY; // object_tokens = t->size; // // if (object_tokens == 0) // state = STOP; // // if (object_tokens % 2 != 0) // printf("failed: %d\n", tokenIndex); // // break; // // case KEY: // object_tokens--; // // if (t->type != JSMN_STRING) // printf("failed: Key is not string %d\n", tokenIndex); // // state = SKIP; // // for (i = 0; i < sizeof(KEYS) / sizeof(char *); i++) { // if (json_token_streq(js, t, KEYS[i])) { // printf("%s: ", KEYS[i]); // state = PRINT; // break; // } // } // // break; // // case SKIP: // if (t->type != JSMN_STRING && t->type != JSMN_PRIMITIVE) // printf("failed: not string and not primitive skip %d\n", tokenIndex); // // object_tokens--; // state = KEY; // // if (object_tokens == 0) // state = STOP; // // break; // // case PRINT: // if (t->type != JSMN_STRING && t->type != JSMN_PRIMITIVE) // printf("failed not string and not primitive print: %d\n", tokenIndex); // // char *str = json_token_tostr(js, t); // puts(str); // // object_tokens--; // state = KEY; // // if (object_tokens == 0) // state = STOP; // // break; // // case STOP: // // Just consume the tokens // break; // // default: // log_die("Invalid state %u", state); // } // } }