00001 #include <stdlib.h>
00002
00003 #include "jsmn.h"
00004
00008 static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
00009 jsmntok_t *tokens, size_t num_tokens) {
00010 jsmntok_t *tok;
00011 if (parser->toknext >= num_tokens) {
00012 return NULL;
00013 }
00014 tok = &tokens[parser->toknext++];
00015 tok->start = tok->end = -1;
00016 tok->size = 0;
00017 #ifdef JSMN_PARENT_LINKS
00018 tok->parent = -1;
00019 #endif
00020 return tok;
00021 }
00022
00026 static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
00027 int start, int end) {
00028 token->type = type;
00029 token->start = start;
00030 token->end = end;
00031 token->size = 0;
00032 }
00033
00037 static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
00038 jsmntok_t *tokens, size_t num_tokens) {
00039 jsmntok_t *token;
00040 int start;
00041
00042 start = parser->pos;
00043
00044 for (; js[parser->pos] != '\0'; parser->pos++) {
00045 switch (js[parser->pos]) {
00046 #ifndef JSMN_STRICT
00047
00048 case ':':
00049 #endif
00050 case '\t' : case '\r' : case '\n' : case ' ' :
00051 case ',' : case ']' : case '}' :
00052 goto found;
00053 }
00054 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
00055 parser->pos = start;
00056 return JSMN_ERROR_INVAL;
00057 }
00058 }
00059 #ifdef JSMN_STRICT
00060
00061 parser->pos = start;
00062 return JSMN_ERROR_PART;
00063 #endif
00064
00065 found:
00066 token = jsmn_alloc_token(parser, tokens, num_tokens);
00067 if (token == NULL) {
00068 parser->pos = start;
00069 return JSMN_ERROR_NOMEM;
00070 }
00071 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
00072 #ifdef JSMN_PARENT_LINKS
00073 token->parent = parser->toksuper;
00074 #endif
00075 parser->pos--;
00076 return JSMN_SUCCESS;
00077 }
00078
00082 static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
00083 jsmntok_t *tokens, size_t num_tokens) {
00084 jsmntok_t *token;
00085
00086 int start = parser->pos;
00087
00088 parser->pos++;
00089
00090
00091 for (; js[parser->pos] != '\0'; parser->pos++) {
00092 char c = js[parser->pos];
00093
00094
00095 if (c == '\"') {
00096 token = jsmn_alloc_token(parser, tokens, num_tokens);
00097 if (token == NULL) {
00098 parser->pos = start;
00099 return JSMN_ERROR_NOMEM;
00100 }
00101 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
00102 #ifdef JSMN_PARENT_LINKS
00103 token->parent = parser->toksuper;
00104 #endif
00105 return JSMN_SUCCESS;
00106 }
00107
00108
00109 if (c == '\\') {
00110 parser->pos++;
00111 switch (js[parser->pos]) {
00112
00113 case '\"': case '/' : case '\\' : case 'b' :
00114 case 'f' : case 'r' : case 'n' : case 't' :
00115 break;
00116
00117 case 'u':
00118
00119 break;
00120
00121 default:
00122 parser->pos = start;
00123 return JSMN_ERROR_INVAL;
00124 }
00125 }
00126 }
00127 parser->pos = start;
00128 return JSMN_ERROR_PART;
00129 }
00130
00134 jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens,
00135 unsigned int num_tokens) {
00136 jsmnerr_t r;
00137 int i;
00138 jsmntok_t *token;
00139
00140 for (; js[parser->pos] != '\0'; parser->pos++) {
00141 char c;
00142 jsmntype_t type;
00143
00144 c = js[parser->pos];
00145 switch (c) {
00146 case '{': case '[':
00147 token = jsmn_alloc_token(parser, tokens, num_tokens);
00148 if (token == NULL)
00149 return JSMN_ERROR_NOMEM;
00150 if (parser->toksuper != -1) {
00151 tokens[parser->toksuper].size++;
00152 #ifdef JSMN_PARENT_LINKS
00153 token->parent = parser->toksuper;
00154 #endif
00155 }
00156 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
00157 token->start = parser->pos;
00158 parser->toksuper = parser->toknext - 1;
00159 break;
00160 case '}': case ']':
00161 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
00162 #ifdef JSMN_PARENT_LINKS
00163 if (parser->toknext < 1) {
00164 return JSMN_ERROR_INVAL;
00165 }
00166 token = &tokens[parser->toknext - 1];
00167 for (;;) {
00168 if (token->start != -1 && token->end == -1) {
00169 if (token->type != type) {
00170 return JSMN_ERROR_INVAL;
00171 }
00172 token->end = parser->pos + 1;
00173 parser->toksuper = token->parent;
00174 break;
00175 }
00176 if (token->parent == -1) {
00177 break;
00178 }
00179 token = &tokens[token->parent];
00180 }
00181 #else
00182 for (i = parser->toknext - 1; i >= 0; i--) {
00183 token = &tokens[i];
00184 if (token->start != -1 && token->end == -1) {
00185 if (token->type != type) {
00186 return JSMN_ERROR_INVAL;
00187 }
00188 parser->toksuper = -1;
00189 token->end = parser->pos + 1;
00190 break;
00191 }
00192 }
00193
00194 if (i == -1) return JSMN_ERROR_INVAL;
00195 for (; i >= 0; i--) {
00196 token = &tokens[i];
00197 if (token->start != -1 && token->end == -1) {
00198 parser->toksuper = i;
00199 break;
00200 }
00201 }
00202 #endif
00203 break;
00204 case '\"':
00205 r = jsmn_parse_string(parser, js, tokens, num_tokens);
00206 if (r < 0) return r;
00207 if (parser->toksuper != -1)
00208 tokens[parser->toksuper].size++;
00209 break;
00210 case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ':
00211 break;
00212 #ifdef JSMN_STRICT
00213
00214 case '-': case '0': case '1' : case '2': case '3' : case '4':
00215 case '5': case '6': case '7' : case '8': case '9':
00216 case 't': case 'f': case 'n' :
00217 #else
00218
00219 default:
00220 #endif
00221 r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
00222 if (r < 0) return r;
00223 if (parser->toksuper != -1)
00224 tokens[parser->toksuper].size++;
00225 break;
00226
00227 #ifdef JSMN_STRICT
00228
00229 default:
00230 return JSMN_ERROR_INVAL;
00231 #endif
00232
00233 }
00234 }
00235
00236 for (i = parser->toknext - 1; i >= 0; i--) {
00237
00238 if (tokens[i].start != -1 && tokens[i].end == -1) {
00239 return JSMN_ERROR_PART;
00240 }
00241 }
00242
00243 return JSMN_SUCCESS;
00244 }
00245
00250 void jsmn_init(jsmn_parser *parser) {
00251 parser->pos = 0;
00252 parser->toknext = 0;
00253 parser->toksuper = -1;
00254 }
00255