Initial VES for DANOS vRouter
[demo.git] / vnfs / VESreporting_vFW5.0_DANOS / evel / evel-library / code / evel_library / jsmn.c
1 /*************************************************************************//**
2  *
3  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
4  *
5  * Unless otherwise specified, all software contained herein is
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and 
15  * limitations under the License.
16  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
17  ****************************************************************************/
18
19 #include "jsmn.h"
20
21 /**
22  * Allocates a fresh unused token from the token pull.
23  */
24 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
25                 jsmntok_t *tokens, size_t num_tokens) {
26         jsmntok_t *tok;
27         if (parser->toknext >= num_tokens) {
28                 return NULL;
29         }
30         tok = &tokens[parser->toknext++];
31         tok->start = tok->end = -1;
32         tok->size = 0;
33 #ifdef JSMN_PARENT_LINKS
34         tok->parent = -1;
35 #endif
36         return tok;
37 }
38
39 /**
40  * Fills token type and boundaries.
41  */
42 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
43                             int start, int end) {
44         token->type = type;
45         token->start = start;
46         token->end = end;
47         token->size = 0;
48 }
49
50 /**
51  * Fills next available token with JSON primitive.
52  */
53 static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
54                 size_t len, jsmntok_t *tokens, size_t num_tokens) {
55         jsmntok_t *token;
56         int start;
57
58         start = parser->pos;
59
60         for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
61                 switch (js[parser->pos]) {
62 #ifndef JSMN_STRICT
63                         /* In strict mode primitive must be followed by "," or "}" or "]" */
64                         case ':':
65 #endif
66                         case '\t' : case '\r' : case '\n' : case ' ' :
67                         case ','  : case ']'  : case '}' :
68                                 goto found;
69                 }
70                 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
71                         parser->pos = start;
72                         return JSMN_ERROR_INVAL;
73                 }
74         }
75 #ifdef JSMN_STRICT
76         /* In strict mode primitive must be followed by a comma/object/array */
77         parser->pos = start;
78         return JSMN_ERROR_PART;
79 #endif
80
81 found:
82         if (tokens == NULL) {
83                 parser->pos--;
84                 return 0;
85         }
86         token = jsmn_alloc_token(parser, tokens, num_tokens);
87         if (token == NULL) {
88                 parser->pos = start;
89                 return JSMN_ERROR_NOMEM;
90         }
91         jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
92 #ifdef JSMN_PARENT_LINKS
93         token->parent = parser->toksuper;
94 #endif
95         parser->pos--;
96         return 0;
97 }
98
99 /**
100  * Fills next token with JSON string.
101  */
102 static int jsmn_parse_string(jsmn_parser *parser, const char *js,
103                 size_t len, jsmntok_t *tokens, size_t num_tokens) {
104         jsmntok_t *token;
105
106         int start = parser->pos;
107
108         parser->pos++;
109
110         /* Skip starting quote */
111         for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
112                 char c = js[parser->pos];
113
114                 /* Quote: end of string */
115                 if (c == '\"') {
116                         if (tokens == NULL) {
117                                 return 0;
118                         }
119                         token = jsmn_alloc_token(parser, tokens, num_tokens);
120                         if (token == NULL) {
121                                 parser->pos = start;
122                                 return JSMN_ERROR_NOMEM;
123                         }
124                         jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
125 #ifdef JSMN_PARENT_LINKS
126                         token->parent = parser->toksuper;
127 #endif
128                         return 0;
129                 }
130
131                 /* Backslash: Quoted symbol expected */
132                 if (c == '\\' && parser->pos + 1 < len) {
133                         int i;
134                         parser->pos++;
135                         switch (js[parser->pos]) {
136                                 /* Allowed escaped symbols */
137                                 case '\"': case '/' : case '\\' : case 'b' :
138                                 case 'f' : case 'r' : case 'n'  : case 't' :
139                                         break;
140                                 /* Allows escaped symbol \uXXXX */
141                                 case 'u':
142                                         parser->pos++;
143                                         for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
144                                                 /* If it isn't a hex character we have an error */
145                                                 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
146                                                                         (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
147                                                                         (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
148                                                         parser->pos = start;
149                                                         return JSMN_ERROR_INVAL;
150                                                 }
151                                                 parser->pos++;
152                                         }
153                                         parser->pos--;
154                                         break;
155                                 /* Unexpected symbol */
156                                 default:
157                                         parser->pos = start;
158                                         return JSMN_ERROR_INVAL;
159                         }
160                 }
161         }
162         parser->pos = start;
163         return JSMN_ERROR_PART;
164 }
165
166 /**
167  * Parse JSON string and fill tokens.
168  */
169 int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
170                 jsmntok_t *tokens, unsigned int num_tokens) {
171         int r;
172         int i;
173         jsmntok_t *token;
174         int count = parser->toknext;
175
176         for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
177                 char c;
178                 jsmntype_t type;
179
180                 c = js[parser->pos];
181                 switch (c) {
182                         case '{': case '[':
183                                 count++;
184                                 if (tokens == NULL) {
185                                         break;
186                                 }
187                                 token = jsmn_alloc_token(parser, tokens, num_tokens);
188                                 if (token == NULL)
189                                         return JSMN_ERROR_NOMEM;
190                                 if (parser->toksuper != -1) {
191                                         tokens[parser->toksuper].size++;
192 #ifdef JSMN_PARENT_LINKS
193                                         token->parent = parser->toksuper;
194 #endif
195                                 }
196                                 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
197                                 token->start = parser->pos;
198                                 parser->toksuper = parser->toknext - 1;
199                                 break;
200                         case '}': case ']':
201                                 if (tokens == NULL)
202                                         break;
203                                 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
204 #ifdef JSMN_PARENT_LINKS
205                                 if (parser->toknext < 1) {
206                                         return JSMN_ERROR_INVAL;
207                                 }
208                                 token = &tokens[parser->toknext - 1];
209                                 for (;;) {
210                                         if (token->start != -1 && token->end == -1) {
211                                                 if (token->type != type) {
212                                                         return JSMN_ERROR_INVAL;
213                                                 }
214                                                 token->end = parser->pos + 1;
215                                                 parser->toksuper = token->parent;
216                                                 break;
217                                         }
218                                         if (token->parent == -1) {
219                                                 break;
220                                         }
221                                         token = &tokens[token->parent];
222                                 }
223 #else
224                                 for (i = parser->toknext - 1; i >= 0; i--) {
225                                         token = &tokens[i];
226                                         if (token->start != -1 && token->end == -1) {
227                                                 if (token->type != type) {
228                                                         return JSMN_ERROR_INVAL;
229                                                 }
230                                                 parser->toksuper = -1;
231                                                 token->end = parser->pos + 1;
232                                                 break;
233                                         }
234                                 }
235                                 /* Error if unmatched closing bracket */
236                                 if (i == -1) return JSMN_ERROR_INVAL;
237                                 for (; i >= 0; i--) {
238                                         token = &tokens[i];
239                                         if (token->start != -1 && token->end == -1) {
240                                                 parser->toksuper = i;
241                                                 break;
242                                         }
243                                 }
244 #endif
245                                 break;
246                         case '\"':
247                                 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
248                                 if (r < 0) return r;
249                                 count++;
250                                 if (parser->toksuper != -1 && tokens != NULL)
251                                         tokens[parser->toksuper].size++;
252                                 break;
253                         case '\t' : case '\r' : case '\n' : case ' ':
254                                 break;
255                         case ':':
256                                 parser->toksuper = parser->toknext - 1;
257                                 break;
258                         case ',':
259                                 if (tokens != NULL && parser->toksuper != -1 &&
260                                                 tokens[parser->toksuper].type != JSMN_ARRAY &&
261                                                 tokens[parser->toksuper].type != JSMN_OBJECT) {
262 #ifdef JSMN_PARENT_LINKS
263                                         parser->toksuper = tokens[parser->toksuper].parent;
264 #else
265                                         for (i = parser->toknext - 1; i >= 0; i--) {
266                                                 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
267                                                         if (tokens[i].start != -1 && tokens[i].end == -1) {
268                                                                 parser->toksuper = i;
269                                                                 break;
270                                                         }
271                                                 }
272                                         }
273 #endif
274                                 }
275                                 break;
276 #ifdef JSMN_STRICT
277                         /* In strict mode primitives are: numbers and booleans */
278                         case '-': case '0': case '1' : case '2': case '3' : case '4':
279                         case '5': case '6': case '7' : case '8': case '9':
280                         case 't': case 'f': case 'n' :
281                                 /* And they must not be keys of the object */
282                                 if (tokens != NULL && parser->toksuper != -1) {
283                                         jsmntok_t *t = &tokens[parser->toksuper];
284                                         if (t->type == JSMN_OBJECT ||
285                                                         (t->type == JSMN_STRING && t->size != 0)) {
286                                                 return JSMN_ERROR_INVAL;
287                                         }
288                                 }
289 #else
290                         /* In non-strict mode every unquoted value is a primitive */
291                         default:
292 #endif
293                                 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
294                                 if (r < 0) return r;
295                                 count++;
296                                 if (parser->toksuper != -1 && tokens != NULL)
297                                         tokens[parser->toksuper].size++;
298                                 break;
299
300 #ifdef JSMN_STRICT
301                         /* Unexpected char in strict mode */
302                         default:
303                                 return JSMN_ERROR_INVAL;
304 #endif
305                 }
306         }
307
308         if (tokens != NULL) {
309                 for (i = parser->toknext - 1; i >= 0; i--) {
310                         /* Unmatched opened object or array */
311                         if (tokens[i].start != -1 && tokens[i].end == -1) {
312                                 return JSMN_ERROR_PART;
313                         }
314                 }
315         }
316
317         return count;
318 }
319
320 /**
321  * Creates a new parser based over a given  buffer with an array of tokens
322  * available.
323  */
324 void jsmn_init(jsmn_parser *parser) {
325         parser->pos = 0;
326         parser->toknext = 0;
327         parser->toksuper = -1;
328 }
329