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