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