Contiki-NG
jsonparse.c
1/*
2 * Copyright (c) 2011-2012, Swedish Institute of Computer Science.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 */
31
32#include "jsonparse.h"
33#include <stdlib.h>
34#include <string.h>
35#include <stdbool.h>
36
37/*--------------------------------------------------------------------*/
38static bool
39push(struct jsonparse_state *state, char c)
40{
41 if(state->depth < JSONPARSE_MAX_DEPTH) {
42 state->stack[state->depth] = c;
43 state->depth++;
44 state->vtype = 0;
45 return true;
46 } else {
47 return false;
48 }
49}
50/*--------------------------------------------------------------------*/
51static bool
52modify(struct jsonparse_state *state, char c)
53{
54 if(state->depth > 0) {
55 state->stack[state->depth - 1] = c;
56 return true;
57 } else {
58 return false;
59 }
60}
61/*--------------------------------------------------------------------*/
62static bool
63pop(struct jsonparse_state *state)
64{
65 if(state->depth == 0) {
66 return false;
67 }
68 state->depth--;
69 state->vtype = state->stack[state->depth];
70 return true;
71}
72/*--------------------------------------------------------------------*/
73/* will pass by the value and store the start and length of the value for
74 atomic types */
75/*--------------------------------------------------------------------*/
76static char
77atomic(struct jsonparse_state *state, char type)
78{
79 char c;
80 const char *str;
81 int len;
82
83 state->vstart = state->pos;
84 if(type == JSON_TYPE_STRING || type == JSON_TYPE_PAIR_NAME) {
85 while((c = state->json[state->pos++]) && c != '"') {
86 if(c == '\\') {
87 state->pos++; /* skip current char */
88 }
89 }
90 if (c != '"') {
91 state->error = JSON_ERROR_SYNTAX;
92 return JSON_TYPE_ERROR;
93 }
94 state->vlen = state->pos - state->vstart - 1;
95 } else if(type == JSON_TYPE_NUMBER) {
96 do {
97 c = state->json[state->pos];
98 if((c < '0' || c > '9') && c != '.') {
99 c = 0;
100 } else {
101 state->pos++;
102 }
103 } while(c);
104 /* need to back one step since first char is already gone */
105 state->vstart--;
106 state->vlen = state->pos - state->vstart;
107 } else if(type == JSON_TYPE_NULL || type == JSON_TYPE_TRUE || type == JSON_TYPE_FALSE) {
108 state->vstart--;
109 switch (type) {
110 case JSON_TYPE_NULL: str = "null"; break;
111 case JSON_TYPE_TRUE: str = "true"; break;
112 case JSON_TYPE_FALSE: str = "false"; break;
113 default: str = ""; break;
114 }
115
116 while ((c = state->json[state->pos]) && c != ' ' && c != ',' && c != ']' && c != '}') {
117 state->pos++;
118 }
119
120 state->vlen = state->pos - state->vstart;
121 len = strlen(str);
122 len = state->vlen > len ? state->vlen : len;
123
124 if (strncmp(str, &state->json[state->vstart], len) != 0) {
125 state->error = JSON_ERROR_SYNTAX;
126 return JSON_TYPE_ERROR;
127 }
128 }
129
130 state->vtype = type;
131 return state->vtype;
132}
133/*--------------------------------------------------------------------*/
134static void
135skip_ws(struct jsonparse_state *state)
136{
137 char c;
138
139 while(state->pos < state->len &&
140 ((c = state->json[state->pos]) == ' ' || c == '\n')) {
141 state->pos++;
142 }
143}
144/*--------------------------------------------------------------------*/
145static bool
146is_atomic(struct jsonparse_state *state)
147{
148 char v = state->vtype;
149 return v == 'N' || v == '"' || v == '0' || v == 'n' || v == 't' || v == 'f';
150}
151/*--------------------------------------------------------------------*/
152void
153jsonparse_setup(struct jsonparse_state *state, const char *json, int len)
154{
155 state->json = json;
156 state->len = len;
157 state->pos = 0;
158 state->depth = 0;
159 state->error = 0;
160 state->vtype = 0;
161 state->stack[0] = 0;
162}
163/*--------------------------------------------------------------------*/
164int
165jsonparse_next(struct jsonparse_state *state)
166{
167 char c;
168 char s;
169 char v;
170 bool ret;
171
172 skip_ws(state);
173 c = state->json[state->pos];
174 s = jsonparse_get_type(state);
175 v = state->vtype;
176 state->pos++;
177
178 switch(c) {
179 case '{':
180 if((s == 0 && v == 0) || s == '[' || s == ':') {
181 if(push(state, c)) {
182 return c;
183 }
184 }
185 state->error = JSON_ERROR_UNEXPECTED_OBJECT;
186 return JSON_TYPE_ERROR;
187 case '}':
188 if((s == ':' && v != ',' && v != 0 ) || (s == '{' && v == 0)) {
189 if(pop(state)) {
190 return c;
191 }
192 }
193 state->error = JSON_ERROR_UNEXPECTED_END_OF_OBJECT;
194 return JSON_TYPE_ERROR;
195 case ']':
196 if(s == '[' && v != ',') {
197 if(pop(state)) {
198 return c;
199 }
200 }
201 state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY;
202 return JSON_TYPE_ERROR;
203 case ':':
204 if(s == '{' && v == 'N') {
205 ret = modify(state, ':');
206 state->vtype = 0;
207 if(ret) {
208 return jsonparse_next(state);
209 }
210 }
211 state->error = JSON_ERROR_SYNTAX;
212 return JSON_TYPE_ERROR;
213 case ',':
214 if(s == ':' && v != 0) {
215 ret = modify(state, '{');
216 state->vtype = c;
217 if(ret) {
218 return c;
219 }
220 } else if(s == '[') {
221 state->vtype = c;
222 return c;
223 }
224 state->error = JSON_ERROR_SYNTAX;
225 return JSON_TYPE_ERROR;
226 case '"':
227 if((s == 0 && v == 0) || s == '{' || s == '[' || s == ':') {
228 return atomic(state, c = (s == '{' ? JSON_TYPE_PAIR_NAME : c));
229 } else {
230 state->error = JSON_ERROR_UNEXPECTED_STRING;
231 return JSON_TYPE_ERROR;
232 }
233 return c;
234 case '[':
235 if((s == 0 && v == 0) || s == '[' || s == ':') {
236 if(push(state, c)) {
237 return c;
238 }
239 }
240 state->error = JSON_ERROR_UNEXPECTED_ARRAY;
241 return JSON_TYPE_ERROR;
242 case 0:
243 if(v == 0 || state->depth > 0) {
244 state->error = JSON_ERROR_SYNTAX;
245 }
246 return JSON_TYPE_ERROR;
247 default:
248 if(s == 0 || s == ':' || s == '[') {
249 if (v != 0 && v != ',') {
250 state->error = JSON_ERROR_SYNTAX;
251 return JSON_TYPE_ERROR;
252 }
253 if(c == '-' || (c <= '9' && c >= '0')) {
254 return atomic(state, JSON_TYPE_NUMBER);
255 } else if(c == 'n') {
256 return atomic(state, JSON_TYPE_NULL);
257 } else if(c == 't') {
258 return atomic(state, JSON_TYPE_TRUE);
259 } else if(c == 'f') {
260 return atomic(state, JSON_TYPE_FALSE);
261 } else {
262 state->error = JSON_ERROR_SYNTAX;
263 return JSON_TYPE_ERROR;
264 }
265 } else if(s == '{') {
266 state->error = JSON_ERROR_SYNTAX;
267 return JSON_TYPE_ERROR;
268 }
269 }
270 return 0;
271}
272/*--------------------------------------------------------------------*/
273/* get the json value of the current position
274 * works only on "atomic" values such as string, number, null, false, true
275 */
276/*--------------------------------------------------------------------*/
277int
278jsonparse_copy_value(struct jsonparse_state *state, char *str, int size)
279{
280 int i, o;
281 char c;
282
283 if(!is_atomic(state)) {
284 return 0;
285 }
286 for(i = 0, o = 0; i < state->vlen && o < size - 1; i++) {
287 c = state->json[state->vstart + i];
288 if(c == '\\') {
289 i++;
290 switch(state->json[state->vstart + i]) {
291 case '"': str[o++] = '"'; break;
292 case '\\': str[o++] = '\\'; break;
293 case '/': str[o++] = '/'; break;
294 case 'b': str[o++] = '\b'; break;
295 case 'f': str[o++] = '\f'; break;
296 case 'n': str[o++] = '\n'; break;
297 case 'r': str[o++] = '\r'; break;
298 case 't': str[o++] = '\t'; break;
299 }
300 continue;
301 }
302 str[o++] = c;
303 }
304 str[o] = 0;
305 return state->vtype;
306}
307/*--------------------------------------------------------------------*/
308int
309jsonparse_get_value_as_int(struct jsonparse_state *state)
310{
311 if(state->vtype != JSON_TYPE_NUMBER) {
312 return 0;
313 }
314 return atoi(&state->json[state->vstart]);
315}
316/*--------------------------------------------------------------------*/
317long
318jsonparse_get_value_as_long(struct jsonparse_state *state)
319{
320 if(state->vtype != JSON_TYPE_NUMBER) {
321 return 0;
322 }
323 return atol(&state->json[state->vstart]);
324}
325/*--------------------------------------------------------------------*/
326/* strcmp - assume no strange chars that needs to be stuffed in string... */
327/*--------------------------------------------------------------------*/
328int
329jsonparse_strcmp_value(struct jsonparse_state *state, const char *str)
330{
331 if(!is_atomic(state)) {
332 return -1;
333 }
334 return strncmp(str, &state->json[state->vstart], state->vlen);
335}
336/*--------------------------------------------------------------------*/
337int
338jsonparse_get_len(struct jsonparse_state *state)
339{
340 return state->vlen;
341}
342/*--------------------------------------------------------------------*/
343int
344jsonparse_get_type(struct jsonparse_state *state)
345{
346 if(state->depth == 0) {
347 return 0;
348 }
349 return state->stack[state->depth - 1];
350}
351/*--------------------------------------------------------------------*/
352int
353jsonparse_has_next(struct jsonparse_state *state)
354{
355 return state->pos < state->len;
356}
357/*--------------------------------------------------------------------*/