]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libpmc/pmu-events/jsmn.c
MFV: zlib 1.3
[FreeBSD/FreeBSD.git] / lib / libpmc / pmu-events / jsmn.c
1 /*
2  * Copyright (c) 2010 Serge A. Zaitsev
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  *
22  * Slightly modified by AK to not assume 0 terminated input.
23  *
24  */
25
26 #include <stdlib.h>
27 #include "jsmn.h"
28 #define JSMN_STRICT
29
30 /*
31  * Allocates a fresh unused token from the token pool.
32  */
33 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
34                                    jsmntok_t *tokens, size_t num_tokens)
35 {
36         jsmntok_t *tok;
37
38         if ((unsigned)parser->toknext >= num_tokens)
39                 return NULL;
40         tok = &tokens[parser->toknext++];
41         tok->start = tok->end = -1;
42         tok->size = 0;
43         return tok;
44 }
45
46 /*
47  * Fills token type and boundaries.
48  */
49 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
50                             int start, int end)
51 {
52         token->type = type;
53         token->start = start;
54         token->end = end;
55         token->size = 0;
56 }
57
58 /*
59  * Fills next available token with JSON primitive.
60  */
61 static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
62                                       size_t len,
63                                       jsmntok_t *tokens, size_t num_tokens)
64 {
65         jsmntok_t *token;
66         int start;
67
68         start = parser->pos;
69
70         for (; parser->pos < len; parser->pos++) {
71                 switch (js[parser->pos]) {
72 #ifndef JSMN_STRICT
73                 /*
74                  * In strict mode primitive must be followed by ","
75                  * or "}" or "]"
76                  */
77                 case ':':
78 #endif
79                 case '\t':
80                 case '\r':
81                 case '\n':
82                 case ' ':
83                 case ',':
84                 case ']':
85                 case '}':
86                         goto found;
87                 default:
88                         break;
89                 }
90                 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
91                         parser->pos = start;
92                         return JSMN_ERROR_INVAL;
93                 }
94         }
95 #ifdef JSMN_STRICT
96         /*
97          * In strict mode primitive must be followed by a
98          * comma/object/array.
99          */
100         parser->pos = start;
101         return JSMN_ERROR_PART;
102 #endif
103
104 found:
105         token = jsmn_alloc_token(parser, tokens, num_tokens);
106         if (token == NULL) {
107                 parser->pos = start;
108                 return JSMN_ERROR_NOMEM;
109         }
110         jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
111         parser->pos--; /* parent sees closing brackets */
112         return JSMN_SUCCESS;
113 }
114
115 /*
116  * Fills next token with JSON string.
117  */
118 static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
119                                    size_t len,
120                                    jsmntok_t *tokens, size_t num_tokens)
121 {
122         jsmntok_t *token;
123         int start = parser->pos;
124
125         /* Skip starting quote */
126         parser->pos++;
127
128         for (; parser->pos < len; parser->pos++) {
129                 char c = js[parser->pos];
130
131                 /* Quote: end of string */
132                 if (c == '\"') {
133                         token = jsmn_alloc_token(parser, tokens, num_tokens);
134                         if (token == NULL) {
135                                 parser->pos = start;
136                                 return JSMN_ERROR_NOMEM;
137                         }
138                         jsmn_fill_token(token, JSMN_STRING, start+1,
139                                         parser->pos);
140                         return JSMN_SUCCESS;
141                 }
142
143                 /* Backslash: Quoted symbol expected */
144                 if (c == '\\') {
145                         parser->pos++;
146                         switch (js[parser->pos]) {
147                                 /* Allowed escaped symbols */
148                         case '\"':
149                         case '/':
150                         case '\\':
151                         case 'b':
152                         case 'f':
153                         case 'r':
154                         case 'n':
155                         case 't':
156                                 break;
157                                 /* Allows escaped symbol \uXXXX */
158                         case 'u':
159                                 /* TODO */
160                                 break;
161                                 /* Unexpected symbol */
162                         default:
163                                 parser->pos = start;
164                                 return JSMN_ERROR_INVAL;
165                         }
166                 }
167         }
168         parser->pos = start;
169         return JSMN_ERROR_PART;
170 }
171
172 /*
173  * Parse JSON string and fill tokens.
174  */
175 jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
176                      jsmntok_t *tokens, unsigned int num_tokens)
177 {
178         jsmnerr_t r;
179         int i;
180         jsmntok_t *token;
181 #ifdef JSMN_STRICT
182         /*
183          * Keeps track of whether a new object/list/primitive is expected. New items are only
184          * allowed after an opening brace, comma or colon. A closing brace after a comma is not
185          * valid JSON.
186          */
187         int expecting_item = 1;
188 #endif
189
190         for (; parser->pos < len; parser->pos++) {
191                 char c;
192                 jsmntype_t type;
193
194                 c = js[parser->pos];
195                 switch (c) {
196                 case '{':
197                 case '[':
198 #ifdef JSMN_STRICT
199                         if (!expecting_item)
200                                 return JSMN_ERROR_INVAL;
201 #endif
202                         token = jsmn_alloc_token(parser, tokens, num_tokens);
203                         if (token == NULL)
204                                 return JSMN_ERROR_NOMEM;
205                         if (parser->toksuper != -1)
206                                 tokens[parser->toksuper].size++;
207                         token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
208                         token->start = parser->pos;
209                         parser->toksuper = parser->toknext - 1;
210                         break;
211                 case '}':
212                 case ']':
213 #ifdef JSMN_STRICT
214                         if (expecting_item)
215                                 return JSMN_ERROR_INVAL;
216 #endif
217                         type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
218                         for (i = parser->toknext - 1; i >= 0; i--) {
219                                 token = &tokens[i];
220                                 if (token->start != -1 && token->end == -1) {
221                                         if (token->type != type)
222                                                 return JSMN_ERROR_INVAL;
223                                         parser->toksuper = -1;
224                                         token->end = parser->pos + 1;
225                                         break;
226                                 }
227                         }
228                         /* Error if unmatched closing bracket */
229                         if (i == -1)
230                                 return JSMN_ERROR_INVAL;
231                         for (; i >= 0; i--) {
232                                 token = &tokens[i];
233                                 if (token->start != -1 && token->end == -1) {
234                                         parser->toksuper = i;
235                                         break;
236                                 }
237                         }
238                         break;
239                 case '\"':
240 #ifdef JSMN_STRICT
241                         if (!expecting_item)
242                                 return JSMN_ERROR_INVAL;
243                         expecting_item = 0;
244 #endif
245                         r = jsmn_parse_string(parser, js, len, tokens,
246                                               num_tokens);
247                         if (r < 0)
248                                 return r;
249                         if (parser->toksuper != -1)
250                                 tokens[parser->toksuper].size++;
251                         break;
252                 case '\t':
253                 case '\r':
254                 case '\n':
255                 case ' ':
256                         break;
257 #ifdef JSMN_STRICT
258                 case ':':
259                 case ',':
260                         if (expecting_item)
261                                 return JSMN_ERROR_INVAL;
262                         expecting_item = 1;
263                         break;
264                         /*
265                          * In strict mode primitives are:
266                          * numbers and booleans.
267                          */
268                 case '-':
269                 case '0':
270                 case '1':
271                 case '2':
272                 case '3':
273                 case '4':
274                 case '5':
275                 case '6':
276                 case '7':
277                 case '8':
278                 case '9':
279                 case 't':
280                 case 'f':
281                 case 'n':
282 #else
283                 case ':':
284                 case ',':
285                         break;
286                         /*
287                          * In non-strict mode every unquoted value
288                          * is a primitive.
289                          */
290                         /*FALL THROUGH */
291                 default:
292 #endif
293
294 #ifdef JSMN_STRICT
295                         if (!expecting_item)
296                                 return JSMN_ERROR_INVAL;
297                         expecting_item = 0;
298 #endif
299                         r = jsmn_parse_primitive(parser, js, len, tokens,
300                                                  num_tokens);
301                         if (r < 0)
302                                 return r;
303                         if (parser->toksuper != -1)
304                                 tokens[parser->toksuper].size++;
305                         break;
306
307 #ifdef JSMN_STRICT
308                         /* Unexpected char in strict mode */
309                 default:
310                         return JSMN_ERROR_INVAL;
311 #endif
312                 }
313         }
314
315         for (i = parser->toknext - 1; i >= 0; i--) {
316                 /* Unmatched opened object or array */
317                 if (tokens[i].start != -1 && tokens[i].end == -1)
318                         return JSMN_ERROR_PART;
319         }
320
321 #ifdef JSMN_STRICT
322         return expecting_item ? JSMN_ERROR_INVAL : JSMN_SUCCESS;
323 #else
324         return JSMN_SUCCESS;
325 #endif
326 }
327
328 /*
329  * Creates a new parser based over a given  buffer with an array of tokens
330  * available.
331  */
332 void jsmn_init(jsmn_parser *parser)
333 {
334         parser->pos = 0;
335         parser->toknext = 0;
336         parser->toksuper = -1;
337 }
338
339 const char *jsmn_strerror(jsmnerr_t err)
340 {
341         switch (err) {
342         case JSMN_ERROR_NOMEM:
343                 return "No enough tokens";
344         case JSMN_ERROR_INVAL:
345                 return "Invalid character inside JSON string";
346         case JSMN_ERROR_PART:
347                 return "The string is not a full JSON packet, more bytes expected";
348         case JSMN_SUCCESS:
349                 return "Success";
350         default:
351                 return "Unknown json error";
352         }
353 }