(root)/
libredwg-0.13/
jsmn/
jsmn.h
       1  /*
       2   * MIT License
       3   *
       4   * Copyright (c) 2010 Serge Zaitsev
       5   *
       6   * Permission is hereby granted, free of charge, to any person obtaining a copy
       7   * of this software and associated documentation files (the "Software"), to deal
       8   * in the Software without restriction, including without limitation the rights
       9   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      10   * copies of the Software, and to permit persons to whom the Software is
      11   * furnished to do so, subject to the following conditions:
      12   *
      13   * The above copyright notice and this permission notice shall be included in
      14   * all copies or substantial portions of the Software.
      15   *
      16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      22   * SOFTWARE.
      23   */
      24  #ifndef JSMN_H
      25  #define JSMN_H
      26  
      27  #include <stddef.h>
      28  
      29  #ifdef __cplusplus
      30  extern "C" {
      31  #endif
      32  
      33  #ifdef JSMN_STATIC
      34  #define JSMN_API static
      35  #else
      36  #define JSMN_API extern
      37  #endif
      38  
      39  /**
      40   * JSON type identifier. Basic types are:
      41   * 	o Object
      42   * 	o Array
      43   * 	o String
      44   * 	o Other primitive: number, boolean (true/false) or null
      45   */
      46  typedef enum {
      47    JSMN_UNDEFINED = 0,
      48    JSMN_OBJECT = 1,
      49    JSMN_ARRAY = 2,
      50    JSMN_STRING = 3,
      51    JSMN_PRIMITIVE = 4
      52  } jsmntype_t;
      53  
      54  enum jsmnerr {
      55    /* Not enough tokens were provided */
      56    JSMN_ERROR_NOMEM = -1,
      57    /* Invalid character inside JSON string */
      58    JSMN_ERROR_INVAL = -2,
      59    /* The string is not a full JSON packet, more bytes expected */
      60    JSMN_ERROR_PART = -3
      61  };
      62  
      63  /**
      64   * JSON token description.
      65   * type		type (object, array, string etc.)
      66   * start	start position in JSON data string
      67   * end		end position in JSON data string
      68   */
      69  typedef struct {
      70    jsmntype_t type;
      71    int start;
      72    int end;
      73    int size;
      74  #ifdef JSMN_PARENT_LINKS
      75    int parent;
      76  #endif
      77  } jsmntok_t;
      78  
      79  /**
      80   * JSON parser. Contains an array of token blocks available. Also stores
      81   * the string being parsed now and current position in that string.
      82   */
      83  typedef struct {
      84    unsigned int pos;     /* offset in the JSON string */
      85    unsigned int toknext; /* next token to allocate */
      86    int toksuper;         /* superior token node, e.g. parent object or array */
      87  } jsmn_parser;
      88  
      89  /**
      90   * Create JSON parser over an array of tokens
      91   */
      92  JSMN_API void jsmn_init(jsmn_parser *parser);
      93  
      94  /**
      95   * Run JSON parser. It parses a JSON data string into and array of tokens, each
      96   * describing
      97   * a single JSON object.
      98   */
      99  JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
     100                          jsmntok_t *tokens, const unsigned int num_tokens);
     101  
     102  #ifndef JSMN_HEADER
     103  /**
     104   * Allocates a fresh unused token from the token pool.
     105   */
     106  static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
     107                                     const size_t num_tokens) {
     108    jsmntok_t *tok;
     109    if (parser->toknext >= num_tokens) {
     110      return NULL;
     111    }
     112    tok = &tokens[parser->toknext++];
     113    tok->start = tok->end = -1;
     114    tok->size = 0;
     115  #ifdef JSMN_PARENT_LINKS
     116    tok->parent = -1;
     117  #endif
     118    return tok;
     119  }
     120  
     121  /**
     122   * Fills token type and boundaries.
     123   */
     124  static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
     125                              const int start, const int end) {
     126    token->type = type;
     127    token->start = start;
     128    token->end = end;
     129    token->size = 0;
     130  }
     131  
     132  /**
     133   * Fills next available token with JSON primitive.
     134   */
     135  static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
     136                                  const size_t len, jsmntok_t *tokens,
     137                                  const size_t num_tokens) {
     138    jsmntok_t *token;
     139    int start;
     140  
     141    start = parser->pos;
     142  
     143    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
     144      switch (js[parser->pos]) {
     145  #ifndef JSMN_STRICT
     146      /* In strict mode primitive must be followed by "," or "}" or "]" */
     147      case ':':
     148  #endif
     149      case '\t':
     150      case '\r':
     151      case '\n':
     152      case ' ':
     153      case ',':
     154      case ']':
     155      case '}':
     156        goto found;
     157      default:
     158                     /* to quiet a warning from gcc*/
     159        break;
     160      }
     161      if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
     162        parser->pos = start;
     163        return JSMN_ERROR_INVAL;
     164      }
     165    }
     166  #ifdef JSMN_STRICT
     167    /* In strict mode primitive must be followed by a comma/object/array */
     168    parser->pos = start;
     169    return JSMN_ERROR_PART;
     170  #endif
     171  
     172  found:
     173    if (tokens == NULL) {
     174      parser->pos--;
     175      return 0;
     176    }
     177    token = jsmn_alloc_token(parser, tokens, num_tokens);
     178    if (token == NULL) {
     179      parser->pos = start;
     180      return JSMN_ERROR_NOMEM;
     181    }
     182    jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
     183  #ifdef JSMN_PARENT_LINKS
     184    token->parent = parser->toksuper;
     185  #endif
     186    parser->pos--;
     187    return 0;
     188  }
     189  
     190  /**
     191   * Fills next token with JSON string.
     192   */
     193  static int jsmn_parse_string(jsmn_parser *parser, const char *js,
     194                               const size_t len, jsmntok_t *tokens,
     195                               const size_t num_tokens) {
     196    jsmntok_t *token;
     197  
     198    int start = parser->pos;
     199  
     200    parser->pos++;
     201  
     202    /* Skip starting quote */
     203    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
     204      char c = js[parser->pos];
     205  
     206      /* Quote: end of string */
     207      if (c == '\"') {
     208        if (tokens == NULL) {
     209          return 0;
     210        }
     211        token = jsmn_alloc_token(parser, tokens, num_tokens);
     212        if (token == NULL) {
     213          parser->pos = start;
     214          return JSMN_ERROR_NOMEM;
     215        }
     216        jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
     217  #ifdef JSMN_PARENT_LINKS
     218        token->parent = parser->toksuper;
     219  #endif
     220        return 0;
     221      }
     222  
     223      /* Backslash: Quoted symbol expected */
     224      if (c == '\\' && parser->pos + 1 < len) {
     225        int i;
     226        parser->pos++;
     227        switch (js[parser->pos]) {
     228        /* Allowed escaped symbols */
     229        case '\"':
     230        case '/':
     231        case '\\':
     232        case 'b':
     233        case 'f':
     234        case 'r':
     235        case 'n':
     236        case 't':
     237          break;
     238        /* Allows escaped symbol \uXXXX */
     239        case 'u':
     240          parser->pos++;
     241          for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0';
     242               i++) {
     243            /* If it isn't a hex character we have an error */
     244            if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) ||   /* 0-9 */
     245                  (js[parser->pos] >= 65 && js[parser->pos] <= 70) ||   /* A-F */
     246                  (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
     247              parser->pos = start;
     248              return JSMN_ERROR_INVAL;
     249            }
     250            parser->pos++;
     251          }
     252          parser->pos--;
     253          break;
     254        /* Unexpected symbol */
     255        default:
     256          parser->pos = start;
     257          return JSMN_ERROR_INVAL;
     258        }
     259      }
     260    }
     261    parser->pos = start;
     262    return JSMN_ERROR_PART;
     263  }
     264  
     265  /**
     266   * Parse JSON string and fill tokens.
     267   */
     268  JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
     269                          jsmntok_t *tokens, const unsigned int num_tokens) {
     270    int r;
     271    int i;
     272    jsmntok_t *token;
     273    int count = parser->toknext;
     274  
     275    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
     276      char c;
     277      jsmntype_t type;
     278  
     279      c = js[parser->pos];
     280      switch (c) {
     281      case '{':
     282      case '[':
     283        count++;
     284        if (tokens == NULL) {
     285          break;
     286        }
     287        token = jsmn_alloc_token(parser, tokens, num_tokens);
     288        if (token == NULL) {
     289          return JSMN_ERROR_NOMEM;
     290        }
     291        if (parser->toksuper != -1) {
     292          jsmntok_t *t = &tokens[parser->toksuper];
     293  #ifdef JSMN_STRICT
     294          /* In strict mode an object or array can't become a key */
     295          if (t->type == JSMN_OBJECT) {
     296            return JSMN_ERROR_INVAL;
     297          }
     298  #endif
     299          t->size++;
     300  #ifdef JSMN_PARENT_LINKS
     301          token->parent = parser->toksuper;
     302  #endif
     303        }
     304        token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
     305        token->start = parser->pos;
     306        parser->toksuper = parser->toknext - 1;
     307        break;
     308      case '}':
     309      case ']':
     310        if (tokens == NULL) {
     311          break;
     312        }
     313        type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
     314  #ifdef JSMN_PARENT_LINKS
     315        if (parser->toknext < 1) {
     316          return JSMN_ERROR_INVAL;
     317        }
     318        token = &tokens[parser->toknext - 1];
     319        for (;;) {
     320          if (token->start != -1 && token->end == -1) {
     321            if (token->type != type) {
     322              return JSMN_ERROR_INVAL;
     323            }
     324            token->end = parser->pos + 1;
     325            parser->toksuper = token->parent;
     326            break;
     327          }
     328          if (token->parent == -1) {
     329            if (token->type != type || parser->toksuper == -1) {
     330              return JSMN_ERROR_INVAL;
     331            }
     332            break;
     333          }
     334          token = &tokens[token->parent];
     335        }
     336  #else
     337        for (i = parser->toknext - 1; i >= 0; i--) {
     338          token = &tokens[i];
     339          if (token->start != -1 && token->end == -1) {
     340            if (token->type != type) {
     341              return JSMN_ERROR_INVAL;
     342            }
     343            parser->toksuper = -1;
     344            token->end = parser->pos + 1;
     345            break;
     346          }
     347        }
     348        /* Error if unmatched closing bracket */
     349        if (i == -1) {
     350          return JSMN_ERROR_INVAL;
     351        }
     352        for (; i >= 0; i--) {
     353          token = &tokens[i];
     354          if (token->start != -1 && token->end == -1) {
     355            parser->toksuper = i;
     356            break;
     357          }
     358        }
     359  #endif
     360        break;
     361      case '\"':
     362        r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
     363        if (r < 0) {
     364          return r;
     365        }
     366        count++;
     367        if (parser->toksuper != -1 && tokens != NULL) {
     368          tokens[parser->toksuper].size++;
     369        }
     370        break;
     371      case '\t':
     372      case '\r':
     373      case '\n':
     374      case ' ':
     375        break;
     376      case ':':
     377        parser->toksuper = parser->toknext - 1;
     378        break;
     379      case ',':
     380        if (tokens != NULL && parser->toksuper != -1 &&
     381            tokens[parser->toksuper].type != JSMN_ARRAY &&
     382            tokens[parser->toksuper].type != JSMN_OBJECT) {
     383  #ifdef JSMN_PARENT_LINKS
     384          parser->toksuper = tokens[parser->toksuper].parent;
     385  #else
     386          for (i = parser->toknext - 1; i >= 0; i--) {
     387            if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
     388              if (tokens[i].start != -1 && tokens[i].end == -1) {
     389                parser->toksuper = i;
     390                break;
     391              }
     392            }
     393          }
     394  #endif
     395        }
     396        break;
     397  #ifdef JSMN_STRICT
     398      /* In strict mode primitives are: numbers and booleans */
     399      case '-':
     400      case '0':
     401      case '1':
     402      case '2':
     403      case '3':
     404      case '4':
     405      case '5':
     406      case '6':
     407      case '7':
     408      case '8':
     409      case '9':
     410      case 't':
     411      case 'f':
     412      case 'n':
     413        /* And they must not be keys of the object */
     414        if (tokens != NULL && parser->toksuper != -1) {
     415          const jsmntok_t *t = &tokens[parser->toksuper];
     416          if (t->type == JSMN_OBJECT ||
     417              (t->type == JSMN_STRING && t->size != 0)) {
     418            return JSMN_ERROR_INVAL;
     419          }
     420        }
     421  #else
     422      /* In non-strict mode every unquoted value is a primitive */
     423      default:
     424  #endif
     425        r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
     426        if (r < 0) {
     427          return r;
     428        }
     429        count++;
     430        if (parser->toksuper != -1 && tokens != NULL) {
     431          tokens[parser->toksuper].size++;
     432        }
     433        break;
     434  
     435  #ifdef JSMN_STRICT
     436      /* Unexpected char in strict mode */
     437      default:
     438        return JSMN_ERROR_INVAL;
     439  #endif
     440      }
     441    }
     442  
     443    if (tokens != NULL) {
     444      for (i = parser->toknext - 1; i >= 0; i--) {
     445        /* Unmatched opened object or array */
     446        if (tokens[i].start != -1 && tokens[i].end == -1) {
     447          return JSMN_ERROR_PART;
     448        }
     449      }
     450    }
     451  
     452    return count;
     453  }
     454  
     455  /**
     456   * Creates a new parser based over a given buffer with an array of tokens
     457   * available.
     458   */
     459  JSMN_API void jsmn_init(jsmn_parser *parser) {
     460    parser->pos = 0;
     461    parser->toknext = 0;
     462    parser->toksuper = -1;
     463  }
     464  
     465  #endif /* JSMN_HEADER */
     466  
     467  #ifdef __cplusplus
     468  }
     469  #endif
     470  
     471  #endif /* JSMN_H */