Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: jsmn.c
- Revision:
- 0:c1cd8e6ecdc9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jsmn.c Thu May 25 15:14:50 2017 +0545
@@ -0,0 +1,340 @@
+/* Author: Faheem Inayat
+ * Created by "Night Crue" Team @ TechShop San Jose, CA
+ *
+ * --- DISCLAIMER ---
+ * This code is a modified version of original JSMN lirary, written by
+ * *** Serge A. Zaitsev ***
+ * and hosted at https://github.com/zserge/jsmn
+ * Any modification to the original source is not guaranteed to be included
+ * in this version. As of writing of this file, the original source is
+ * licensed under MIT License
+ * (http://www.opensource.org/licenses/mit-license.php).
+ */
+
+#include "jsmn.h"
+
+/**
+ * Allocates a fresh unused token from the token pull.
+ */
+static jsmntok_t *jsmn_alloc_token ( jsmn_parser *parser, jsmntok_t *tokens, size_t num_tokens )
+{
+ jsmntok_t *tok;
+ if ( parser->toknext >= num_tokens )
+ {
+ return NULL ;
+ }
+ tok = &tokens [ parser->toknext++ ];
+ tok->start = tok->end = -1;
+ tok->childCount = 0;
+ tok->parent = -1;
+ return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token ( jsmntok_t *token, jsmntype_t type, int start, int end )
+{
+ token->type = type;
+ token->start = start;
+ token->end = end;
+ token->childCount = 0;
+}
+
+/**
+ * Fills next available token with JSON primitive.
+ */
+static int jsmn_parse_primitive ( jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens )
+{
+ jsmntok_t *token;
+ int start;
+
+ start = parser->pos;
+
+ for ( ; parser->pos < len && js [ parser->pos ] != '\0'; parser->pos++ )
+ {
+ switch ( js [ parser->pos ] )
+ {
+ case '\t':
+ case '\r':
+ case '\n':
+ case ' ':
+ case ',':
+ case ']':
+ case '}':
+ goto found;
+ }
+ if ( js [ parser->pos ] < 32 || js [ parser->pos ] >= 127 )
+ {
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ /* primitive must be followed by a comma/object/array */
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+
+ found: if ( tokens == NULL )
+ {
+ parser->pos--;
+ return 0;
+ }
+ token = jsmn_alloc_token ( parser, tokens, num_tokens );
+ if ( token == NULL )
+ {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ jsmn_fill_token ( token, JSMN_PRIMITIVE, start, parser->pos );
+ token->parent = parser->toksuper;
+ parser->pos--;
+ return 0;
+}
+
+/**
+ * Fills next token with JSON string.
+ */
+static int jsmn_parse_string ( jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens, unsigned char isKey )
+{
+ jsmntok_t *token;
+
+ int start = parser->pos;
+
+ parser->pos++;
+
+ /* Skip starting quote */
+ for ( ; parser->pos < len && js [ parser->pos ] != '\0'; parser->pos++ )
+ {
+ char c = js [ parser->pos ];
+
+ /* Quote: end of string */
+ if ( c == '\"' )
+ {
+ if ( tokens == NULL )
+ {
+ return 0;
+ }
+ token = jsmn_alloc_token ( parser, tokens, num_tokens );
+ if ( token == NULL )
+ {
+ parser->pos = start;
+ return JSMN_ERROR_NOMEM;
+ }
+ if ( isKey == 1 )
+ {
+ jsmn_fill_token ( token, JSMN_KEY, start + 1, parser->pos );
+ }
+ else
+ {
+ jsmn_fill_token ( token, JSMN_STRING, start + 1, parser->pos );
+ }
+ token->parent = parser->toksuper;
+ return 0;
+ }
+
+ /* Backslash: Quoted symbol expected */
+ if ( c == '\\' && parser->pos + 1 < len )
+ {
+ int i;
+ parser->pos++;
+ switch ( js [ parser->pos ] )
+ {
+ /* Allowed escaped symbols */
+ case '\"':
+ case '/':
+ case '\\':
+ case 'b':
+ case 'f':
+ case 'r':
+ case 'n':
+ case 't':
+ break;
+ /* Allows escaped symbol \uXXXX */
+ case 'u':
+ parser->pos++;
+ for ( i = 0; i < 4 && parser->pos < len && js [ parser->pos ] != '\0'; i++ )
+ {
+ /* If it isn't a hex character we have an error */
+ if ( ! ( ( js [ parser->pos ] >= 48 && js [ parser->pos ] <= 57 ) || /* 0-9 */
+ ( js [ parser->pos ] >= 65 && js [ parser->pos ] <= 70 )
+ || /* A-F */
+ ( js [ parser->pos ] >= 97 && js [ parser->pos ] <= 102 ) ) )
+ { /* a-f */
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ parser->pos++;
+ }
+ parser->pos--;
+ break;
+ /* Unexpected symbol */
+ default:
+ parser->pos = start;
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ }
+ parser->pos = start;
+ return JSMN_ERROR_PART;
+}
+
+/**
+ * Parse JSON string and fill tokens.
+ */
+int jsmn_parse ( jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens )
+{
+ int r;
+ int i;
+ jsmntok_t *token;
+ int count = parser->toknext;
+
+ unsigned char isKey = 1;
+
+ for ( ; parser->pos < len && js [ parser->pos ] != '\0'; parser->pos++ )
+ {
+ char c;
+ jsmntype_t type;
+
+ c = js [ parser->pos ];
+ switch ( c )
+ {
+ case '{':
+ case '[':
+ count++;
+ if ( tokens == NULL )
+ {
+ break;
+ }
+ token = jsmn_alloc_token ( parser, tokens, num_tokens );
+ if ( token == NULL )
+ return JSMN_ERROR_NOMEM;
+ if ( parser->toksuper != -1 )
+ {
+ tokens [ parser->toksuper ].childCount++;
+ token->parent = parser->toksuper;
+ }
+ token->type = ( c == '{' ? JSMN_OBJECT : JSMN_ARRAY );
+ token->start = parser->pos;
+ parser->toksuper = parser->toknext - 1;
+ if ( token->type == JSMN_OBJECT )
+ {
+ isKey = 1;
+ }
+ break;
+ case '}':
+ case ']':
+ if ( tokens == NULL )
+ break;
+ type = ( c == '}' ? JSMN_OBJECT : JSMN_ARRAY );
+ if ( parser->toknext < 1 )
+ {
+ return JSMN_ERROR_INVAL;
+ }
+ token = &tokens [ parser->toknext - 1 ];
+ for ( ;; )
+ {
+ if ( token->start != -1 && token->end == -1 )
+ {
+ if ( token->type != type )
+ {
+ return JSMN_ERROR_INVAL;
+ }
+ token->end = parser->pos + 1;
+ parser->toksuper = token->parent;
+ break;
+ }
+ if ( token->parent == -1 )
+ {
+ break;
+ }
+ token = &tokens [ token->parent ];
+ }
+ break;
+ case '\"':
+ r = jsmn_parse_string ( parser, js, len, tokens, num_tokens, isKey );
+ if ( r < 0 )
+ return r;
+ count++;
+ if ( parser->toksuper != -1 && tokens != NULL )
+ tokens [ parser->toksuper ].childCount++;
+ break;
+ case '\t':
+ case '\r':
+ case '\n':
+ case ' ':
+ break;
+ case ':':
+ isKey = 0;
+ parser->toksuper = parser->toknext - 1;
+ break;
+ case ',':
+ if ( tokens != NULL && parser->toksuper != -1 && tokens [ parser->toksuper ].type != JSMN_ARRAY && tokens [ parser->toksuper ].type != JSMN_OBJECT )
+ {
+ parser->toksuper = tokens [ parser->toksuper ].parent;
+ }
+ isKey = 1;
+ break;
+ /* In strict mode primitives are: numbers and booleans */
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 't':
+ case 'f':
+ case 'n':
+ /* And they must not be keys of the object */
+ if ( tokens != NULL && parser->toksuper != -1 )
+ {
+ jsmntok_t *t = &tokens [ parser->toksuper ];
+ if ( t->type == JSMN_OBJECT || ( t->type == JSMN_STRING && t->childCount != 0 ) )
+ {
+ return JSMN_ERROR_INVAL;
+ }
+ }
+ r = jsmn_parse_primitive ( parser, js, len, tokens, num_tokens );
+ if ( r < 0 )
+ return r;
+ count++;
+ if ( parser->toksuper != -1 && tokens != NULL )
+ tokens [ parser->toksuper ].childCount++;
+ break;
+
+ /* Unexpected char in strict mode */
+ default:
+ return JSMN_ERROR_INVAL;
+ }
+ }
+
+ if ( tokens != NULL )
+ {
+ for ( i = parser->toknext - 1; i >= 0; i-- )
+ {
+ /* Unmatched opened object or array */
+ if ( tokens [ i ].start != -1 && tokens [ i ].end == -1 )
+ {
+ return JSMN_ERROR_PART;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
+ * Creates a new parser based over a given buffer with an array of tokens
+ * available.
+ */
+void jsmn_init ( jsmn_parser *parser )
+{
+ parser->pos = 0;
+ parser->toknext = 0;
+ parser->toksuper = -1;
+}
+