From: sparky4 Date: Thu, 1 Oct 2015 18:50:02 +0000 (-0500) Subject: jsmn X-Git-Url: http://4ch.mooo.com/gitweb/?a=commitdiff_plain;h=41e63e4391942b7bff6a4bb72fc6a0c05981d4bd;p=16.git jsmn --- diff --git a/16.exe b/16.exe index 1cf94b9a..338b53aa 100755 Binary files a/16.exe and b/16.exe differ diff --git a/16.map b/16.map index 1c2f72ef..e2ba6e06 100755 --- a/16.map +++ b/16.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: 16.exe creating a DOS executable diff --git a/bakapi.map b/bakapi.map index 57b2eb66..52684745 100755 --- a/bakapi.map +++ b/bakapi.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: bakapi.exe creating a DOS executable diff --git a/exmmtest.map b/exmmtest.map index 4acc0c27..c6276fea 100755 --- a/exmmtest.map +++ b/exmmtest.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: exmmtest.exe creating a DOS executable diff --git a/fmemtest.map b/fmemtest.map index 7ff95e71..042c8829 100755 --- a/fmemtest.map +++ b/fmemtest.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: fmemtest.exe creating a DOS executable diff --git a/fontgfx.map b/fontgfx.map index bde25846..1f10da82 100755 --- a/fontgfx.map +++ b/fontgfx.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: fontgfx.exe creating a DOS executable diff --git a/maptest.map b/maptest.map index f7656aad..1c11826f 100755 --- a/maptest.map +++ b/maptest.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: maptest.exe creating a DOS executable diff --git a/palettec.map b/palettec.map index 5c3e4a81..ec898cba 100755 --- a/palettec.map +++ b/palettec.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: palettec.exe creating a DOS executable diff --git a/pcxtest.map b/pcxtest.map index eb65bfad..ad4f02e8 100755 --- a/pcxtest.map +++ b/pcxtest.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: pcxtest.exe creating a DOS executable diff --git a/pcxtest2.map b/pcxtest2.map index 6edfd1e5..cebc4f47 100755 --- a/pcxtest2.map +++ b/pcxtest2.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: pcxtest2.exe creating a DOS executable diff --git a/scroll.exe b/scroll.exe index 8dfc01f1..cb242334 100755 Binary files a/scroll.exe and b/scroll.exe differ diff --git a/scroll.map b/scroll.map index 5d85cd1f..561a5413 100755 --- a/scroll.map +++ b/scroll.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: scroll.exe creating a DOS executable diff --git a/src/lib/jsmn/.hg/00changelog.i b/src/lib/00jsmn00/.hg/00changelog.i similarity index 100% rename from src/lib/jsmn/.hg/00changelog.i rename to src/lib/00jsmn00/.hg/00changelog.i diff --git a/src/lib/jsmn/.hg/branch b/src/lib/00jsmn00/.hg/branch similarity index 100% rename from src/lib/jsmn/.hg/branch rename to src/lib/00jsmn00/.hg/branch diff --git a/src/lib/jsmn/.hg/cache/branch2-served b/src/lib/00jsmn00/.hg/cache/branch2-served similarity index 100% rename from src/lib/jsmn/.hg/cache/branch2-served rename to src/lib/00jsmn00/.hg/cache/branch2-served diff --git a/src/lib/jsmn/.hg/dirstate b/src/lib/00jsmn00/.hg/dirstate similarity index 100% rename from src/lib/jsmn/.hg/dirstate rename to src/lib/00jsmn00/.hg/dirstate diff --git a/src/lib/jsmn/.hg/hgrc b/src/lib/00jsmn00/.hg/hgrc similarity index 100% rename from src/lib/jsmn/.hg/hgrc rename to src/lib/00jsmn00/.hg/hgrc diff --git a/src/lib/jsmn/.hg/requires b/src/lib/00jsmn00/.hg/requires similarity index 100% rename from src/lib/jsmn/.hg/requires rename to src/lib/00jsmn00/.hg/requires diff --git a/src/lib/jsmn/.hg/store/00changelog.i b/src/lib/00jsmn00/.hg/store/00changelog.i similarity index 100% rename from src/lib/jsmn/.hg/store/00changelog.i rename to src/lib/00jsmn00/.hg/store/00changelog.i diff --git a/src/lib/jsmn/.hg/store/00manifest.i b/src/lib/00jsmn00/.hg/store/00manifest.i similarity index 100% rename from src/lib/jsmn/.hg/store/00manifest.i rename to src/lib/00jsmn00/.hg/store/00manifest.i diff --git a/src/lib/jsmn/.hg/store/data/_l_i_c_e_n_s_e.i b/src/lib/00jsmn00/.hg/store/data/_l_i_c_e_n_s_e.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/_l_i_c_e_n_s_e.i rename to src/lib/00jsmn00/.hg/store/data/_l_i_c_e_n_s_e.i diff --git a/src/lib/jsmn/.hg/store/data/_makefile.i b/src/lib/00jsmn00/.hg/store/data/_makefile.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/_makefile.i rename to src/lib/00jsmn00/.hg/store/data/_makefile.i diff --git a/src/lib/jsmn/.hg/store/data/_r_e_a_d_m_e.i b/src/lib/00jsmn00/.hg/store/data/_r_e_a_d_m_e.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/_r_e_a_d_m_e.i rename to src/lib/00jsmn00/.hg/store/data/_r_e_a_d_m_e.i diff --git a/src/lib/jsmn/.hg/store/data/_r_e_a_d_m_e.md.i b/src/lib/00jsmn00/.hg/store/data/_r_e_a_d_m_e.md.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/_r_e_a_d_m_e.md.i rename to src/lib/00jsmn00/.hg/store/data/_r_e_a_d_m_e.md.i diff --git a/src/lib/jsmn/.hg/store/data/demo.c.i b/src/lib/00jsmn00/.hg/store/data/demo.c.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/demo.c.i rename to src/lib/00jsmn00/.hg/store/data/demo.c.i diff --git a/src/lib/jsmn/.hg/store/data/example/jsondump.c.i b/src/lib/00jsmn00/.hg/store/data/example/jsondump.c.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/example/jsondump.c.i rename to src/lib/00jsmn00/.hg/store/data/example/jsondump.c.i diff --git a/src/lib/jsmn/.hg/store/data/example/simple.c.i b/src/lib/00jsmn00/.hg/store/data/example/simple.c.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/example/simple.c.i rename to src/lib/00jsmn00/.hg/store/data/example/simple.c.i diff --git a/src/lib/jsmn/.hg/store/data/jsmn.c.i b/src/lib/00jsmn00/.hg/store/data/jsmn.c.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/jsmn.c.i rename to src/lib/00jsmn00/.hg/store/data/jsmn.c.i diff --git a/src/lib/jsmn/.hg/store/data/jsmn.h.i b/src/lib/00jsmn00/.hg/store/data/jsmn.h.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/jsmn.h.i rename to src/lib/00jsmn00/.hg/store/data/jsmn.h.i diff --git a/src/lib/jsmn/.hg/store/data/jsmn__test.c.i b/src/lib/00jsmn00/.hg/store/data/jsmn__test.c.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/jsmn__test.c.i rename to src/lib/00jsmn00/.hg/store/data/jsmn__test.c.i diff --git a/src/lib/jsmn/.hg/store/data/test.sh.i b/src/lib/00jsmn00/.hg/store/data/test.sh.i similarity index 100% rename from src/lib/jsmn/.hg/store/data/test.sh.i rename to src/lib/00jsmn00/.hg/store/data/test.sh.i diff --git a/src/lib/jsmn/.hg/store/fncache b/src/lib/00jsmn00/.hg/store/fncache similarity index 100% rename from src/lib/jsmn/.hg/store/fncache rename to src/lib/00jsmn00/.hg/store/fncache diff --git a/src/lib/jsmn/.hg/store/phaseroots b/src/lib/00jsmn00/.hg/store/phaseroots similarity index 100% rename from src/lib/jsmn/.hg/store/phaseroots rename to src/lib/00jsmn00/.hg/store/phaseroots diff --git a/src/lib/jsmn/.hg/store/undo b/src/lib/00jsmn00/.hg/store/undo similarity index 100% rename from src/lib/jsmn/.hg/store/undo rename to src/lib/00jsmn00/.hg/store/undo diff --git a/src/lib/jsmn/.hg/store/undo.phaseroots b/src/lib/00jsmn00/.hg/store/undo.phaseroots similarity index 100% rename from src/lib/jsmn/.hg/store/undo.phaseroots rename to src/lib/00jsmn00/.hg/store/undo.phaseroots diff --git a/src/lib/jsmn/.hg/undo.bookmarks b/src/lib/00jsmn00/.hg/undo.bookmarks similarity index 100% rename from src/lib/jsmn/.hg/undo.bookmarks rename to src/lib/00jsmn00/.hg/undo.bookmarks diff --git a/src/lib/jsmn/.hg/undo.branch b/src/lib/00jsmn00/.hg/undo.branch similarity index 100% rename from src/lib/jsmn/.hg/undo.branch rename to src/lib/00jsmn00/.hg/undo.branch diff --git a/src/lib/jsmn/.hg/undo.desc b/src/lib/00jsmn00/.hg/undo.desc similarity index 100% rename from src/lib/jsmn/.hg/undo.desc rename to src/lib/00jsmn00/.hg/undo.desc diff --git a/src/lib/jsmn/.hg/undo.dirstate b/src/lib/00jsmn00/.hg/undo.dirstate similarity index 100% rename from src/lib/jsmn/.hg/undo.dirstate rename to src/lib/00jsmn00/.hg/undo.dirstate diff --git a/src/lib/00jsmn00/LICENSE b/src/lib/00jsmn00/LICENSE new file mode 100755 index 00000000..c84fb2e9 --- /dev/null +++ b/src/lib/00jsmn00/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2010 Serge A. Zaitsev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/src/lib/00jsmn00/Makefile b/src/lib/00jsmn00/Makefile new file mode 100755 index 00000000..5e3e2a97 --- /dev/null +++ b/src/lib/00jsmn00/Makefile @@ -0,0 +1,35 @@ +# You can put your build options here +-include config.mk + +all: libjsmn.a + +libjsmn.a: jsmn.o + $(AR) rc $@ $^ + +%.o: %.c jsmn.h + $(CC) -c $(CFLAGS) $< -o $@ + +test: jsmn_test + ./jsmn_test + +jsmn_test: jsmn_test.o + $(CC) $(LDFLAGS) -L. -ljsmn $< -o $@ + +jsmn_test.o: jsmn_test.c libjsmn.a + +simple_example: example/simple.o libjsmn.a + $(CC) $(LDFLAGS) $^ -o $@ + +jsondump: example/jsondump.o libjsmn.a + $(CC) $(LDFLAGS) $^ -o $@ + +clean: + rm -f jsmn.o jsmn_test.o example/simple.o + rm -f jsmn_test + rm -f jsmn_test.exe + rm -f libjsmn.a + rm -f simple_example + rm -f jsondump + +.PHONY: all clean test + diff --git a/src/lib/00jsmn00/README.md b/src/lib/00jsmn00/README.md new file mode 100755 index 00000000..353af94a --- /dev/null +++ b/src/lib/00jsmn00/README.md @@ -0,0 +1,167 @@ + +JSMN +==== + +jsmn (pronounced like 'jasmine') is a minimalistic JSON parser in C. It can be +easily integrated into resource-limited or embedded projects. + +You can find more information about JSON format at [json.org][1] + +Library sources are available at [bitbucket.org/zserge/jsmn][2] + +The web page with some information about jsmn can be found at +[http://zserge.com/jsmn.html][3] + +Philosophy +---------- + +Most JSON parsers offer you a bunch of functions to load JSON data, parse it +and extract any value by its name. jsmn proves that checking the correctness of +every JSON packet or allocating temporary objects to store parsed JSON fields +often is an overkill. + +JSON format itself is extremely simple, so why should we complicate it? + +jsmn is designed to be **robust** (it should work fine even with erroneous +data), **fast** (it should parse data on the fly), **portable** (no superfluous +dependencies or non-standard C extensions). An of course, **simplicity** is a +key feature - simple code style, simple algorithm, simple integration into +other projects. + +Features +-------- + +* compatible with C89 +* no dependencies (even libc!) +* highly portable (tested on x86/amd64, ARM, AVR) +* about 200 lines of code +* extremely small code footprint +* API contains only 2 functions +* no dynamic memory allocation +* incremental single-pass parsing +* library code is covered with unit-tests + +Design +------ + +The rudimentary jsmn object is a **token**. Let's consider a JSON string: + + '{ "name" : "Jack", "age" : 27 }' + +It holds the following tokens: + +* Object: `{ "name" : "Jack", "age" : 27}` (the whole object) +* Strings: `"name"`, `"Jack"`, `"age"` (keys and some values) +* Number: `27` + +In jsmn, tokens do not hold any data, but point to token boundaries in JSON +string instead. In the example above jsmn will create tokens like: Object +[0..31], String [3..7], String [12..16], String [20..23], Number [27..29]. + +Every jsmn token has a type, which indicates the type of corresponding JSON +token. jsmn supports the following token types: + +* Object - a container of key-value pairs, e.g.: + `{ "foo":"bar", "x":0.3 }` +* Array - a sequence of values, e.g.: + `[ 1, 2, 3 ]` +* String - a quoted sequence of chars, e.g.: `"foo"` +* Primitive - a number, a boolean (`true`, `false`) or `null` + +Besides start/end positions, jsmn tokens for complex types (like arrays +or objects) also contain a number of child items, so you can easily follow +object hierarchy. + +This approach provides enough information for parsing any JSON data and makes +it possible to use zero-copy techniques. + +Install +------- + +To clone the repository you should have mercurial installed. Just run: + + $ hg clone http://bitbucket.org/zserge/jsmn jsmn + +Repository layout is simple: jsmn.c and jsmn.h are library files, tests are in +the jsmn\_test.c, you will also find README, LICENSE and Makefile files inside. + +To build the library, run `make`. It is also recommended to run `make test`. +Let me know, if some tests fail. + +If build was successful, you should get a `libjsmn.a` library. +The header file you should include is called `"jsmn.h"`. + +API +--- + +Token types are described by `jsmntype_t`: + + typedef enum { + JSMN_PRIMITIVE = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3 + } jsmntype_t; + +**Note:** Unlike JSON data types, primitive tokens are not divided into +numbers, booleans and null, because one can easily tell the type using the +first character: + +* 't', 'f' - boolean +* 'n' - null +* '-', '0'..'9' - number + +Token is an object of `jsmntok_t` type: + + typedef struct { + jsmntype_t type; // Token type + int start; // Token start position + int end; // Token end position + int size; // Number of child (nested) tokens + } jsmntok_t; + +**Note:** string tokens point to the first character after +the opening quote and the previous symbol before final quote. This was made +to simplify string extraction from JSON data. + +All job is done by `jsmn_parser` object. You can initialize a new parser using: + + jsmn_parser parser; + jsmntok_t tokens[10]; + + jsmn_init(&parser); + + // js - pointer to JSON string + // tokens - an array of tokens available + // 10 - number of tokens available + jsmn_parse(&parser, js, tokens, 10); + +This will create a parser, and then it tries to parse up to 10 JSON tokens from +the `js` string. + +A non-negative reutrn value of `jsmn_parse` is the number of tokens actually +used by the parser. +Passing NULL instead of the tokens array would not store parsing results, but +instead the function will return the value of tokens needed to parse the given +string. This can be useful if you don't know yet how many tokens to allocate. + +If something goes wrong, you will get an error. Error will be one of these: + +* `JSMN_ERROR_INVAL` - bad token, JSON string is corrupted +* `JSMN_ERROR_NOMEM` - not enough tokens, JSON string is too large +* `JSMN_ERROR_PART` - JSON string is too short, expecting more JSON data + +If you get `JSON_ERROR_NOMEM`, you can re-allocate more tokens and call +`jsmn_parse` once more. If you read json data from the stream, you can +periodically call `jsmn_parse` and check if return value is `JSON_ERROR_PART`. +You will get this error until you reach the end of JSON data. + +Other info +---------- + +This software is distributed under [MIT license](http://www.opensource.org/licenses/mit-license.php), + so feel free to integrate it in your commercial products. + +[1]: http://www.json.org/ +[2]: https://bitbucket.org/zserge/jsmn/wiki/Home +[3]: http://zserge.com/jsmn.html diff --git a/src/lib/jsmn/example/JSONDUMP.EXE b/src/lib/00jsmn00/example/JSONDUMP.EXE similarity index 100% rename from src/lib/jsmn/example/JSONDUMP.EXE rename to src/lib/00jsmn00/example/JSONDUMP.EXE diff --git a/src/lib/jsmn/example/MAPTEST.EXE b/src/lib/00jsmn00/example/MAPTEST.EXE similarity index 100% rename from src/lib/jsmn/example/MAPTEST.EXE rename to src/lib/00jsmn00/example/MAPTEST.EXE diff --git a/src/lib/jsmn/example/MAPTEST2.EXE b/src/lib/00jsmn00/example/MAPTEST2.EXE similarity index 100% rename from src/lib/jsmn/example/MAPTEST2.EXE rename to src/lib/00jsmn00/example/MAPTEST2.EXE diff --git a/src/lib/jsmn/example/SIMPLE.EXE b/src/lib/00jsmn00/example/SIMPLE.EXE similarity index 100% rename from src/lib/jsmn/example/SIMPLE.EXE rename to src/lib/00jsmn00/example/SIMPLE.EXE diff --git a/src/lib/jsmn/example/jsondump b/src/lib/00jsmn00/example/jsondump similarity index 100% rename from src/lib/jsmn/example/jsondump rename to src/lib/00jsmn00/example/jsondump diff --git a/src/lib/00jsmn00/example/jsondump.c b/src/lib/00jsmn00/example/jsondump.c new file mode 100755 index 00000000..b7d25cb0 --- /dev/null +++ b/src/lib/00jsmn00/example/jsondump.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include "../jsmn.c" + +/* + * An example of reading JSON from stdin and printing its content to stdout. + * The output looks like YAML, but I'm not sure if it's really compatible. + */ +static int jsoneq(const char *json, jsmntok_t *tok, const char *s) { + if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start && + strncmp(json + tok->start, s, tok->end - tok->start) == 0) { + return 0; + } + return -1; +} + +static int dump(const char *js, jsmntok_t *t, size_t count, int indent) { + int i, j, k; + if (count == 0) { + return 0; + } + if (t->type == JSMN_PRIMITIVE) { + printf("%.*s", t->end - t->start, js+t->start); + return 1; + } else if (t->type == JSMN_STRING) { + if(jsoneq(js, t, "data") == 0 ) + { +// printf("[[[[%d|%d]]]]\n", &(t+1)->size, (t+1)->size); + printf("\n%.*s[xx[%d|%d]xx]\n", (t+1)->end - (t+1)->start, js+(t+1)->start, &(t+1)->size, (t+1)->size); + } + printf("'%.*s'", t->end - t->start, js+t->start); + return 1; + } else if (t->type == JSMN_OBJECT) { + printf("\n"); + j = 0; + for (i = 0; i < t->size; i++) { + for (k = 0; k < indent; k++) printf(" "); + j += dump(js, t+1+j, count-j, indent+1); + printf(": "); + j += dump(js, t+1+j, count-j, indent+1); + printf("\n"); + } + return j+1; + } else if (t->type == JSMN_ARRAY) { + j = 0; + printf("\n"); + for (i = 0; i < t->size; i++) { + for (k = 0; k < indent-1; k++) printf(" "); + printf(" - "); + j += dump(js, t+1+j, count-j, indent+1); + printf("\n"); + } + return j+1; + } + return 0; +} + +int main() { + int r; + int eof_expected = 0; + char *js = NULL; + size_t jslen = 0; + char buf[BUFSIZ]; + + jsmn_parser p; + jsmntok_t *tok; + size_t tokcount = 2; + + /* Prepare parser */ + jsmn_init(&p); + + /* Allocate some tokens as a start */ + tok = malloc(sizeof(*tok) * tokcount); + if (tok == NULL) { + fprintf(stderr, "malloc(): errno=%d\n", errno); + return 3; + } + + for (;;) { + /* Read another chunk */ + r = fread(buf, 1, sizeof(buf), stdin); + if (r < 0) { + fprintf(stderr, "fread(): %d, errno=%d\n", r, errno); + return 1; + } + if (r == 0) { + if (eof_expected != 0) { + return 0; + } else { + fprintf(stderr, "fread(): unexpected EOF\n"); + return 2; + } + } + + js = realloc(js, jslen + r + 1); + if (js == NULL) { + fprintf(stderr, "realloc(): errno=%d\n", errno); + return 3; + } + strncpy(js + jslen, buf, r); + jslen = jslen + r; + +again: + r = jsmn_parse(&p, js, jslen, tok, tokcount); + if (r < 0) { + if (r == JSMN_ERROR_NOMEM) { + tokcount = tokcount * 2; + tok = realloc(tok, sizeof(*tok) * tokcount); + if (tok == NULL) { + fprintf(stderr, "realloc(): errno=%d\n", errno); + return 3; + } + goto again; + } + } else { + dump(js, tok, p.toknext, 0); + eof_expected = 1; + } + } + + return 0; +} diff --git a/src/lib/jsmn/example/maptest b/src/lib/00jsmn00/example/maptest similarity index 100% rename from src/lib/jsmn/example/maptest rename to src/lib/00jsmn00/example/maptest diff --git a/src/lib/jsmn/example/maptest.c b/src/lib/00jsmn00/example/maptest.c similarity index 100% rename from src/lib/jsmn/example/maptest.c rename to src/lib/00jsmn00/example/maptest.c diff --git a/src/lib/jsmn/example/maptest2 b/src/lib/00jsmn00/example/maptest2 similarity index 100% rename from src/lib/jsmn/example/maptest2 rename to src/lib/00jsmn00/example/maptest2 diff --git a/src/lib/jsmn/example/maptest2.c b/src/lib/00jsmn00/example/maptest2.c similarity index 100% rename from src/lib/jsmn/example/maptest2.c rename to src/lib/00jsmn00/example/maptest2.c diff --git a/src/lib/00jsmn00/example/simple.c b/src/lib/00jsmn00/example/simple.c new file mode 100755 index 00000000..ca2902b5 --- /dev/null +++ b/src/lib/00jsmn00/example/simple.c @@ -0,0 +1,75 @@ +#include +#include +#include "../jsmn.c" + +/* + * A small example of jsmn parsing when JSON structure is known and number of + * tokens is predictable. + */ + +const char *JSON_STRING = + "{\"user\": \"johndoe\", \"admin\": false, \"uid\": 1000,\n " + "\"groups\": [\"users\", \"wheel\", \"audio\", \"video\"]}"; + +static int jsoneq(const char *json, jsmntok_t *tok, const char *s) { + if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start && + strncmp(json + tok->start, s, tok->end - tok->start) == 0) { + return 0; + } + return -1; +} + +int main() { + int i; + int r; + jsmn_parser p; + jsmntok_t t[128]; /* We expect no more than 128 tokens */ + + jsmn_init(&p); + r = jsmn_parse(&p, JSON_STRING, strlen(JSON_STRING), t, sizeof(t)/sizeof(t[0])); + if (r < 0) { + printf("Failed to parse JSON: %d\n", r); + return 1; + } + + /* Assume the top-level element is an object */ + if (r < 1 || t[0].type != JSMN_OBJECT) { + printf("Object expected\n"); + return 1; + } + + /* Loop over all keys of the root object */ + for (i = 1; i < r; i++) { + if (jsoneq(JSON_STRING, &t[i], "user") == 0) { + /* We may use strndup() to fetch string value */ + printf("- User: %.*s\n", t[i+1].end-t[i+1].start, + JSON_STRING + t[i+1].start); + i++; + } else if (jsoneq(JSON_STRING, &t[i], "admin") == 0) { + /* We may additionally check if the value is either "true" or "false" */ + printf("- Admin: %.*s\n", t[i+1].end-t[i+1].start, + JSON_STRING + t[i+1].start); + i++; + } else if (jsoneq(JSON_STRING, &t[i], "uid") == 0) { + /* We may want to do strtol() here to get numeric value */ + printf("- UID: %.*s\n", t[i+1].end-t[i+1].start, + JSON_STRING + t[i+1].start); + i++; + } else if (jsoneq(JSON_STRING, &t[i], "groups") == 0) { + int j; + printf("- Groups:\n"); + if (t[i+1].type != JSMN_ARRAY) { + continue; /* We expect groups to be an array of strings */ + } + for (j = 0; j < t[i+1].size; j++) { + jsmntok_t *g = &t[i+j+2]; + printf(" * %.*s\n", g->end - g->start, JSON_STRING + g->start); + } + i += t[i+1].size + 1; + } else { + printf("Unexpected key: %.*s\n", t[i].end-t[i].start, + JSON_STRING + t[i].start); + } + } + return 0; +} diff --git a/src/lib/jsmn/farjsmn.c b/src/lib/00jsmn00/farjsmn.c similarity index 100% rename from src/lib/jsmn/farjsmn.c rename to src/lib/00jsmn00/farjsmn.c diff --git a/src/lib/jsmn/farjsmn.h b/src/lib/00jsmn00/farjsmn.h similarity index 100% rename from src/lib/jsmn/farjsmn.h rename to src/lib/00jsmn00/farjsmn.h diff --git a/src/lib/00jsmn00/jsmn.c b/src/lib/00jsmn00/jsmn.c new file mode 100755 index 00000000..a0f4f69c --- /dev/null +++ b/src/lib/00jsmn00/jsmn.c @@ -0,0 +1,311 @@ +#include + +#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->size = 0; +#ifdef JSMN_PARENT_LINKS + tok->parent = -1; +#endif + 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->size = 0; +} + +/** + * Fills next available token with JSON primitive. + */ +static jsmnerr_t 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]) { +#ifndef JSMN_STRICT + /* In strict mode primitive must be followed by "," or "}" or "]" */ + case ':': +#endif + 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; + } + } +#ifdef JSMN_STRICT + /* In strict mode primitive must be followed by a comma/object/array */ + parser->pos = start; + return JSMN_ERROR_PART; +#endif + +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); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + parser->pos--; + return 0; +} + +/** + * Filsl next token with JSON string. + */ +static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, + size_t len, jsmntok_t *tokens, size_t num_tokens) { + 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; + } + jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos); +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + 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. + */ +jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens) { + jsmnerr_t r; + int i; + jsmntok_t *token; + int count = 0; + + 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].size++; +#ifdef JSMN_PARENT_LINKS + token->parent = parser->toksuper; +#endif + } + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); + token->start = parser->pos; + parser->toksuper = parser->toknext - 1; + break; + case '}': case ']': + if (tokens == NULL) + break; + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); +#ifdef JSMN_PARENT_LINKS + 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]; + } +#else + for (i = parser->toknext - 1; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + if (token->type != type) { + return JSMN_ERROR_INVAL; + } + parser->toksuper = -1; + token->end = parser->pos + 1; + break; + } + } + /* Error if unmatched closing bracket */ + if (i == -1) return JSMN_ERROR_INVAL; + for (; i >= 0; i--) { + token = &tokens[i]; + if (token->start != -1 && token->end == -1) { + parser->toksuper = i; + break; + } + } +#endif + break; + case '\"': + r = jsmn_parse_string(parser, js, len, tokens, num_tokens); + if (r < 0) return r; + count++; + if (parser->toksuper != -1 && tokens != NULL) + tokens[parser->toksuper].size++; + break; + case '\t' : case '\r' : case '\n' : case ' ': + break; + case ':': + parser->toksuper = parser->toknext - 1; + break; + case ',': + if (tokens != NULL && + tokens[parser->toksuper].type != JSMN_ARRAY && + tokens[parser->toksuper].type != JSMN_OBJECT) { +#ifdef JSMN_PARENT_LINKS + parser->toksuper = tokens[parser->toksuper].parent; +#else + for (i = parser->toknext - 1; i >= 0; i--) { + if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { + if (tokens[i].start != -1 && tokens[i].end == -1) { + parser->toksuper = i; + break; + } + } + } +#endif + } + break; +#ifdef JSMN_STRICT + /* 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) { + jsmntok_t *t = &tokens[parser->toksuper]; + if (t->type == JSMN_OBJECT || + (t->type == JSMN_STRING && t->size != 0)) { + return JSMN_ERROR_INVAL; + } + } +#else + /* In non-strict mode every unquoted value is a primitive */ + default: +#endif + 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].size++; + break; + +#ifdef JSMN_STRICT + /* Unexpected char in strict mode */ + default: + return JSMN_ERROR_INVAL; +#endif + } + } + + 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; +} + diff --git a/src/lib/00jsmn00/jsmn.h b/src/lib/00jsmn00/jsmn.h new file mode 100755 index 00000000..95fb2cab --- /dev/null +++ b/src/lib/00jsmn00/jsmn.h @@ -0,0 +1,75 @@ +#ifndef __JSMN_H_ +#define __JSMN_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * JSON type identifier. Basic types are: + * o Object + * o Array + * o String + * o Other primitive: number, boolean (true/false) or null + */ +typedef enum { + JSMN_PRIMITIVE = 0, + JSMN_OBJECT = 1, + JSMN_ARRAY = 2, + JSMN_STRING = 3 +} jsmntype_t; + +typedef enum { + /* Not enough tokens were provided */ + JSMN_ERROR_NOMEM = -1, + /* Invalid character inside JSON string */ + JSMN_ERROR_INVAL = -2, + /* The string is not a full JSON packet, more bytes expected */ + JSMN_ERROR_PART = -3 +} jsmnerr_t; + +/** + * JSON token description. + * @param type type (object, array, string etc.) + * @param start start position in JSON data string + * @param end end position in JSON data string + */ +typedef struct { + jsmntype_t type; + int start; + int end; + int size; +#ifdef JSMN_PARENT_LINKS + int parent; +#endif +} jsmntok_t; + +/** + * JSON parser. Contains an array of token blocks available. Also stores + * the string being parsed now and current position in that string + */ +typedef struct { + unsigned int pos; /* offset in the JSON string */ + unsigned int toknext; /* next token to allocate */ + int toksuper; /* superior token node, e.g parent object or array */ +} jsmn_parser; + +/** + * Create JSON parser over an array of tokens + */ +void jsmn_init(jsmn_parser *parser); + +/** + * Run JSON parser. It parses a JSON data string into and array of tokens, each describing + * a single JSON object. + */ +jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len, + jsmntok_t *tokens, unsigned int num_tokens); + +#ifdef __cplusplus +} +#endif + +#endif /* __JSMN_H_ */ diff --git a/src/lib/jsmn/jsmn_test b/src/lib/00jsmn00/jsmn_test similarity index 100% rename from src/lib/jsmn/jsmn_test rename to src/lib/00jsmn00/jsmn_test diff --git a/src/lib/00jsmn00/jsmn_test.c b/src/lib/00jsmn00/jsmn_test.c new file mode 100755 index 00000000..39688592 --- /dev/null +++ b/src/lib/00jsmn00/jsmn_test.c @@ -0,0 +1,608 @@ +#include +#include +#include + +static int test_passed = 0; +static int test_failed = 0; + +/* Terminate current test with error */ +#define fail() return __LINE__ + +/* Successfull end of the test case */ +#define done() return 0 + +/* Check single condition */ +#define check(cond) do { if (!(cond)) fail(); } while (0) + +/* Test runner */ +static void test(int (*func)(void), const char *name) { + int r = func(); + if (r == 0) { + test_passed++; + } else { + test_failed++; + printf("FAILED: %s (at line %d)\n", name, r); + } +} + +#define TOKEN_EQ(t, tok_start, tok_end, tok_type) \ + ((t).start == tok_start \ + && (t).end == tok_end \ + && (t).type == (tok_type)) + +#define TOKEN_STRING(js, t, s) \ + (strncmp(js+(t).start, s, (t).end - (t).start) == 0 \ + && strlen(s) == (t).end - (t).start) + +#define TOKEN_PRINT(t) \ + printf("start: %d, end: %d, type: %d, size: %d\n", \ + (t).start, (t).end, (t).type, (t).size) + +#define JSMN_STRICT +#include "jsmn.c" + +int test_empty() { + const char *js; + int r; + jsmn_parser p; + jsmntok_t t[10]; + + js = "{}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), t, 10); + check(r >= 0); + check(t[0].type == JSMN_OBJECT); + check(t[0].start == 0 && t[0].end == 2); + + js = "[]"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), t, 10); + check(r >= 0); + check(t[0].type == JSMN_ARRAY); + check(t[0].start == 0 && t[0].end == 2); + + js = "{\"a\":[]}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), t, 10); + check(r >= 0); + check(t[0].type == JSMN_OBJECT && t[0].start == 0 && t[0].end == 8); + check(t[1].type == JSMN_STRING && t[1].start == 2 && t[1].end == 3); + check(t[2].type == JSMN_ARRAY && t[2].start == 5 && t[2].end == 7); + + js = "[{},{}]"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), t, 10); + check(r >= 0); + check(t[0].type == JSMN_ARRAY && t[0].start == 0 && t[0].end == 7); + check(t[1].type == JSMN_OBJECT && t[1].start == 1 && t[1].end == 3); + check(t[2].type == JSMN_OBJECT && t[2].start == 4 && t[2].end == 6); + return 0; +} + +int test_simple() { + const char *js; + int r; + jsmn_parser p; + jsmntok_t tokens[10]; + + js = "{\"a\": 0}"; + + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r >= 0); + check(TOKEN_EQ(tokens[0], 0, 8, JSMN_OBJECT)); + check(TOKEN_EQ(tokens[1], 2, 3, JSMN_STRING)); + check(TOKEN_EQ(tokens[2], 6, 7, JSMN_PRIMITIVE)); + + check(TOKEN_STRING(js, tokens[0], js)); + check(TOKEN_STRING(js, tokens[1], "a")); + check(TOKEN_STRING(js, tokens[2], "0")); + + jsmn_init(&p); + js = "[\"a\":{},\"b\":{}]"; + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r >= 0); + + jsmn_init(&p); + js = "{\n \"Day\": 26,\n \"Month\": 9,\n \"Year\": 12\n }"; + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r >= 0); + + return 0; +} + +int test_primitive() { +#ifndef JSMN_STRICT + int r; + jsmn_parser p; + jsmntok_t tok[10]; + const char *js; + js = "\"boolVar\" : true"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_PRIMITIVE); + check(TOKEN_STRING(js, tok[0], "boolVar")); + check(TOKEN_STRING(js, tok[1], "true")); + + js = "\"boolVar\" : false"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_PRIMITIVE); + check(TOKEN_STRING(js, tok[0], "boolVar")); + check(TOKEN_STRING(js, tok[1], "false")); + + js = "\"intVar\" : 12345"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_PRIMITIVE); + check(TOKEN_STRING(js, tok[0], "intVar")); + check(TOKEN_STRING(js, tok[1], "12345")); + + js = "\"floatVar\" : 12.345"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_PRIMITIVE); + check(TOKEN_STRING(js, tok[0], "floatVar")); + check(TOKEN_STRING(js, tok[1], "12.345")); + + js = "\"nullVar\" : null"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_PRIMITIVE); + check(TOKEN_STRING(js, tok[0], "nullVar")); + check(TOKEN_STRING(js, tok[1], "null")); +#endif + return 0; +} + +int test_string() { + int r; + jsmn_parser p; + jsmntok_t tok[10]; + const char *js; + + js = "\"strVar\" : \"hello world\""; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_STRING); + check(TOKEN_STRING(js, tok[0], "strVar")); + check(TOKEN_STRING(js, tok[1], "hello world")); + + js = "\"strVar\" : \"escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\\""; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_STRING); + check(TOKEN_STRING(js, tok[0], "strVar")); + check(TOKEN_STRING(js, tok[1], "escapes: \\/\\r\\n\\t\\b\\f\\\"\\\\")); + + js = "\"strVar\" : \"\""; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_STRING); + check(TOKEN_STRING(js, tok[0], "strVar")); + check(TOKEN_STRING(js, tok[1], "")); + + return 0; +} + +int test_partial_string() { + int r; + jsmn_parser p; + jsmntok_t tok[10]; + const char *js; + + jsmn_init(&p); + js = "\"x\": \"va"; + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r == JSMN_ERROR_PART && tok[0].type == JSMN_STRING); + check(TOKEN_STRING(js, tok[0], "x")); + check(p.toknext == 1); + + jsmn_init(&p); + char js_slash[9] = "\"x\": \"va\\"; + r = jsmn_parse(&p, js_slash, sizeof(js_slash), tok, 10); + check(r == JSMN_ERROR_PART); + + jsmn_init(&p); + char js_unicode[10] = "\"x\": \"va\\u"; + r = jsmn_parse(&p, js_unicode, sizeof(js_unicode), tok, 10); + check(r == JSMN_ERROR_PART); + + js = "\"x\": \"valu"; + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r == JSMN_ERROR_PART && tok[0].type == JSMN_STRING); + check(TOKEN_STRING(js, tok[0], "x")); + check(p.toknext == 1); + + js = "\"x\": \"value\""; + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_STRING); + check(TOKEN_STRING(js, tok[0], "x")); + check(TOKEN_STRING(js, tok[1], "value")); + + js = "\"x\": \"value\", \"y\": \"value y\""; + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_STRING + && tok[1].type == JSMN_STRING && tok[2].type == JSMN_STRING + && tok[3].type == JSMN_STRING); + check(TOKEN_STRING(js, tok[0], "x")); + check(TOKEN_STRING(js, tok[1], "value")); + check(TOKEN_STRING(js, tok[2], "y")); + check(TOKEN_STRING(js, tok[3], "value y")); + + return 0; +} + +int test_unquoted_keys() { +#ifndef JSMN_STRICT + int r; + jsmn_parser p; + jsmntok_t tok[10]; + const char *js; + + jsmn_init(&p); + js = "key1: \"value\"\nkey2 : 123"; + + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_PRIMITIVE + && tok[1].type == JSMN_STRING && tok[2].type == JSMN_PRIMITIVE + && tok[3].type == JSMN_PRIMITIVE); + check(TOKEN_STRING(js, tok[0], "key1")); + check(TOKEN_STRING(js, tok[1], "value")); + check(TOKEN_STRING(js, tok[2], "key2")); + check(TOKEN_STRING(js, tok[3], "123")); +#endif + return 0; +} + +int test_partial_array() { + int r; + jsmn_parser p; + jsmntok_t tok[10]; + const char *js; + + jsmn_init(&p); + js = " [ 1, true, "; + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY + && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE); + + js = " [ 1, true, [123, \"hello"; + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY + && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE + && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE); + + js = " [ 1, true, [123, \"hello\"]"; + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r == JSMN_ERROR_PART && tok[0].type == JSMN_ARRAY + && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE + && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE + && tok[5].type == JSMN_STRING); + /* check child nodes of the 2nd array */ + check(tok[3].size == 2); + + js = " [ 1, true, [123, \"hello\"]]"; + r = jsmn_parse(&p, js, strlen(js), tok, 10); + check(r >= 0 && tok[0].type == JSMN_ARRAY + && tok[1].type == JSMN_PRIMITIVE && tok[2].type == JSMN_PRIMITIVE + && tok[3].type == JSMN_ARRAY && tok[4].type == JSMN_PRIMITIVE + && tok[5].type == JSMN_STRING); + check(tok[3].size == 2); + check(tok[0].size == 3); + return 0; +} + +int test_array_nomem() { + int i; + int r; + jsmn_parser p; + jsmntok_t toksmall[10], toklarge[10]; + const char *js; + + js = " [ 1, true, [123, \"hello\"]]"; + + for (i = 0; i < 6; i++) { + jsmn_init(&p); + memset(toksmall, 0, sizeof(toksmall)); + memset(toklarge, 0, sizeof(toklarge)); + r = jsmn_parse(&p, js, strlen(js), toksmall, i); + check(r == JSMN_ERROR_NOMEM); + + memcpy(toklarge, toksmall, sizeof(toksmall)); + + r = jsmn_parse(&p, js, strlen(js), toklarge, 10); + check(r >= 0); + + check(toklarge[0].type == JSMN_ARRAY && toklarge[0].size == 3); + check(toklarge[3].type == JSMN_ARRAY && toklarge[3].size == 2); + } + return 0; +} + +int test_objects_arrays() { + int r; + jsmn_parser p; + jsmntok_t tokens[10]; + const char *js; + + js = "[10}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + + js = "[10]"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r >= 0); + + js = "{\"a\": 1]"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + + js = "{\"a\": 1}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r >= 0); + + return 0; +} + +int test_issue_22() { + int r; + jsmn_parser p; + jsmntok_t tokens[128]; + const char *js; + + js = "{ \"height\":10, \"layers\":[ { \"data\":[6,6], \"height\":10, " + "\"name\":\"Calque de Tile 1\", \"opacity\":1, \"type\":\"tilelayer\", " + "\"visible\":true, \"width\":10, \"x\":0, \"y\":0 }], " + "\"orientation\":\"orthogonal\", \"properties\": { }, \"tileheight\":32, " + "\"tilesets\":[ { \"firstgid\":1, \"image\":\"..\\/images\\/tiles.png\", " + "\"imageheight\":64, \"imagewidth\":160, \"margin\":0, \"name\":\"Tiles\", " + "\"properties\":{}, \"spacing\":0, \"tileheight\":32, \"tilewidth\":32 }], " + "\"tilewidth\":32, \"version\":1, \"width\":10 }"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 128); + check(r >= 0); +#if 0 + for (i = 1; tokens[i].end < tokens[0].end; i++) { + if (tokens[i].type == JSMN_STRING || tokens[i].type == JSMN_PRIMITIVE) { + printf("%.*s\n", tokens[i].end - tokens[i].start, js + tokens[i].start); + } else if (tokens[i].type == JSMN_ARRAY) { + printf("[%d elems]\n", tokens[i].size); + } else if (tokens[i].type == JSMN_OBJECT) { + printf("{%d elems}\n", tokens[i].size); + } else { + TOKEN_PRINT(tokens[i]); + } + } +#endif + return 0; +} + +int test_unicode_characters() { + jsmn_parser p; + jsmntok_t tokens[10]; + const char *js; + + int r; + js = "{\"a\":\"\\uAbcD\"}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r >= 0); + + js = "{\"a\":\"str\\u0000\"}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r >= 0); + + js = "{\"a\":\"\\uFFFFstr\"}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r >= 0); + + js = "{\"a\":\"str\\uFFGFstr\"}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + + js = "{\"a\":\"str\\u@FfF\"}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + + js = "{\"a\":[\"\\u028\"]}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + + js = "{\"a\":[\"\\u0280\"]}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r >= 0); + + return 0; +} + +int test_input_length() { + const char *js; + int r; + jsmn_parser p; + jsmntok_t tokens[10]; + + js = "{\"a\": 0}garbage"; + + jsmn_init(&p); + r = jsmn_parse(&p, js, 8, tokens, 10); + check(r == 3); + check(TOKEN_STRING(js, tokens[0], "{\"a\": 0}")); + check(TOKEN_STRING(js, tokens[1], "a")); + check(TOKEN_STRING(js, tokens[2], "0")); + + return 0; +} + +int test_count() { + jsmn_parser p; + const char *js; + + js = "{}"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 1); + + js = "[]"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 1); + + js = "[[]]"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 2); + + js = "[[], []]"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 3); + + js = "[[], []]"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 3); + + js = "[[], [[]], [[], []]]"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 7); + + js = "[\"a\", [[], []]]"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 5); + + js = "[[], \"[], [[]]\", [[]]]"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 5); + + js = "[1, 2, 3]"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 4); + + js = "[1, 2, [3, \"a\"], null]"; + jsmn_init(&p); + check(jsmn_parse(&p, js, strlen(js), NULL, 0) == 7); + + return 0; +} + +int test_keyvalue() { + const char *js; + int r; + jsmn_parser p; + jsmntok_t tokens[10]; + + js = "{\"a\": 0, \"b\": \"c\"}"; + + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == 5); + check(tokens[0].size == 2); /* two keys */ + check(tokens[1].size == 1 && tokens[3].size == 1); /* one value per key */ + check(tokens[2].size == 0 && tokens[4].size == 0); /* values have zero size */ + + js = "{\"a\"\n0}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + + js = "{\"a\", 0}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + + js = "{\"a\": {2}}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + + js = "{\"a\": {2: 3}}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + + + js = "{\"a\": {\"a\": 2 3}}"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == JSMN_ERROR_INVAL); + return 0; +} + +/** A huge redefinition of everything to include jsmn in non-script mode */ +#define jsmn_init jsmn_init_nonstrict +#define jsmn_parse jsmn_parse_nonstrict +#define jsmn_parser jsmn_parser_nonstrict +#define jsmn_alloc_token jsmn_alloc_token_nonstrict +#define jsmn_fill_token jsmn_fill_token_nonstrict +#define jsmn_parse_primitive jsmn_parse_primitive_nonstrict +#define jsmn_parse_string jsmn_parse_string_nonstrict +#define jsmntype_t jsmntype_nonstrict_t +#define jsmnerr_t jsmnerr_nonstrict_t +#define jsmntok_t jsmntok_nonstrict_t +#define JSMN_PRIMITIVE JSMN_PRIMITIVE_NONSTRICT +#define JSMN_OBJECT JSMN_OBJECT_NONSTRICT +#define JSMN_ARRAY JSMN_ARRAY_NONSTRICT +#define JSMN_STRING JSMN_STRING_NONSTRICT +#define JSMN_ERROR_NOMEM JSMN_ERROR_NOMEM_NONSTRICT +#define JSMN_ERROR_INVAL JSMN_ERROR_INVAL_NONSTRICT +#define JSMN_ERROR_PART JSMN_ERROR_PART_NONSTRICT +#undef __JSMN_H_ +#undef JSMN_STRICT +#include "jsmn.c" + +int test_nonstrict() { + const char *js; + int r; + jsmn_parser p; + jsmntok_t tokens[10]; + + js = "a: 0garbage"; + + jsmn_init(&p); + r = jsmn_parse(&p, js, 4, tokens, 10); + check(r == 2); + check(TOKEN_STRING(js, tokens[0], "a")); + check(TOKEN_STRING(js, tokens[1], "0")); + + js = "Day : 26\nMonth : Sep\n\nYear: 12"; + jsmn_init(&p); + r = jsmn_parse(&p, js, strlen(js), tokens, 10); + check(r == 6); + return 0; +} + +int main() { + test(test_empty, "general test for a empty JSON objects/arrays"); + test(test_simple, "general test for a simple JSON string"); + test(test_primitive, "test primitive JSON data types"); + test(test_string, "test string JSON data types"); + test(test_partial_string, "test partial JSON string parsing"); + test(test_partial_array, "test partial array reading"); + test(test_array_nomem, "test array reading with a smaller number of tokens"); + test(test_unquoted_keys, "test unquoted keys (like in JavaScript)"); + test(test_objects_arrays, "test objects and arrays"); + test(test_unicode_characters, "test unicode characters"); + test(test_input_length, "test strings that are not null-terminated"); + test(test_issue_22, "test issue #22"); + test(test_count, "test tokens count estimation"); + test(test_nonstrict, "test for non-strict mode"); + test(test_keyvalue, "test for keys/values"); + printf("\nPASSED: %d\nFAILED: %d\n", test_passed, test_failed); + return 0; +} + diff --git a/src/lib/jsmn/README.md b/src/lib/jsmn/README.md index 353af94a..c7837f75 100755 --- a/src/lib/jsmn/README.md +++ b/src/lib/jsmn/README.md @@ -7,10 +7,10 @@ easily integrated into resource-limited or embedded projects. You can find more information about JSON format at [json.org][1] -Library sources are available at [bitbucket.org/zserge/jsmn][2] +Library sources are available at https://github.com/zserge/jsmn The web page with some information about jsmn can be found at -[http://zserge.com/jsmn.html][3] +[http://zserge.com/jsmn.html][2] Philosophy ---------- @@ -78,9 +78,9 @@ it possible to use zero-copy techniques. Install ------- -To clone the repository you should have mercurial installed. Just run: +To clone the repository you should have Git installed. Just run: - $ hg clone http://bitbucket.org/zserge/jsmn jsmn + $ git clone https://github.com/zserge/jsmn Repository layout is simple: jsmn.c and jsmn.h are library files, tests are in the jsmn\_test.c, you will also find README, LICENSE and Makefile files inside. @@ -163,5 +163,4 @@ This software is distributed under [MIT license](http://www.opensource.org/licen so feel free to integrate it in your commercial products. [1]: http://www.json.org/ -[2]: https://bitbucket.org/zserge/jsmn/wiki/Home -[3]: http://zserge.com/jsmn.html +[2]: http://zserge.com/jsmn.html diff --git a/src/lib/jsmn/example/jsondump.c b/src/lib/jsmn/example/jsondump.c index b7d25cb0..3490bbf4 100755 --- a/src/lib/jsmn/example/jsondump.c +++ b/src/lib/jsmn/example/jsondump.c @@ -2,19 +2,12 @@ #include #include #include -#include "../jsmn.c" +#include "../jsmn.h" /* * An example of reading JSON from stdin and printing its content to stdout. * The output looks like YAML, but I'm not sure if it's really compatible. */ -static int jsoneq(const char *json, jsmntok_t *tok, const char *s) { - if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start && - strncmp(json + tok->start, s, tok->end - tok->start) == 0) { - return 0; - } - return -1; -} static int dump(const char *js, jsmntok_t *t, size_t count, int indent) { int i, j, k; @@ -25,11 +18,6 @@ static int dump(const char *js, jsmntok_t *t, size_t count, int indent) { printf("%.*s", t->end - t->start, js+t->start); return 1; } else if (t->type == JSMN_STRING) { - if(jsoneq(js, t, "data") == 0 ) - { -// printf("[[[[%d|%d]]]]\n", &(t+1)->size, (t+1)->size); - printf("\n%.*s[xx[%d|%d]xx]\n", (t+1)->end - (t+1)->start, js+(t+1)->start, &(t+1)->size, (t+1)->size); - } printf("'%.*s'", t->end - t->start, js+t->start); return 1; } else if (t->type == JSMN_OBJECT) { diff --git a/src/lib/jsmn/example/simple.c b/src/lib/jsmn/example/simple.c index ca2902b5..a6f8e6a9 100755 --- a/src/lib/jsmn/example/simple.c +++ b/src/lib/jsmn/example/simple.c @@ -1,6 +1,6 @@ #include #include -#include "../jsmn.c" +#include "../jsmn.h" /* * A small example of jsmn parsing when JSON structure is known and number of diff --git a/test.map b/test.map index 373faa7a..762f5543 100755 --- a/test.map +++ b/test.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: test.exe creating a DOS executable diff --git a/test2.map b/test2.map index ecfc7e24..5560558e 100755 --- a/test2.map +++ b/test2.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: test2.exe creating a DOS executable diff --git a/vgmtest.map b/vgmtest.map index 9e6e4605..9473c94c 100755 --- a/vgmtest.map +++ b/vgmtest.map @@ -1,7 +1,7 @@ Open Watcom Linker Version 2.0 beta Sep 21 2015 09:27:06 (32-bit) Copyright (c) 2002-2015 The Open Watcom Contributors. All Rights Reserved. Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved. -Created on: 15/10/01 13:45:21 +Created on: 15/10/01 13:49:51 Executable Image: vgmtest.exe creating a DOS executable