diff --git a/src/Makefile b/src/Makefile index ea851162b..512bbf55f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -79,6 +79,7 @@ include $(LIBCOM)/error/RULES include $(LIBCOM)/flex/RULES include $(LIBCOM)/misc/RULES include $(LIBCOM)/osi/RULES +include $(LIBCOM)/yajl/RULES # Can't use EXPAND as generated headers must appear # in O.Common, but EXPAND emits rules for O.$(T_A) diff --git a/src/osi/os/Darwin/osdSock.h b/src/osi/os/Darwin/osdSock.h index 1d4556eee..e7c344062 100644 --- a/src/osi/os/Darwin/osdSock.h +++ b/src/osi/os/Darwin/osdSock.h @@ -31,6 +31,7 @@ typedef int SOCKET; #define socket_ioctl(A,B,C) ioctl(A,B,C) typedef int osiSockIoctl_t; typedef socklen_t osiSocklen_t; +typedef int osiSockOptMcastLoop_t; #define FD_IN_FDSET(FD) ((FD)=0) #ifndef SHUT_RD #define SHUT_RD 0 diff --git a/src/osi/os/freebsd/osdSock.h b/src/osi/os/freebsd/osdSock.h index fe28d4cd5..b402ec120 100644 --- a/src/osi/os/freebsd/osdSock.h +++ b/src/osi/os/freebsd/osdSock.h @@ -36,6 +36,7 @@ typedef int SOCKET; #define socket_ioctl(A,B,C) ioctl(A,B,C) typedef int osiSockIoctl_t; typedef socklen_t osiSocklen_t; +typedef int osiSockOptMcastLoop_t; #define FD_IN_FDSET(FD) ((FD)=0) diff --git a/src/std/rec/test/regressLinkMS.db b/src/std/rec/test/regressLinkMS.db deleted file mode 100644 index 612c18afa..000000000 --- a/src/std/rec/test/regressLinkMS.db +++ /dev/null @@ -1,13 +0,0 @@ -record(ai, "alarm") { - field(HIGH, 1) - field(HSV, MINOR) - field(HIHI, 2) - field(HHSV, MAJOR) - field(FLNK, "latch") -} - -record(calc, "latch") { - field(INPA, "alarm NPP MS") - field(INPB, "latch NPP MS") - field(CALC, "A") -} diff --git a/src/std/rec/test/softTest.c b/src/std/rec/test/softTest.c deleted file mode 100644 index d92bf64dd..000000000 --- a/src/std/rec/test/softTest.c +++ /dev/null @@ -1,169 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2017 UChicago Argonne LLC, as operator of Argonne -* National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -#include - -#include "dbAccess.h" -#include "dbStaticLib.h" -#include "dbTest.h" -#include "dbUnitTest.h" -#include "errlog.h" -#include "registryFunction.h" -#include "subRecord.h" -#include "testMain.h" - -static -void checkDtyp(const char *rec) -{ - char dtyp[16]; - - strcpy(dtyp, rec); - strcat(dtyp, ".DTYP"); - - testdbGetFieldEqual(dtyp, DBF_LONG, 0); /* Soft Channel = 0 */ -} - -static -void checkInput(const char *rec, int value) -{ - char proc[16]; - - testDiag("Checking record '%s'", rec); - - strcpy(proc, rec); - strcat(proc, ".PROC"); - - testdbPutFieldOk(proc, DBF_CHAR, 1); - - testdbGetFieldEqual(rec, DBF_LONG, value); -} - -static -void testGroup0(void) -{ - const char ** rec; - const char * records[] = { - "ai0", "bi0", "di0", "ii0", "li0", "lsi0", "mi0", "si0", NULL - }; - - testDiag("============ Starting %s ============", EPICS_FUNCTION); - - testdbPutFieldOk("source", DBF_LONG, 1); - for (rec = records; *rec; rec++) { - checkInput(*rec, 1); - checkDtyp(*rec); - } - - testdbPutFieldOk("source", DBF_LONG, 0); - for (rec = records; *rec; rec++) { - checkInput(*rec, 0); - } -} - -static -void testGroup1(void) -{ - const char ** rec; - const char * records[] = { - "bi1", - "ai1", "di1", "ii1", "li1", "lsi1", "mi1", "si1", NULL - }; - int init = 1; /* bi1 initializes to 1 */ - - testDiag("============ Starting %s ============", EPICS_FUNCTION); - - for (rec = records; *rec; rec++) { - checkInput(*rec, init); - init = 9; /* remainder initialize to 9 */ - } -} - -int dest; - -static -long destSubr(subRecord *prec) -{ - dest = prec->val; - return 0; -} - -static -void checkOutput(const char *rec, int value) -{ - testDiag("Checking record '%s'", rec); - - testdbPutFieldOk(rec, DBF_LONG, value); - - testOk(dest == value, "value %d output -> %d", value, dest); -} - -static -void testGroup2(void) -{ - const char ** rec; - const char * records[] = { - "ao0", "bo0", "io0", "lo0", "lso0", "mo0", "so0", NULL, - }; - - testDiag("============ Starting %s ============", EPICS_FUNCTION); - - for (rec = records; *rec; rec++) { - checkOutput(*rec, 1); - checkDtyp(*rec); - } - checkOutput("do0.B0", 1); - checkDtyp("do0"); - - for (rec = records; *rec; rec++) { - checkOutput(*rec, 0); - } - checkOutput("do0.B0", 0); -} - -static -void testGroup3(void) -{ - const char ** rec; - const char * records[] = { - "ao1", "bo1", "do1.B0", "io1", "lo1", "lso1", "mo1", "so1", NULL, - }; - - testDiag("============ Starting %s ============", EPICS_FUNCTION); - - for (rec = records; *rec; rec++) { - checkOutput(*rec, 0); - } -} - -void recTestIoc_registerRecordDeviceDriver(struct dbBase *); - -MAIN(softTest) -{ - testPlan(114); - - testdbPrepare(); - testdbReadDatabase("recTestIoc.dbd", NULL, NULL); - - recTestIoc_registerRecordDeviceDriver(pdbbase); - registryFunctionAdd("destSubr", (REGISTRYFUNCTION) destSubr); - - testdbReadDatabase("softTest.db", NULL, NULL); - - eltc(0); - testIocInitOk(); - eltc(1); - - testGroup0(); - testGroup1(); - testGroup2(); - testGroup3(); - - testIocShutdownOk(); - testdbCleanup(); - - return testDone(); -} diff --git a/src/std/rec/test/softTest.db b/src/std/rec/test/softTest.db deleted file mode 100644 index 010a47a5c..000000000 --- a/src/std/rec/test/softTest.db +++ /dev/null @@ -1,227 +0,0 @@ -# Group 0 are input records with INP being a DB link to 'source'. -# Processing them reads that value. - -record(longin, "source") {} - -record(ai, "ai0") { - field(DTYP, "Soft Channel") - field(INP, "source") -} -record(bi, "bi0") { - field(DTYP, "Soft Channel") - field(INP, "source") - field(ZNAM, "Zero") - field(ONAM, "One") -} -record(int64in, "ii0") { - field(DTYP, "Soft Channel") - field(INP, "source") -} -record(longin, "li0") { - field(DTYP, "Soft Channel") - field(INP, "source") -} -record(mbbiDirect, "di0") { - field(DTYP, "Soft Channel") - field(NOBT, 4) - field(INP, "source") -} -record(mbbi, "mi0") { - field(DTYP, "Soft Channel") - field(NOBT, 4) - field(INP, "source") - field(ZRST, "Zero") - field(ONST, "One") - field(TWST, "Two") - field(THST, "Three") - field(FRST, "Four") - field(FVST, "Five") - field(SXST, "Six") - field(SVST, "Seven") - field(EIST, "Eight") - field(NIST, "Nine") - field(TEST, "Ten") - field(ELST, "Eleven") - field(TWST, "Twelve") - field(TTST, "Thirteen") - field(FTST, "Fourteen") - field(FFST, "Fifteen") -} -record(lsi, "lsi0") { - field(DTYP, "Soft Channel") - field(SIZV, 40) - field(INP, "source") -} -record(stringin, "si0") { - field(DTYP, "Soft Channel") - field(INP, "source") -} - -# Group 1 are input records with INP being a non-zero constant. -# Processing them succeeds but does not change VAL. - -record(ai, "ai1") { - field(DTYP, "Soft Channel") - field(INP, {const:9}) -} -record(bi, "bi1") { - field(DTYP, "Soft Channel") - field(INP, {const:1}) - field(ZNAM, "Zero") - field(ONAM, "One") -} -record(int64in, "ii1") { - field(DTYP, "Soft Channel") - field(INP, {const:9}) -} -record(longin, "li1") { - field(DTYP, "Soft Channel") - field(INP, {const:9}) -} -record(mbbiDirect, "di1") { - field(DTYP, "Soft Channel") - field(NOBT, 4) - field(INP, {const:9}) -} -record(mbbi, "mi1") { - field(DTYP, "Soft Channel") - field(NOBT, 4) - field(INP, {const:9}) - field(ZRST, "Zero") - field(ONST, "One") - field(TWST, "Two") - field(THST, "Three") - field(FRST, "Four") - field(FVST, "Five") - field(SXST, "Six") - field(SVST, "Seven") - field(EIST, "Eight") - field(NIST, "Nine") - field(TEST, "Ten") - field(ELST, "Eleven") - field(TWST, "Twelve") - field(TTST, "Thirteen") - field(FTST, "Fourteen") - field(FFST, "Fifteen") -} -record(lsi, "lsi1") { - field(DTYP, "Soft Channel") - field(SIZV, 40) - field(INP, {const:"9"}) -} -record(stringin, "si1") { - field(DTYP, "Soft Channel") - field(INP, {const:"9"}) -} - - -# Group 2 are output records with OUT being a DB link to 'dest' with PP. -# Putting a value to them writes that value to 'dest'. - -record(sub, "dest") { - field(SNAM, "destSubr") -} - -record(ao, "ao0") { - field(DTYP, "Soft Channel") - field(OUT, "dest PP") -} -record(bo, "bo0") { - field(DTYP, "Soft Channel") - field(OUT, "dest PP") - field(ZNAM, "Zero") - field(ONAM, "One") -} -record(int64out, "io0") { - field(DTYP, "Soft Channel") - field(OUT, "dest PP") -} -record(longout, "lo0") { - field(DTYP, "Soft Channel") - field(OUT, "dest PP") -} -record(mbboDirect, "do0") { - field(DTYP, "Soft Channel") - field(NOBT, 4) - field(OUT, "dest PP") -} -record(mbbo, "mo0") { - field(DTYP, "Soft Channel") - field(NOBT, 4) - field(OUT, "dest PP") - field(ZRST, "Zero") - field(ONST, "One") - field(TWST, "Two") - field(THST, "Three") - field(FRST, "Four") - field(FVST, "Five") - field(SXST, "Six") - field(SVST, "Seven") - field(EIST, "Eight") - field(NIST, "Nine") - field(TEST, "Ten") - field(ELST, "Eleven") - field(TWST, "Twelve") - field(TTST, "Thirteen") - field(FTST, "Fourteen") - field(FFST, "Fifteen") -} -record(lso, "lso0") { - field(DTYP, "Soft Channel") - field(OUT, "dest PP") - field(SIZV, 40) -} -record(stringout, "so0") { - field(DTYP, "Soft Channel") - field(OUT, "dest PP") -} - - -# Group 3 are output records with OUT being empty (a constant link). -# Putting a value to them must succeed. - -record(ao, "ao1") { - field(DTYP, "Soft Channel") -} -record(bo, "bo1") { - field(DTYP, "Soft Channel") - field(ZNAM, "Zero") - field(ONAM, "One") -} -record(int64out, "io1") { - field(DTYP, "Soft Channel") -} -record(longout, "lo1") { - field(DTYP, "Soft Channel") -} -record(mbboDirect, "do1") { - field(DTYP, "Soft Channel") - field(NOBT, 4) -} -record(mbbo, "mo1") { - field(DTYP, "Soft Channel") - field(NOBT, 4) - field(ZRST, "Zero") - field(ONST, "One") - field(TWST, "Two") - field(THST, "Three") - field(FRST, "Four") - field(FVST, "Five") - field(SXST, "Six") - field(SVST, "Seven") - field(EIST, "Eight") - field(NIST, "Nine") - field(TEST, "Ten") - field(ELST, "Eleven") - field(TWST, "Twelve") - field(TTST, "Thirteen") - field(FTST, "Fourteen") - field(FFST, "Fifteen") -} -record(lso, "lso1") { - field(DTYP, "Soft Channel") - field(SIZV, 40) -} -record(stringout, "so1") { - field(DTYP, "Soft Channel") -} diff --git a/src/yajl/RULES b/src/yajl/RULES new file mode 100644 index 000000000..9cd228cbe --- /dev/null +++ b/src/yajl/RULES @@ -0,0 +1,17 @@ +#************************************************************************* +# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +# This is a Makefile fragment, see src/libCom/Makefile. + +# Ensure epicsVersion.h gets built first +yajl$(DEP): $(COMMON_DIR)/epicsVersion.h +yajl_alloc$(DEP): $(COMMON_DIR)/epicsVersion.h +yajl_buf$(DEP): $(COMMON_DIR)/epicsVersion.h +yajl_encode$(DEP): $(COMMON_DIR)/epicsVersion.h +yajl_gen$(DEP): $(COMMON_DIR)/epicsVersion.h +yajl_lex$(DEP): $(COMMON_DIR)/epicsVersion.h +yajl_parser$(DEP): $(COMMON_DIR)/epicsVersion.h diff --git a/src/yajl/yajl.c b/src/yajl/yajl.c index 063e8f8b9..6c4977598 100644 --- a/src/yajl/yajl.c +++ b/src/yajl/yajl.c @@ -1,37 +1,22 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include #include +#include #include #define epicsExportSharedSymbols @@ -51,9 +36,6 @@ yajl_status_to_string(yajl_status stat) case yajl_status_client_canceled: statStr = "client canceled parse"; break; - case yajl_status_insufficient_data: - statStr = "eof was met before the parse could complete"; - break; case yajl_status_error: statStr = "parse error"; break; @@ -63,15 +45,12 @@ yajl_status_to_string(yajl_status stat) yajl_handle yajl_alloc(const yajl_callbacks * callbacks, - const yajl_parser_config * config, - const yajl_alloc_funcs * afs, + yajl_alloc_funcs * afs, void * ctx) { - unsigned int allowComments = 0; - unsigned int validateUTF8 = 0; yajl_handle hand = NULL; yajl_alloc_funcs afsBuffer; - + /* first order of business is to set up memory allocation routines */ if (afs != NULL) { if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) @@ -84,65 +63,108 @@ yajl_alloc(const yajl_callbacks * callbacks, } hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t)); + if (hand == NULL) { + return NULL; + } /* copy in pointers to allocation routines */ memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); - if (config != NULL) { - allowComments = config->allowComments; - validateUTF8 = config->checkUTF8; - } - hand->callbacks = callbacks; hand->ctx = ctx; - hand->lexer = yajl_lex_alloc(&(hand->alloc), allowComments, validateUTF8); + hand->lexer = NULL; hand->bytesConsumed = 0; hand->decodeBuf = yajl_buf_alloc(&(hand->alloc)); + hand->flags = 0; yajl_bs_init(hand->stateStack, &(hand->alloc)); - - yajl_bs_push(hand->stateStack, yajl_state_start); + yajl_bs_push(hand->stateStack, yajl_state_start); return hand; } +int +yajl_config(yajl_handle h, yajl_option opt, ...) +{ + int rv = 1; + va_list ap; + va_start(ap, opt); + + switch(opt) { + case yajl_allow_comments: + case yajl_dont_validate_strings: + case yajl_allow_trailing_garbage: + case yajl_allow_multiple_values: + case yajl_allow_partial_values: + if (va_arg(ap, int)) h->flags |= opt; + else h->flags &= ~opt; + break; + default: + rv = 0; + } + va_end(ap); + + return rv; +} + void yajl_free(yajl_handle handle) { yajl_bs_free(handle->stateStack); yajl_buf_free(handle->decodeBuf); - yajl_lex_free(handle->lexer); + if (handle->lexer) { + yajl_lex_free(handle->lexer); + handle->lexer = NULL; + } YA_FREE(&(handle->alloc), handle); } yajl_status yajl_parse(yajl_handle hand, const unsigned char * jsonText, - unsigned int jsonTextLen) + size_t jsonTextLen) { yajl_status status; + + /* lazy allocation of the lexer */ + if (hand->lexer == NULL) { + hand->lexer = yajl_lex_alloc(&(hand->alloc), + hand->flags & yajl_allow_comments, + !(hand->flags & yajl_dont_validate_strings)); + } + if (hand->lexer == NULL) { + return yajl_status_error; + } + status = yajl_do_parse(hand, jsonText, jsonTextLen); return status; } + yajl_status -yajl_parse_complete(yajl_handle hand) +yajl_complete_parse(yajl_handle hand) { - /* The particular case we want to handle is a trailing number. - * Further input consisting of digits could cause our interpretation - * of the number to change (buffered "1" but "2" comes in). - * A very simple approach to this is to inject whitespace to terminate - * any number in the lex buffer. - */ - return yajl_parse(hand, (const unsigned char *)" ", 1); + /* The lexer is lazy allocated in the first call to parse. if parse is + * never called, then no data was provided to parse at all. This is a + * "premature EOF" error unless yajl_allow_partial_values is specified. + * allocating the lexer now is the simplest possible way to handle this + * case while preserving all the other semantics of the parser + * (multiple values, partial values, etc). */ + if (hand->lexer == NULL) { + hand->lexer = yajl_lex_alloc(&(hand->alloc), + hand->flags & yajl_allow_comments, + !(hand->flags & yajl_dont_validate_strings)); + } + + return yajl_do_finish(hand); } unsigned char * yajl_get_error(yajl_handle hand, int verbose, - const unsigned char * jsonText, unsigned int jsonTextLen) + const unsigned char * jsonText, size_t jsonTextLen) { return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose); } -unsigned int +size_t yajl_get_bytes_consumed(yajl_handle hand) { if (!hand) return 0; diff --git a/src/yajl/yajl_alloc.c b/src/yajl/yajl_alloc.c index 2f6e5650c..5b2601685 100644 --- a/src/yajl/yajl_alloc.c +++ b/src/yajl/yajl_alloc.c @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ /** * \file yajl_alloc.h @@ -41,13 +25,13 @@ #define epicsExportSharedSymbols #include "yajl_alloc.h" -static void * yajl_internal_malloc(void *ctx, unsigned int sz) +static void * yajl_internal_malloc(void *ctx, size_t sz) { return malloc(sz); } static void * yajl_internal_realloc(void *ctx, void * previous, - unsigned int sz) + size_t sz) { return realloc(previous, sz); } diff --git a/src/yajl/yajl_alloc.h b/src/yajl/yajl_alloc.h index 3935eef58..471f76f66 100644 --- a/src/yajl/yajl_alloc.h +++ b/src/yajl/yajl_alloc.h @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ /** * \file yajl_alloc.h diff --git a/src/yajl/yajl_buf.c b/src/yajl/yajl_buf.c index 132633c9a..0f9c28046 100644 --- a/src/yajl/yajl_buf.c +++ b/src/yajl/yajl_buf.c @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include #include @@ -40,16 +24,16 @@ #define YAJL_BUF_INIT_SIZE 2048 struct yajl_buf_t { - unsigned int len; - unsigned int used; + size_t len; + size_t used; unsigned char * data; yajl_alloc_funcs * alloc; }; static -void yajl_buf_ensure_available(yajl_buf buf, unsigned int want) +void yajl_buf_ensure_available(yajl_buf buf, size_t want) { - unsigned int need; + size_t need; assert(buf != NULL); @@ -73,6 +57,10 @@ void yajl_buf_ensure_available(yajl_buf buf, unsigned int want) yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc) { yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t)); + if (b == NULL) { + return NULL; + } + memset((void *) b, 0, sizeof(struct yajl_buf_t)); b->alloc = alloc; return b; @@ -85,7 +73,7 @@ void yajl_buf_free(yajl_buf buf) YA_FREE(buf->alloc, buf); } -void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len) +void yajl_buf_append(yajl_buf buf, const void * data, size_t len) { yajl_buf_ensure_available(buf, len); if (len > 0) { @@ -107,13 +95,13 @@ const unsigned char * yajl_buf_data(yajl_buf buf) return buf->data; } -unsigned int yajl_buf_len(yajl_buf buf) +size_t yajl_buf_len(yajl_buf buf) { return buf->used; } void -yajl_buf_truncate(yajl_buf buf, unsigned int len) +yajl_buf_truncate(yajl_buf buf, size_t len) { assert(len <= buf->used); buf->used = len; diff --git a/src/yajl/yajl_buf.h b/src/yajl/yajl_buf.h index a6dcbe9a5..0ae73aa35 100644 --- a/src/yajl/yajl_buf.h +++ b/src/yajl/yajl_buf.h @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #ifndef __YAJL_BUF_H__ #define __YAJL_BUF_H__ @@ -56,7 +40,7 @@ yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc); void yajl_buf_free(yajl_buf buf); /* append a number of bytes to the buffer */ -void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len); +void yajl_buf_append(yajl_buf buf, const void * data, size_t len); /* empty the buffer */ void yajl_buf_clear(yajl_buf buf); @@ -65,9 +49,9 @@ void yajl_buf_clear(yajl_buf buf); const unsigned char * yajl_buf_data(yajl_buf buf); /* get the length of the buffer */ -unsigned int yajl_buf_len(yajl_buf buf); +size_t yajl_buf_len(yajl_buf buf); /* truncate the buffer */ -void yajl_buf_truncate(yajl_buf buf, unsigned int len); +void yajl_buf_truncate(yajl_buf buf, size_t len); #endif diff --git a/src/yajl/yajl_bytestack.h b/src/yajl/yajl_bytestack.h index 3b49d17f9..d75e456b4 100644 --- a/src/yajl/yajl_bytestack.h +++ b/src/yajl/yajl_bytestack.h @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ /* * A header only implementation of a simple stack of bytes, used in YAJL @@ -45,8 +29,8 @@ typedef struct yajl_bytestack_t { unsigned char * stack; - unsigned int size; - unsigned int used; + size_t size; + size_t used; yajl_alloc_funcs * yaf; } yajl_bytestack; @@ -61,7 +45,7 @@ typedef struct yajl_bytestack_t /* initialize a bytestack */ #define yajl_bs_free(obs) \ - if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack); + if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack); #define yajl_bs_current(obs) \ (assert((obs).used > 0), (obs).stack[(obs).used - 1]) @@ -74,12 +58,12 @@ typedef struct yajl_bytestack_t } \ (obs).stack[((obs).used)++] = (byte); \ } - + /* removes the top item of the stack, returns nothing */ #define yajl_bs_pop(obs) { ((obs).used)--; } #define yajl_bs_set(obs, byte) \ - (obs).stack[((obs).used) - 1] = (byte); - + (obs).stack[((obs).used) - 1] = (byte); + #endif diff --git a/src/yajl/yajl_common.h b/src/yajl/yajl_common.h index b9badbf1e..4bc63eead 100644 --- a/src/yajl/yajl_common.h +++ b/src/yajl/yajl_common.h @@ -1,58 +1,59 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #ifndef __YAJL_COMMON_H__ #define __YAJL_COMMON_H__ +#include #include +#include + #ifdef __cplusplus extern "C" { #endif +/** YAJL API history in brief + * + * Originally macro not defined + * YAJL 1.0.12 + * Bundled with EPICS Base 3.15.0.1 + * + * YAJL 2.1.0 + * Changes argument type for yajl_integer() from 'int' to 'long long' + * Changes argument type for yajl_string() and yajl_map_key() from 'unsigned' to 'size_t' + * Replacement of struct yajl_parser_config with yajl_config() + * Replacement of yajl_parse_complete() with yajl_complete_parse() + */ +#define EPICS_YAJL_VERSION VERSION_INT(2,1,0,0) + #define YAJL_MAX_DEPTH 128 #define YAJL_API epicsShareFunc /** pointer to a malloc function, supporting client overriding memory * allocation routines */ -typedef void * (*yajl_malloc_func)(void *ctx, unsigned int sz); +typedef void * (*yajl_malloc_func)(void *ctx, size_t sz); /** pointer to a free function, supporting client overriding memory * allocation routines */ typedef void (*yajl_free_func)(void *ctx, void * ptr); /** pointer to a realloc function which can resize an allocation. */ -typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, unsigned int sz); +typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, size_t sz); /** A structure which can be passed to yajl_*_alloc routines to allow the * client to specify memory allocation functions to be used. */ @@ -71,6 +72,6 @@ typedef struct #ifdef __cplusplus } -#endif +#endif #endif diff --git a/src/yajl/yajl_encode.c b/src/yajl/yajl_encode.c index d6f9dc0fe..980021ee5 100644 --- a/src/yajl/yajl_encode.c +++ b/src/yajl/yajl_encode.c @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include #include @@ -46,20 +30,14 @@ static void CharToHex(unsigned char c, char * hexBuf) } void -yajl_string_encode(yajl_buf buf, const unsigned char * str, - unsigned int len) +yajl_string_encode(const yajl_print_t print, + void * ctx, + const unsigned char * str, + size_t len, + int escape_solidus) { - yajl_string_encode2((const yajl_print_t) &yajl_buf_append, buf, str, len); -} - -void -yajl_string_encode2(const yajl_print_t print, - void * ctx, - const unsigned char * str, - unsigned int len) -{ - unsigned int beg = 0; - unsigned int end = 0; + size_t beg = 0; + size_t end = 0; char hexBuf[7]; hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0'; hexBuf[6] = 0; @@ -70,7 +48,12 @@ yajl_string_encode2(const yajl_print_t print, case '\r': escaped = "\\r"; break; case '\n': escaped = "\\n"; break; case '\\': escaped = "\\\\"; break; - /* case '/': escaped = "\\/"; break; */ + /* it is not required to escape a solidus in JSON: + * read sec. 2.5: http://www.ietf.org/rfc/rfc4627.txt + * specifically, this production from the grammar: + * unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + */ + case '/': if (escape_solidus) escaped = "\\/"; break; case '"': escaped = "\\\""; break; case '\f': escaped = "\\f"; break; case '\b': escaped = "\\b"; break; @@ -132,10 +115,10 @@ static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf) } void yajl_string_decode(yajl_buf buf, const unsigned char * str, - unsigned int len) + size_t len) { - unsigned int beg = 0; - unsigned int end = 0; + size_t beg = 0; + size_t end = 0; while (end < len) { if (str[end] == '\\') { @@ -194,3 +177,45 @@ void yajl_string_decode(yajl_buf buf, const unsigned char * str, } yajl_buf_append(buf, str + beg, end - beg); } + +#define ADV_PTR s++; if (!(len--)) return 0; + +int yajl_string_validate_utf8(const unsigned char * s, size_t len) +{ + if (!len) return 1; + if (!s) return 0; + + while (len--) { + /* single byte */ + if (*s <= 0x7f) { + /* noop */ + } + /* two byte */ + else if ((*s >> 5) == 0x6) { + ADV_PTR; + if (!((*s >> 6) == 0x2)) return 0; + } + /* three byte */ + else if ((*s >> 4) == 0x0e) { + ADV_PTR; + if (!((*s >> 6) == 0x2)) return 0; + ADV_PTR; + if (!((*s >> 6) == 0x2)) return 0; + } + /* four byte */ + else if ((*s >> 3) == 0x1e) { + ADV_PTR; + if (!((*s >> 6) == 0x2)) return 0; + ADV_PTR; + if (!((*s >> 6) == 0x2)) return 0; + ADV_PTR; + if (!((*s >> 6) == 0x2)) return 0; + } else { + return 0; + } + + s++; + } + + return 1; +} diff --git a/src/yajl/yajl_encode.h b/src/yajl/yajl_encode.h index 3e3b0923d..28d63958c 100644 --- a/src/yajl/yajl_encode.h +++ b/src/yajl/yajl_encode.h @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #ifndef __YAJL_ENCODE_H__ #define __YAJL_ENCODE_H__ @@ -36,15 +20,15 @@ #include "yajl_buf.h" #include "yajl_gen.h" -void yajl_string_encode2(const yajl_print_t printer, - void * ctx, - const unsigned char * str, - unsigned int length); - -void yajl_string_encode(yajl_buf buf, const unsigned char * str, - unsigned int length); +void yajl_string_encode(const yajl_print_t printer, + void * ctx, + const unsigned char * str, + size_t length, + int escape_solidus); void yajl_string_decode(yajl_buf buf, const unsigned char * str, - unsigned int length); + size_t length); + +int yajl_string_validate_utf8(const unsigned char * s, size_t len); #endif diff --git a/src/yajl/yajl_gen.c b/src/yajl/yajl_gen.c index 8d93e2726..7f669247d 100644 --- a/src/yajl/yajl_gen.c +++ b/src/yajl/yajl_gen.c @@ -1,38 +1,23 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include #include #include +#include #define epicsExportSharedSymbols #include "epicsMath.h" @@ -51,10 +36,10 @@ typedef enum { yajl_gen_error } yajl_gen_state; -struct yajl_gen_t +struct yajl_gen_t { + unsigned int flags; unsigned int depth; - unsigned int pretty; const char * indentString; yajl_gen_state state[YAJL_MAX_DEPTH]; yajl_print_t print; @@ -63,18 +48,54 @@ struct yajl_gen_t yajl_alloc_funcs alloc; }; -yajl_gen -yajl_gen_alloc(const yajl_gen_config * config, - const yajl_alloc_funcs * afs) +int +yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...) { - return yajl_gen_alloc2(NULL, config, afs, NULL); + int rv = 1; + va_list ap; + va_start(ap, opt); + + switch(opt) { + case yajl_gen_beautify: + case yajl_gen_validate_utf8: + if (va_arg(ap, int)) g->flags |= opt; + else g->flags &= ~opt; + break; + case yajl_gen_indent_string: { + const char *indent = va_arg(ap, const char *); + g->indentString = indent; + for (; *indent; indent++) { + if (*indent != '\n' + && *indent != '\v' + && *indent != '\f' + && *indent != '\t' + && *indent != '\r' + && *indent != ' ') + { + g->indentString = NULL; + rv = 0; + } + } + break; + } + case yajl_gen_print_callback: + yajl_buf_free(g->ctx); + g->print = va_arg(ap, const yajl_print_t); + g->ctx = va_arg(ap, void *); + break; + default: + rv = 0; + } + + va_end(ap); + + return rv; } + + yajl_gen -yajl_gen_alloc2(const yajl_print_t callback, - const yajl_gen_config * config, - const yajl_alloc_funcs * afs, - void * ctx) +yajl_gen_alloc(const yajl_alloc_funcs * afs) { yajl_gen g = NULL; yajl_alloc_funcs afsBuffer; @@ -97,35 +118,9 @@ yajl_gen_alloc2(const yajl_print_t callback, /* copy in pointers to allocation routines */ memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); - if (config) { - const char *indent = config->indentString; - g->pretty = config->beautify; - g->indentString = config->indentString; - if (indent) { - for (; *indent; indent++) { - if (*indent != '\n' - && *indent != '\v' - && *indent != '\f' - && *indent != '\t' - && *indent != '\r' - && *indent != ' ') { - g->indentString = NULL; - break; - } - } - } - if (!g->indentString) { - g->indentString = " "; - } - } - - if (callback) { - g->print = callback; - g->ctx = ctx; - } else { - g->print = (yajl_print_t)&yajl_buf_append; - g->ctx = yajl_buf_alloc(&(g->alloc)); - } + g->print = (yajl_print_t)&yajl_buf_append; + g->ctx = yajl_buf_alloc(&(g->alloc)); + g->indentString = " "; return g; } @@ -141,14 +136,14 @@ yajl_gen_free(yajl_gen g) if (g->state[g->depth] == yajl_gen_map_key || \ g->state[g->depth] == yajl_gen_in_array) { \ g->print(g->ctx, ",", 1); \ - if (g->pretty) g->print(g->ctx, "\n", 1); \ + if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); \ } else if (g->state[g->depth] == yajl_gen_map_val) { \ g->print(g->ctx, ":", 1); \ - if (g->pretty) g->print(g->ctx, " ", 1); \ + if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, " ", 1); \ } #define INSERT_WHITESPACE \ - if (g->pretty) { \ + if ((g->flags & yajl_gen_beautify)) { \ if (g->state[g->depth] != yajl_gen_map_val) { \ unsigned int _i; \ for (_i=0;_idepth;_i++) \ @@ -199,15 +194,15 @@ yajl_gen_free(yajl_gen g) } \ #define FINAL_NEWLINE \ - if (g->pretty && g->state[g->depth] == yajl_gen_complete) \ - g->print(g->ctx, "\n", 1); - + if ((g->flags & yajl_gen_beautify) && g->state[g->depth] == yajl_gen_complete) \ + g->print(g->ctx, "\n", 1); + yajl_gen_status -yajl_gen_integer(yajl_gen g, long int number) +yajl_gen_integer(yajl_gen g, long long int number) { char i[32]; ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; - sprintf(i, "%ld", number); + sprintf(i, "%lld", number); g->print(g->ctx, i, (unsigned int)strlen(i)); APPENDED_ATOM; FINAL_NEWLINE; @@ -229,7 +224,7 @@ yajl_gen_double(yajl_gen g, double number) } yajl_gen_status -yajl_gen_number(yajl_gen g, const char * s, unsigned int l) +yajl_gen_number(yajl_gen g, const char * s, size_t l) { ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; g->print(g->ctx, s, l); @@ -240,11 +235,19 @@ yajl_gen_number(yajl_gen g, const char * s, unsigned int l) yajl_gen_status yajl_gen_string(yajl_gen g, const unsigned char * str, - unsigned int len) + size_t len) { + // if validation is enabled, check that the string is valid utf8 + // XXX: This checking could be done a little faster, in the same pass as + // the string encoding + if (g->flags & yajl_gen_validate_utf8) { + if (!yajl_string_validate_utf8(str, len)) { + return yajl_gen_invalid_string; + } + } ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE; g->print(g->ctx, "\"", 1); - yajl_string_encode2(g->print, g->ctx, str, len); + yajl_string_encode(g->print, g->ctx, str, len, g->flags & yajl_gen_escape_solidus); g->print(g->ctx, "\"", 1); APPENDED_ATOM; FINAL_NEWLINE; @@ -281,7 +284,7 @@ yajl_gen_map_open(yajl_gen g) g->state[g->depth] = yajl_gen_map_start; g->print(g->ctx, "{", 1); - if (g->pretty) g->print(g->ctx, "\n", 1); + if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } @@ -292,7 +295,7 @@ yajl_gen_map_close(yajl_gen g) ENSURE_VALID_STATE; DECREMENT_DEPTH; - if (g->pretty) g->print(g->ctx, "\n", 1); + if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); APPENDED_ATOM; INSERT_WHITESPACE; g->print(g->ctx, "}", 1); @@ -307,7 +310,7 @@ yajl_gen_array_open(yajl_gen g) INCREMENT_DEPTH; g->state[g->depth] = yajl_gen_array_start; g->print(g->ctx, "[", 1); - if (g->pretty) g->print(g->ctx, "\n", 1); + if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); FINAL_NEWLINE; return yajl_gen_status_ok; } @@ -317,7 +320,7 @@ yajl_gen_array_close(yajl_gen g) { ENSURE_VALID_STATE; DECREMENT_DEPTH; - if (g->pretty) g->print(g->ctx, "\n", 1); + if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); APPENDED_ATOM; INSERT_WHITESPACE; g->print(g->ctx, "]", 1); @@ -327,7 +330,7 @@ yajl_gen_array_close(yajl_gen g) yajl_gen_status yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf, - unsigned int * len) + size_t * len) { if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf; *buf = yajl_buf_data((yajl_buf)g->ctx); diff --git a/src/yajl/yajl_gen.h b/src/yajl/yajl_gen.h index 34b147596..3ea05e555 100644 --- a/src/yajl/yajl_gen.h +++ b/src/yajl/yajl_gen.h @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ /** * \file yajl_gen.h @@ -38,11 +22,11 @@ #ifndef __YAJL_GEN_H__ #define __YAJL_GEN_H__ -#include +#include "yajl_common.h" #ifdef __cplusplus extern "C" { -#endif +#endif /** generator status codes */ typedef enum { /** no error */ @@ -63,7 +47,11 @@ extern "C" { yajl_gen_invalid_number, /** A print callback was passed in, so there is no internal * buffer to get from */ - yajl_gen_no_buf + yajl_gen_no_buf, + /** returned from yajl_gen_string() when the yajl_gen_validate_utf8 + * option is enabled and an invalid was passed by client code. + */ + yajl_gen_invalid_string } yajl_gen_status; /** an opaque handle to a generator */ @@ -72,21 +60,52 @@ extern "C" { /** a callback used for "printing" the results. */ typedef void (*yajl_print_t)(void * ctx, const char * str, - unsigned int len); + size_t len); - /** configuration structure for the generator */ - typedef struct { + /** configuration parameters for the parser, these may be passed to + * yajl_gen_config() along with option specific argument(s). In general, + * all configuration parameters default to *off*. */ + typedef enum { /** generate indented (beautiful) output */ - unsigned int beautify; - /** an opportunity to define an indent string. such as \\t or - * some number of spaces. default is four spaces ' '. This - * member is only relevant when beautify is true */ - const char * indentString; - } yajl_gen_config; + yajl_gen_beautify = 0x01, + /** + * Set an indent string which is used when yajl_gen_beautify + * is enabled. Maybe something like \\t or some number of + * spaces. The default is four spaces ' '. + */ + yajl_gen_indent_string = 0x02, + /** + * Set a function and context argument that should be used to + * output generated json. the function should conform to the + * yajl_print_t prototype while the context argument is a + * void * of your choosing. + * + * example: + * yajl_gen_config(g, yajl_gen_print_callback, myFunc, myVoidPtr); + */ + yajl_gen_print_callback = 0x04, + /** + * Normally the generator does not validate that strings you + * pass to it via yajl_gen_string() are valid UTF8. Enabling + * this option will cause it to do so. + */ + yajl_gen_validate_utf8 = 0x08, + /** + * the forward solidus (slash or '/' in human) is not required to be + * escaped in json text. By default, YAJL will not escape it in the + * iterest of saving bytes. Setting this flag will cause YAJL to + * always escape '/' in generated JSON strings. + */ + yajl_gen_escape_solidus = 0x10 + } yajl_gen_option; + + /** allow the modification of generator options subsequent to handle + * allocation (via yajl_alloc) + * \returns zero in case of errors, non-zero otherwise + */ + YAJL_API int yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...); /** allocate a generator handle - * \param config a pointer to a structure containing parameters which - * configure the behavior of the json generator * \param allocFuncs an optional pointer to a structure which allows * the client to overide the memory allocation * used by yajl. May be NULL, in which case @@ -94,47 +113,24 @@ extern "C" { * * \returns an allocated handle on success, NULL on failure (bad params) */ - YAJL_API yajl_gen yajl_gen_alloc(const yajl_gen_config * config, - const yajl_alloc_funcs * allocFuncs); + YAJL_API yajl_gen yajl_gen_alloc(const yajl_alloc_funcs * allocFuncs); - /** allocate a generator handle that will print to the specified - * callback rather than storing the results in an internal buffer. - * \param callback a pointer to a printer function. May be NULL - * in which case, the results will be store in an - * internal buffer. - * \param config a pointer to a structure containing parameters - * which configure the behavior of the json - * generator. - * \param allocFuncs an optional pointer to a structure which allows - * the client to overide the memory allocation - * used by yajl. May be NULL, in which case - * malloc/free/realloc will be used. - * \param ctx a context pointer that will be passed to the - * printer callback. - * - * \returns an allocated handle on success, NULL on failure (bad params) - */ - YAJL_API yajl_gen yajl_gen_alloc2(const yajl_print_t callback, - const yajl_gen_config * config, - const yajl_alloc_funcs * allocFuncs, - void * ctx); - - /** free a generator handle */ + /** free a generator handle */ YAJL_API void yajl_gen_free(yajl_gen handle); - YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long int number); + YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long long int number); /** generate a floating point number. number may not be infinity or * NaN, as these have no representation in JSON. In these cases the * generator will return 'yajl_gen_invalid_number' */ YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number); YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand, const char * num, - unsigned int len); + size_t len); YAJL_API yajl_gen_status yajl_gen_string(yajl_gen hand, const unsigned char * str, - unsigned int len); + size_t len); YAJL_API yajl_gen_status yajl_gen_null(yajl_gen hand); - YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean); + YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean); YAJL_API yajl_gen_status yajl_gen_map_open(yajl_gen hand); YAJL_API yajl_gen_status yajl_gen_map_close(yajl_gen hand); YAJL_API yajl_gen_status yajl_gen_array_open(yajl_gen hand); @@ -145,7 +141,7 @@ extern "C" { * buffer. This allows stream generation. */ YAJL_API yajl_gen_status yajl_gen_get_buf(yajl_gen hand, const unsigned char ** buf, - unsigned int * len); + size_t * len); /** clear yajl's output buffer, but maintain all internal generation * state. This function will not "reset" the generator state, and is diff --git a/src/yajl/yajl_lex.c b/src/yajl/yajl_lex.c index 3abd21698..0159cfa55 100644 --- a/src/yajl/yajl_lex.c +++ b/src/yajl/yajl_lex.c @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include #include @@ -84,8 +68,8 @@ tokToStr(yajl_tok tok) struct yajl_lexer_t { /* the overal line and char offset into the data */ - unsigned int lineOff; - unsigned int charOff; + size_t lineOff; + size_t charOff; /* error */ yajl_lex_error error; @@ -96,7 +80,7 @@ struct yajl_lexer_t { /* in the case where we have data in the lexBuf, bufOff holds * the current offset into the lexBuf. */ - unsigned int bufOff; + size_t bufOff; /* are we using the lex buf? */ unsigned int bufInUse; @@ -122,6 +106,10 @@ yajl_lex_alloc(yajl_alloc_funcs * alloc, unsigned int allowComments, unsigned int validateUTF8) { yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t)); + if (lxr == NULL) { + return NULL; + } + memset((void *) lxr, 0, sizeof(struct yajl_lexer_t)); lxr->buf = yajl_buf_alloc(alloc); lxr->allowComments = allowComments; @@ -139,15 +127,19 @@ yajl_lex_free(yajl_lexer lxr) } /* a lookup table which lets us quickly determine three things: - * VEC - valid escaped conrol char + * VEC - valid escaped control char + * note. the solidus '/' may be escaped or not. * IJC - invalid json char * VHC - valid hex char - * note. the solidus '/' may be escaped or not. - * note. the + * NFP - needs further processing (from a string scanning perspective) + * NUC - needs utf8 checking when enabled (from a string scanning perspective) */ -#define VEC 1 -#define IJC 2 -#define VHC 4 +#define VEC 0x01 +#define IJC 0x02 +#define VHC 0x04 +#define NFP 0x08 +#define NUC 0x10 + static const char charLookupTable[256] = { /*00*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , @@ -155,7 +147,7 @@ static const char charLookupTable[256] = /*10*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , /*18*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , -/*20*/ 0 , 0 , VEC|IJC, 0 , 0 , 0 , 0 , 0 , +/*20*/ 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 , 0 , 0 , /*28*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , VEC , /*30*/ VHC , VHC , VHC , VHC , VHC , VHC , VHC , VHC , /*38*/ VHC , VHC , 0 , 0 , 0 , 0 , 0 , 0 , @@ -163,33 +155,32 @@ static const char charLookupTable[256] = /*40*/ 0 , VHC , VHC , VHC , VHC , VHC , VHC , 0 , /*48*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , /*50*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , -/*58*/ 0 , 0 , 0 , 0 , VEC|IJC, 0 , 0 , 0 , +/*58*/ 0 , 0 , 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 , /*60*/ 0 , VHC , VEC|VHC, VHC , VHC , VHC , VEC|VHC, 0 , /*68*/ 0 , 0 , 0 , 0 , 0 , 0 , VEC , 0 , /*70*/ 0 , 0 , VEC , 0 , VEC , 0 , 0 , 0 , /*78*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , -/* include these so we don't have to always check the range of the char */ - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC , + NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC }; /** process a variable length utf8 encoded codepoint. @@ -207,7 +198,7 @@ static const char charLookupTable[256] = static yajl_tok yajl_lex_utf8_char(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset, + size_t jsonTextLen, size_t * offset, unsigned char curChar) { if (curChar <= 0x7f) { @@ -261,17 +252,56 @@ if (*offset >= jsonTextLen) { \ goto finish_string_lex; \ } +/** scan a string for interesting characters that might need further + * review. return the number of chars that are uninteresting and can + * be skipped. + * (lth) hi world, any thoughts on how to make this routine faster? */ +static size_t +yajl_string_scan(const unsigned char * buf, size_t len, int utf8check) +{ + unsigned char mask = IJC|NFP|(utf8check ? NUC : 0); + size_t skip = 0; + while (skip < len && !(charLookupTable[*buf] & mask)) + { + skip++; + buf++; + } + return skip; +} + static yajl_tok yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset) + size_t jsonTextLen, size_t * offset) { yajl_tok tok = yajl_tok_error; int hasEscapes = 0; for (;;) { - unsigned char curChar; + unsigned char curChar; - STR_CHECK_EOF; + /* now jump into a faster scanning routine to skip as much + * of the buffers as possible */ + { + const unsigned char * p; + size_t len; + + if ((lexer->bufInUse && yajl_buf_len(lexer->buf) && + lexer->bufOff < yajl_buf_len(lexer->buf))) + { + p = ((const unsigned char *) yajl_buf_data(lexer->buf) + + (lexer->bufOff)); + len = yajl_buf_len(lexer->buf) - lexer->bufOff; + lexer->bufOff += yajl_string_scan(p, len, lexer->validateUTF8); + } + else if (*offset < jsonTextLen) + { + p = jsonText + *offset; + len = jsonTextLen - *offset; + *offset += yajl_string_scan(p, len, lexer->validateUTF8); + } + } + + STR_CHECK_EOF; curChar = readChar(lexer, jsonText, offset); @@ -344,7 +374,7 @@ yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText, static yajl_tok yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset) + size_t jsonTextLen, size_t * offset) { /** XXX: numbers are the only entities in json that we must lex * _beyond_ in order to know that they are complete. There @@ -431,7 +461,7 @@ yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText, static yajl_tok yajl_lex_comment(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset) + size_t jsonTextLen, size_t * offset) { unsigned char c; @@ -472,12 +502,12 @@ yajl_lex_comment(yajl_lexer lexer, const unsigned char * jsonText, yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset, - const unsigned char ** outBuf, unsigned int * outLen) + size_t jsonTextLen, size_t * offset, + const unsigned char ** outBuf, size_t * outLen) { yajl_tok tok = yajl_tok_error; unsigned char c; - unsigned int startOffset = *offset; + size_t startOffset = *offset; *outBuf = NULL; *outLen = 0; @@ -494,17 +524,17 @@ yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, switch (c) { case '{': - tok = yajl_tok_left_bracket; - goto lexed; - case '}': - tok = yajl_tok_right_bracket; - goto lexed; - case '[': tok = yajl_tok_left_brace; goto lexed; - case ']': + case '}': tok = yajl_tok_right_brace; goto lexed; + case '[': + tok = yajl_tok_left_bracket; + goto lexed; + case ']': + tok = yajl_tok_right_bracket; + goto lexed; case ',': tok = yajl_tok_comma; goto lexed; @@ -707,23 +737,23 @@ yajl_lex_get_error(yajl_lexer lexer) return lexer->error; } -unsigned int yajl_lex_current_line(yajl_lexer lexer) +size_t yajl_lex_current_line(yajl_lexer lexer) { return lexer->lineOff; } -unsigned int yajl_lex_current_char(yajl_lexer lexer) +size_t yajl_lex_current_char(yajl_lexer lexer) { return lexer->charOff; } yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int offset) + size_t jsonTextLen, size_t offset) { const unsigned char * outBuf; - unsigned int outLen; - unsigned int bufLen = yajl_buf_len(lexer->buf); - unsigned int bufOff = lexer->bufOff; + size_t outLen; + size_t bufLen = yajl_buf_len(lexer->buf); + size_t bufOff = lexer->bufOff; unsigned int bufInUse = lexer->bufInUse; yajl_tok tok; diff --git a/src/yajl/yajl_lex.h b/src/yajl/yajl_lex.h index 559e54dba..40c434427 100644 --- a/src/yajl/yajl_lex.h +++ b/src/yajl/yajl_lex.h @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #ifndef __YAJL_LEX_H__ #define __YAJL_LEX_H__ @@ -92,12 +76,12 @@ n * error messages. * size to get adequate performance. */ yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int * offset, - const unsigned char ** outBuf, unsigned int * outLen); + size_t jsonTextLen, size_t * offset, + const unsigned char ** outBuf, size_t * outLen); /** have a peek at the next token, but don't move the lexer forward */ yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, - unsigned int jsonTextLen, unsigned int offset); + size_t jsonTextLen, size_t offset); typedef enum { @@ -121,13 +105,13 @@ const char * yajl_lex_error_to_string(yajl_lex_error error); yajl_lex_error yajl_lex_get_error(yajl_lexer lexer); /** get the current offset into the most recently lexed json string. */ -unsigned int yajl_lex_current_offset(yajl_lexer lexer); +size_t yajl_lex_current_offset(yajl_lexer lexer); /** get the number of lines lexed by this lexer instance */ -unsigned int yajl_lex_current_line(yajl_lexer lexer); +size_t yajl_lex_current_line(yajl_lexer lexer); /** get the number of chars lexed by this lexer instance since the last * \n or \r */ -unsigned int yajl_lex_current_char(yajl_lexer lexer); +size_t yajl_lex_current_char(yajl_lexer lexer); #endif diff --git a/src/yajl/yajl_parse.h b/src/yajl/yajl_parse.h index a70a8fd56..f113c7cf4 100644 --- a/src/yajl/yajl_parse.h +++ b/src/yajl/yajl_parse.h @@ -1,58 +1,38 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ /** * \file yajl_parse.h - * Interface to YAJL's JSON parsing facilities. + * Interface to YAJL's JSON stream parsing facilities. */ #ifndef __YAJL_PARSE_H__ #define __YAJL_PARSE_H__ -#include +#include "yajl_common.h" #ifdef __cplusplus extern "C" { -#endif +#endif /** error codes returned from this interface */ typedef enum { /** no error was encountered */ yajl_status_ok, /** a client callback returned zero, stopping the parse */ yajl_status_client_canceled, - /** The parse cannot yet complete because more json input text - * is required, call yajl_parse with the next buffer of input text. - * (pertinent only when stream parsing) */ - yajl_status_insufficient_data, /** An error occured during the parse. Call yajl_get_error for * more information about the encountered error */ yajl_status_error @@ -75,64 +55,115 @@ extern "C" { * continue. If zero, the parse will be canceled and * yajl_status_client_canceled will be returned from the parse. * - * Note about handling of numbers: - * yajl will only convert numbers that can be represented in a double - * or a long int. All other numbers will be passed to the client - * in string form using the yajl_number callback. Furthermore, if - * yajl_number is not NULL, it will always be used to return numbers, - * that is yajl_integer and yajl_double will be ignored. If - * yajl_number is NULL but one of yajl_integer or yajl_double are - * defined, parsing of a number larger than is representable - * in a double or long int will result in a parse error. + * \attention { + * A note about the handling of numbers: + * + * yajl will only convert numbers that can be represented in a + * double or a 64 bit (long long) int. All other numbers will + * be passed to the client in string form using the yajl_number + * callback. Furthermore, if yajl_number is not NULL, it will + * always be used to return numbers, that is yajl_integer and + * yajl_double will be ignored. If yajl_number is NULL but one + * of yajl_integer or yajl_double are defined, parsing of a + * number larger than is representable in a double or 64 bit + * integer will result in a parse error. + * } */ typedef struct { int (* yajl_null)(void * ctx); int (* yajl_boolean)(void * ctx, int boolVal); - int (* yajl_integer)(void * ctx, long integerVal); + int (* yajl_integer)(void * ctx, long long integerVal); int (* yajl_double)(void * ctx, double doubleVal); /** A callback which passes the string representation of the number * back to the client. Will be used for all numbers when present */ int (* yajl_number)(void * ctx, const char * numberVal, - unsigned int numberLen); + size_t numberLen); /** strings are returned as pointers into the JSON text when, * possible, as a result, they are _not_ null padded */ int (* yajl_string)(void * ctx, const unsigned char * stringVal, - unsigned int stringLen); + size_t stringLen); int (* yajl_start_map)(void * ctx); int (* yajl_map_key)(void * ctx, const unsigned char * key, - unsigned int stringLen); - int (* yajl_end_map)(void * ctx); + size_t stringLen); + int (* yajl_end_map)(void * ctx); int (* yajl_start_array)(void * ctx); - int (* yajl_end_array)(void * ctx); + int (* yajl_end_array)(void * ctx); } yajl_callbacks; - - /** configuration structure for the generator */ - typedef struct { - /** if nonzero, javascript style comments will be allowed in - * the json input, both slash star and slash slash */ - unsigned int allowComments; - /** if nonzero, invalid UTF8 strings will cause a parse - * error */ - unsigned int checkUTF8; - } yajl_parser_config; /** allocate a parser handle * \param callbacks a yajl callbacks structure specifying the * functions to call when different JSON entities * are encountered in the input text. May be NULL, * which is only useful for validation. - * \param config configuration parameters for the parse. + * \param afs memory allocation functions, may be NULL for to use + * C runtime library routines (malloc and friends) * \param ctx a context pointer that will be passed to callbacks. */ YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks, - const yajl_parser_config * config, - const yajl_alloc_funcs * allocFuncs, + yajl_alloc_funcs * afs, void * ctx); - /** free a parser handle */ + + /** configuration parameters for the parser, these may be passed to + * yajl_config() along with option specific argument(s). In general, + * all configuration parameters default to *off*. */ + typedef enum { + /** Ignore javascript style comments present in + * JSON input. Non-standard, but rather fun + * arguments: toggled off with integer zero, on otherwise. + * + * example: + * yajl_config(h, yajl_allow_comments, 1); // turn comment support on + */ + yajl_allow_comments = 0x01, + /** + * When set the parser will verify that all strings in JSON input are + * valid UTF8 and will emit a parse error if this is not so. When set, + * this option makes parsing slightly more expensive (~7% depending + * on processor and compiler in use) + * + * example: + * yajl_config(h, yajl_dont_validate_strings, 1); // disable utf8 checking + */ + yajl_dont_validate_strings = 0x02, + /** + * By default, upon calls to yajl_complete_parse(), yajl will + * ensure the entire input text was consumed and will raise an error + * otherwise. Enabling this flag will cause yajl to disable this + * check. This can be useful when parsing json out of a that contains more + * than a single JSON document. + */ + yajl_allow_trailing_garbage = 0x04, + /** + * Allow multiple values to be parsed by a single handle. The + * entire text must be valid JSON, and values can be seperated + * by any kind of whitespace. This flag will change the + * behavior of the parser, and cause it continue parsing after + * a value is parsed, rather than transitioning into a + * complete state. This option can be useful when parsing multiple + * values from an input stream. + */ + yajl_allow_multiple_values = 0x08, + /** + * When yajl_complete_parse() is called the parser will + * check that the top level value was completely consumed. I.E., + * if called whilst in the middle of parsing a value + * yajl will enter an error state (premature EOF). Setting this + * flag suppresses that check and the corresponding error. + */ + yajl_allow_partial_values = 0x10 + } yajl_option; + + /** allow the modification of parser options subsequent to handle + * allocation (via yajl_alloc) + * \returns zero in case of errors, non-zero otherwise + */ + YAJL_API int yajl_config(yajl_handle h, yajl_option opt, ...); + + /** free a parser handle */ YAJL_API void yajl_free(yajl_handle handle); /** Parse some json! @@ -142,7 +173,7 @@ extern "C" { */ YAJL_API yajl_status yajl_parse(yajl_handle hand, const unsigned char * jsonText, - unsigned int jsonTextLength); + size_t jsonTextLength); /** Parse any remaining buffered json. * Since yajl is a stream-based parser, without an explicit end of @@ -153,8 +184,8 @@ extern "C" { * * \param hand - a handle to the json parser allocated with yajl_alloc */ - YAJL_API yajl_status yajl_parse_complete(yajl_handle hand); - + YAJL_API yajl_status yajl_complete_parse(yajl_handle hand); + /** get an error string describing the state of the * parse. * @@ -163,31 +194,31 @@ extern "C" { * the specific char. * * \returns A dynamically allocated string will be returned which should - * be freed with yajl_free_error + * be freed with yajl_free_error */ YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose, const unsigned char * jsonText, - unsigned int jsonTextLength); + size_t jsonTextLength); /** * get the amount of data consumed from the last chunk passed to YAJL. * * In the case of a successful parse this can help you understand if * the entire buffer was consumed (which will allow you to handle - * "junk at end of input". - * + * "junk at end of input"). + * * In the event an error is encountered during parsing, this function * affords the client a way to get the offset into the most recent * chunk where the error occured. 0 will be returned if no error * was encountered. */ - YAJL_API unsigned int yajl_get_bytes_consumed(yajl_handle hand); + YAJL_API size_t yajl_get_bytes_consumed(yajl_handle hand); /** free an error returned from yajl_get_error */ YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str); #ifdef __cplusplus } -#endif +#endif #endif diff --git a/src/yajl/yajl_parser.c b/src/yajl/yajl_parser.c index bbcf80880..7e4da6924 100644 --- a/src/yajl/yajl_parser.c +++ b/src/yajl/yajl_parser.c @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include #include @@ -40,21 +24,55 @@ #include #define epicsExportSharedSymbols +#include "yajl_parse.h" #include "yajl_lex.h" #include "yajl_parser.h" #include "yajl_encode.h" #include "yajl_bytestack.h" +#ifndef LLONG_MAX +#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL +#define LLONG_MIN (-0x7FFFFFFFFFFFFFFFLL - 1) +#endif + +#define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10)) + + /* same semantics as strtol */ +long long +yajl_parse_integer(const unsigned char *number, size_t length) +{ + long long ret = 0; + long sign = 1; + const unsigned char *pos = number; + if (*pos == '-') { pos++; sign = -1; } + if (*pos == '+') { pos++; } + + while (pos < number + length) { + if ( ret > MAX_VALUE_TO_MULTIPLY ) { + errno = ERANGE; + return sign == 1 ? LLONG_MAX : LLONG_MIN; + } + ret *= 10; + if (LLONG_MAX - ret < (*pos - '0')) { + errno = ERANGE; + return sign == 1 ? LLONG_MAX : LLONG_MIN; + } + ret += (*pos++ - '0'); + } + + return sign * ret; +} + unsigned char * yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, - unsigned int jsonTextLen, int verbose) + size_t jsonTextLen, int verbose) { - unsigned int offset = hand->bytesConsumed; + size_t offset = hand->bytesConsumed; unsigned char * str; const char * errorType = NULL; const char * errorText = NULL; char text[72]; - const char * arrow = " (right here) ------^\n"; + const char * arrow = " (right here) ------^\n"; if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) { errorType = "parse"; @@ -67,34 +85,35 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, } { - unsigned int memneeded = 0; + size_t memneeded = 0; memneeded += strlen(errorType); memneeded += strlen(" error"); if (errorText != NULL) { - memneeded += strlen(": "); - memneeded += strlen(errorText); + memneeded += strlen(": "); + memneeded += strlen(errorText); } str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2); + if (!str) return NULL; str[0] = 0; strcat((char *) str, errorType); - strcat((char *) str, " error"); + strcat((char *) str, " error"); if (errorText != NULL) { - strcat((char *) str, ": "); - strcat((char *) str, errorText); + strcat((char *) str, ": "); + strcat((char *) str, errorText); } - strcat((char *) str, "\n"); + strcat((char *) str, "\n"); } /* now we append as many spaces as needed to make sure the error * falls at char 41, if verbose was specified */ if (verbose) { - unsigned int start, end, i; - unsigned int spacesNeeded; + size_t start, end, i; + size_t spacesNeeded; spacesNeeded = (offset < 30 ? 40 - offset : 10); start = (offset >= 30 ? offset - 30 : 0); end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30); - + for (i=0;ialloc), (unsigned int)(strlen((char *) str) + strlen((char *) text) + strlen(arrow) + 1)); - newStr[0] = 0; - strcat((char *) newStr, (char *) str); - strcat((char *) newStr, text); - strcat((char *) newStr, arrow); + if (newStr) { + newStr[0] = 0; + strcat((char *) newStr, (char *) str); + strcat((char *) newStr, text); + strcat((char *) newStr, arrow); + } YA_FREE(&(hand->alloc), str); str = (unsigned char *) newStr; } @@ -136,35 +157,78 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, } +yajl_status +yajl_do_finish(yajl_handle hand) +{ + yajl_status stat; + stat = yajl_do_parse(hand,(const unsigned char *) " ",1); + + if (stat != yajl_status_ok) return stat; + + switch(yajl_bs_current(hand->stateStack)) + { + case yajl_state_parse_error: + case yajl_state_lexical_error: + return yajl_status_error; + case yajl_state_got_value: + case yajl_state_parse_complete: + return yajl_status_ok; + default: + if (!(hand->flags & yajl_allow_partial_values)) + { + yajl_bs_set(hand->stateStack, yajl_state_parse_error); + hand->parseError = "premature EOF"; + return yajl_status_error; + } + return yajl_status_ok; + } +} + yajl_status yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, - unsigned int jsonTextLen) + size_t jsonTextLen) { yajl_tok tok; const unsigned char * buf; - unsigned int bufLen; - unsigned int * offset = &(hand->bytesConsumed); + size_t bufLen; + size_t * offset = &(hand->bytesConsumed); *offset = 0; - around_again: switch (yajl_bs_current(hand->stateStack)) { case yajl_state_parse_complete: + if (hand->flags & yajl_allow_multiple_values) { + yajl_bs_set(hand->stateStack, yajl_state_got_value); + goto around_again; + } + if (!(hand->flags & yajl_allow_trailing_garbage)) { + if (*offset != jsonTextLen) { + tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, + offset, &buf, &bufLen); + if (tok != yajl_tok_eof) { + yajl_bs_set(hand->stateStack, yajl_state_parse_error); + hand->parseError = "trailing garbage"; + } + goto around_again; + } + } return yajl_status_ok; case yajl_state_lexical_error: - case yajl_state_parse_error: + case yajl_state_parse_error: return yajl_status_error; case yajl_state_start: + case yajl_state_got_value: case yajl_state_map_need_val: case yajl_state_array_need_val: - case yajl_state_array_start: { + case yajl_state_array_start: { /* for arrays and maps, we advance the state for this * depth, then push the state of the next depth. * If an error occurs during the parsing of the nesting * enitity, the state at this level will not matter. * a state that needs pushing will be anything other * than state_start */ + yajl_state stateToPush = yajl_state_start; tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, @@ -172,7 +236,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, switch (tok) { case yajl_tok_eof: - return yajl_status_insufficient_data; + return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; @@ -191,53 +255,38 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, yajl_buf_len(hand->decodeBuf))); } break; - case yajl_tok_bool: + case yajl_tok_bool: if (hand->callbacks && hand->callbacks->yajl_boolean) { _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx, *buf == 't')); } break; - case yajl_tok_null: + case yajl_tok_null: if (hand->callbacks && hand->callbacks->yajl_null) { _CC_CHK(hand->callbacks->yajl_null(hand->ctx)); } break; - case yajl_tok_left_bracket: + case yajl_tok_left_brace: if (hand->callbacks && hand->callbacks->yajl_start_map) { _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx)); } stateToPush = yajl_state_map_start; break; - case yajl_tok_left_brace: + case yajl_tok_left_bracket: if (hand->callbacks && hand->callbacks->yajl_start_array) { _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx)); } stateToPush = yajl_state_array_start; break; case yajl_tok_integer: - /* - * note. strtol does not respect the length of - * the lexical token. in a corner case where the - * lexed number is a integer with a trailing zero, - * immediately followed by the end of buffer, - * sscanf could run off into oblivion and cause a - * crash. for this reason we copy the integer - * (and doubles), into our parse buffer (the same - * one used for unescaping strings), before - * calling strtol. yajl_buf ensures null padding, - * so we're safe. - */ if (hand->callbacks) { if (hand->callbacks->yajl_number) { _CC_CHK(hand->callbacks->yajl_number( hand->ctx,(const char *) buf, bufLen)); } else if (hand->callbacks->yajl_integer) { - long int i = 0; - yajl_buf_clear(hand->decodeBuf); - yajl_buf_append(hand->decodeBuf, buf, bufLen); - buf = yajl_buf_data(hand->decodeBuf); - i = strtol((const char *) buf, NULL, 10); - if ((i == LONG_MIN || i == LONG_MAX) && + long long int i = 0; + i = yajl_parse_integer(buf, bufLen); + if ((i == LLONG_MIN || i == LLONG_MAX) && errno == ERANGE) { yajl_bs_set(hand->stateStack, @@ -281,9 +330,10 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, } } break; - case yajl_tok_right_brace: { - if (yajl_bs_current(hand->stateStack) == - yajl_state_array_start) + case yajl_tok_right_bracket: { + yajl_state s = yajl_bs_current(hand->stateStack); + if (s == yajl_state_array_start || + s == yajl_state_array_need_val) { if (hand->callbacks && hand->callbacks->yajl_end_array) @@ -291,13 +341,13 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); } yajl_bs_pop(hand->stateStack); - goto around_again; + goto around_again; } /* intentional fall-through */ } - case yajl_tok_colon: - case yajl_tok_comma: - case yajl_tok_right_bracket: + case yajl_tok_colon: + case yajl_tok_comma: + case yajl_tok_right_brace: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "unallowed token at this point in JSON text"; @@ -310,11 +360,11 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, /* got a value. transition depends on the state we're in. */ { yajl_state s = yajl_bs_current(hand->stateStack); - if (s == yajl_state_start) { + if (s == yajl_state_start || s == yajl_state_got_value) { yajl_bs_set(hand->stateStack, yajl_state_parse_complete); } else if (s == yajl_state_map_need_val) { yajl_bs_set(hand->stateStack, yajl_state_map_got_val); - } else { + } else { yajl_bs_set(hand->stateStack, yajl_state_array_got_val); } } @@ -324,7 +374,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, goto around_again; } - case yajl_state_map_start: + case yajl_state_map_start: case yajl_state_map_need_key: { /* only difference between these two states is that in * start '}' is valid, whereas in need_key, we've parsed @@ -333,7 +383,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, offset, &buf, &bufLen); switch (tok) { case yajl_tok_eof: - return yajl_status_insufficient_data; + return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; @@ -352,20 +402,21 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, } yajl_bs_set(hand->stateStack, yajl_state_map_sep); goto around_again; - case yajl_tok_right_bracket: - if (yajl_bs_current(hand->stateStack) == - yajl_state_map_start) - { + case yajl_tok_right_brace: { + yajl_state s = yajl_bs_current(hand->stateStack); + if (s == yajl_state_map_start || + s == yajl_state_map_need_key) { if (hand->callbacks && hand->callbacks->yajl_end_map) { _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); } yajl_bs_pop(hand->stateStack); - goto around_again; + goto around_again; } + } default: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = - "invalid object key (must be a string)"; + "invalid object key (must be a string)"; goto around_again; } } @@ -375,9 +426,9 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, switch (tok) { case yajl_tok_colon: yajl_bs_set(hand->stateStack, yajl_state_map_need_val); - goto around_again; + goto around_again; case yajl_tok_eof: - return yajl_status_insufficient_data; + return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; @@ -392,24 +443,24 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, offset, &buf, &bufLen); switch (tok) { - case yajl_tok_right_bracket: + case yajl_tok_right_brace: if (hand->callbacks && hand->callbacks->yajl_end_map) { _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); } yajl_bs_pop(hand->stateStack); - goto around_again; + goto around_again; case yajl_tok_comma: yajl_bs_set(hand->stateStack, yajl_state_map_need_key); - goto around_again; + goto around_again; case yajl_tok_eof: - return yajl_status_insufficient_data; + return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; default: yajl_bs_set(hand->stateStack, yajl_state_parse_error); - hand->parseError = "after key and value, inside map, " - "I expect ',' or '}'"; + hand->parseError = "after key and value, inside map, " + "I expect ',' or '}'"; /* try to restore error offset */ if (*offset >= bufLen) *offset -= bufLen; else *offset = 0; @@ -420,17 +471,17 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, offset, &buf, &bufLen); switch (tok) { - case yajl_tok_right_brace: + case yajl_tok_right_bracket: if (hand->callbacks && hand->callbacks->yajl_end_array) { _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); } yajl_bs_pop(hand->stateStack); - goto around_again; + goto around_again; case yajl_tok_comma: yajl_bs_set(hand->stateStack, yajl_state_array_need_val); - goto around_again; + goto around_again; case yajl_tok_eof: - return yajl_status_insufficient_data; + return yajl_status_ok; case yajl_tok_error: yajl_bs_set(hand->stateStack, yajl_state_lexical_error); goto around_again; @@ -442,8 +493,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, } } } - + abort(); return yajl_status_error; } - diff --git a/src/yajl/yajl_parser.h b/src/yajl/yajl_parser.h index 2d59882a3..bd5a74dfd 100644 --- a/src/yajl/yajl_parser.h +++ b/src/yajl/yajl_parser.h @@ -1,34 +1,18 @@ /* - * Copyright 2010, Lloyd Hilaiel. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. Neither the name of Lloyd Hilaiel nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ + * Copyright (c) 2007-2011, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #ifndef __YAJL_PARSER_H__ #define __YAJL_PARSER_H__ @@ -36,6 +20,7 @@ #include "yajl_parse.h" #include "yajl_bytestack.h" #include "yajl_buf.h" +#include "yajl_lex.h" typedef enum { @@ -44,13 +29,14 @@ typedef enum { yajl_state_parse_error, yajl_state_lexical_error, yajl_state_map_start, - yajl_state_map_sep, + yajl_state_map_sep, yajl_state_map_need_val, yajl_state_map_got_val, yajl_state_map_need_key, yajl_state_array_start, yajl_state_array_got_val, - yajl_state_array_need_val + yajl_state_array_need_val, + yajl_state_got_value, } yajl_state; struct yajl_handle_t { @@ -61,22 +47,32 @@ struct yajl_handle_t { /* the number of bytes consumed from the last client buffer, * in the case of an error this will be an error offset, in the * case of an error this can be used as the error offset */ - unsigned int bytesConsumed; + size_t bytesConsumed; /* temporary storage for decoded strings */ yajl_buf decodeBuf; /* a stack of states. access with yajl_state_XXX routines */ yajl_bytestack stateStack; /* memory allocation routines */ yajl_alloc_funcs alloc; + /* bitfield */ + unsigned int flags; }; yajl_status yajl_do_parse(yajl_handle handle, const unsigned char * jsonText, - unsigned int jsonTextLen); + size_t jsonTextLen); + +yajl_status +yajl_do_finish(yajl_handle handle); unsigned char * yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, - unsigned int jsonTextLen, int verbose); + size_t jsonTextLen, int verbose); + +/* A little built in integer parsing routine with the same semantics as strtol + * that's unaffected by LOCALE. */ +long long +yajl_parse_integer(const unsigned char *number, size_t length); #endif diff --git a/test/Makefile b/test/Makefile index 9514918cf..e72c46c61 100755 --- a/test/Makefile +++ b/test/Makefile @@ -12,6 +12,7 @@ include $(TOP)/configure/CONFIG PROD_LIBS += Com PROD_SYS_LIBS_WIN32 += ws2_32 advapi32 user32 +PROD_SYS_LIBS_solaris += socket nsl TESTPROD_HOST += epicsUnitTestTest epicsUnitTestTest_SRCS += epicsUnitTestTest.c @@ -48,8 +49,6 @@ TESTS += epicsMathTest TESTPROD_HOST += epicsMMIOTest epicsMMIOTest_SRCS += epicsMMIOTest.c -epicsMMIOTest_SYS_LIBS_solaris = socket -epicsMMIOTest_SYS_LIBS_WIN32 = ws2_32 user32 testHarness_SRCS += epicsMMIOTest.c TESTS += epicsMMIOTest @@ -65,8 +64,6 @@ TESTS += epicsEnvTest TESTPROD_HOST += epicsErrlogTest epicsErrlogTest_SRCS += epicsErrlogTest.c -epicsErrlogTest_SYS_LIBS_solaris = socket -epicsErrlogTest_SYS_LIBS_WIN32 = ws2_32 user32 testHarness_SRCS += epicsErrlogTest.c TESTS += epicsErrlogTest @@ -82,8 +79,6 @@ TESTS += epicsStdlibTest TESTPROD_HOST += epicsSockResolveTest epicsSockResolveTest_SRCS += epicsSockResolveTest.c -epicsSockResolveTest_SYS_LIBS_solaris = socket -epicsSockResolveTest_SYS_LIBS_WIN32 = ws2_32 user32 testHarness_SRCS += epicsSockResolveTest.c TESTS += epicsSockResolveTest @@ -198,9 +193,6 @@ TESTS += taskwdTest TESTPROD_HOST += blockingSockTest blockingSockTest_SRCS += blockingSockTest.cpp testHarness_SRCS += blockingSockTest.cpp -# needed when its an object library build -blockingSockTest_SYS_LIBS_WIN32 = ws2_32 advapi32 user32 -blockingSockTest_SYS_LIBS_solaris = socket TESTS += blockingSockTest TESTPROD_HOST += epicsMessageQueueTest @@ -218,6 +210,18 @@ ipAddrToAsciiTest_SRCS += ipAddrToAsciiTest.cpp testHarness_SRCS += ipAddrToAsciiTest.cpp TESTS += ipAddrToAsciiTest +TESTPROD_HOST += osiSockTest +osiSockTest_SRCS += osiSockTest.c +testHarness_SRCS += osiSockTest.c +TESTS += osiSockTest + +ifneq ($(OS_CLASS),WIN32) +# This test can only be run on a build host, and is broken on Windows +TESTPROD_HOST += yajl_test +yajl_test_SRCS += yajl_test.c +TESTS += yajlTest +endif + # The testHarness runs all the test programs in a known working order. testHarness_SRCS += epicsRunLibComTests.c @@ -262,4 +266,3 @@ cvtFastPerform_SRCS += cvtFastPerform.cpp testHarness_SRCS += cvtFastPerform.cpp include $(TOP)/configure/RULES - diff --git a/test/epicsRunLibComTests.c b/test/epicsRunLibComTests.c index c4a76e777..29c5eda3f 100644 --- a/test/epicsRunLibComTests.c +++ b/test/epicsRunLibComTests.c @@ -51,6 +51,7 @@ int epicsInlineTest(void); int ipAddrToAsciiTest(void); int macDefExpandTest(void); int macLibTest(void); +int osiSockTest(void); int ringBytesTest(void); int ringPointerTest(void); int taskwdTest(void); @@ -104,6 +105,7 @@ void epicsRunLibComTests(void) runTest(ipAddrToAsciiTest); runTest(macDefExpandTest); runTest(macLibTest); + runTest(osiSockTest); runTest(ringBytesTest); runTest(ringPointerTest); runTest(taskwdTest); diff --git a/test/osiSockTest.c b/test/osiSockTest.c new file mode 100644 index 000000000..39eb0ba2b --- /dev/null +++ b/test/osiSockTest.c @@ -0,0 +1,74 @@ +/*************************************************************************\ +* Copyright (c) 2017 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include +#include + +#include "osiSock.h" +#include "epicsUnitTest.h" +#include "testMain.h" + +/* This could easily be generalized to test more options */ +void udpBroadcast(SOCKET s, int put) +{ + int status; + int flag = put; + osiSocklen_t len = sizeof(flag); + + status = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&flag, len); + testOk(status >= 0, "setsockopt BROADCAST := %d", put); + + status = getsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&flag, &len); + testOk(status >= 0 && len == sizeof(flag) && !flag == !put, + "getsockopt BROADCAST => %d", flag); +} + +void multiCastLoop(SOCKET s, int put) +{ + int status; + osiSockOptMcastLoop_t flag = put; + osiSocklen_t len = sizeof(flag); + + status = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, + (char *)&flag, len); + testOk(status >= 0, "setsockopt MULTICAST_LOOP := %d", put); + + status = getsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&flag, &len); + testOk(status >= 0 && len == sizeof(flag) && !flag == !put, + "getsockopt MULTICAST_LOOP => %d", (int) flag); +} + +void udpSockTest(void) +{ + SOCKET s; + + s = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); + testOk(s != INVALID_SOCKET, "epicsSocketCreate INET, DGRAM, 0"); + + udpBroadcast(s, 1); + udpBroadcast(s, 0); + + multiCastLoop(s, 1); + multiCastLoop(s, 0); + + epicsSocketDestroy(s); +} + + +MAIN(osiSockTest) +{ + int status; + testPlan(10); + + status = osiSockAttach(); + testOk(status, "osiSockAttach"); + + udpSockTest(); + + osiSockRelease(); + return testDone(); +} diff --git a/test/ringPointerTest.c b/test/ringPointerTest.c index 92401d123..65a349489 100644 --- a/test/ringPointerTest.c +++ b/test/ringPointerTest.c @@ -238,9 +238,11 @@ MAIN(ringPointerTest) testPlan(37); testSingle(); - epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityScanLow); + if (prio) + epicsThreadSetPriority(epicsThreadGetIdSelf(), epicsThreadPriorityScanLow); testPair(0); testPair(1); - epicsThreadSetPriority(epicsThreadGetIdSelf(), prio); + if (prio) + epicsThreadSetPriority(epicsThreadGetIdSelf(), prio); return testDone(); } diff --git a/test/taskwdTest.c b/test/taskwdTest.c index 6cec429d2..78bd17a0f 100644 --- a/test/taskwdTest.c +++ b/test/taskwdTest.c @@ -10,6 +10,7 @@ */ #include +#include #include "taskwd.h" #include "errlog.h" @@ -17,50 +18,78 @@ #include "epicsUnitTest.h" #include "testMain.h" +/* This is a unique prefix used for the names of the test threads */ +#define baseName "testTask" void monInsert(void *usr, epicsThreadId tid) { - testPass("monInsert(tid=%p)", (void *)tid); + char tname[32]; + + epicsThreadGetName(tid, tname, sizeof(tname)); + if (strncmp(tname, baseName, strlen(baseName)) == 0) + testPass("monInsert(thread='%s')", tname); + else + testDiag("monInsert(thread='%s')", tname); } void monNotify(void *usr, epicsThreadId tid, int suspended) { - testPass("monNotify(tid=%p, suspended=%d)", (void *)tid, suspended); + char tname[32]; + + epicsThreadGetName(tid, tname, sizeof(tname)); + testPass("monNotify(thread='%s', suspended=%d)", tname, suspended); epicsThreadResume(tid); } void monRemove(void *usr, epicsThreadId tid) { - testPass("monRemove(tid=%p)", (void *)tid); + char tname[32]; + + epicsThreadGetName(tid, tname, sizeof(tname)); + if (strncmp(tname, baseName, strlen(baseName)) == 0) + testPass("monRemove(thread='%s')", tname); + else + testDiag("monRemove(thread='%s')", tname); } taskwdMonitor monFuncs = {monInsert, monNotify, monRemove}; void anyNotify(void *usr, epicsThreadId tid) { - testPass("anyNotify(tid=%p)", (void *)tid); + char tname[32]; + + epicsThreadGetName(tid, tname, sizeof(tname)); + if (strncmp(tname, baseName, strlen(baseName)) == 0) + testPass("anyNotify(thread='%s')", tname); + else + testDiag("anyNotify(thread='%s')", tname); } void taskNotify(void *usr) { - testPass("taskNotify"); + const char *id = (const char *) usr; + + testPass("taskNotify id='%s'", id); } void testTask1(void *arg) { - taskwdInsert(0, taskNotify, NULL); - epicsThreadSleep(10.0); + taskwdInsert(0, taskNotify, "1"); + epicsThreadSleep(14.0); + testDiag("Task 1 cleaning up"); taskwdRemove(0); } void testTask2(void *arg) { - taskwdInsert(0, taskNotify, NULL); - testDiag("Task suspending"); + taskwdInsert(0, taskNotify, "2"); + epicsThreadSleep(1.0); + testDiag("Task 2 suspending"); epicsThreadSuspendSelf(); epicsThreadSleep(1.0); - testDiag("Alive again"); - epicsThreadSleep(10.0); + testDiag("Task 2 alive again"); + epicsThreadSleep(6.0); + testDiag("Task 2 cleaning up"); taskwdRemove(0); } @@ -73,12 +102,12 @@ MAIN(taskwdTest) taskwdMonitorAdd(&monFuncs, NULL); taskwdAnyInsert(NULL, anyNotify, NULL); - epicsThreadCreate("testTask1", epicsThreadPriorityMax, + epicsThreadCreate(baseName "1", epicsThreadPriorityMax, epicsThreadGetStackSize(epicsThreadStackSmall), testTask1, NULL); epicsThreadSleep(1.0); - epicsThreadCreate("testTask2", epicsThreadPriorityMax, + epicsThreadCreate(baseName "2", epicsThreadPriorityMax, epicsThreadGetStackSize(epicsThreadStackSmall), testTask2, NULL); @@ -91,4 +120,3 @@ MAIN(taskwdTest) eltc(1); return testDone(); } - diff --git a/test/yajlTest.plt b/test/yajlTest.plt new file mode 100644 index 000000000..5c9052032 --- /dev/null +++ b/test/yajlTest.plt @@ -0,0 +1,51 @@ +#!/usr/bin/perl +# +# This is a test director for running yajl JSON parser tests. +# The tests are actually defined in the yajlTestCases.pm module, +# which is generated from the yajl cases by yajlTestConverter.pl + +use strict; +use Test::More; +use IO::Handle; +use IPC::Open3; + +# Load test cases +use lib ".."; +use yajlTestCases; + +my @cases = cases(); +plan tests => scalar @cases; + +# The yajl_test program reads JSON from stdin and sends a description +# of what it got to stdout, with errors going to stderr. We merge the +# two output streams for the purpose of checking the test results. +my $prog = './yajl_test'; +$prog .= '.exe' if ($^O eq 'MSWin32') || ($^O eq 'cygwin'); + +foreach my $case (@cases) { + my $name = $case->{name}; + my @opts = @{$case->{opts}}; + my @input = @{$case->{input}}; + my @gives = @{$case->{gives}}; + + my ($rx, $tx); + my $pid = open3($tx, $rx, 0, $prog, @opts); + + # Send the test case, then EOF + print $tx join "\n", @input; + close $tx; + + # Receive the result + my @result; + while (!$rx->eof) { + chomp(my $line = <$rx>); + push @result, $line; + } + close $rx; + + # Clean up the child process + waitpid $pid, 0; + + # Report the result of this test case + is_deeply(\@result, \@gives, $name); +} diff --git a/test/yajlTestCases.pm b/test/yajlTestCases.pm new file mode 100644 index 000000000..40eaff6e7 --- /dev/null +++ b/test/yajlTestCases.pm @@ -0,0 +1,3069 @@ +# Parser test cases from https://github.com/lloyd/yajl +# +# This file is generated, DO NOT EDIT! +# +# See comments in yajlTestConverter.pl for instructions on +# how to regenerate this file from the original yajl sources. + +sub cases { + my $VAR1 = [ + { + name => "difficult_json_c_test_case_with_comments", + opts => [ + "-c" + ], + input => [ + "{ \"glossary\": { /* you */ \"title\": /**/ \"example glossary\", /*should*/\"GlossDiv\": { \"title\": /*never*/\"S\", /*ever*/\"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", /*see*/\"GlossSeeAlso\"/*this*/:/*coming*/[/*out*/\"GML\"/*of*/,/*the*/\"XML\"/*parser!*/, \"markup\"] /*hey*/}/*ho*/]/*hey*/}/*ho*/} } // and the parser won't even get this far, so chill. /* hah!", + "" + ], + gives => [ + "map open '{'", + "key: 'glossary'", + "map open '{'", + "key: 'title'", + "string: 'example glossary'", + "key: 'GlossDiv'", + "map open '{'", + "key: 'title'", + "string: 'S'", + "key: 'GlossList'", + "array open '['", + "map open '{'", + "key: 'ID'", + "string: 'SGML'", + "key: 'SortAs'", + "string: 'SGML'", + "key: 'GlossTerm'", + "string: 'Standard Generalized Markup Language'", + "key: 'Acronym'", + "string: 'SGML'", + "key: 'Abbrev'", + "string: 'ISO 8879:1986'", + "key: 'GlossDef'", + "string: 'A meta-markup language, used to create markup languages such as DocBook.'", + "key: 'GlossSeeAlso'", + "array open '['", + "string: 'GML'", + "string: 'XML'", + "string: 'markup'", + "array close ']'", + "map close '}'", + "array close ']'", + "map close '}'", + "map close '}'", + "map close '}'", + "memory leaks:\t0" + ] + }, + { + name => "simple_with_comments", + opts => [ + "-c" + ], + input => [ + "{", + " \"this\": \"is\", // ignore this", + " \"really\": \"simple\",", + " /* ignore", + "this", + "too * / ", + "** //", + "(/", + "******/", + " \"json\": \"right?\"", + "}", + "" + ], + gives => [ + "map open '{'", + "key: 'this'", + "string: 'is'", + "key: 'really'", + "string: 'simple'", + "key: 'json'", + "string: 'right?'", + "map close '}'", + "memory leaks:\t0" + ] + }, + { + name => "false_then_garbage", + opts => [ + "-g" + ], + input => [ + "falsex" + ], + gives => [ + "bool: false", + "memory leaks:\t0" + ] + }, + { + name => "null_then_garbage", + opts => [ + "-g" + ], + input => [ + "nullx", + "" + ], + gives => [ + "null", + "memory leaks:\t0" + ] + }, + { + name => "true_then_garbage", + opts => [ + "-g" + ], + input => [ + "truex" + ], + gives => [ + "bool: true", + "memory leaks:\t0" + ] + }, + { + name => "eof", + opts => [ + "-m" + ], + input => [ + "{ \"123\":", + "" + ], + gives => [ + "map open '{'", + "key: '123'", + "parse error: premature EOF", + "memory leaks:\t0" + ] + }, + { + name => "integers", + opts => [ + "-m" + ], + input => [ + "1221 21", + "" + ], + gives => [ + "integer: 1221", + "integer: 21", + "memory leaks:\t0" + ] + }, + { + name => "multiple", + opts => [ + "-m" + ], + input => [ + "", + "{}", + "{}", + "" + ], + gives => [ + "map open '{'", + "map close '}'", + "map open '{'", + "map close '}'", + "memory leaks:\t0" + ] + }, + { + name => "stuff", + opts => [ + "-m" + ], + input => [ + "{}", + "[]", + "[]", + "\"sdfasd\"", + 123, + "{ \"123\" : 123 }", + "3.1e124", + "" + ], + gives => [ + "map open '{'", + "map close '}'", + "array open '['", + "array close ']'", + "array open '['", + "array close ']'", + "string: 'sdfasd'", + "integer: 123", + "map open '{'", + "key: '123'", + "integer: 123", + "map close '}'", + "double: 3.1e+124", + "memory leaks:\t0" + ] + }, + { + name => "array_open", + opts => [ + "-p" + ], + input => [ + "[", + "" + ], + gives => [ + "array open '['", + "memory leaks:\t0" + ] + }, + { + name => "eof_str", + opts => [ + "-p" + ], + input => [ + "\"abc" + ], + gives => [ + "memory leaks:\t0" + ] + }, + { + name => "map_open", + opts => [ + "-p" + ], + input => [ + "{", + "" + ], + gives => [ + "map open '{'", + "memory leaks:\t0" + ] + }, + { + name => "partial_ok", + opts => [ + "-p" + ], + input => [ + "[ \"foo\", \"bar\"", + "" + ], + gives => [ + "array open '['", + "string: 'foo'", + "string: 'bar'", + "memory leaks:\t0" + ] + }, + { + name => "array", + opts => [], + input => [ + "[\"foo\",", + " \"bar\", \"baz\",", + " true,false,null,{\"key\":\"value\"},", + " [null,null,null,[]],", + " \"\\n\\r\\\\\"", + "]", + "" + ], + gives => [ + "array open '['", + "string: 'foo'", + "string: 'bar'", + "string: 'baz'", + "bool: true", + "bool: false", + "null", + "map open '{'", + "key: 'key'", + "string: 'value'", + "map close '}'", + "array open '['", + "null", + "null", + "null", + "array open '['", + "array close ']'", + "array close ']'", + "string: '", + "\r\\'", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "array_close", + opts => [], + input => [ + "]", + "" + ], + gives => [ + "parse error: unallowed token at this point in JSON text", + "memory leaks:\t0" + ] + }, + { + name => "bignums", + opts => [], + input => [ + "[ 9223372036854775807, -9223372036854775807 ]", + "" + ], + gives => [ + "array open '['", + "integer: 9223372036854775807", + "integer: -9223372036854775807", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "bogus_char", + opts => [], + input => [ + "[\"this\",\"is\",\"what\",\"should\",\"be\",", + " \"a happy bit of json\",", + " \"but someone, misspelled \\\"true\\\"\", ture,", + " \"who says JSON is easy for humans to generate?\"]", + "" + ], + gives => [ + "array open '['", + "string: 'this'", + "string: 'is'", + "string: 'what'", + "string: 'should'", + "string: 'be'", + "string: 'a happy bit of json'", + "string: 'but someone, misspelled \"true\"'", + "lexical error: invalid string in json text.", + "memory leaks:\t0" + ] + }, + { + name => "codepoints_from_unicode_org", + opts => [], + input => [ + "\"\\u004d\\u0430\\u4e8c\\ud800\\udf02\"", + "" + ], + gives => [ + "string: 'M\320\260\344\272\214\360\220\214\202'", + "memory leaks:\t0" + ] + }, + { + name => "deep_arrays", + opts => [], + input => [ + "[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" + ], + gives => [ + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array open '['", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "difficult_json_c_test_case", + opts => [], + input => [ + "{ \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }", + "" + ], + gives => [ + "map open '{'", + "key: 'glossary'", + "map open '{'", + "key: 'title'", + "string: 'example glossary'", + "key: 'GlossDiv'", + "map open '{'", + "key: 'title'", + "string: 'S'", + "key: 'GlossList'", + "array open '['", + "map open '{'", + "key: 'ID'", + "string: 'SGML'", + "key: 'SortAs'", + "string: 'SGML'", + "key: 'GlossTerm'", + "string: 'Standard Generalized Markup Language'", + "key: 'Acronym'", + "string: 'SGML'", + "key: 'Abbrev'", + "string: 'ISO 8879:1986'", + "key: 'GlossDef'", + "string: 'A meta-markup language, used to create markup languages such as DocBook.'", + "key: 'GlossSeeAlso'", + "array open '['", + "string: 'GML'", + "string: 'XML'", + "string: 'markup'", + "array close ']'", + "map close '}'", + "array close ']'", + "map close '}'", + "map close '}'", + "map close '}'", + "memory leaks:\t0" + ] + }, + { + name => "doubles", + opts => [], + input => [ + "[ 0.1e2, 1e1, 3.141569, 10000000000000e-10]", + "" + ], + gives => [ + "array open '['", + "double: 10", + "double: 10", + "double: 3.14157", + "double: 1000", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "doubles_in_array", + opts => [], + input => [ + "[0.00011999999999999999, 6E-06, 6E-06, 1E-06, 1E-06]", + "" + ], + gives => [ + "array open '['", + "double: 0.00012", + "double: 6e-06", + "double: 6e-06", + "double: 1e-06", + "double: 1e-06", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "empty_array", + opts => [], + input => [ + "[]" + ], + gives => [ + "array open '['", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "empty_string", + opts => [], + input => [ + "\"\"", + "" + ], + gives => [ + "string: ''", + "memory leaks:\t0" + ] + }, + { + name => "escaped_bulgarian", + opts => [], + input => [ + "[\"\\u0414\\u0430\",", + " \"\\u041c\\u0443\",", + " \"\\u0415\\u0431\\u0430\",", + " \"\\u041c\\u0430\\u0439\\u043a\\u0430\\u0442\\u0430\"]", + "" + ], + gives => [ + "array open '['", + "string: '\320\224\320\260'", + "string: '\320\234\321\203'", + "string: '\320\225\320\261\320\260'", + "string: '\320\234\320\260\320\271\320\272\320\260\321\202\320\260'", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "escaped_foobar", + opts => [], + input => [ + "\"\\u0066\\u006f\\u006f\\u0062\\u0061\\u0072\"", + "" + ], + gives => [ + "string: 'foobar'", + "memory leaks:\t0" + ] + }, + { + name => "false", + opts => [], + input => [ + "false", + "" + ], + gives => [ + "bool: false", + "memory leaks:\t0" + ] + }, + { + name => "false_then_garbage", + opts => [], + input => [ + "falsex" + ], + gives => [ + "bool: false", + "parse error: trailing garbage", + "memory leaks:\t0" + ] + }, + { + name => "issue_7", + opts => [], + input => [ + "2009-10-20\@20:38:21.539575", + "" + ], + gives => [ + "integer: 2009", + "parse error: trailing garbage", + "memory leaks:\t0" + ] + }, + { + name => "null_then_garbage", + opts => [], + input => [ + "nullx", + "" + ], + gives => [ + "null", + "parse error: trailing garbage", + "memory leaks:\t0" + ] + }, + { + name => "true_then_garbage", + opts => [], + input => [ + "truex", + "" + ], + gives => [ + "bool: true", + "parse error: trailing garbage", + "memory leaks:\t0" + ] + }, + { + name => "four_byte_utf8", + opts => [], + input => [ + "{ \"U+10ABCD\": \"\364\212\257\215\" }", + "" + ], + gives => [ + "map open '{'", + "key: 'U+10ABCD'", + "string: '\364\212\257\215'", + "map close '}'", + "memory leaks:\t0" + ] + }, + { + name => "high_overflow", + opts => [], + input => [ + "9223372036854775808" + ], + gives => [ + "parse error: integer overflow", + "memory leaks:\t0" + ] + }, + { + name => "integers", + opts => [], + input => [ + "[ 1,2,3,4,5,6,7,", + " 123456789 , -123456789,", + " 2147483647, -2147483647 ]", + "" + ], + gives => [ + "array open '['", + "integer: 1", + "integer: 2", + "integer: 3", + "integer: 4", + "integer: 5", + "integer: 6", + "integer: 7", + "integer: 123456789", + "integer: -123456789", + "integer: 2147483647", + "integer: -2147483647", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "invalid_utf8", + opts => [], + input => [ + "[\"\320\224\320\260 \320\234\321 \320\225\320\261\320\260 \320\234\320\260\320\271\320\272\320\260\321\202\320\260\"]", + "" + ], + gives => [ + "array open '['", + "lexical error: invalid bytes in UTF8 string.", + "memory leaks:\t0" + ] + }, + { + name => "isolated_surrogate_marker", + opts => [], + input => [ + "\"\\ud800\"", + "" + ], + gives => [ + "string: '?'", + "memory leaks:\t0" + ] + }, + { + name => "leading_zero_in_number", + opts => [], + input => [ + "{ \"bad thing\": 01 }", + "" + ], + gives => [ + "map open '{'", + "key: 'bad thing'", + "integer: 0", + "parse error: after key and value, inside map, I expect ',' or '}'", + "memory leaks:\t0" + ] + }, + { + name => "lonely_minus_sign", + opts => [], + input => [ + "[", + "\t\t\"foo\", true,", + "\t\ttrue, \"blue\",", + "\t\t\"baby where are you?\", \"oh boo hoo!\",", + " - ", + "]", + "" + ], + gives => [ + "array open '['", + "string: 'foo'", + "bool: true", + "bool: true", + "string: 'blue'", + "string: 'baby where are you?'", + "string: 'oh boo hoo!'", + "lexical error: malformed number, a digit is required after the minus sign.", + "memory leaks:\t0" + ] + }, + { + name => "lonely_number", + opts => [], + input => [ + 123456789 + ], + gives => [ + "integer: 123456789", + "memory leaks:\t0" + ] + }, + { + name => "low_overflow", + opts => [], + input => [ + "-9223372036854775808" + ], + gives => [ + "parse error: integer overflow", + "memory leaks:\t0" + ] + }, + { + name => "map_close", + opts => [], + input => [ + "}", + "" + ], + gives => [ + "parse error: unallowed token at this point in JSON text", + "memory leaks:\t0" + ] + }, + { + name => "missing_integer_after_decimal_point", + opts => [], + input => [ + "10.e2", + "" + ], + gives => [ + "lexical error: malformed number, a digit is required after the decimal point.", + "memory leaks:\t0" + ] + }, + { + name => "missing_integer_after_exponent", + opts => [], + input => [ + "10e", + "" + ], + gives => [ + "lexical error: malformed number, a digit is required after the exponent.", + "memory leaks:\t0" + ] + }, + { + name => "multiple", + opts => [], + input => [ + "", + "{}", + "{}", + "" + ], + gives => [ + "map open '{'", + "map close '}'", + "parse error: trailing garbage", + "memory leaks:\t0" + ] + }, + { + name => "non_utf8_char_in_string", + opts => [], + input => [ + "{\"CoreletAPIVersion\":2,\"CoreletType\":\"standalone\",\"documentation\":\"A corelet that provides the capability to upload a folder\222s contents into a user\222s locker.\",\"functions\":[{\"documentation\":\"Displays a dialog box that allows user to select a folder on the local system.\",\"name\":\"ShowBrowseDialog\",\"parameters\":[{\"documentation\":\"The callback function for results.\",\"name\":\"callback\",\"required\":true,\"type\":\"callback\"}]},{\"documentation\":\"Uploads all mp3 files in the folder provided.\",\"name\":\"UploadFolder\",\"parameters\":[{\"documentation\":\"The path to upload mp3 files from.\",\"name\":\"path\",\"required\":true,\"type\":\"string\"},{\"documentation\":\"The callback function for progress.\",\"name\":\"callback\",\"required\":true,\"type\":\"callback\"}]},{\"documentation\":\"Returns the server name to the current locker service.\",\"name\":\"GetLockerService\",\"parameters\":[]},{\"documentation\":\"Changes the name of the locker service.\",\"name\":\"SetLockerService\",\"parameters\":[{\"documentation\":\"The value of the locker service to set active.\",\"name\":\"LockerService\",\"required\":true,\"type\":\"string\"}]},{\"documentation\":\"Downloads locker files to the suggested folder.\",\"name\":\"DownloadFile\",\"parameters\":[{\"documentation\":\"The origin path of the locker file.\",\"name\":\"path\",\"required\":true,\"type\":\"string\"},{\"documentation\":\"The Window destination path of the locker file.\",\"name\":\"destination\",\"required\":true,\"type\":\"integer\"},{\"documentation\":\"The callback function for progress.\",\"name\":\"callback\",\"required\":true,\"type\":\"callback\"}]}],\"name\":\"LockerUploader\",\"version\":{\"major\":0,\"micro\":1,\"minor\":0},\"versionString\":\"0.0.1\"}" + ], + gives => [ + "map open '{'", + "key: 'CoreletAPIVersion'", + "integer: 2", + "key: 'CoreletType'", + "string: 'standalone'", + "key: 'documentation'", + "lexical error: invalid bytes in UTF8 string.", + "memory leaks:\t0" + ] + }, + { + name => "partial_bad", + opts => [], + input => [ + "[ \"foo\", \"bar\"", + "" + ], + gives => [ + "array open '['", + "string: 'foo'", + "string: 'bar'", + "parse error: premature EOF", + "memory leaks:\t0" + ] + }, + { + name => "null", + opts => [], + input => [ + "null", + "" + ], + gives => [ + "null", + "memory leaks:\t0" + ] + }, + { + name => "nulls_and_bools", + opts => [], + input => [ + "{", + "\t\"boolean, true\": true,", + "\t\"boolean, false\": false,", + "\t\"null\": null", + "}", + "" + ], + gives => [ + "map open '{'", + "key: 'boolean, true'", + "bool: true", + "key: 'boolean, false'", + "bool: false", + "key: 'null'", + "null", + "map close '}'", + "memory leaks:\t0" + ] + }, + { + name => "simple", + opts => [], + input => [ + "{", + " \"this\": \"is\",", + " \"really\": \"simple\",", + " \"json\": \"right?\"", + "}", + "" + ], + gives => [ + "map open '{'", + "key: 'this'", + "string: 'is'", + "key: 'really'", + "string: 'simple'", + "key: 'json'", + "string: 'right?'", + "map close '}'", + "memory leaks:\t0" + ] + }, + { + name => "simple_with_comments", + opts => [], + input => [ + "{", + " \"this\": \"is\", // ignore this", + " \"really\": \"simple\",", + " /* ignore", + "this", + "too * / ", + "** //", + "(/", + "******/", + " \"json\": \"right?\"", + "}", + "" + ], + gives => [ + "map open '{'", + "key: 'this'", + "string: 'is'", + "lexical error: probable comment found in input text, comments are not enabled.", + "memory leaks:\t0" + ] + }, + { + name => "string_invalid_escape", + opts => [], + input => [ + "[\"\\n foo \\/ bar \\r\\f\\\\\\uffff\\t\\b\\\"\\\\ and you can't escape thi\\s\"]", + "" + ], + gives => [ + "array open '['", + "lexical error: inside a string, '\\' occurs before a character which it may not.", + "memory leaks:\t0" + ] + }, + { + name => "string_invalid_hex_char", + opts => [], + input => [ + "\"foo foo, blah blah \\u0123 \\u4567 \\u89ab \\uc/ef \\uABCD \\uEFFE bar baz bing\"", + "" + ], + gives => [ + "lexical error: invalid (non-hex) character occurs after '\\u' inside string.", + "memory leaks:\t0" + ] + }, + { + name => "string_with_escapes", + opts => [], + input => [ + "[\"\\n foo \\/ bar \\r\\f\\\\\\uffff\\t\\b\\\"\\\\\",", + " \"\\\"and this string has an escape at the beginning\",", + " \"and this string has no escapes\" ]", + "" + ], + gives => [ + "array open '['", + "string: '", + " foo / bar \r\f\\\357\277\277\t\b\"\\'", + "string: '\"and this string has an escape at the beginning'", + "string: 'and this string has no escapes'", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "string_with_invalid_newline", + opts => [], + input => [ + "\"la di dah. this is a string, and I can do this, \\n, but not this", + "\"", + "" + ], + gives => [ + "lexical error: invalid character inside string.", + "memory leaks:\t0" + ] + }, + { + name => "three_byte_utf8", + opts => [], + input => [ + "{\"matzue\": \"\346\235\276\346\261\237\", \"asakusa\": \"\346\265\205\350\215\211\"}", + "" + ], + gives => [ + "map open '{'", + "key: 'matzue'", + "string: '\346\235\276\346\261\237'", + "key: 'asakusa'", + "string: '\346\265\205\350\215\211'", + "map close '}'", + "memory leaks:\t0" + ] + }, + { + name => "trailing_commas", + opts => [], + input => [ + "{\"array\":[1,2,],\"map\":{\"a\":1,},}", + "" + ], + gives => [ + "map open '{'", + "key: 'array'", + "array open '['", + "integer: 1", + "integer: 2", + "array close ']'", + "key: 'map'", + "map open '{'", + "key: 'a'", + "integer: 1", + "map close '}'", + "map close '}'", + "memory leaks:\t0" + ] + }, + { + name => "true", + opts => [], + input => [ + "true", + "" + ], + gives => [ + "bool: true", + "memory leaks:\t0" + ] + }, + { + name => "unescaped_bulgarian", + opts => [], + input => [ + "[\"\320\224\320\260 \320\234\321\203 \320\225\320\261\320\260 \320\234\320\260\320\271\320\272\320\260\321\202\320\260\"]", + "" + ], + gives => [ + "array open '['", + "string: '\320\224\320\260 \320\234\321\203 \320\225\320\261\320\260 \320\234\320\260\320\271\320\272\320\260\321\202\320\260'", + "array close ']'", + "memory leaks:\t0" + ] + }, + { + name => "zerobyte", + opts => [], + input => [ + "\"\\u0000\"", + "" + ], + gives => [ + "string: '\0'", + "memory leaks:\t0" + ] + } + ]; + + return @{$VAR1}; +} + +1; diff --git a/test/yajlTestConverter.pl b/test/yajlTestConverter.pl new file mode 100755 index 000000000..c3d2b54b6 --- /dev/null +++ b/test/yajlTestConverter.pl @@ -0,0 +1,98 @@ +#!/usr/bin/perl +# +# This script converts the parsing test cases from the yajl release tree +# into the yajlTestCases module as used by libCom/test/yajlTest.plt +# +# Re-do this conversion and commit after checking out a new version of yajl +# from https://github.com/lloyd/yajl as follows: +# $ cd /src/libCom/test +# $ perl yajlTestConverter.pl /path/to/yajl +# The tests are saved into the file yajlTestCases.pm in the src/libCom/test +# directory which will be read by the yajlTest.t test script. + +use Data::Dumper; + +my $yajl = shift @ARGV + or die "Usage: $0 /path/to/yajl\n"; + +my @files = glob "$yajl/test/parsing/cases/*.json"; + +my $caseFile = 'yajlTestCases.pm'; + +my @cases; + +for my $file (@files) { + $file =~ m|/([afn][cgmp]_)?([^/]*)\.json$|; + my $allow = $1; + my $name = $2; + next if $name eq ''; + + my $case = { name => $name }; + + if ($allow eq 'ac_') { + $case->{opts} = ['-c']; + } + elsif ($allow eq 'ag_') { + $case->{opts} = ['-g']; + } + elsif ($allow eq 'am_') { + $case->{opts} = ['-m']; + } + elsif ($allow eq 'ap_') { + $case->{opts} = ['-p']; + } + else { + $case->{opts} = []; + } + + my $input = slurp($file); + my @input = split "\n", $input; + push @input, '' if $input =~ m/\n$/; + $case->{input} = \@input; + + my @gives = split "\n", slurp("$file.gold"); + $case->{gives} = \@gives; + + push @cases, $case; +} + +# Configure Dumper() output +$Data::Dumper::Pad = ' '; +$Data::Dumper::Indent = 1; +$Data::Dumper::Useqq = 1; +$Data::Dumper::Quotekeys = 0; +$Data::Dumper::Sortkeys = sub { return ['name', 'opts', 'input', 'gives'] }; + +my $data = Dumper(\@cases); + +open my $out, '>', $caseFile + or die "Can't open/create $caseFile: $@\n"; +print $out <<"EOF"; +# Parser test cases from https://github.com/lloyd/yajl +# +# This file is generated, DO NOT EDIT! +# +# See comments in yajlTestConverter.pl for instructions on +# how to regenerate this file from the original yajl sources. + +sub cases { + my$data + return \@{\$VAR1}; +} + +1; +EOF + +close $out + or die "Problem writing $caseFile: $@\n"; + +exit 0; + + +sub slurp { + my ($file) = @_; + open my $in, '<', $file + or die "Can't open file $file: $!\n"; + my $contents = do { local $/; <$in> }; + return $contents; +} diff --git a/test/yajl_test.c b/test/yajl_test.c new file mode 100644 index 000000000..cacfdcb5c --- /dev/null +++ b/test/yajl_test.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2007-2014, Lloyd Hilaiel + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +#include + +/* memory debugging routines */ +typedef struct +{ + unsigned int numFrees; + unsigned int numMallocs; + /* XXX: we really need a hash table here with per-allocation + * information */ +} yajlTestMemoryContext; + +/* cast void * into context */ +#define TEST_CTX(vptr) ((yajlTestMemoryContext *) (vptr)) + +static void yajlTestFree(void * ctx, void * ptr) +{ + assert(ptr != NULL); + TEST_CTX(ctx)->numFrees++; + free(ptr); +} + +static void * yajlTestMalloc(void * ctx, size_t sz) +{ + assert(sz != 0); + TEST_CTX(ctx)->numMallocs++; + return malloc(sz); +} + +static void * yajlTestRealloc(void * ctx, void * ptr, size_t sz) +{ + if (ptr == NULL) { + assert(sz != 0); + TEST_CTX(ctx)->numMallocs++; + } else if (sz == 0) { + TEST_CTX(ctx)->numFrees++; + } + + return realloc(ptr, sz); +} + + +/* begin parsing callback routines */ +#define BUF_SIZE 2048 + +static int test_yajl_null(void *ctx) +{ + printf("null\n"); + return 1; +} + +static int test_yajl_boolean(void * ctx, int boolVal) +{ + printf("bool: %s\n", boolVal ? "true" : "false"); + return 1; +} + +static int test_yajl_integer(void *ctx, long long integerVal) +{ + printf("integer: %lld\n", integerVal); + return 1; +} + +static int test_yajl_double(void *ctx, double doubleVal) +{ + printf("double: %g\n", doubleVal); + return 1; +} + +static int test_yajl_string(void *ctx, const unsigned char * stringVal, + size_t stringLen) +{ + printf("string: '"); + fwrite(stringVal, 1, stringLen, stdout); + printf("'\n"); + return 1; +} + +static int test_yajl_map_key(void *ctx, const unsigned char * stringVal, + size_t stringLen) +{ + char * str = (char *) malloc(stringLen + 1); + str[stringLen] = 0; + memcpy(str, stringVal, stringLen); + printf("key: '%s'\n", str); + free(str); + return 1; +} + +static int test_yajl_start_map(void *ctx) +{ + printf("map open '{'\n"); + return 1; +} + + +static int test_yajl_end_map(void *ctx) +{ + printf("map close '}'\n"); + return 1; +} + +static int test_yajl_start_array(void *ctx) +{ + printf("array open '['\n"); + return 1; +} + +static int test_yajl_end_array(void *ctx) +{ + printf("array close ']'\n"); + return 1; +} + +static yajl_callbacks callbacks = { + test_yajl_null, + test_yajl_boolean, + test_yajl_integer, + test_yajl_double, + NULL, + test_yajl_string, + test_yajl_start_map, + test_yajl_map_key, + test_yajl_end_map, + test_yajl_start_array, + test_yajl_end_array +}; + +static void usage(const char * progname) +{ + fprintf(stderr, + "usage: %s [options]\n" + "Parse input from stdin as JSON and ouput parsing details " + "to stdout\n" + " -b set the read buffer size\n" + " -c allow comments\n" + " -g allow *g*arbage after valid JSON text\n" + " -h print this help message\n" + " -m allows the parser to consume multiple JSON values\n" + " from a single string separated by whitespace\n" + " -p partial JSON documents should not cause errors\n", + progname); + exit(1); +} + +int +main(int argc, char ** argv) +{ + yajl_handle hand; + const char * fileName = NULL; + static unsigned char * fileData = NULL; + FILE *file; + size_t bufSize = BUF_SIZE; + yajl_status stat; + size_t rd; + int i, j; + + /* memory allocation debugging: allocate a structure which collects + * statistics */ + yajlTestMemoryContext memCtx = { 0,0 }; + + /* memory allocation debugging: allocate a structure which holds + * allocation routines */ + yajl_alloc_funcs allocFuncs = { + yajlTestMalloc, + yajlTestRealloc, + yajlTestFree, + (void *) NULL + }; + + allocFuncs.ctx = (void *) &memCtx; + + /* allocate the parser */ + hand = yajl_alloc(&callbacks, &allocFuncs, NULL); + + /* check arguments. We expect exactly one! */ + for (i=1;i= argc) usage(argv[0]); + + /* validate integer */ + for (j=0;j<(int)strlen(argv[i]);j++) { + if (argv[i][j] <= '9' && argv[i][j] >= '0') continue; + fprintf(stderr, "-b requires an integer argument. '%s' " + "is invalid\n", argv[i]); + usage(argv[0]); + } + + bufSize = atoi(argv[i]); + if (!bufSize) { + fprintf(stderr, "%zu is an invalid buffer size\n", + bufSize); + } + } else if (!strcmp("-g", argv[i])) { + yajl_config(hand, yajl_allow_trailing_garbage, 1); + } else if (!strcmp("-h", argv[i])) { + usage(argv[0]); + } else if (!strcmp("-m", argv[i])) { + yajl_config(hand, yajl_allow_multiple_values, 1); + } else if (!strcmp("-p", argv[i])) { + yajl_config(hand, yajl_allow_partial_values, 1); + } else { + fileName = argv[i]; + break; + } + } + + fileData = (unsigned char *) malloc(bufSize); + + if (fileData == NULL) { + fprintf(stderr, + "failed to allocate read buffer of %zu bytes, exiting.", + bufSize); + yajl_free(hand); + exit(2); + } + + if (fileName) + { + file = fopen(fileName, "r"); + } + else + { + file = stdin; + } + for (;;) { + rd = fread((void *) fileData, 1, bufSize, file); + + if (rd == 0) { + if (!feof(file)) { + fprintf(stderr, "error reading from '%s'\n", fileName); + } + break; + } + /* read file data, now pass to parser */ + stat = yajl_parse(hand, fileData, rd); + + if (stat != yajl_status_ok) break; + } + + stat = yajl_complete_parse(hand); + if (stat != yajl_status_ok) + { + unsigned char * str = yajl_get_error(hand, 0, fileData, rd); + fflush(stdout); + fprintf(stderr, "%s", (char *) str); + yajl_free_error(hand, str); + } + + yajl_free(hand); + free(fileData); + + if (fileName) + { + fclose(file); + } + /* finally, print out some memory statistics */ + +/* (lth) only print leaks here, as allocations and frees may vary depending + * on read buffer size, causing false failures. + * + * printf("allocations:\t%u\n", memCtx.numMallocs); + * printf("frees:\t\t%u\n", memCtx.numFrees); +*/ + fflush(stderr); + fflush(stdout); + printf("memory leaks:\t%u\n", memCtx.numMallocs - memCtx.numFrees); + + return 0; +}