#include "JSON.h" #include #include #include struct json_write_control g_json_write_control; #define JWC(x) g_json_write_control.x void json_write_putch(char c); void json_write_putstr(char *str); void json_write_putraw(char *str); void modp_itoa10(int32_t value, char* str); void modp_dtoa2(double value, char* str, int prec); void json_write_pretty(void); enum json_node_type json_write_pop(void); void json_write_push(enum json_node_type nodeType ); void json_write_open(char *buffer, unsigned int buflen, enum json_node_type rootType, int isPretty) { memset( buffer, 0, buflen ); // zap the whole destination buffer JWC(buffer)= buffer; JWC(buflen)= buflen; JWC(bufp)= buffer; JWC(nodeStack)[0].nodeType = rootType; JWC(nodeStack)[0].elementNo = 0; JWC(stackpos)=0; JWC(error)= json_success; JWC(callNo)= 1; JWC(isPretty)= isPretty; json_write_putch((rootType == json_object_type) ? '{' : '[' ); } int json_write_close(void) { if(JWC(error) == json_success){ if( JWC(stackpos) == 0 ){ enum json_node_type node= JWC(nodeStack)[0].nodeType; if(JWC(isPretty)) json_write_putch('\n'); json_write_putch((node == json_object_type) ? '}' : ']'); } else{ JWC(error)= json_nest_err; // nesting error, not all objects closed when jwClose() called } } return JWC(error); } int json_write_end(void) { if(JWC(error) == json_success){ enum json_node_type node; int lastElemNo = JWC(nodeStack)[JWC(stackpos)].elementNo; node = json_write_pop(); if(lastElemNo > 0 )json_write_pretty(); json_write_putch((node == json_object_type) ? '}' : ']'); } return JWC(error); } enum json_node_type json_write_pop(void) { enum json_node_type retval= JWC(nodeStack[JWC(stackpos)]).nodeType; if( JWC(stackpos) == 0 ) JWC(error) = json_stack_empty; // stack underflow error (too many 'end's) else JWC(stackpos)--; return retval; } void json_write_putch(char c) { if((unsigned int)(JWC(bufp) - JWC(buffer)) >= JWC(buflen)) JWC(error)= json_buf_full; else *JWC(bufp)++ = c; } void json_write_putraw(char *str) { while(*str != '\0') json_write_putch(*str++); } void json_write_pretty(void) { int i; if( JWC(isPretty) ) { json_write_putch('\n'); for( i=0; i= JSON_WRITE_STACK_DEPTH)JWC(error)= json_stack_full; // array/object nesting > JWRITE_STACK_DEPTH else { JWC(nodeStack[++JWC(stackpos)]).nodeType= nodeType; JWC(nodeStack[JWC(stackpos)]).elementNo= 0; } } /* object */ int _json_write_obj(char *key); void json_write_obj_raw(char *key, char *rawtext) { if(_json_write_obj(key) == json_success) json_write_putraw(rawtext); } void json_write_obj_string(char *key, char *value) { if(_json_write_obj(key ) == json_success) json_write_putstr(value); } void json_write_obj_int(char *key, int value) { modp_itoa10( value, JWC(tmpbuf) ); json_write_obj_raw(key, JWC(tmpbuf) ); } void json_write_obj_double(char *key, double value) { modp_dtoa2( value, JWC(tmpbuf), 6 ); json_write_obj_raw(key, JWC(tmpbuf) ); } void json_write_obj_bool(char *key, int oneOrZero) { json_write_obj_raw(key, (oneOrZero) ? "true" : "false" ); } void json_write_obj_null(char *key) { json_write_obj_raw(key, "null"); } void json_write_obj_object(char *key) { if(_json_write_obj(key) == json_success) { json_write_putch('{'); json_write_push(json_object_type); } } void json_write_obj_array(char *key) { if(_json_write_obj(key) == json_success) { json_write_putch('['); json_write_push(json_array_type); } } int _json_write_obj(char *key) { if(JWC(error) == json_success) { JWC(callNo)++; if( JWC(nodeStack)[JWC(stackpos)].nodeType != json_object_type)JWC(error) = json_not_object; // tried to write Object key/value into Array else if( JWC(nodeStack)[JWC(stackpos)].elementNo++ > 0 ) json_write_putch(','); json_write_pretty(); json_write_putstr(key); json_write_putch(':'); if(JWC(isPretty))json_write_putch(' '); } return JWC(error); } /************/ /* array */ int _json_write_arr(void); // put raw string to array (i.e. contents of rawtext without quotes) // void json_write_arr_raw(char *rawtext) { if(_json_write_arr() == json_success) json_write_putraw(rawtext); } // put "quoted" string to array // void json_write_arr_string(char *value) { if(_json_write_arr() == json_success) json_write_putstr(value); } void json_write_arr_int(int value) { modp_itoa10( value, JWC(tmpbuf) ); json_write_arr_raw(JWC(tmpbuf)); } void json_write_arr_double(double value) { modp_dtoa2( value, JWC(tmpbuf), 6 ); json_write_arr_raw(JWC(tmpbuf)); } void json_write_arr_bool(int oneOrZero) { json_write_arr_raw((oneOrZero) ? "true" : "false" ); } void json_write_arr_null(void) { json_write_arr_raw("null"); } void json_write_arr_object(void) { if(_json_write_arr() == json_success){ json_write_putch('{' ); json_write_push(json_object_type); } } void json_write_arr_array(void) { if(_json_write_arr() == json_success){ json_write_putch('['); json_write_push(json_array_type); } } int _json_write_arr(void) { if(JWC(error) == json_success){ JWC(callNo)++; if( JWC(nodeStack)[JWC(stackpos)].nodeType != json_array_type) JWC(error)= json_not_array; // tried to write array value into Object else if( JWC(nodeStack)[JWC(stackpos)].elementNo++ > 0 ) json_write_putch(','); json_write_pretty(); } return JWC(error); } /**************/ static void strreverse(char* begin, char* end) { char aux; while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux; } void modp_itoa10(int32_t value, char* str) { char* wstr=str; // Take care of sign unsigned int uvalue = (value < 0) ? -value : value; // Conversion. Number is reversed. do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10); if (value < 0) *wstr++ = '-'; *wstr='\0'; // Reverse string strreverse(str,wstr-1); } static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; void modp_dtoa2(double value, char* str, int prec) { /* if input is larger than thres_max, revert to exponential */ const double thres_max = (double)(0x7FFFFFFF); int count; double diff = 0.0; char* wstr = str; int neg= 0; int whole; double tmp; uint32_t frac; /* Hacky test for NaN * under -fast-math this won't work, but then you also won't * have correct nan values anyways. The alternative is * to link with libmath (bad) or hack IEEE double bits (bad) */ if (! (value == value)) { str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0'; return; } if (prec < 0) { prec = 0; } else if (prec > 9) { /* precision of >= 10 can lead to overflow errors */ prec = 9; } /* we'll work in positive values and deal with the negative sign issue later */ if (value < 0) { neg = 1; value = -value; } whole = (int) value; tmp = (value - whole) * pow10[prec]; frac = (uint32_t)(tmp); diff = tmp - frac; if (diff > 0.5) { ++frac; /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */ if (frac >= pow10[prec]) { frac = 0; ++whole; } } else if (diff == 0.5 && ((frac == 0) || (frac & 1))) { ++frac; } if (value > thres_max) { sprintf(str, "%e", neg ? -value : value); return; } if (prec == 0) { diff = value - whole; if (diff > 0.5) { /* greater than 0.5, round up, e.g. 1.6 -> 2 */ ++whole; } else if (diff == 0.5 && (whole & 1)) { /* exactly 0.5 and ODD, then round up */ /* 1.5 -> 2, but 2.5 -> 2 */ ++whole; } //vvvvvvvvvvvvvvvvvvv Diff from modp_dto2 } else if (frac) { count = prec; // now do fractional part, as an unsigned number // we know it is not 0 but we can have leading zeros, these // should be removed while (!(frac % 10)) { --count; frac /= 10; } //^^^^^^^^^^^^^^^^^^^ Diff from modp_dto2 // now do fractional part, as an unsigned number do { --count; *wstr++ = (char)(48 + (frac % 10)); } while (frac /= 10); // add extra 0s while (count-- > 0) *wstr++ = '0'; // add decimal *wstr++ = '.'; } // do whole part // Take care of sign // Conversion. Number is reversed. do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10); if (neg) { *wstr++ = '-'; } *wstr='\0'; strreverse(str, wstr-1); } int json_status_is_good(json_status_t status) { return status == json_success; } int json_status_is_bad(json_status_t status) { return !json_status_is_good(status); } /* tokens_data - указатель на токеты и данные Key - указатель на ключ value - указатель на переменную куда вернуть данные index - индекс в массиве type - тип получаемого значения возвращает статус выполнения: если входной параметр value = NULL, то при корректном выполнении вернет json_success, так можно проверить есть ли поле в запросе */ //json_status_t json_get_value_array(json_tokens_data_t *tokens_data, const char *Key, void *value, uint8_t index, json_token_type_t type, json_search_in_type_t in) //{ // if((tokens_data == NULL) || (Key == NULL) || (value == NULL)) return json_invalid_arguments; // json_token_t *tokens = tokens_data->tokens; // uint8_t massIndex = 0; // /* ишем ключ */ // if(in == json_root) tokens_data->current_token = 0; // for(/*tokens_data->current_token = 0*/; tokens_data->current_token < tokens_data->tokens_count; tokens_data->current_token++){ // if(tokens[tokens_data->current_token].type == json_type_string){ // if((tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0) continue; // if(memcmp(Key, &tokens_data->json_data[tokens[tokens_data->current_token].start], tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0){ // бинго нужный ключ // if(tokens[tokens_data->current_token + 1].type == json_type_array){ // массив // for(tokens_data->current_token += 2; tokens_data->current_token < tokens_data->tokens_count; tokens_data->current_token++){ // if(massIndex++ == index){ // if((tokens[tokens_data->current_token].type == json_type_string) && tokens[tokens_data->current_token].type == type){ // текущий элемент string? // if(value != NULL){ // memset(value, 0x00, strlen(value)); // memcpy(value, &tokens_data->json_data[tokens[tokens_data->current_token].start], tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start); // если сторка копируем ее // } // return json_success; // } // else if((tokens[tokens_data->current_token].type == json_type_integer) && (tokens[tokens_data->current_token].type == type)){ // текущий элемент integer? // if(value != NULL) *(int*)value = atoi(&tokens_data->json_data[tokens[tokens_data->current_token].start]); // return json_success; // } // else if((tokens[tokens_data->current_token].type == json_type_double) && (tokens[tokens_data->current_token].type == type)){ // текущий элемент double? // if(value != NULL) *(double*)value = atof(&tokens_data->json_data[tokens[tokens_data->current_token].start]); // return json_success; // } // else if((tokens[tokens_data->current_token].type == json_type_boolean) && (tokens[tokens_data->current_token].type == type)){ // текущий элемент boolean? // if(value != NULL){ // if(memcmp("true", &tokens_data->json_data[tokens[tokens_data->current_token].start], tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0) *(_Bool*)value = 1; // else *(_Bool*)value = 0; // } // return json_success; // } // else return json_invalid_arguments; // } // } // return json_invalid_arguments; // } // else return json_invalid_arguments; // } // } // } // return json_not_found; //} json_status_t json_get_value_array(json_tokens_data_t *tokens_data, void *value, uint8_t index, json_token_type_t type, json_search_in_type_t in) { if((tokens_data == NULL) || (value == NULL)) return json_invalid_arguments; json_token_t *tokens = tokens_data->tokens; uint8_t massIndex = 0; uint8_t temp_token_count = 0; /* ишем ключ */ if(in == json_root) tokens_data->current_token = 0; temp_token_count = tokens_data->current_token; for(/*tokens_data->current_token = 0*/; temp_token_count < tokens_data->tokens_count; temp_token_count++){ if((tokens[temp_token_count].end - tokens[temp_token_count].start) == 0) continue; if(tokens[temp_token_count + 1].type == json_type_array){ // массив for((temp_token_count += 2); temp_token_count < tokens_data->tokens_count; temp_token_count++){ if(massIndex++ == index){ if((tokens[temp_token_count].type == json_type_string) && tokens[temp_token_count].type == type){ // текущий элемент string? if(value != NULL){ memset(value, 0x00, strlen(value)); memcpy(value, &tokens_data->json_data[tokens[temp_token_count].start], tokens[temp_token_count].end - tokens[temp_token_count].start); // если сторка копируем ее } return json_success; } else if((tokens[temp_token_count].type == json_type_integer) && (tokens[temp_token_count].type == type)){ // текущий элемент integer? if(value != NULL) *(int*)value = atoi(&tokens_data->json_data[tokens[temp_token_count].start]); return json_success; } else if((tokens[temp_token_count].type == json_type_double) && (tokens[temp_token_count].type == type)){ // текущий элемент double? if(value != NULL) *(double*)value = atof(&tokens_data->json_data[tokens[temp_token_count].start]); return json_success; } else if((tokens[temp_token_count].type == json_type_boolean) && (tokens[temp_token_count].type == type)){ // текущий элемент boolean? if(value != NULL){ if(memcmp("true", &tokens_data->json_data[tokens[temp_token_count].start], tokens[temp_token_count].end - tokens[temp_token_count].start) == 0) *(_Bool*)value = 1; else *(_Bool*)value = 0; } return json_success; } else return json_invalid_arguments; } } return json_invalid_arguments; } else return json_invalid_arguments; } return json_not_found; } /* tokens_data - указатель на токеты и данные Key - указатель на ключ value - указатель на переменную куда вернуть данные type - тип получаемого значения возвращает статус выполнения: если входной параметр value = NULL, то при корректном выполнении вернет json_success, так можно проверить есть ли поле в запросе */ json_status_t json_get_value_object(json_tokens_data_t *tokens_data, const char *Key, void *value, json_token_type_t type, json_search_in_type_t in) { if((tokens_data == NULL) || (Key == NULL)) return json_invalid_arguments; json_token_t *tokens = tokens_data->tokens; /* ишем ключ */ if(in == json_root) tokens_data->current_token = 0; for(/*tokens_data->current_token = 0*/; tokens_data->current_token < tokens_data->tokens_count; tokens_data->current_token++){ if(tokens[tokens_data->current_token].type == json_type_string){ if((tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0) continue; if(memcmp(Key, &tokens_data->json_data[tokens[tokens_data->current_token].start], tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0){ // бинго нужный ключ if(tokens[tokens_data->current_token + 1].type != json_type_array){ if((tokens[tokens_data->current_token + 1].type == json_type_string) && (tokens[tokens_data->current_token + 1].type == type)){ // следующий элемент string? if(value != NULL){ memset(value, 0x00, strlen(value)); memcpy(value, &tokens_data->json_data[tokens[tokens_data->current_token + 1].start], tokens[tokens_data->current_token + 1].end - tokens[tokens_data->current_token + 1].start); // если сторка копируем ее } return json_success; } else if((tokens[tokens_data->current_token + 1].type == json_type_integer) && (tokens[tokens_data->current_token + 1].type == type)){ // следующий элемент integer? if(value != NULL) *(int*)value = atoi(&tokens_data->json_data[tokens[tokens_data->current_token + 1].start]); return json_success; } else if((tokens[tokens_data->current_token + 1].type == json_type_double) && (tokens[tokens_data->current_token + 1].type == type)){ // следующий элемент double? if(value != NULL) *(double*)value = atof(&tokens_data->json_data[tokens[tokens_data->current_token + 1].start]); return json_success; } else if((tokens[tokens_data->current_token + 1].type == json_type_boolean) && (tokens[tokens_data->current_token + 1].type == type)){ // следующий элемент boolean? if(value != NULL){ if(memcmp("true", &tokens_data->json_data[tokens[tokens_data->current_token + 1].start], tokens[tokens_data->current_token + 1].end - tokens[tokens_data->current_token + 1].start) == 0) *(_Bool*)value = 1; else *(_Bool*)value = 0; } return json_success; } else if((tokens[tokens_data->current_token + 1].type == json_type_object) && (tokens[tokens_data->current_token + 1].type == type))return json_success; else return json_invalid_arguments; } else if((tokens[tokens_data->current_token + 1].type == json_type_array) && (tokens[tokens_data->current_token + 1].type == type))return json_success; else return json_invalid_arguments; } } } return json_not_found; } //json_status_t json_get_object(json_tokens_data_t *tokens_data, const char *Key, json_tokens_data_t *retVal) //{ // if((tokens_data == NULL) || (Key == NULL)) return json_invalid_arguments; // json_token_t *tokens = tokens_data->tokens; // for(tokens_data->current_token = 0; tokens_data->current_token < tokens_data->tokens_count; tokens_data->current_token++){ // if(tokens[tokens_data->current_token].type == json_type_string){ // if((tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0) continue; // if(memcmp(Key, &tokens_data->json_data[tokens[tokens_data->current_token].start], tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0){ // бинго нужный ключ // if(tokens[tokens_data->current_token + 1].type == json_type_object) { // // retVal->tokens_count = tokens_data->tokens_count - (tokens_data->current_token + 2); // memcpy(retVal->tokens, &tokens[tokens_data->current_token + 2], retVal->tokens_count); // retVal->json_data = tokens_data->json_data; // // return json_success; // } // } // } // } // return json_not_found; //} static json_token_t *json_allocate_token(json_parser_t *parser, json_token_t *tokens, json_size_t max_tokens) { if (!parser || !tokens || max_tokens == 0 || parser->next_token >= max_tokens) return NULL; json_token_t *token = &tokens[parser->next_token++]; token->start = token->end = -1; token->size = 0; return token; } json_status_t json_reset_parser(json_parser_t *parser) { if (!parser) return json_invalid_arguments; parser->pos = 0; parser->next_token = 0; parser->superior_token = -1; return json_success; } json_status_t json_init_parser(json_parser_t *parser, const json_config_t *config) { if (!parser || !config) return json_invalid_arguments; parser->config = config; return json_reset_parser(parser); } static json_status_t json_parse_string(json_parser_t *parser, const char *json, json_size_t length, json_token_t *tokens, json_size_t max_tokens_count) { if (!parser || !json || length == 0 || !tokens || max_tokens_count == 0) return json_invalid_arguments; json_size_t start = parser->pos++; while (parser->pos < length && json[parser->pos] != '\0') { char c = json[parser->pos]; if (c == '\"') { json_token_t *token = json_allocate_token(parser, tokens, max_tokens_count); if (!token) { parser->pos = start; return json_no_memory; } token->type = json_type_string; token->start = start + 1; token->end = parser->pos; token->size = 0; return json_success; } else if (c == '\\' && parser->pos + 1 < length) { parser->pos++; switch (json[parser->pos]) { case '\"': case '/': case '\\': case 'b': case 'f': case 'r': case 'n': case 't': break; case 'u': parser->pos++; for (json_size_t i = 0; i < 4 && parser->pos < length && json[parser->pos] != '\0'; i++, parser->pos++) { char symbol = json[parser->pos]; if ((symbol < (int)'0' || symbol > (int)'9') && (symbol < (int)'A' || symbol > (int)'F') && (symbol < (int)'a' || symbol > (int)'f')) { parser->pos = start; return json_invalid_input; } } parser->pos--; break; default: parser->pos = start; return json_invalid_input; } } parser->pos++; } parser->pos = start; return json_error_part; } static int json_is_null(const char *data, json_size_t length) { if (!data) return 0; if (length == 0) length = strlen(data); return length == strlen("null") && memcmp(data, "null", length) == 0; } static int json_is_boolean(const char *data, json_size_t length) { if (!data) return 0; if (length == 0) length = strlen(data); return (length == strlen("true") && memcmp(data, "true", length) == 0) || (length == strlen("false") && memcmp(data, "false", length) == 0); } static int json_is_integer(const char *data, json_size_t length) { if (!data) return 0; if (length == 0) length = strlen(data); json_size_t offset = 0; if (data[0] == '-') offset = 1; int hexadecimal_case = 0; if (length > offset + 2 && data[offset] == '0' && (data[offset + 1] == 'x' || data[offset + 1] == 'X')) { hexadecimal_case = 1; } int is_integer = 1; for (json_size_t i = offset; i < length; i++) { if ((data[i] >= '0' && data[i] <= '9') || (hexadecimal_case && ((data[i] >= 'A' && data[i] <= 'F') || (data[i] >= 'a' && data[i] <= 'f'))) || (i == offset + 1 && ((data[i] == 'x') || (data[i] == 'X')) && length > offset + 2)) { if (hexadecimal_case && i == offset && data[i] != '0') { is_integer = 0; break; } continue; } is_integer = 0; break; } return is_integer; } static int json_is_double(const char *data, json_size_t length) { if (!data) return 0; if (length == 0) length = strlen(data); json_size_t offset = 0; if (data[0] == '-') offset = 1; int dot_already_been = 0; int exp_already_been = 0; for (json_size_t i = offset; i < length; i++) { if (data[i] < '0' || data[i] > '9') { if (data[i] == '.' && !dot_already_been) { dot_already_been = 1; continue; } else if ((data[i] == 'e' || data[i] == 'E') && i + 2 < length && (data[i + 1] == '+' || data[i + 1] == '-') && !exp_already_been) { exp_already_been = 1; i++; continue; } return 0; } } return 1; } static json_token_type_t json_get_token_type(const char *data, json_size_t length) { if (!data || length == 0) return json_type_undefined; if (json_is_null(data, length)) return json_type_null; else if (json_is_boolean(data, length)) return json_type_boolean; else if (json_is_integer(data, length)) return json_type_integer; else if (json_is_double(data, length)) return json_type_double; return json_type_undefined; } static json_status_t json_parse_primitive(json_parser_t *parser, const char *json, json_size_t length, json_token_t *tokens, json_size_t max_tokens_count) { if (!parser || !json || length == 0 || !tokens || max_tokens_count == 0) return json_invalid_arguments; json_size_t start = parser->pos; while (length && json[parser->pos] != '\0') { char c = json[parser->pos]; if (c == '\t' || c == '\n' || c == '\r' || c == ' ' || c == ',' || c == ']' || c == '}' || c == ':') { break; } parser->pos++; } json_token_t *token = json_allocate_token(parser, tokens, max_tokens_count); if (!token) { parser->pos = start; return json_no_memory; } json_size_t token_length = parser->pos - start; json_token_type_t type = json_get_token_type(json + start, token_length); token->type = type; token->start = start; token->end = parser->pos; token->size = 0; parser->pos--; return json_success; } json_status_t json_parse_tokens(json_parser_t *parser, const char *json, json_size_t length, json_token_t *tokens, json_size_t *max_tokens_count) { if (!parser || !json || length == 0 || !tokens || !max_tokens_count || *max_tokens_count == 0) return json_invalid_arguments; json_reset_parser(parser); json_token_t *token = NULL; json_size_t count = parser->next_token; while (parser->pos < length && json[parser->pos] != '\0') { char c = json[parser->pos]; switch (c) { case '{': case '[': count++; token = json_allocate_token(parser, tokens, *max_tokens_count); if (!token) return json_no_memory; if (parser->superior_token != -1) tokens[parser->superior_token].size++; token->type = (c == '{' ? json_type_object : json_type_array); token->start = parser->pos; parser->superior_token = parser->next_token - 1; break; case '}': case ']':{ int i = 0; for (i = (int)parser->next_token - 1; i >= 0; i--) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { parser->superior_token = -1; token->end = parser->pos + 1; break; } } if (i == -1) return json_invalid_input; while (i >= 0) { token = &tokens[i]; if (token->start != -1 && token->end == -1) { parser->superior_token = i; break; } i--; } } break; case '\"': { json_status_t status = json_parse_string(parser, json, length, tokens, *max_tokens_count); if (json_status_is_bad(status)) return status; count++; if (parser->superior_token != -1 && tokens != NULL) tokens[parser->superior_token].size++; } break; case '\t': case '\r': case '\n': case ' ': break; case ':': parser->superior_token = parser->next_token - 1; break; case ',': if (parser->superior_token != -1 && tokens[parser->superior_token].type != json_type_array && tokens[parser->superior_token].type != json_type_object) { for (int i = parser->next_token - 1; i >= 0; i--) { if (tokens[i].type == json_type_array || tokens[i].type == json_type_object) { if (tokens[i].start != -1 && tokens[i].end == -1) { parser->superior_token = i; break; } } } } break; default: { json_status_t status = json_parse_primitive(parser, json, length, tokens, *max_tokens_count); if (json_status_is_bad(status)) { return status; } count++; if (parser->superior_token != -1) { tokens[parser->superior_token].size++; } } break; } parser->pos++; } for (int i = (int)parser->next_token - 1; i >= 0; i--) { if (tokens[i].start != -1 && tokens[i].end == -1) { return json_error_part; } } *max_tokens_count = count; return json_success; }