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