source: S-port/trunk/Core/Src/JSON.c

Last change on this file was 1, checked in by AlexLir, 3 years ago
File size: 28.8 KB
RevLine 
[1]1#include "JSON.h"
2#include <string.h>
3#include <stdlib.h>
4#include <stdio.h>
5
6struct json_write_control g_json_write_control;
7#define JWC(x) g_json_write_control.x
8
9
10void json_write_putch(char c);
11void json_write_putstr(char *str);
12void json_write_putraw(char *str);
13void modp_itoa10(int32_t value, char* str);
14void modp_dtoa2(double value, char* str, int prec);
15void json_write_pretty(void);
16enum json_node_type json_write_pop(void);
17void json_write_push(enum json_node_type nodeType );
18
19
20void json_write_open(char *buffer, unsigned int buflen, enum json_node_type rootType, int isPretty)
21{
22 memset( buffer, 0, buflen ); // zap the whole destination buffer
23 JWC(buffer)= buffer;
24 JWC(buflen)= buflen;
25 JWC(bufp)= buffer;
26 JWC(nodeStack)[0].nodeType = rootType;
27 JWC(nodeStack)[0].elementNo = 0;
28 JWC(stackpos)=0;
29 JWC(error)= json_success;
30 JWC(callNo)= 1;
31 JWC(isPretty)= isPretty;
32 json_write_putch((rootType == json_object_type) ? '{' : '[' );
33}
34
35int json_write_close(void)
36{
37 if(JWC(error) == json_success){
38 if( JWC(stackpos) == 0 ){
39 enum json_node_type node= JWC(nodeStack)[0].nodeType;
40 if(JWC(isPretty)) json_write_putch('\n');
41 json_write_putch((node == json_object_type) ? '}' : ']');
42 }
43 else{
44 JWC(error)= json_nest_err; // nesting error, not all objects closed when jwClose() called
45 }
46 }
47 return JWC(error);
48}
49
50int json_write_end(void)
51{
52 if(JWC(error) == json_success){
53 enum json_node_type node;
54 int lastElemNo = JWC(nodeStack)[JWC(stackpos)].elementNo;
55 node = json_write_pop();
56 if(lastElemNo > 0 )json_write_pretty();
57 json_write_putch((node == json_object_type) ? '}' : ']');
58 }
59 return JWC(error);
60}
61
62enum json_node_type json_write_pop(void)
63{
64 enum json_node_type retval= JWC(nodeStack[JWC(stackpos)]).nodeType;
65 if( JWC(stackpos) == 0 ) JWC(error) = json_stack_empty; // stack underflow error (too many 'end's)
66 else JWC(stackpos)--;
67 return retval;
68}
69
70void json_write_putch(char c)
71{
72 if((unsigned int)(JWC(bufp) - JWC(buffer)) >= JWC(buflen)) JWC(error)= json_buf_full;
73 else *JWC(bufp)++ = c;
74}
75
76void json_write_putraw(char *str)
77{
78 while(*str != '\0') json_write_putch(*str++);
79}
80
81void json_write_pretty(void)
82{
83 int i;
84 if( JWC(isPretty) )
85 {
86 json_write_putch('\n');
87 for( i=0; i<JWC(stackpos)+1; i++ )json_write_putraw(" " );
88 }
89}
90
91void json_write_putstr(char *str)
92{
93 json_write_putch('\"');
94 while( *str != '\0' ) json_write_putch(*str++);
95 json_write_putch('\"');
96}
97
98void json_write_push(enum json_node_type nodeType )
99{
100 if( (JWC(stackpos)+1) >= JSON_WRITE_STACK_DEPTH)JWC(error)= json_stack_full; // array/object nesting > JWRITE_STACK_DEPTH
101 else
102 {
103 JWC(nodeStack[++JWC(stackpos)]).nodeType= nodeType;
104 JWC(nodeStack[JWC(stackpos)]).elementNo= 0;
105 }
106}
107
108/* object */
109int _json_write_obj(char *key);
110
111void json_write_obj_raw(char *key, char *rawtext)
112{
113 if(_json_write_obj(key) == json_success)
114 json_write_putraw(rawtext);
115}
116
117void json_write_obj_string(char *key, char *value)
118{
119 if(_json_write_obj(key ) == json_success)
120 json_write_putstr(value);
121}
122
123void json_write_obj_int(char *key, int value)
124{
125 modp_itoa10( value, JWC(tmpbuf) );
126 json_write_obj_raw(key, JWC(tmpbuf) );
127}
128
129void json_write_obj_double(char *key, double value)
130{
131 modp_dtoa2( value, JWC(tmpbuf), 6 );
132 json_write_obj_raw(key, JWC(tmpbuf) );
133}
134
135void json_write_obj_bool(char *key, int oneOrZero)
136{
137 json_write_obj_raw(key, (oneOrZero) ? "true" : "false" );
138}
139
140void json_write_obj_null(char *key)
141{
142 json_write_obj_raw(key, "null");
143}
144
145void json_write_obj_object(char *key)
146{
147 if(_json_write_obj(key) == json_success)
148 {
149 json_write_putch('{');
150 json_write_push(json_object_type);
151 }
152}
153
154void json_write_obj_array(char *key)
155{
156 if(_json_write_obj(key) == json_success)
157 {
158 json_write_putch('[');
159 json_write_push(json_array_type);
160 }
161}
162
163int _json_write_obj(char *key)
164{
165 if(JWC(error) == json_success)
166 {
167 JWC(callNo)++;
168 if( JWC(nodeStack)[JWC(stackpos)].nodeType != json_object_type)JWC(error) = json_not_object; // tried to write Object key/value into Array
169 else if( JWC(nodeStack)[JWC(stackpos)].elementNo++ > 0 )
170 json_write_putch(',');
171 json_write_pretty();
172 json_write_putstr(key);
173 json_write_putch(':');
174 if(JWC(isPretty))json_write_putch(' ');
175 }
176 return JWC(error);
177}
178/************/
179/* array */
180int _json_write_arr(void);
181
182// put raw string to array (i.e. contents of rawtext without quotes)
183//
184void json_write_arr_raw(char *rawtext)
185{
186 if(_json_write_arr() == json_success)
187 json_write_putraw(rawtext);
188}
189
190// put "quoted" string to array
191//
192void json_write_arr_string(char *value)
193{
194 if(_json_write_arr() == json_success)
195 json_write_putstr(value);
196}
197
198void json_write_arr_int(int value)
199{
200 modp_itoa10( value, JWC(tmpbuf) );
201 json_write_arr_raw(JWC(tmpbuf));
202}
203
204void json_write_arr_double(double value)
205{
206 modp_dtoa2( value, JWC(tmpbuf), 6 );
207 json_write_arr_raw(JWC(tmpbuf));
208}
209
210void json_write_arr_bool(int oneOrZero)
211{
212 json_write_arr_raw((oneOrZero) ? "true" : "false" );
213}
214
215void json_write_arr_null(void)
216{
217 json_write_arr_raw("null");
218}
219
220void json_write_arr_object(void)
221{
222 if(_json_write_arr() == json_success){
223 json_write_putch('{' );
224 json_write_push(json_object_type);
225 }
226}
227
228void json_write_arr_array(void)
229{
230 if(_json_write_arr() == json_success){
231 json_write_putch('[');
232 json_write_push(json_array_type);
233 }
234}
235
236int _json_write_arr(void)
237{
238 if(JWC(error) == json_success){
239 JWC(callNo)++;
240 if( JWC(nodeStack)[JWC(stackpos)].nodeType != json_array_type) JWC(error)= json_not_array; // tried to write array value into Object
241 else if( JWC(nodeStack)[JWC(stackpos)].elementNo++ > 0 )
242 json_write_putch(',');
243 json_write_pretty();
244 }
245 return JWC(error);
246}
247/**************/
248static void strreverse(char* begin, char* end)
249{
250 char aux;
251 while (end > begin)
252 aux = *end, *end-- = *begin, *begin++ = aux;
253}
254
255void modp_itoa10(int32_t value, char* str)
256{
257 char* wstr=str;
258 // Take care of sign
259 unsigned int uvalue = (value < 0) ? -value : value;
260 // Conversion. Number is reversed.
261 do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
262 if (value < 0) *wstr++ = '-';
263 *wstr='\0';
264
265 // Reverse string
266 strreverse(str,wstr-1);
267}
268
269static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
270
271void modp_dtoa2(double value, char* str, int prec)
272{
273 /* if input is larger than thres_max, revert to exponential */
274 const double thres_max = (double)(0x7FFFFFFF);
275 int count;
276 double diff = 0.0;
277 char* wstr = str;
278 int neg= 0;
279 int whole;
280 double tmp;
281 uint32_t frac;
282
283 /* Hacky test for NaN
284 * under -fast-math this won't work, but then you also won't
285 * have correct nan values anyways. The alternative is
286 * to link with libmath (bad) or hack IEEE double bits (bad)
287 */
288 if (! (value == value)) {
289 str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0';
290 return;
291 }
292
293 if (prec < 0) {
294 prec = 0;
295 } else if (prec > 9) {
296 /* precision of >= 10 can lead to overflow errors */
297 prec = 9;
298 }
299
300 /* we'll work in positive values and deal with the
301 negative sign issue later */
302 if (value < 0) {
303 neg = 1;
304 value = -value;
305 }
306
307
308 whole = (int) value;
309 tmp = (value - whole) * pow10[prec];
310 frac = (uint32_t)(tmp);
311 diff = tmp - frac;
312
313 if (diff > 0.5) {
314 ++frac;
315 /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
316 if (frac >= pow10[prec]) {
317 frac = 0;
318 ++whole;
319 }
320 } else if (diff == 0.5 && ((frac == 0) || (frac & 1))) {
321 ++frac;
322 }
323 if (value > thres_max) {
324 sprintf(str, "%e", neg ? -value : value);
325 return;
326 }
327
328 if (prec == 0) {
329 diff = value - whole;
330 if (diff > 0.5) {
331 /* greater than 0.5, round up, e.g. 1.6 -> 2 */
332 ++whole;
333 } else if (diff == 0.5 && (whole & 1)) {
334 /* exactly 0.5 and ODD, then round up */
335 /* 1.5 -> 2, but 2.5 -> 2 */
336 ++whole;
337 }
338
339 //vvvvvvvvvvvvvvvvvvv Diff from modp_dto2
340 } else if (frac) {
341 count = prec;
342 // now do fractional part, as an unsigned number
343 // we know it is not 0 but we can have leading zeros, these
344 // should be removed
345 while (!(frac % 10)) {
346 --count;
347 frac /= 10;
348 }
349 //^^^^^^^^^^^^^^^^^^^ Diff from modp_dto2
350
351 // now do fractional part, as an unsigned number
352 do {
353 --count;
354 *wstr++ = (char)(48 + (frac % 10));
355 } while (frac /= 10);
356 // add extra 0s
357 while (count-- > 0) *wstr++ = '0';
358 // add decimal
359 *wstr++ = '.';
360 }
361
362 // do whole part
363 // Take care of sign
364 // Conversion. Number is reversed.
365 do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10);
366 if (neg) {
367 *wstr++ = '-';
368 }
369 *wstr='\0';
370 strreverse(str, wstr-1);
371}
372
373int json_status_is_good(json_status_t status)
374{
375 return status == json_success;
376}
377
378int json_status_is_bad(json_status_t status)
379{
380 return !json_status_is_good(status);
381}
382
383/*
384 tokens_data - óêàçàòåëü íà òîêåòû è äàííûå
385 Key - óêàçàòåëü íà êëþ÷
386 value - óêàçàòåëü íà ïåðåìåííóþ êóäà âåðíóòü äàííûå
387 index - èíäåêñ â ìàññèâå
388 type - òèï ïîëó÷àåìîãî çíà÷åíèÿ
389
390âîçâðàùàåò ñòàòóñ âûïîëíåíèÿ:
391 åñëè âõîäíîé ïàðàìåòð value = NULL, òî ïðè êîððåêòíîì âûïîëíåíèè âåðíåò json_success,
392 òàê ìîæíî ïðîâåðèòü åñòü ëè ïîëå â çàïðîñå
393*/
394//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)
395//{
396// if((tokens_data == NULL) || (Key == NULL) || (value == NULL)) return json_invalid_arguments;
397// json_token_t *tokens = tokens_data->tokens;
398// uint8_t massIndex = 0;
399// /* èøåì êëþ÷ */
400// if(in == json_root) tokens_data->current_token = 0;
401// for(/*tokens_data->current_token = 0*/; tokens_data->current_token < tokens_data->tokens_count; tokens_data->current_token++){
402// if(tokens[tokens_data->current_token].type == json_type_string){
403// if((tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0) continue;
404// 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){ // áèíãî íóæíûé êëþ÷
405// if(tokens[tokens_data->current_token + 1].type == json_type_array){ // ìàññèâ
406// for(tokens_data->current_token += 2; tokens_data->current_token < tokens_data->tokens_count; tokens_data->current_token++){
407// if(massIndex++ == index){
408// if((tokens[tokens_data->current_token].type == json_type_string) && tokens[tokens_data->current_token].type == type){ // òåêóùèé ýëåìåíò string?
409// if(value != NULL){
410// memset(value, 0x00, strlen(value));
411// memcpy(value, &tokens_data->json_data[tokens[tokens_data->current_token].start], tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start); // åñëè ñòîðêà êîïèðóåì åå
412// }
413// return json_success;
414// }
415// else if((tokens[tokens_data->current_token].type == json_type_integer) && (tokens[tokens_data->current_token].type == type)){ // òåêóùèé ýëåìåíò integer?
416// if(value != NULL) *(int*)value = atoi(&tokens_data->json_data[tokens[tokens_data->current_token].start]);
417// return json_success;
418// }
419// else if((tokens[tokens_data->current_token].type == json_type_double) && (tokens[tokens_data->current_token].type == type)){ // òåêóùèé ýëåìåíò double?
420// if(value != NULL) *(double*)value = atof(&tokens_data->json_data[tokens[tokens_data->current_token].start]);
421// return json_success;
422// }
423// else if((tokens[tokens_data->current_token].type == json_type_boolean) && (tokens[tokens_data->current_token].type == type)){ // òåêóùèé ýëåìåíò boolean?
424// if(value != NULL){
425// 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;
426// else *(_Bool*)value = 0;
427// }
428// return json_success;
429// }
430// else return json_invalid_arguments;
431// }
432// }
433// return json_invalid_arguments;
434// }
435// else return json_invalid_arguments;
436// }
437// }
438// }
439// return json_not_found;
440//}
441
442json_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)
443{
444 if((tokens_data == NULL) || (value == NULL)) return json_invalid_arguments;
445 json_token_t *tokens = tokens_data->tokens;
446 uint8_t massIndex = 0;
447 uint8_t temp_token_count = 0;
448 /* èøåì êëþ÷ */
449 if(in == json_root) tokens_data->current_token = 0;
450
451 temp_token_count = tokens_data->current_token;
452 for(/*tokens_data->current_token = 0*/; temp_token_count < tokens_data->tokens_count; temp_token_count++){
453 if((tokens[temp_token_count].end - tokens[temp_token_count].start) == 0) continue;
454 if(tokens[temp_token_count + 1].type == json_type_array){ // ìàññèâ
455 for((temp_token_count += 2); temp_token_count < tokens_data->tokens_count; temp_token_count++){
456 if(massIndex++ == index){
457 if((tokens[temp_token_count].type == json_type_string) && tokens[temp_token_count].type == type){ // òåêóùèé ýëåìåíò string?
458 if(value != NULL){
459 memset(value, 0x00, strlen(value));
460 memcpy(value, &tokens_data->json_data[tokens[temp_token_count].start], tokens[temp_token_count].end - tokens[temp_token_count].start); // åñëè ñòîðêà êîïèðóåì åå
461 }
462 return json_success;
463 }
464 else if((tokens[temp_token_count].type == json_type_integer) && (tokens[temp_token_count].type == type)){ // òåêóùèé ýëåìåíò integer?
465 if(value != NULL) *(int*)value = atoi(&tokens_data->json_data[tokens[temp_token_count].start]);
466 return json_success;
467 }
468 else if((tokens[temp_token_count].type == json_type_double) && (tokens[temp_token_count].type == type)){ // òåêóùèé ýëåìåíò double?
469 if(value != NULL) *(double*)value = atof(&tokens_data->json_data[tokens[temp_token_count].start]);
470 return json_success;
471 }
472 else if((tokens[temp_token_count].type == json_type_boolean) && (tokens[temp_token_count].type == type)){ // òåêóùèé ýëåìåíò boolean?
473 if(value != NULL){
474 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;
475 else *(_Bool*)value = 0;
476 }
477 return json_success;
478 }
479 else return json_invalid_arguments;
480 }
481 }
482 return json_invalid_arguments;
483 }
484 else return json_invalid_arguments;
485
486
487 }
488 return json_not_found;
489}
490
491/*
492 tokens_data - óêàçàòåëü íà òîêåòû è äàííûå
493 Key - óêàçàòåëü íà êëþ÷
494 value - óêàçàòåëü íà ïåðåìåííóþ êóäà âåðíóòü äàííûå
495 type - òèï ïîëó÷àåìîãî çíà÷åíèÿ
496
497âîçâðàùàåò ñòàòóñ âûïîëíåíèÿ:
498 åñëè âõîäíîé ïàðàìåòð value = NULL, òî ïðè êîððåêòíîì âûïîëíåíèè âåðíåò json_success,
499 òàê ìîæíî ïðîâåðèòü åñòü ëè ïîëå â çàïðîñå
500*/
501json_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)
502{
503 if((tokens_data == NULL) || (Key == NULL)) return json_invalid_arguments;
504 json_token_t *tokens = tokens_data->tokens;
505 /* èøåì êëþ÷ */
506 if(in == json_root) tokens_data->current_token = 0;
507 for(/*tokens_data->current_token = 0*/; tokens_data->current_token < tokens_data->tokens_count; tokens_data->current_token++){
508 if(tokens[tokens_data->current_token].type == json_type_string){
509 if((tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0) continue;
510 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){ // áèíãî íóæíûé êëþ÷
511 if(tokens[tokens_data->current_token + 1].type != json_type_array){
512 if((tokens[tokens_data->current_token + 1].type == json_type_string) && (tokens[tokens_data->current_token + 1].type == type)){ // ñëåäóþùèé ýëåìåíò string?
513 if(value != NULL){
514 memset(value, 0x00, strlen(value));
515 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); // åñëè ñòîðêà êîïèðóåì åå
516 }
517 return json_success;
518 }
519 else if((tokens[tokens_data->current_token + 1].type == json_type_integer) && (tokens[tokens_data->current_token + 1].type == type)){ // ñëåäóþùèé ýëåìåíò integer?
520 if(value != NULL) *(int*)value = atoi(&tokens_data->json_data[tokens[tokens_data->current_token + 1].start]);
521 return json_success;
522 }
523 else if((tokens[tokens_data->current_token + 1].type == json_type_double) && (tokens[tokens_data->current_token + 1].type == type)){ // ñëåäóþùèé ýëåìåíò double?
524 if(value != NULL) *(double*)value = atof(&tokens_data->json_data[tokens[tokens_data->current_token + 1].start]);
525 return json_success;
526 }
527 else if((tokens[tokens_data->current_token + 1].type == json_type_boolean) && (tokens[tokens_data->current_token + 1].type == type)){ // ñëåäóþùèé ýëåìåíò boolean?
528 if(value != NULL){
529 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;
530 else *(_Bool*)value = 0;
531 }
532 return json_success;
533 }
534 else if((tokens[tokens_data->current_token + 1].type == json_type_object) && (tokens[tokens_data->current_token + 1].type == type))return json_success;
535
536 else return json_invalid_arguments;
537 }
538 else if((tokens[tokens_data->current_token + 1].type == json_type_array) && (tokens[tokens_data->current_token + 1].type == type))return json_success;
539 else return json_invalid_arguments;
540 }
541 }
542 }
543 return json_not_found;
544}
545
546//json_status_t json_get_object(json_tokens_data_t *tokens_data, const char *Key, json_tokens_data_t *retVal)
547//{
548// if((tokens_data == NULL) || (Key == NULL)) return json_invalid_arguments;
549// json_token_t *tokens = tokens_data->tokens;
550// for(tokens_data->current_token = 0; tokens_data->current_token < tokens_data->tokens_count; tokens_data->current_token++){
551// if(tokens[tokens_data->current_token].type == json_type_string){
552// if((tokens[tokens_data->current_token].end - tokens[tokens_data->current_token].start) == 0) continue;
553// 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){ // áèíãî íóæíûé êëþ÷
554// if(tokens[tokens_data->current_token + 1].type == json_type_object) {
555//
556// retVal->tokens_count = tokens_data->tokens_count - (tokens_data->current_token + 2);
557// memcpy(retVal->tokens, &tokens[tokens_data->current_token + 2], retVal->tokens_count);
558// retVal->json_data = tokens_data->json_data;
559//
560// return json_success;
561// }
562// }
563// }
564// }
565// return json_not_found;
566//}
567
568static json_token_t *json_allocate_token(json_parser_t *parser, json_token_t *tokens, json_size_t max_tokens)
569{
570 if (!parser || !tokens || max_tokens == 0 || parser->next_token >= max_tokens) return NULL;
571 json_token_t *token = &tokens[parser->next_token++];
572 token->start = token->end = -1;
573 token->size = 0;
574 return token;
575}
576
577json_status_t json_reset_parser(json_parser_t *parser)
578{
579 if (!parser) return json_invalid_arguments;
580 parser->pos = 0;
581 parser->next_token = 0;
582 parser->superior_token = -1;
583 return json_success;
584}
585
586json_status_t json_init_parser(json_parser_t *parser, const json_config_t *config)
587{
588 if (!parser || !config) return json_invalid_arguments;
589 parser->config = config;
590 return json_reset_parser(parser);
591}
592
593static 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)
594{
595 if (!parser || !json || length == 0 || !tokens || max_tokens_count == 0) return json_invalid_arguments;
596
597 json_size_t start = parser->pos++;
598 while (parser->pos < length && json[parser->pos] != '\0') {
599 char c = json[parser->pos];
600 if (c == '\"') {
601 json_token_t *token = json_allocate_token(parser, tokens, max_tokens_count);
602 if (!token) {
603 parser->pos = start;
604 return json_no_memory;
605 }
606 token->type = json_type_string;
607 token->start = start + 1;
608 token->end = parser->pos;
609 token->size = 0;
610 return json_success;
611 }
612 else if (c == '\\' && parser->pos + 1 < length) {
613 parser->pos++;
614 switch (json[parser->pos]) {
615 case '\"': case '/': case '\\': case 'b': case 'f':
616 case 'r': case 'n': case 't':
617 break;
618
619 case 'u':
620 parser->pos++;
621 for (json_size_t i = 0; i < 4 && parser->pos < length && json[parser->pos] != '\0'; i++, parser->pos++) {
622 char symbol = json[parser->pos];
623 if ((symbol < (int)'0' || symbol > (int)'9') &&
624 (symbol < (int)'A' || symbol > (int)'F') &&
625 (symbol < (int)'a' || symbol > (int)'f')) {
626 parser->pos = start;
627 return json_invalid_input;
628 }
629 }
630 parser->pos--;
631 break;
632 default:
633 parser->pos = start;
634 return json_invalid_input;
635 }
636 }
637 parser->pos++;
638 }
639 parser->pos = start;
640 return json_error_part;
641}
642
643static int json_is_null(const char *data, json_size_t length)
644{
645 if (!data) return 0;
646 if (length == 0) length = strlen(data);
647 return length == strlen("null") && memcmp(data, "null", length) == 0;
648}
649
650static int json_is_boolean(const char *data, json_size_t length) {
651 if (!data) return 0;
652 if (length == 0) length = strlen(data);
653 return (length == strlen("true") && memcmp(data, "true", length) == 0) ||
654 (length == strlen("false") && memcmp(data, "false", length) == 0);
655}
656
657static int json_is_integer(const char *data, json_size_t length)
658{
659 if (!data) return 0;
660 if (length == 0) length = strlen(data);
661 json_size_t offset = 0;
662 if (data[0] == '-') offset = 1;
663 int hexadecimal_case = 0;
664 if (length > offset + 2 && data[offset] == '0' &&
665 (data[offset + 1] == 'x' || data[offset + 1] == 'X')) {
666 hexadecimal_case = 1;
667 }
668 int is_integer = 1;
669 for (json_size_t i = offset; i < length; i++) {
670 if ((data[i] >= '0' && data[i] <= '9') || (hexadecimal_case &&
671 ((data[i] >= 'A' && data[i] <= 'F') || (data[i] >= 'a' && data[i] <= 'f'))) ||
672 (i == offset + 1 && ((data[i] == 'x') || (data[i] == 'X')) && length > offset + 2)) {
673
674 if (hexadecimal_case && i == offset && data[i] != '0') {
675 is_integer = 0;
676 break;
677 }
678 continue;
679 }
680 is_integer = 0;
681 break;
682 }
683 return is_integer;
684}
685
686static int json_is_double(const char *data, json_size_t length)
687{
688 if (!data) return 0;
689 if (length == 0) length = strlen(data);
690 json_size_t offset = 0;
691 if (data[0] == '-') offset = 1;
692 int dot_already_been = 0;
693 int exp_already_been = 0;
694
695 for (json_size_t i = offset; i < length; i++) {
696 if (data[i] < '0' || data[i] > '9') {
697 if (data[i] == '.' && !dot_already_been) {
698 dot_already_been = 1;
699 continue;
700 }
701 else if ((data[i] == 'e' || data[i] == 'E') && i + 2 < length &&
702 (data[i + 1] == '+' || data[i + 1] == '-') && !exp_already_been) {
703 exp_already_been = 1;
704 i++;
705 continue;
706 }
707
708 return 0;
709 }
710 }
711 return 1;
712}
713
714static json_token_type_t json_get_token_type(const char *data, json_size_t length)
715{
716 if (!data || length == 0) return json_type_undefined;
717 if (json_is_null(data, length)) return json_type_null;
718 else if (json_is_boolean(data, length)) return json_type_boolean;
719 else if (json_is_integer(data, length)) return json_type_integer;
720 else if (json_is_double(data, length)) return json_type_double;
721 return json_type_undefined;
722}
723
724static 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)
725{
726 if (!parser || !json || length == 0 || !tokens || max_tokens_count == 0) return json_invalid_arguments;
727
728 json_size_t start = parser->pos;
729 while (length && json[parser->pos] != '\0') {
730 char c = json[parser->pos];
731 if (c == '\t' || c == '\n' || c == '\r' || c == ' ' || c == ',' || c == ']' || c == '}' || c == ':') {
732 break;
733 }
734 parser->pos++;
735 }
736 json_token_t *token = json_allocate_token(parser, tokens, max_tokens_count);
737 if (!token) {
738 parser->pos = start;
739 return json_no_memory;
740 }
741
742 json_size_t token_length = parser->pos - start;
743 json_token_type_t type = json_get_token_type(json + start, token_length);
744
745 token->type = type;
746 token->start = start;
747 token->end = parser->pos;
748 token->size = 0;
749 parser->pos--;
750
751 return json_success;
752}
753
754json_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)
755{
756 if (!parser || !json || length == 0 || !tokens || !max_tokens_count || *max_tokens_count == 0) return json_invalid_arguments;
757 json_reset_parser(parser);
758 json_token_t *token = NULL;
759 json_size_t count = parser->next_token;
760 while (parser->pos < length && json[parser->pos] != '\0') {
761 char c = json[parser->pos];
762 switch (c) {
763 case '{': case '[':
764 count++;
765 token = json_allocate_token(parser, tokens, *max_tokens_count);
766 if (!token) return json_no_memory;
767 if (parser->superior_token != -1) tokens[parser->superior_token].size++;
768 token->type = (c == '{' ? json_type_object : json_type_array);
769 token->start = parser->pos;
770 parser->superior_token = parser->next_token - 1;
771 break;
772 case '}': case ']':{
773 int i = 0;
774 for (i = (int)parser->next_token - 1; i >= 0; i--) {
775 token = &tokens[i];
776 if (token->start != -1 && token->end == -1) {
777 parser->superior_token = -1;
778 token->end = parser->pos + 1;
779 break;
780 }
781 }
782 if (i == -1) return json_invalid_input;
783 while (i >= 0) {
784 token = &tokens[i];
785 if (token->start != -1 && token->end == -1) {
786 parser->superior_token = i;
787 break;
788 }
789 i--;
790 }
791 }
792 break;
793 case '\"':
794 {
795 json_status_t status = json_parse_string(parser, json, length, tokens, *max_tokens_count);
796 if (json_status_is_bad(status)) return status;
797 count++;
798 if (parser->superior_token != -1 && tokens != NULL) tokens[parser->superior_token].size++;
799 }
800 break;
801
802 case '\t': case '\r': case '\n': case ' ':
803 break;
804
805 case ':':
806 parser->superior_token = parser->next_token - 1;
807 break;
808
809 case ',':
810 if (parser->superior_token != -1 &&
811 tokens[parser->superior_token].type != json_type_array &&
812 tokens[parser->superior_token].type != json_type_object) {
813 for (int i = parser->next_token - 1; i >= 0; i--) {
814 if (tokens[i].type == json_type_array || tokens[i].type == json_type_object) {
815 if (tokens[i].start != -1 && tokens[i].end == -1) {
816 parser->superior_token = i;
817 break;
818 }
819 }
820 }
821 }
822 break;
823 default:
824 {
825 json_status_t status = json_parse_primitive(parser, json, length, tokens, *max_tokens_count);
826 if (json_status_is_bad(status)) {
827 return status;
828 }
829
830 count++;
831 if (parser->superior_token != -1) {
832 tokens[parser->superior_token].size++;
833 }
834 }
835 break;
836 }
837 parser->pos++;
838 }
839
840 for (int i = (int)parser->next_token - 1; i >= 0; i--) {
841 if (tokens[i].start != -1 && tokens[i].end == -1) {
842 return json_error_part;
843 }
844 }
845
846 *max_tokens_count = count;
847 return json_success;
848}
849
850
Note: See TracBrowser for help on using the repository browser.