yjson.c
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * $Id: yjson.c 29354 2017-11-29 17:09:16Z seb $
4  *
5  * Simple JSON parser (actually a slightly enhanced lexer)
6  *
7  * - - - - - - - - - License information: - - - - - - - - -
8  *
9  * Copyright (C) 2011 and beyond by Yoctopuce Sarl, Switzerland.
10  *
11  * Yoctopuce Sarl (hereafter Licensor) grants to you a perpetual
12  * non-exclusive license to use, modify, copy and integrate this
13  * file into your software for the sole purpose of interfacing
14  * with Yoctopuce products.
15  *
16  * You may reproduce and distribute copies of this file in
17  * source or object form, as long as the sole purpose of this
18  * code is to interface with Yoctopuce products. You must retain
19  * this notice in the distributed source file.
20  *
21  * You should refer to Yoctopuce General Terms and Conditions
22  * for additional information regarding your rights and
23  * obligations.
24  *
25  * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
26  * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
27  * WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS
28  * FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO
29  * EVENT SHALL LICENSOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
30  * INDIRECT OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
31  * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR
32  * SERVICES, ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT
33  * LIMITED TO ANY DEFENSE THEREOF), ANY CLAIMS FOR INDEMNITY OR
34  * CONTRIBUTION, OR OTHER SIMILAR COSTS, WHETHER ASSERTED ON THE
35  * BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF
36  * WARRANTY, OR OTHERWISE.
37  *
38  *********************************************************************/
39 #define __FILE_ID__ "yjson"
40 #include <string.h>
41 #include "yjson.h"
42 
43 #ifdef MICROCHIP_API
44 #define atoi parseUInt
45 #else
46 #include <stdio.h>
47 #include <stdlib.h>
48 #ifdef WINDOWS_API
49 #if defined(__BORLANDC__)
50 #pragma warn -8019
51 #include <windows.h>
52 #pragma warn +8019
53 #else
54 #include <windows.h>
55 #endif
56 #endif
57 #endif
58 
59 #ifdef DEBUG_JSON_PARSE
60 const char* yJsonStateStr[] = {
61  "YJSON_HTTP_START", // about to parse HTTP header, up to first space before return code
62  "YJSON_HTTP_READ_CODE", // reading HTTP return code
63  "YJSON_HTTP_READ_MSG", // reading HTTP return message
64  "YJSON_HTTP_SKIP", // skipping rest of HTTP header until double-CRLF
65  "YJSON_START", // about to parse JSON reply
66  "YJSON_PARSE_ANY", // parsing anything to come
67  "YJSON_PARSE_SYMBOL", // parsing a symbol (boolean)
68  "YJSON_PARSE_NUM", // parsing a number
69  "YJSON_PARSE_STRING", // parsing a quoted string
70  "YJSON_PARSE_STRINGQ", // parsing a quoted string, within quoted character
71  "YJSON_PARSE_STRINGCONT", // parsing the continuation of a quoted string
72  "YJSON_PARSE_STRINGCONTQ",// parsing the continuation of a quoted string, within quoted character
73  "YJSON_PARSE_ARRAY", // parsing an unnamed array
74  "YJSON_PARSE_STRUCT", // parsing a named structure
75  "YJSON_PARSE_MEMBSTART", // parsing a structure member (before name)
76  "YJSON_PARSE_MEMBNAME", // parsing a structure member name
77  "YJSON_PARSE_MEMBCOL", // parsing the colon between member name and value
78  "YJSON_PARSE_DONE", // parse completed, end of input data (or end of container)
79  "YJSON_PARSE_ERROR" // dead end, parse error encountered
80 };
81 #endif
82 
84 {
85  yJsonRetCode res;
86  yJsonState st = j->st;
87  _FAR const char *src = j->src;
88  _FAR const char *end = j->end;
89  char *pt = j->pt;
90  char *ept = j->token + sizeof(j->token) - 1;
91  unsigned char c=0;
92 
93 skip:
94  res = YJSON_NEED_INPUT;
95  if(st == YJSON_HTTP_START || st == YJSON_START || st == YJSON_PARSE_ANY) {
97  } else if(j->next != YJSON_PARSE_SPECIAL) {
98  st = j->next;
100  }
101 
102  while(1) {
103  switch(st) {
104  case YJSON_HTTP_START: // about to parse HTTP header, up to first space before return code
105  while(src < end && (c = *src) != ' ' && c != 'O' && c != '\r') src++;
106  if(src >= end) goto done;
107  if(c == ' ') src++; // skip space
108  pt = j->token;
110  // fall through
111  case YJSON_HTTP_READ_CODE: // reading HTTP return code
112  while(src < end && pt < ept && (c = *src) != ' ' && c != 'O' && c != '\r') {
113  if(c < '0' || c > '9') goto push_error;
114  *pt++ = c;
115  src++;
116  }
117  if(src >= end) goto done;
118  if(pt >= ept) goto push_error;
119  if(c == ' ') src++; // skip space
120  else if(c == 'O' && pt == j->token) {
121  // Handle short status "OK" as "HTTP/1.1 200 OK"
122  *pt++ = '2';*pt++ = '0';*pt++ = '0';
123  }
124  *pt = 0;
125  pt = j->token;
127  res = YJSON_PARSE_AVAIL;
128  goto done;
129  case YJSON_HTTP_READ_MSG: // reading HTTP return message
130  while(src < end && pt < ept && (c = *src) != '\r' && c != '\n') {
131  *pt++ = c;
132  src++;
133  }
134  if(src >= end) goto done;
135  *pt = 0;
136  pt = j->token;
137  j->next = YJSON_HTTP_SKIP;
138  res = YJSON_PARSE_AVAIL;
139  goto done;
140  case YJSON_HTTP_SKIP: // skipping rest of HTTP header until double-CRLF
141  while(src < end && pt < j->token+2) {
142  c = *src++;
143  if(c == '\n') *pt++ = '\n';
144  else if(c != '\r') pt = j->token;
145  }
146  if(src >= end) goto done;
147  st = YJSON_START;
148  // fall through
149  case YJSON_START: // about to parse JSON reply
150  j->depth = 0;
151  j->skipcnt = 0;
153  // fall through
154  case YJSON_PARSE_ANY: // parsing anything to come
155  while(src < end && ((c = *src) == ' ' || c == '\r' || c == '\n')) src++;
156  if(src >= end) goto done;
157  pt = j->token;
158  if(c == '{') {
159 #ifndef YAPI_IN_YDEVICE
160  j->state_start = src;
161 #endif
162  src++; st = YJSON_PARSE_STRUCT;
163 
164  }
165  else if(c == '[') {
166 #ifndef YAPI_IN_YDEVICE
167  j->state_start = src;
168 #endif
169  src++; st = YJSON_PARSE_ARRAY;
170  }
171  else if(c == '"') {
172 #ifndef YAPI_IN_YDEVICE
173  j->state_start = src;
174 #endif
175  src++; st = YJSON_PARSE_STRING;
176  }
177  else if(c=='-' || (c >= '0' && c <= '9')) {
178 #ifndef YAPI_IN_YDEVICE
179  j->state_start = src;
180 #endif
181  st = YJSON_PARSE_NUM;
182  }
183  else if(c >= 'A' && c <= 'z') {
184 #ifndef YAPI_IN_YDEVICE
185  j->state_start = src;
186 #endif
187  st = YJSON_PARSE_SYMBOL;
188  }
189  else if(j->depth > 0 && c == ']') { st = YJSON_PARSE_DONE; }
190  else goto push_error;
191  // continue into the selected state
192  continue;
193  case YJSON_PARSE_SYMBOL: // parsing a symbol (boolean)
194  while(src < end && pt < ept && (c = *src) >= 'A' && c <= 'z') {
195  *pt++ = c;
196  src++;
197  }
198  if(src >= end) goto done;
199  if(pt >= ept) goto push_error;
200  token_done:
201  *pt = 0;
202  j->next = YJSON_PARSE_DONE;
203 #ifndef YAPI_IN_YDEVICE
204  j->state_end = src;
205 #endif
206  res = YJSON_PARSE_AVAIL;
207  goto done;
208  case YJSON_PARSE_NUM: // parsing a number
209  while(src < end && pt < ept && ( (c = *src)=='-' || (c >= '0' && c <= '9') )) {
210  *pt++ = c;
211  src++;
212  }
213  if(src >= end) goto done;
214  if(pt >= ept) goto push_error;
215  goto token_done;
216  case YJSON_PARSE_STRING: // parsing a quoted string
217  case YJSON_PARSE_STRINGCONT: // parsing the continuation of a quoted string
218  while(src < end && pt < ept && (c = *src) != '"' && c != '\\') {
219  *pt++ = c;
220  src++;
221  }
222  if(src >= end) goto done;
223  if(pt >= ept) {
224  *pt = 0;
225  pt = j->token;
227  res = YJSON_PARSE_AVAIL;
228  goto done;
229  }
230  src++; // skip double-quote or backslash
231  if(c == '"') goto token_done;
232  if (st == YJSON_PARSE_STRING) {
233  st = YJSON_PARSE_STRINGQ;
234  } else {
236  }
237  // fall through
238  case YJSON_PARSE_STRINGQ: // parsing a quoted string, within quoted character
239  case YJSON_PARSE_STRINGCONTQ:// parsing the continuation of a quoted string, within quoted character
240  if(src >= end) goto done;
241  c = *src++;
242  switch(c) {
243  case 'r': *pt++ = '\r'; break;
244  case 'n': *pt++ = '\n'; break;
245  case 't': *pt++ = '\t'; break;
246  default: *pt++ = c;
247  }
248  if (st == YJSON_PARSE_STRINGQ) {
249  st = YJSON_PARSE_STRING;
250  } else {
252  }
253  // continue string parsing;
254  continue;
255  case YJSON_PARSE_ARRAY: // parsing an unnamed array
256  while(src < end && (*src == ' ' || *src == '\r' || *src == '\n')) src++;
257  if(src >= end) goto done;
258  if(*src == ']') {
259  j->next = YJSON_PARSE_DONE;
260  }else{
261  j->next = YJSON_PARSE_ANY;
262  }
263  c = '[';
264  goto nest;
265  case YJSON_PARSE_STRUCT: // parsing a named structure
267  c = '{';
268  nest:
269  if(j->depth >= YJSON_MAX_DEPTH) goto push_error;
270  j->stack[j->depth++] = st;
271  *pt++ = c;
272  *pt = 0;
273  res = YJSON_PARSE_AVAIL;
274  goto done;
275  case YJSON_PARSE_MEMBSTART: // parsing a structure member (before name)
276  while(src < end && ((c = *src) == ' ' || c == '\r' || c == '\n')) src++;
277  if(src >= end) goto done;
278  if(c == '}') {
279  st = YJSON_PARSE_DONE;
280  continue;
281  }
282  if(c != '"') goto push_error;
283  src++;
284  pt = j->token;
286  // fall through
287  case YJSON_PARSE_MEMBNAME: // parsing a structure member name
288  while(src < end && pt < ept && (c = *src) != '"') {
289  *pt++ = c;
290  src++;
291  }
292  if(src >= end) goto done;
293  if(pt >= ept) goto push_error;
294  src++;
295  *pt = 0;
297  res = YJSON_PARSE_AVAIL;
298  goto done;
299  case YJSON_PARSE_MEMBCOL: // parsing the colon between member name and value
300  while(src < end && ((c = *src) == ' ' || c == '\r' || c == '\n')) src++;
301  if(src >= end) goto done;
302  if(c != ':') goto push_error;
303  src++;
304  st = YJSON_PARSE_ANY;
305  continue; // continue parse
306  case YJSON_PARSE_DONE: // parse completed, end of input data
307  while(src < end && ((c = *src) == ' ' || c == '\r' || c == '\n')) src++;
308  pt = j->token;
309  if(j->depth > 0) {
310  if(src >= end) goto done;
311  if(j->stack[j->depth-1] == YJSON_PARSE_STRUCT) {
312  if(c == ',') { src++; st = YJSON_PARSE_MEMBSTART; }
313  else if(c == '}') goto un_nest;
314  else goto push_error;
315  } else { // YJSON_PARSE_ARRAY
316  if(c == ',') { src++; st = YJSON_PARSE_ANY; }
317  else if(c == ']') {
318  un_nest:
319  *pt++ = *src++;
320  st = j->stack[--(j->depth)];
321  goto token_done;
322  }
323  else goto push_error;
324  }
325  continue; // continue to parse nested block
326  }
327  if(src < end) goto push_error; // unexpected content at end of JSON data
328  *pt = 0;
329  res = YJSON_SUCCESS;
330  goto done;
331  // save current state if possible, and trigger an error
332  push_error:
333  if(j->depth < YJSON_MAX_DEPTH)
334  j->stack[j->depth++] = st;
335  st = YJSON_PARSE_ERROR;
336  // fall through
337  case YJSON_PARSE_ERROR: // dead end, parse error encountered
338  res = YJSON_FAILED;
339  goto done;
340  case YJSON_PARSE_SPECIAL: // should never happen
341  res = YJSON_FAILED;
342  goto done;
343  }
344  }
345 done:
346  if(st >= YJSON_START && res == YJSON_PARSE_AVAIL) {
347  if(j->skipdepth <= j->depth) {
348  if(j->skipdepth == j->depth) {
350  }
351  goto skip;
352  }
353  if(j->skipcnt > 0) {
354  if(st == YJSON_PARSE_STRUCT || st == YJSON_PARSE_ARRAY) {
355  j->skipdepth = j->depth-1;
356  }
357  j->skipcnt--;
358  goto skip;
359  }
360  }
361  j->st = st;
362  j->src = src;
363  j->pt = pt;
364  return res;
365 }
366 
367 void yJsonSkip(yJsonStateMachine *j, int nitems)
368 {
369  j->skipcnt += nitems;
370 }
371 
372 #if 0
373 void yJsonInitEx(yJsonStateMachineEx *j, const char *jzon, int jzon_len, const char *ref, int ref_len)
374 {
375 
376  memset(j, 0, sizeof(yJsonStateMachineEx));
377  j->jzon.src = jzon;
378  j->jzon.end = jzon + jzon_len;
379  j->jzon.st = YJSON_START;
380  if (ref) {
381  j->ref.src = ref;
382  j->ref.end = ref + ref_len;
383  j->ref.st = YJSON_START;
384  }
385  j->sst = JZON_PARSE_SYNCRO;
386 }
387 
388 
389 yJsonRetCode yJsonParseEx(yJsonStateMachineEx *j)
390 {
391  yJsonRetCode ref_res;
392  if (j->ref.src == NULL) {
393  ref_res = yJsonParse(&j->jzon);
394  j->st = j->jzon.st;
395  j->next = j->jzon.next;
396  memcpy(j->token, j->jzon.token, sizeof(j->token));
397  return ref_res;
398  }
399 
400  switch (j->sst) {
401  case JZON_PARSE_SYNCRO:
402  ref_res = yJsonParse(&j->ref);
403  if (ref_res != YJSON_PARSE_AVAIL) {
404  return ref_res;
405  }
406  ref_res = yJsonParse(&j->jzon);
407  if (ref_res != YJSON_PARSE_AVAIL) {
408  return ref_res;
409  }
410  switch (j->ref.st) {
411  case YJSON_PARSE_STRUCT:
412  if (j->jzon.st == YJSON_PARSE_ARRAY) {
413  j->sst = JZON_PARSE_ONLY_REF;
414  }
415  j->sst_stack[j->depth++] = j->sst;
416  // no break on purpose
418  j->st = j->ref.st;
419  j->next = j->ref.next;
420  memcpy(j->token, j->ref.token, sizeof(j->token));
421  break;
422  case YJSON_PARSE_STRING:
423  // skip value with potential continuation
424  while (j->ref.next == YJSON_PARSE_STRINGCONT && yJsonParse(&j->ref) == YJSON_PARSE_AVAIL);
425  if (j->jzon.next == YJSON_PARSE_STRINGCONT) {
426  j->sst = JZON_PARSE_ONLY_YZON;
427  }
428  //no break on purpose
429  default:
430  j->st = j->jzon.st;
431  j->next = j->jzon.next;
432  memcpy(j->token, j->jzon.token, sizeof(j->token));
433  if (j->next == YJSON_PARSE_DONE) {
434  j->sst = j->sst_stack[j->depth - 1];
435  }
436  break;
437  }
438  break;
439  case JZON_PARSE_ONLY_REF:
440  ref_res = yJsonParse(&j->ref);
441  if (ref_res != YJSON_PARSE_AVAIL) {
442  return -1;
443  }
444  j->st = j->ref.st;
445  j->next = j->ref.next;
446  memcpy(j->token, j->ref.token, sizeof(j->token));
447  if (j->ref.st == YJSON_PARSE_MEMBNAME) {
448  j->sst = JZON_PARSE_SYNCRO;
449  }
450  break;
451  case JZON_PARSE_ONLY_YZON:
452  ref_res = yJsonParse(&j->jzon);
453  if (ref_res != YJSON_PARSE_AVAIL) {
454  return -1;
455  }
456  j->st = j->jzon.st;
457  j->next = j->jzon.next;
458  memcpy(j->token, j->jzon.token, sizeof(j->token));
459  if (j->jzon.next != YJSON_PARSE_STRINGCONT) {
460  j->sst = JZON_PARSE_SYNCRO;
461  }
462  break;
463  }
464 
465  return YJSON_PARSE_AVAIL;
466 }
467 
468 
469 void yJsonSkipEx(yJsonStateMachineEx *j, int nitems)
470 {
471  if (j->ref.src == NULL) {
472  j->jzon.skipcnt += nitems;
473  return;
474  }
475  switch (j->sst) {
476  case JZON_PARSE_SYNCRO:
477  j->ref.skipcnt += nitems;
478  j->jzon.skipcnt += nitems;
479  break;
480 
481  case JZON_PARSE_ONLY_REF:
482  j->ref.skipcnt += nitems;
483  break;
484  case JZON_PARSE_ONLY_YZON:
485  j->jzon.skipcnt += nitems;
486  break;
487  }
488 }
489 #endif
490 
_FAR const char * state_start
Definition: yjson.h:93
char token[62]
Definition: yjson.h:88
yJsonState next
Definition: yjson.h:85
yJsonRetCode yJsonParse(yJsonStateMachine *j)
Definition: yjson.c:83
_FAR const char * src
Definition: yjson.h:82
void yJsonSkip(yJsonStateMachine *j, int nitems)
Definition: yjson.c:367
#define YJSON_MAX_DEPTH
Definition: yjson.h:50
_FAR const char * end
Definition: yjson.h:83
char * pt
Definition: yjson.h:89
yJsonState st
Definition: yjson.h:84
yJsonState stack[YJSON_MAX_DEPTH]
Definition: yjson.h:86
yJsonState
Definition: yjson.h:52
#define _FAR
Definition: ydef.h:285
yJsonRetCode
Definition: yjson.h:99
_FAR const char * state_end
Definition: yjson.h:94


yoctopuce_altimeter
Author(s): Anja Sheppard
autogenerated on Mon Jun 10 2019 15:49:10