Merge tag 'mips_5.16_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
[linux-2.6-microblaze.git] / tools / perf / 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 #include <stdlib.h>
26 #include "jsmn.h"
27 #define JSMN_STRICT
28
29 /*
30  * Allocates a fresh unused token from the token pool.
31  */
32 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
33                                    jsmntok_t *tokens, size_t num_tokens)
34 {
35         jsmntok_t *tok;
36
37         if ((unsigned)parser->toknext >= num_tokens)
38                 return NULL;
39         tok = &tokens[parser->toknext++];
40         tok->start = tok->end = -1;
41         tok->size = 0;
42         return tok;
43 }
44
45 /*
46  * Fills token type and boundaries.
47  */
48 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
49                             int start, int end)
50 {
51         token->type = type;
52         token->start = start;
53         token->end = end;
54         token->size = 0;
55 }
56
57 /*
58  * Fills next available token with JSON primitive.
59  */
60 static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
61                                       size_t len,
62                                       jsmntok_t *tokens, size_t num_tokens)
63 {
64         jsmntok_t *token;
65         int start;
66
67         start = parser->pos;
68
69         for (; parser->pos < len; parser->pos++) {
70                 switch (js[parser->pos]) {
71 #ifndef JSMN_STRICT
72                 /*
73                  * In strict mode primitive must be followed by ","
74                  * or "}" or "]"
75                  */
76                 case ':':
77 #endif
78                 case '\t':
79                 case '\r':
80                 case '\n':
81                 case ' ':
82                 case ',':
83                 case ']':
84                 case '}':
85                         goto found;
86                 default:
87                         break;
88                 }
89                 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
90                         parser->pos = start;
91                         return JSMN_ERROR_INVAL;
92                 }
93         }
94 #ifdef JSMN_STRICT
95         /*
96          * In strict mode primitive must be followed by a
97          * comma/object/array.
98          */
99         parser->pos = start;
100         return JSMN_ERROR_PART;
101 #endif
102
103 found:
104         token = jsmn_alloc_token(parser, tokens, num_tokens);
105         if (token == NULL) {
106                 parser->pos = start;
107                 return JSMN_ERROR_NOMEM;
108         }
109         jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
110         parser->pos--; /* parent sees closing brackets */
111         return JSMN_SUCCESS;
112 }
113
114 /*
115  * Fills next token with JSON string.
116  */
117 static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
118                                    size_t len,
119                                    jsmntok_t *tokens, size_t num_tokens)
120 {
121         jsmntok_t *token;
122         int start = parser->pos;
123
124         /* Skip starting quote */
125         parser->pos++;
126
127         for (; parser->pos < len; parser->pos++) {
128                 char c = js[parser->pos];
129
130                 /* Quote: end of string */
131                 if (c == '\"') {
132                         token = jsmn_alloc_token(parser, tokens, num_tokens);
133                         if (token == NULL) {
134                                 parser->pos = start;
135                                 return JSMN_ERROR_NOMEM;
136                         }
137                         jsmn_fill_token(token, JSMN_STRING, start+1,
138                                         parser->pos);
139                         return JSMN_SUCCESS;
140                 }
141
142                 /* Backslash: Quoted symbol expected */
143                 if (c == '\\') {
144                         parser->pos++;
145                         switch (js[parser->pos]) {
146                                 /* Allowed escaped symbols */
147                         case '\"':
148                         case '/':
149                         case '\\':
150                         case 'b':
151                         case 'f':
152                         case 'r':
153                         case 'n':
154                         case 't':
155                                 break;
156                                 /* Allows escaped symbol \uXXXX */
157                         case 'u':
158                                 /* TODO */
159                                 break;
160                                 /* Unexpected symbol */
161                         default:
162                                 parser->pos = start;
163                                 return JSMN_ERROR_INVAL;
164                         }
165                 }
166         }
167         parser->pos = start;
168         return JSMN_ERROR_PART;
169 }
170
171 /*
172  * Parse JSON string and fill tokens.
173  */
174 jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
175                      jsmntok_t *tokens, unsigned int num_tokens)
176 {
177         jsmnerr_t r;
178         int i;
179         jsmntok_t *token;
180 #ifdef JSMN_STRICT
181         /*
182          * Keeps track of whether a new object/list/primitive is expected. New items are only
183          * allowed after an opening brace, comma or colon. A closing brace after a comma is not
184          * valid JSON.
185          */
186         int expecting_item = 1;
187 #endif
188
189         for (; parser->pos < len; parser->pos++) {
190                 char c;
191                 jsmntype_t type;
192
193                 c = js[parser->pos];
194                 switch (c) {
195                 case '{':
196                 case '[':
197 #ifdef JSMN_STRICT
198                         if (!expecting_item)
199                                 return JSMN_ERROR_INVAL;
200 #endif
201                         token = jsmn_alloc_token(parser, tokens, num_tokens);
202                         if (token == NULL)
203                                 return JSMN_ERROR_NOMEM;
204                         if (parser->toksuper != -1)
205                                 tokens[parser->toksuper].size++;
206                         token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
207                         token->start = parser->pos;
208                         parser->toksuper = parser->toknext - 1;
209                         break;
210                 case '}':
211                 case ']':
212 #ifdef JSMN_STRICT
213                         if (expecting_item)
214                                 return JSMN_ERROR_INVAL;
215 #endif
216                         type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
217                         for (i = parser->toknext - 1; i >= 0; i--) {
218                                 token = &tokens[i];
219                                 if (token->start != -1 && token->end == -1) {
220                                         if (token->type != type)
221                                                 return JSMN_ERROR_INVAL;
222                                         parser->toksuper = -1;
223                                         token->end = parser->pos + 1;
224                                         break;
225                                 }
226                         }
227                         /* Error if unmatched closing bracket */
228                         if (i == -1)
229                                 return JSMN_ERROR_INVAL;
230                         for (; i >= 0; i--) {
231                                 token = &tokens[i];
232                                 if (token->start != -1 && token->end == -1) {
233                                         parser->toksuper = i;
234                                         break;
235                                 }
236                         }
237                         break;
238                 case '\"':
239 #ifdef JSMN_STRICT
240                         if (!expecting_item)
241                                 return JSMN_ERROR_INVAL;
242                         expecting_item = 0;
243 #endif
244                         r = jsmn_parse_string(parser, js, len, tokens,
245                                               num_tokens);
246                         if (r < 0)
247                                 return r;
248                         if (parser->toksuper != -1)
249                                 tokens[parser->toksuper].size++;
250                         break;
251                 case '\t':
252                 case '\r':
253                 case '\n':
254                 case ' ':
255                         break;
256 #ifdef JSMN_STRICT
257                 case ':':
258                 case ',':
259                         if (expecting_item)
260                                 return JSMN_ERROR_INVAL;
261                         expecting_item = 1;
262                         break;
263                         /*
264                          * In strict mode primitives are:
265                          * numbers and booleans.
266                          */
267                 case '-':
268                 case '0':
269                 case '1':
270                 case '2':
271                 case '3':
272                 case '4':
273                 case '5':
274                 case '6':
275                 case '7':
276                 case '8':
277                 case '9':
278                 case 't':
279                 case 'f':
280                 case 'n':
281 #else
282                 case ':':
283                 case ',':
284                         break;
285                         /*
286                          * In non-strict mode every unquoted value
287                          * is a primitive.
288                          */
289                         /*FALL THROUGH */
290                 default:
291 #endif
292
293 #ifdef JSMN_STRICT
294                         if (!expecting_item)
295                                 return JSMN_ERROR_INVAL;
296                         expecting_item = 0;
297 #endif
298                         r = jsmn_parse_primitive(parser, js, len, tokens,
299                                                  num_tokens);
300                         if (r < 0)
301                                 return r;
302                         if (parser->toksuper != -1)
303                                 tokens[parser->toksuper].size++;
304                         break;
305
306 #ifdef JSMN_STRICT
307                         /* Unexpected char in strict mode */
308                 default:
309                         return JSMN_ERROR_INVAL;
310 #endif
311                 }
312         }
313
314         for (i = parser->toknext - 1; i >= 0; i--) {
315                 /* Unmatched opened object or array */
316                 if (tokens[i].start != -1 && tokens[i].end == -1)
317                         return JSMN_ERROR_PART;
318         }
319
320 #ifdef JSMN_STRICT
321         return expecting_item ? JSMN_ERROR_INVAL : JSMN_SUCCESS;
322 #else
323         return JSMN_SUCCESS;
324 #endif
325 }
326
327 /*
328  * Creates a new parser based over a given  buffer with an array of tokens
329  * available.
330  */
331 void jsmn_init(jsmn_parser *parser)
332 {
333         parser->pos = 0;
334         parser->toknext = 0;
335         parser->toksuper = -1;
336 }
337
338 const char *jsmn_strerror(jsmnerr_t err)
339 {
340         switch (err) {
341         case JSMN_ERROR_NOMEM:
342                 return "No enough tokens";
343         case JSMN_ERROR_INVAL:
344                 return "Invalid character inside JSON string";
345         case JSMN_ERROR_PART:
346                 return "The string is not a full JSON packet, more bytes expected";
347         case JSMN_SUCCESS:
348                 return "Success";
349         default:
350                 return "Unknown json error";
351         }
352 }