From de4394108312483a1c0739aeba4b80625ae70c22 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 22 May 2017 19:26:41 -0400 Subject: [PATCH 01/32] Upgrade yajl sources to 2.1.0 --- src/libCom/yajl/yajl.c | 132 ++++++++++-------- src/libCom/yajl/yajl_alloc.c | 48 +++---- src/libCom/yajl/yajl_alloc.h | 44 ++---- src/libCom/yajl/yajl_buf.c | 58 +++----- src/libCom/yajl/yajl_buf.h | 50 +++---- src/libCom/yajl/yajl_bytestack.h | 56 +++----- src/libCom/yajl/yajl_common.h | 51 +++---- src/libCom/yajl/yajl_encode.c | 119 +++++++++------- src/libCom/yajl/yajl_encode.h | 60 +++----- src/libCom/yajl/yajl_gen.c | 173 ++++++++++++----------- src/libCom/yajl/yajl_gen.h | 144 ++++++++++--------- src/libCom/yajl/yajl_lex.c | 172 +++++++++++++---------- src/libCom/yajl/yajl_lex.h | 56 +++----- src/libCom/yajl/yajl_parse.h | 181 ++++++++++++++---------- src/libCom/yajl/yajl_parser.c | 232 ++++++++++++++++++------------- src/libCom/yajl/yajl_parser.h | 66 +++++---- 16 files changed, 826 insertions(+), 816 deletions(-) diff --git a/src/libCom/yajl/yajl.c b/src/libCom/yajl/yajl.c index 063e8f8b9..54dffd11e 100644 --- a/src/libCom/yajl/yajl.c +++ b/src/libCom/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) @@ -88,61 +67,98 @@ yajl_alloc(const yajl_callbacks * callbacks, /* 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)); + } + 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/libCom/yajl/yajl_alloc.c b/src/libCom/yajl/yajl_alloc.c index 2f6e5650c..5b2601685 100644 --- a/src/libCom/yajl/yajl_alloc.c +++ b/src/libCom/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/libCom/yajl/yajl_alloc.h b/src/libCom/yajl/yajl_alloc.h index 3935eef58..471f76f66 100644 --- a/src/libCom/yajl/yajl_alloc.h +++ b/src/libCom/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/libCom/yajl/yajl_buf.c b/src/libCom/yajl/yajl_buf.c index 132633c9a..4b14d9acd 100644 --- a/src/libCom/yajl/yajl_buf.c +++ b/src/libCom/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); @@ -85,7 +69,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 +91,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/libCom/yajl/yajl_buf.h b/src/libCom/yajl/yajl_buf.h index a6dcbe9a5..0ae73aa35 100644 --- a/src/libCom/yajl/yajl_buf.h +++ b/src/libCom/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/libCom/yajl/yajl_bytestack.h b/src/libCom/yajl/yajl_bytestack.h index 3b49d17f9..d75e456b4 100644 --- a/src/libCom/yajl/yajl_bytestack.h +++ b/src/libCom/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/libCom/yajl/yajl_common.h b/src/libCom/yajl/yajl_common.h index b9badbf1e..096cf37a0 100644 --- a/src/libCom/yajl/yajl_common.h +++ b/src/libCom/yajl/yajl_common.h @@ -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. + */ #ifndef __YAJL_COMMON_H__ #define __YAJL_COMMON_H__ +#include #include #ifdef __cplusplus @@ -45,14 +30,14 @@ extern "C" { /** 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 +56,6 @@ typedef struct #ifdef __cplusplus } -#endif +#endif #endif diff --git a/src/libCom/yajl/yajl_encode.c b/src/libCom/yajl/yajl_encode.c index d6f9dc0fe..980021ee5 100644 --- a/src/libCom/yajl/yajl_encode.c +++ b/src/libCom/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/libCom/yajl/yajl_encode.h b/src/libCom/yajl/yajl_encode.h index 3e3b0923d..28d63958c 100644 --- a/src/libCom/yajl/yajl_encode.h +++ b/src/libCom/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/libCom/yajl/yajl_gen.c b/src/libCom/yajl/yajl_gen.c index 8d93e2726..7f669247d 100644 --- a/src/libCom/yajl/yajl_gen.c +++ b/src/libCom/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/libCom/yajl/yajl_gen.h b/src/libCom/yajl/yajl_gen.h index 34b147596..3ea05e555 100644 --- a/src/libCom/yajl/yajl_gen.h +++ b/src/libCom/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/libCom/yajl/yajl_lex.c b/src/libCom/yajl/yajl_lex.c index 3abd21698..c69e593e3 100644 --- a/src/libCom/yajl/yajl_lex.c +++ b/src/libCom/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; @@ -139,15 +123,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 +143,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 +151,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 +194,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 +248,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 +370,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 +457,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 +498,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; @@ -707,23 +733,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/libCom/yajl/yajl_lex.h b/src/libCom/yajl/yajl_lex.h index 559e54dba..40c434427 100644 --- a/src/libCom/yajl/yajl_lex.h +++ b/src/libCom/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/libCom/yajl/yajl_parse.h b/src/libCom/yajl/yajl_parse.h index a70a8fd56..f113c7cf4 100644 --- a/src/libCom/yajl/yajl_parse.h +++ b/src/libCom/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/libCom/yajl/yajl_parser.c b/src/libCom/yajl/yajl_parser.c index bbcf80880..15685ed79 100644 --- a/src/libCom/yajl/yajl_parser.c +++ b/src/libCom/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,50 @@ #include #define epicsExportSharedSymbols +#include "yajl_parse.h" #include "yajl_lex.h" #include "yajl_parser.h" #include "yajl_encode.h" #include "yajl_bytestack.h" +#define MAX_VALUE_TO_MULTIPLY ((LLONG_MAX / 10) + (LLONG_MAX % 10)) + + /* same semantics as strtol */ +long long +yajl_parse_integer(const unsigned char *number, unsigned int 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 +80,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 +152,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 +231,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,13 +250,13 @@ 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)); } @@ -215,29 +274,14 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, 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, @@ -291,13 +335,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_bracket: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "unallowed token at this point in JSON text"; @@ -310,11 +354,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 +368,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 +377,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; @@ -360,7 +404,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, _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); @@ -375,9 +419,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; @@ -397,19 +441,19 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, _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; @@ -425,12 +469,12 @@ 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; 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,7 +486,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, } } } - + abort(); return yajl_status_error; } diff --git a/src/libCom/yajl/yajl_parser.h b/src/libCom/yajl/yajl_parser.h index 2d59882a3..4b4b9352a 100644 --- a/src/libCom/yajl/yajl_parser.h +++ b/src/libCom/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, unsigned int length); #endif From 70a46e9c2cd37dcc062a481b94afcbe47bad03e9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 22 May 2017 22:01:24 -0400 Subject: [PATCH 02/32] Adjust IOC code for yajl-2.1.0 API --- src/ioc/db/dbChannel.c | 23 +++++++++-------------- src/ioc/db/dbConvertJSON.c | 35 ++++++++++++++--------------------- src/ioc/db/dbJLink.c | 27 +++++++++++---------------- 3 files changed, 34 insertions(+), 51 deletions(-) diff --git a/src/ioc/db/dbChannel.c b/src/ioc/db/dbChannel.c index 5ce1be4ef..e16f8e740 100644 --- a/src/ioc/db/dbChannel.c +++ b/src/ioc/db/dbChannel.c @@ -107,7 +107,7 @@ static int chf_boolean(void * ctx, int boolVal) return result; } -static int chf_integer(void * ctx, long integerVal) +static int chf_integer(void * ctx, long long integerVal) { parseContext *parser = (parseContext *) ctx; chFilter *filter = parser->filter; @@ -132,7 +132,7 @@ static int chf_double(void * ctx, double doubleVal) } static int chf_string(void * ctx, const unsigned char * stringVal, - unsigned int stringLen) + size_t stringLen) { parseContext *parser = (parseContext *) ctx; chFilter *filter = parser->filter; @@ -159,7 +159,7 @@ static int chf_start_map(void * ctx) } static int chf_map_key(void * ctx, const unsigned char * key, - unsigned int stringLen) + size_t stringLen) { parseContext *parser = (parseContext *) ctx; chFilter *filter = parser->filter; @@ -243,15 +243,12 @@ static const yajl_callbacks chf_callbacks = { chf_null, chf_boolean, chf_integer, chf_double, NULL, chf_string, chf_start_map, chf_map_key, chf_end_map, chf_start_array, chf_end_array }; -static const yajl_parser_config chf_config = - { 0, 1 }; /* allowComments = NO , checkUTF8 = YES */ - -static void * chf_malloc(void *ctx, unsigned int sz) +static void * chf_malloc(void *ctx, size_t sz) { return malloc(sz); } -static void * chf_realloc(void *ctx, void *ptr, unsigned int sz) +static void * chf_realloc(void *ctx, void *ptr, size_t sz) { return realloc(ptr, sz); } @@ -261,14 +258,14 @@ static void chf_free(void *ctx, void *ptr) free(ptr); } -static const yajl_alloc_funcs chf_alloc = +static yajl_alloc_funcs chf_alloc = { chf_malloc, chf_realloc, chf_free }; static long chf_parse(dbChannel *chan, const char **pjson) { parseContext parser = { chan, NULL, 0 }; - yajl_handle yh = yajl_alloc(&chf_callbacks, &chf_config, &chf_alloc, &parser); + yajl_handle yh = yajl_alloc(&chf_callbacks, &chf_alloc, &parser); const char *json = *pjson; size_t jlen = strlen(json); yajl_status ys; @@ -277,9 +274,7 @@ static long chf_parse(dbChannel *chan, const char **pjson) if (!yh) return S_db_noMemory; - ys = yajl_parse(yh, (const unsigned char *) json, (unsigned int) jlen); - if (ys == yajl_status_insufficient_data) - ys = yajl_parse_complete(yh); + ys = yajl_parse(yh, (const unsigned char *) json, jlen); switch (ys) { case yajl_status_ok: @@ -290,7 +285,7 @@ static long chf_parse(dbChannel *chan, const char **pjson) case yajl_status_error: { unsigned char *err; - err = yajl_get_error(yh, 1, (const unsigned char *) json, (unsigned int) jlen); + err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen); printf("dbChannelCreate: %s\n", err); yajl_free_error(yh, err); } /* fall through */ diff --git a/src/ioc/db/dbConvertJSON.c b/src/ioc/db/dbConvertJSON.c index e2a453549..c9a7d449d 100644 --- a/src/ioc/db/dbConvertJSON.c +++ b/src/ioc/db/dbConvertJSON.c @@ -37,20 +37,20 @@ static int dbcj_boolean(void *ctx, int val) { return 0; /* Illegal */ } -static int dbcj_integer(void *ctx, long num) { +static int dbcj_integer(void *ctx, long long num) { parseContext *parser = (parseContext *) ctx; - epicsInt32 val32 = num; - FASTCONVERT conv = dbFastPutConvertRoutine[DBF_LONG][parser->dbrType]; + epicsInt64 val64 = num; + FASTCONVERT conv = dbFastPutConvertRoutine[DBF_INT64][parser->dbrType]; if (parser->elems > 0) { - conv(&val32, parser->pdest, NULL); + conv(&val64, parser->pdest, NULL); parser->pdest += parser->dbrSize; parser->elems--; } return 1; } -static int dblsj_integer(void *ctx, long num) { +static int dblsj_integer(void *ctx, long long num) { return 0; /* Illegal */ } @@ -70,7 +70,7 @@ static int dblsj_double(void *ctx, double num) { return 0; /* Illegal */ } -static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) { +static int dbcj_string(void *ctx, const unsigned char *val, size_t len) { parseContext *parser = (parseContext *) ctx; char *pdest = parser->pdest; @@ -93,7 +93,7 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) { return 1; } -static int dblsj_string(void *ctx, const unsigned char *val, unsigned int len) { +static int dblsj_string(void *ctx, const unsigned char *val, size_t len) { parseContext *parser = (parseContext *) ctx; char *pdest = parser->pdest; @@ -118,7 +118,7 @@ static int dbcj_start_map(void *ctx) { return 0; /* Illegal */ } -static int dbcj_map_key(void *ctx, const unsigned char *key, unsigned int len) { +static int dbcj_map_key(void *ctx, const unsigned char *key, size_t len) { return 0; /* Illegal */ } @@ -149,9 +149,6 @@ static yajl_callbacks dbcj_callbacks = { dbcj_start_array, dbcj_end_array }; -static const yajl_parser_config dbcj_config = - { 0, 0 }; /* allowComments = NO, checkUTF8 = NO */ - long dbPutConvertJSON(const char *json, short dbrType, void *pdest, long *pnRequest) { @@ -169,13 +166,11 @@ long dbPutConvertJSON(const char *json, short dbrType, parser->elems = *pnRequest; yajl_set_default_alloc_funcs(&dbcj_alloc); - yh = yajl_alloc(&dbcj_callbacks, &dbcj_config, &dbcj_alloc, parser); + yh = yajl_alloc(&dbcj_callbacks, &dbcj_alloc, parser); if (!yh) return S_db_noMemory; - ys = yajl_parse(yh, (const unsigned char *) json, (unsigned int) jlen); - if (ys == yajl_status_insufficient_data) - ys = yajl_parse_complete(yh); + ys = yajl_parse(yh, (const unsigned char *) json, jlen); switch (ys) { case yajl_status_ok: @@ -185,7 +180,7 @@ long dbPutConvertJSON(const char *json, short dbrType, case yajl_status_error: { unsigned char *err = yajl_get_error(yh, 1, - (const unsigned char *) json, (unsigned int) jlen); + (const unsigned char *) json, jlen); fprintf(stderr, "dbConvertJSON: %s\n", err); yajl_free_error(yh, err); } @@ -227,13 +222,11 @@ long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size, parser->elems = 1; yajl_set_default_alloc_funcs(&dbcj_alloc); - yh = yajl_alloc(&dblsj_callbacks, &dbcj_config, &dbcj_alloc, parser); + yh = yajl_alloc(&dblsj_callbacks, &dbcj_alloc, parser); if (!yh) return S_db_noMemory; - ys = yajl_parse(yh, (const unsigned char *) json, (unsigned int) jlen); - if (ys == yajl_status_insufficient_data) - ys = yajl_parse_complete(yh); + ys = yajl_parse(yh, (const unsigned char *) json, jlen); switch (ys) { case yajl_status_ok: @@ -243,7 +236,7 @@ long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size, case yajl_status_error: { unsigned char *err = yajl_get_error(yh, 1, - (const unsigned char *) json, (unsigned int) jlen); + (const unsigned char *) json, jlen); fprintf(stderr, "dbLoadLS_JSON: %s\n", err); yajl_free_error(yh, err); } diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index b68432f6e..109785b6d 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -112,12 +112,12 @@ static int dbjl_boolean(void *ctx, int val) { CALL_OR_STOP(pjlink->pif->parse_boolean)(pjlink, val)); } -static int dbjl_integer(void *ctx, long num) { +static int dbjl_integer(void *ctx, long long num) { parseContext *parser = (parseContext *) ctx; jlink *pjlink = parser->pjlink; IFDEBUG(10) - printf("dbjl_integer(%s@%p, %ld)\n", + printf("dbjl_integer(%s@%p, %lld)\n", pjlink->pif->name, pjlink, num); assert(pjlink); @@ -138,13 +138,13 @@ static int dbjl_double(void *ctx, double num) { CALL_OR_STOP(pjlink->pif->parse_double)(pjlink, num)); } -static int dbjl_string(void *ctx, const unsigned char *val, unsigned len) { +static int dbjl_string(void *ctx, const unsigned char *val, size_t len) { parseContext *parser = (parseContext *) ctx; jlink *pjlink = parser->pjlink; IFDEBUG(10) printf("dbjl_string(%s@%p, \"%.*s\")\n", - pjlink->pif->name, pjlink, len, val); + pjlink->pif->name, pjlink, (int) len, val); assert(pjlink); return dbjl_value(parser, @@ -190,7 +190,7 @@ static int dbjl_start_map(void *ctx) { return dbjl_return(parser, result); } -static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) { +static int dbjl_map_key(void *ctx, const unsigned char *key, size_t len) { parseContext *parser = (parseContext *) ctx; jlink *pjlink = parser->pjlink; char *link_name; @@ -200,13 +200,13 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) { if (!parser->key_is_link) { if (!pjlink) { errlogPrintf("dbJLinkInit: Illegal second link key '%.*s'\n", - len, key); + (int) len, key); return dbjl_return(parser, jlif_stop); } IFDEBUG(10) { printf("dbjl_map_key(%s@%p, \"%.*s\")\t", - pjlink->pif->name, pjlink, len, key); + pjlink->pif->name, pjlink, (int) len, key); printf(" jsonDepth=%d, parseDepth=%d, key_is_link=%d\n", parser->jsonDepth, pjlink ? pjlink->parseDepth : 0, parser->key_is_link); } @@ -218,7 +218,7 @@ static int dbjl_map_key(void *ctx, const unsigned char *key, unsigned len) { } IFDEBUG(10) { - printf("dbjl_map_key(NULL, \"%.*s\")\t", len, key); + printf("dbjl_map_key(NULL, \"%.*s\")\t", (int) len, key); printf(" jsonDepth=%d, parseDepth=00, key_is_link=%d\n", parser->jsonDepth, parser->key_is_link); } @@ -334,9 +334,6 @@ static yajl_callbacks dbjl_callbacks = { dbjl_start_map, dbjl_map_key, dbjl_end_map, dbjl_start_array, dbjl_end_array }; -static const yajl_parser_config dbjl_config = - { 0, 0 }; /* allowComments = NO, checkUTF8 = NO */ - long dbJLinkParse(const char *json, size_t jlen, short dbfType, jlink **ppjlink, unsigned opts) { @@ -363,13 +360,11 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, parser->jsonDepth, parser->key_is_link); yajl_set_default_alloc_funcs(&dbjl_allocs); - yh = yajl_alloc(&dbjl_callbacks, &dbjl_config, &dbjl_allocs, parser); + yh = yajl_alloc(&dbjl_callbacks, &dbjl_allocs, parser); if (!yh) return S_db_noMemory; - ys = yajl_parse(yh, (const unsigned char *) json, (unsigned) jlen); - if (ys == yajl_status_insufficient_data) - ys = yajl_parse_complete(yh); + ys = yajl_parse(yh, (const unsigned char *) json, jlen); switch (ys) { unsigned char *err; @@ -381,7 +376,7 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, break; case yajl_status_error: - err = yajl_get_error(yh, 1, (const unsigned char *) json, (unsigned) jlen); + err = yajl_get_error(yh, 1, (const unsigned char *) json, jlen); errlogPrintf("dbJLinkInit: %s\n", err); yajl_free_error(yh, err); dbJLinkFree(parser->pjlink); From 80fa616a868505bab2810f759c7973d7558231cc Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 23 May 2017 21:19:14 -0400 Subject: [PATCH 03/32] Convert lnkConst to 64 bit integers --- src/std/link/lnkConst.c | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/std/link/lnkConst.c b/src/std/link/lnkConst.c index db824abbc..b8828fa0d 100644 --- a/src/std/link/lnkConst.c +++ b/src/std/link/lnkConst.c @@ -29,13 +29,13 @@ typedef long (*FASTCONVERT)(); typedef struct const_link { jlink jlink; /* embedded object */ int nElems; - enum {s0, si32, sf64, sc40, a0, ai32, af64, ac40} type; + enum {s0, si64, sf64, sc40, a0, ai64, af64, ac40} type; union { - epicsInt32 scalar_integer; /* si32 */ + epicsInt64 scalar_integer; /* si64 */ epicsFloat64 scalar_double; /* sf64 */ char *scalar_string; /* sc40 */ void *pmem; - epicsInt32 *pintegers; /* ai32 */ + epicsInt64 *pintegers; /* ai64 */ epicsFloat64 *pdoubles; /* af64 */ char **pstrings; /* ac40 */ } value; @@ -77,13 +77,13 @@ static void lnkConst_free(jlink *pjlink) free(clink->value.pstrings[i]); /* fall through */ case sc40: - case ai32: + case ai64: case af64: free(clink->value.pmem); break; case s0: case a0: - case si32: + case si64: case sf64: break; } @@ -102,15 +102,15 @@ static jlif_result lnkConst_integer(jlink *pjlink, long long num) void *buf; case s0: - clink->type = si32; + clink->type = si64; clink->value.scalar_integer = num; break; case a0: - clink->type = ai32; + clink->type = ai64; /* fall through */ - case ai32: - buf = realloc(clink->value.pmem, newElems * sizeof(epicsInt32)); + case ai64: + buf = realloc(clink->value.pmem, newElems * sizeof(epicsInt64)); if (!buf) return jlif_stop; @@ -176,7 +176,7 @@ static jlif_result lnkConst_double(jlink *pjlink, double num) clink->value.pdoubles = f64buf; break; - case ai32: /* promote earlier ai32 values to af64 */ + case ai64: /* promote earlier ai64 values to af64 */ f64buf = calloc(newElems, sizeof(epicsFloat64)); if (!f64buf) return jlif_stop; @@ -241,7 +241,7 @@ static jlif_result lnkConst_string(jlink *pjlink, const char *val, size_t len) break; case af64: - case ai32: + case ai64: errlogPrintf("lnkConst: Mixed data types in array\n"); /* fall thorough */ default: @@ -328,10 +328,10 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent) int i; switch (clink->type) { - case ai32: - printf("\n%*s[%d", indent+2, "", clink->value.pintegers[0]); + case ai64: + printf("\n%*s[%lld", indent+2, "", clink->value.pintegers[0]); for (i = 1; i < clink->nElems; i++) { - printf(", %d", clink->value.pintegers[i]); + printf(", %lld", clink->value.pintegers[i]); } break; case af64: @@ -357,8 +357,8 @@ static void lnkConst_report(const jlink *pjlink, int level, int indent) printf("%*s'const': %s", indent, "", dtype); switch (clink->type) { - case si32: - printf(" %d\n", clink->value.scalar_integer); + case si64: + printf(" %lld\n", clink->value.scalar_integer); return; case sf64: printf(" %g\n", clink->value.scalar_double); @@ -394,8 +394,8 @@ static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer clink, dbrType, pbuffer); switch (clink->type) { - case si32: - status = dbFastPutConvertRoutine[DBF_LONG][dbrType] + case si64: + status = dbFastPutConvertRoutine[DBF_INT64][dbrType] (&clink->value.scalar_integer, pbuffer, NULL); break; @@ -409,8 +409,8 @@ static long lnkConst_loadScalar(struct link *plink, short dbrType, void *pbuffer (clink->value.scalar_string, pbuffer, NULL); break; - case ai32: - status = dbFastPutConvertRoutine[DBF_LONG][dbrType] + case ai64: + status = dbFastPutConvertRoutine[DBF_INT64][dbrType] (clink->value.pintegers, pbuffer, NULL); break; @@ -483,8 +483,8 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer, switch (clink->type) { int i; - case si32: - status = dbFastPutConvertRoutine[DBF_LONG][dbrType] + case si64: + status = dbFastPutConvertRoutine[DBF_INT64][dbrType] (&clink->value.scalar_integer, pdest, NULL); break; @@ -498,8 +498,8 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer, (clink->value.scalar_string, pbuffer, NULL); break; - case ai32: - conv = dbFastPutConvertRoutine[DBF_LONG][dbrType]; + case ai64: + conv = dbFastPutConvertRoutine[DBF_INT64][dbrType]; for (i = 0; i < nElems; i++) { conv(&clink->value.pintegers[i], pdest, NULL); pdest += dbrSize; From 7980d78908f8a1b2af1bd1cea66ac7d8040404df Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 23 May 2017 21:20:45 -0400 Subject: [PATCH 04/32] Add tests for 64-bit constant link initializers --- src/std/rec/test/linkInitTest.c | 20 +++++++++++++++++++- src/std/rec/test/linkInitTest.db | 16 ++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/std/rec/test/linkInitTest.c b/src/std/rec/test/linkInitTest.c index cf279b5aa..7225beb1c 100644 --- a/src/std/rec/test/linkInitTest.c +++ b/src/std/rec/test/linkInitTest.c @@ -210,16 +210,34 @@ static void testEventRecord() testdbCleanup(); } +void testInt64Inputs(void) +{ + testDiag("testInt64Inputs"); + + startTestIoc("linkInitTest.db"); + + testdbGetFieldEqual("i1.VAL", DBR_INT64, 1234567890123456789LL); + testdbGetFieldEqual("i2.VAL", DBR_INT64, 1234567890123456789LL); + testdbGetFieldEqual("i3.VAL", DBR_INT64, 1234567890123456789LL); + + testdbGetFieldEqual("i4.NORD", DBR_LONG, 1); + testdbGetFieldEqual("i4.VAL", DBR_INT64, 1234567890123456789LL); + + testIocShutdownOk(); + testdbCleanup(); +} + MAIN(linkInitTest) { - testPlan(72); + testPlan(77); testLongStringInit(); testCalcInit(); testPrintfStrings(); testArrayInputs(); testEventRecord(); + testInt64Inputs(); return testDone(); } diff --git a/src/std/rec/test/linkInitTest.db b/src/std/rec/test/linkInitTest.db index 701490073..99bc0ccfb 100644 --- a/src/std/rec/test/linkInitTest.db +++ b/src/std/rec/test/linkInitTest.db @@ -88,3 +88,19 @@ record(event, "ev1") { record(event, "ev2") { field(INP, "count1.EVNT") } + +record(int64in, "i1") { + field(INP, [1234567890123456789,0]) +} +record(int64in, "i2") { + field(INP, {const:1234567890123456789}) +} +record(int64in, "i3") { + field(INP, 1234567890123456789) +} +record(waveform, "i4") { + field(NELM, 1) + field(FTVL, "INT64") + field(INP, [1234567890123456789,0]) +} + From e1ba1c6bba9dc89a260c12ec45a89d9154ec11b3 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 5 Jun 2017 12:01:37 -0500 Subject: [PATCH 05/32] Fix YAJL token names, brace <=> bracket This breaks future updates from upstream, but it looks like the original author has abandoned the project anyway. --- src/libCom/yajl/yajl_lex.c | 14 +++++++------- src/libCom/yajl/yajl_parser.c | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libCom/yajl/yajl_lex.c b/src/libCom/yajl/yajl_lex.c index c69e593e3..80d713641 100644 --- a/src/libCom/yajl/yajl_lex.c +++ b/src/libCom/yajl/yajl_lex.c @@ -520,17 +520,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; diff --git a/src/libCom/yajl/yajl_parser.c b/src/libCom/yajl/yajl_parser.c index 15685ed79..d4b499bfb 100644 --- a/src/libCom/yajl/yajl_parser.c +++ b/src/libCom/yajl/yajl_parser.c @@ -261,13 +261,13 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, _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)); } @@ -325,7 +325,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, } } break; - case yajl_tok_right_brace: { + case yajl_tok_right_bracket: { if (yajl_bs_current(hand->stateStack) == yajl_state_array_start) { @@ -341,7 +341,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, } case yajl_tok_colon: case yajl_tok_comma: - case yajl_tok_right_bracket: + case yajl_tok_right_brace: yajl_bs_set(hand->stateStack, yajl_state_parse_error); hand->parseError = "unallowed token at this point in JSON text"; @@ -396,7 +396,7 @@ 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: + case yajl_tok_right_brace: if (yajl_bs_current(hand->stateStack) == yajl_state_map_start) { @@ -436,7 +436,7 @@ 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)); } @@ -464,7 +464,7 @@ 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)); } From 4c6b570a465f8131ff00fd3988f04638b04fcca0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 5 Jun 2017 12:49:26 -0500 Subject: [PATCH 06/32] Permit trailing commas in JSON maps & arrays Handled in both dbYacc and yajl parsers. Adds tests to linkInitTest. --- src/ioc/dbStatic/dbYacc.y | 23 ++++++++++++++++------- src/libCom/yajl/yajl_parser.c | 17 +++++++++-------- src/std/rec/test/linkInitTest.db | 6 +++--- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/ioc/dbStatic/dbYacc.y b/src/ioc/dbStatic/dbYacc.y index e61ce58b0..9dc8c5081 100644 --- a/src/ioc/dbStatic/dbYacc.y +++ b/src/ioc/dbStatic/dbYacc.y @@ -4,7 +4,7 @@ * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ %{ static int yyerror(); @@ -97,7 +97,7 @@ choice: tokenCHOICE '(' tokenSTRING ',' tokenSTRING ')' { if(dbStaticDebug>2) printf("choice %s %s\n",$3,$5); dbMenuChoice($3,$5); dbmfFree($3); dbmfFree($5); -} +} | include; recordtype_head: '(' tokenSTRING ')' @@ -139,12 +139,12 @@ recordtype_field_body: '{' recordtype_field_item_list '}' ; recordtype_field_item_list: recordtype_field_item_list recordtype_field_item | recordtype_field_item; -recordtype_field_item: tokenSTRING '(' tokenSTRING ')' +recordtype_field_item: tokenSTRING '(' tokenSTRING ')' { if(dbStaticDebug>2) printf("recordtype_field_item %s %s\n",$1,$3); dbRecordtypeFieldItem($1,$3); dbmfFree($1); dbmfFree($3); } - | tokenMENU '(' tokenSTRING ')' + | tokenMENU '(' tokenSTRING ')' { if(dbStaticDebug>2) printf("recordtype_field_item %s (%s)\n","menu",$3); @@ -154,7 +154,7 @@ recordtype_field_item: tokenSTRING '(' tokenSTRING ')' device: tokenDEVICE '(' tokenSTRING ',' tokenSTRING ',' tokenSTRING ',' tokenSTRING ')' -{ +{ if(dbStaticDebug>2) printf("device %s %s %s %s\n",$3,$5,$7,$9); dbDevice($3,$5,$7,$9); dbmfFree($3); dbmfFree($5); @@ -290,6 +290,7 @@ json_object: '{' '}' }; json_members: json_pair + | json_pair ',' | json_pair ',' json_members { $$ = dbmfStrcat3($1, ",", $3); @@ -325,6 +326,14 @@ json_array: '[' ']' }; json_elements: json_value + | json_value ',' +{ /* Retain the trailing ',' so link parser can distinguish a + * 1-element const list from a PV name (commas are illegal) + */ + $$ = dbmfStrcat3($1, ",", ""); + dbmfFree($1); + if (dbStaticDebug>2) printf("json %s\n", $$); +}; | json_value ',' json_elements { $$ = dbmfStrcat3($1, ",", $3); @@ -342,7 +351,7 @@ json_value: jsonNULL { $$ = dbmfStrdup("null"); } %% - + #include "dbLex.c" @@ -363,7 +372,7 @@ static long pvt_yy_parse(void) { static int FirstFlag = 1; long rtnval; - + if (!FirstFlag) { yyAbort = FALSE; yyFailed = FALSE; diff --git a/src/libCom/yajl/yajl_parser.c b/src/libCom/yajl/yajl_parser.c index d4b499bfb..867108418 100644 --- a/src/libCom/yajl/yajl_parser.c +++ b/src/libCom/yajl/yajl_parser.c @@ -326,8 +326,9 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, } break; case yajl_tok_right_bracket: { - if (yajl_bs_current(hand->stateStack) == - yajl_state_array_start) + 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) @@ -396,20 +397,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_brace: - 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; } + } 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; } } @@ -490,4 +492,3 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, abort(); return yajl_status_error; } - diff --git a/src/std/rec/test/linkInitTest.db b/src/std/rec/test/linkInitTest.db index 99bc0ccfb..2dee3faf5 100644 --- a/src/std/rec/test/linkInitTest.db +++ b/src/std/rec/test/linkInitTest.db @@ -90,10 +90,10 @@ record(event, "ev2") { } record(int64in, "i1") { - field(INP, [1234567890123456789,0]) + field(INP, [1234567890123456789,]) } record(int64in, "i2") { - field(INP, {const:1234567890123456789}) + field(INP, {const:1234567890123456789,}) } record(int64in, "i3") { field(INP, 1234567890123456789) @@ -101,6 +101,6 @@ record(int64in, "i3") { record(waveform, "i4") { field(NELM, 1) field(FTVL, "INT64") - field(INP, [1234567890123456789,0]) + field(INP, [1234567890123456789,]) } From 08ad4de16188ab08589dd41a596f1bcc5e964eec Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 24 Jun 2017 01:20:39 -0500 Subject: [PATCH 07/32] yajl: Out-of-memory handling; another size_t --- src/libCom/yajl/yajl.c | 6 ++++++ src/libCom/yajl/yajl_buf.c | 4 ++++ src/libCom/yajl/yajl_lex.c | 4 ++++ src/libCom/yajl/yajl_parser.c | 2 +- src/libCom/yajl/yajl_parser.h | 2 +- 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/libCom/yajl/yajl.c b/src/libCom/yajl/yajl.c index 54dffd11e..6c4977598 100644 --- a/src/libCom/yajl/yajl.c +++ b/src/libCom/yajl/yajl.c @@ -63,6 +63,9 @@ 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)); @@ -127,6 +130,9 @@ yajl_parse(yajl_handle hand, const unsigned char * jsonText, 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; diff --git a/src/libCom/yajl/yajl_buf.c b/src/libCom/yajl/yajl_buf.c index 4b14d9acd..0f9c28046 100644 --- a/src/libCom/yajl/yajl_buf.c +++ b/src/libCom/yajl/yajl_buf.c @@ -57,6 +57,10 @@ void yajl_buf_ensure_available(yajl_buf buf, size_t 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; diff --git a/src/libCom/yajl/yajl_lex.c b/src/libCom/yajl/yajl_lex.c index 80d713641..0159cfa55 100644 --- a/src/libCom/yajl/yajl_lex.c +++ b/src/libCom/yajl/yajl_lex.c @@ -106,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; diff --git a/src/libCom/yajl/yajl_parser.c b/src/libCom/yajl/yajl_parser.c index 867108418..b1d75fe55 100644 --- a/src/libCom/yajl/yajl_parser.c +++ b/src/libCom/yajl/yajl_parser.c @@ -34,7 +34,7 @@ /* same semantics as strtol */ long long -yajl_parse_integer(const unsigned char *number, unsigned int length) +yajl_parse_integer(const unsigned char *number, size_t length) { long long ret = 0; long sign = 1; diff --git a/src/libCom/yajl/yajl_parser.h b/src/libCom/yajl/yajl_parser.h index 4b4b9352a..bd5a74dfd 100644 --- a/src/libCom/yajl/yajl_parser.h +++ b/src/libCom/yajl/yajl_parser.h @@ -72,7 +72,7 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, /* 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, unsigned int length); +yajl_parse_integer(const unsigned char *number, size_t length); #endif From c288de3bf2802b1fd1b0d928315d4e44c7b1dccf Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 26 Jun 2017 00:40:17 -0500 Subject: [PATCH 08/32] Add yajl parser tests yajl_test.c is the test runner, from the yajl distribution. The yajlTestConverter.pl script converts the yajl distribution's test case files into a data structure in yajlTestCases.pm. yajlTest.plt is a test director which reads the test cases from yajlTestCases.pm and runs them through the yajl_test program. --- src/libCom/test/Makefile | 4 + src/libCom/test/yajlTest.plt | 51 + src/libCom/test/yajlTestCases.pm | 3046 ++++++++++++++++++++++++++ src/libCom/test/yajlTestConverter.pl | 98 + src/libCom/test/yajl_test.c | 294 +++ 5 files changed, 3493 insertions(+) create mode 100644 src/libCom/test/yajlTest.plt create mode 100644 src/libCom/test/yajlTestCases.pm create mode 100755 src/libCom/test/yajlTestConverter.pl create mode 100644 src/libCom/test/yajl_test.c diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index 04438854c..e07360ac9 100755 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -215,6 +215,10 @@ ipAddrToAsciiTest_SRCS += ipAddrToAsciiTest.cpp testHarness_SRCS += ipAddrToAsciiTest.cpp TESTS += ipAddrToAsciiTest +TESTPROD_HOST += yajl_test +yajl_test_SRCS += yajl_test.c +TESTS += yajlTest + # The testHarness runs all the test programs in a known working order. testHarness_SRCS += epicsRunLibComTests.c diff --git a/src/libCom/test/yajlTest.plt b/src/libCom/test/yajlTest.plt new file mode 100644 index 000000000..5c9052032 --- /dev/null +++ b/src/libCom/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/src/libCom/test/yajlTestCases.pm b/src/libCom/test/yajlTestCases.pm new file mode 100644 index 000000000..9064df043 --- /dev/null +++ b/src/libCom/test/yajlTestCases.pm @@ -0,0 +1,3046 @@ +# 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 => "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/src/libCom/test/yajlTestConverter.pl b/src/libCom/test/yajlTestConverter.pl new file mode 100755 index 000000000..c3d2b54b6 --- /dev/null +++ b/src/libCom/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/src/libCom/test/yajl_test.c b/src/libCom/test/yajl_test.c new file mode 100644 index 000000000..c07210ac2 --- /dev/null +++ b/src/libCom/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(stdin)) { + 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; +} From 50028f2eda04afb25d9e5882898c678f08bbfb89 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 26 Jun 2017 23:32:10 -0500 Subject: [PATCH 09/32] Fix yajl_test bug Test program doesn't always read from stdin, although in both the original and the EPICS test director it does. --- src/libCom/test/yajl_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/test/yajl_test.c b/src/libCom/test/yajl_test.c index c07210ac2..cacfdcb5c 100644 --- a/src/libCom/test/yajl_test.c +++ b/src/libCom/test/yajl_test.c @@ -251,7 +251,7 @@ main(int argc, char ** argv) rd = fread((void *) fileData, 1, bufSize, file); if (rd == 0) { - if (!feof(stdin)) { + if (!feof(file)) { fprintf(stderr, "error reading from '%s'\n", fileName); } break; From 7a571989f85c4c1d900edc448344ea91ceec392a Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 26 Jun 2017 23:34:07 -0500 Subject: [PATCH 10/32] Add yajl test for trailing commas in arrays and maps --- src/libCom/test/yajlTestCases.pm | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libCom/test/yajlTestCases.pm b/src/libCom/test/yajlTestCases.pm index 9064df043..40eaff6e7 100644 --- a/src/libCom/test/yajlTestCases.pm +++ b/src/libCom/test/yajlTestCases.pm @@ -3000,6 +3000,29 @@ sub cases { "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 => [], From 78abb258847accb3d893863e486a16657533fbf0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 28 Aug 2017 22:36:25 -0500 Subject: [PATCH 11/32] Add osiSockOptMcastLoop_t and osiSockTest --- src/ca/client/udpiiu.cpp | 2 +- src/ioc/rsrv/caservertask.c | 2 +- src/libCom/osi/os/Darwin/osdSock.h | 1 + src/libCom/osi/os/Linux/osdSock.h | 1 + src/libCom/osi/os/RTEMS/osdSock.h | 1 + src/libCom/osi/os/WIN32/osdSock.h | 1 + src/libCom/osi/os/cygwin32/osdSock.h | 1 + src/libCom/osi/os/freebsd/osdSock.h | 1 + src/libCom/osi/os/iOS/osdSock.h | 1 + src/libCom/osi/os/solaris/osdSock.h | 1 + src/libCom/osi/os/vxWorks/osdSock.h | 1 + src/libCom/test/Makefile | 6 ++- src/libCom/test/epicsRunLibComTests.c | 2 + src/libCom/test/osiSockTest.c | 59 +++++++++++++++++++++++++++ 14 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/libCom/test/osiSockTest.c diff --git a/src/ca/client/udpiiu.cpp b/src/ca/client/udpiiu.cpp index beae07560..ccb2556e8 100644 --- a/src/ca/client/udpiiu.cpp +++ b/src/ca/client/udpiiu.cpp @@ -165,7 +165,7 @@ udpiiu::udpiiu ( #ifdef IP_ADD_MEMBERSHIP { - int flag = 1; + osiSockOptMcastLoop_t flag = 1; if ( setsockopt ( this->sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &flag, sizeof ( flag ) ) == -1 ) { char sockErrBuf[64]; diff --git a/src/ioc/rsrv/caservertask.c b/src/ioc/rsrv/caservertask.c index 50bc650c2..fda442168 100644 --- a/src/ioc/rsrv/caservertask.c +++ b/src/ioc/rsrv/caservertask.c @@ -308,7 +308,7 @@ void rsrv_build_addr_lists(void) } #ifdef IP_ADD_MEMBERSHIP { - int flag = 1; + osiSockOptMcastLoop_t flag = 1; if (setsockopt(beaconSocket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&flag, sizeof(flag))<0) { char sockErrBuf[64]; diff --git a/src/libCom/osi/os/Darwin/osdSock.h b/src/libCom/osi/os/Darwin/osdSock.h index 1d4556eee..e7c344062 100644 --- a/src/libCom/osi/os/Darwin/osdSock.h +++ b/src/libCom/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/libCom/osi/os/freebsd/osdSock.h b/src/libCom/osi/os/freebsd/osdSock.h index fe28d4cd5..b402ec120 100644 --- a/src/libCom/osi/os/freebsd/osdSock.h +++ b/src/libCom/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/libCom/test/Makefile b/src/libCom/test/Makefile index ee4d11071..1ce7a6431 100755 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -210,6 +210,11 @@ ipAddrToAsciiTest_SRCS += ipAddrToAsciiTest.cpp testHarness_SRCS += ipAddrToAsciiTest.cpp TESTS += ipAddrToAsciiTest +TESTPROD_HOST += osiSockTest +osiSockTest_SRCS += osiSockTest.c +testHarness_SRCS += osiSockTest.c +TESTS += osiSockTest + # The testHarness runs all the test programs in a known working order. testHarness_SRCS += epicsRunLibComTests.c @@ -254,4 +259,3 @@ cvtFastPerform_SRCS += cvtFastPerform.cpp testHarness_SRCS += cvtFastPerform.cpp include $(TOP)/configure/RULES - diff --git a/src/libCom/test/epicsRunLibComTests.c b/src/libCom/test/epicsRunLibComTests.c index c4a76e777..29c5eda3f 100644 --- a/src/libCom/test/epicsRunLibComTests.c +++ b/src/libCom/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/src/libCom/test/osiSockTest.c b/src/libCom/test/osiSockTest.c new file mode 100644 index 000000000..d9bbd29f7 --- /dev/null +++ b/src/libCom/test/osiSockTest.c @@ -0,0 +1,59 @@ +/*************************************************************************\ +* 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" + +void udpSockTest(void) +{ + SOCKET s; + int status, one = 1, get = 0; + osiSocklen_t len; + osiSockOptMcastLoop_t flag = 1; + + s = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); + testOk(s != INVALID_SOCKET, "epicsSocketCreate INET, DGRAM, 0"); + + status = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof(one)); + testOk(status >= 0, "setsockopt BROADCAST, 1"); + + len = sizeof(get); + status = getsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&get, &len); + testOk(status >= 0 && len == sizeof(get) && get == 1, + "getsockopt BROADCAST == 1"); + + status = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, + (char *)&flag, sizeof(flag)); + testOk(status >= 0, "setsockopt MULTICAST_LOOP, 1"); + + flag = 0; + len = sizeof(flag); + status = getsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&flag, &len); + testOk(status >= 0 && len == sizeof(flag) && flag == 1, + "getsockopt MULTICAST_LOOP == 1"); + + epicsSocketDestroy(s); +} + + +MAIN(osiSockTest) +{ + int status; + testPlan(6); + + status = osiSockAttach(); + testOk(status, "osiSockAttach"); + + udpSockTest(); + + osiSockRelease(); + return testDone(); +} From e0757204ccef0ecb6daf536fb6686a39e1801972 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 30 Aug 2017 13:58:17 -0500 Subject: [PATCH 12/32] More tests, check both true and false values for options. --- src/libCom/test/osiSockTest.c | 55 ++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/libCom/test/osiSockTest.c b/src/libCom/test/osiSockTest.c index d9bbd29f7..16a184afd 100644 --- a/src/libCom/test/osiSockTest.c +++ b/src/libCom/test/osiSockTest.c @@ -12,33 +12,48 @@ #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; - int status, one = 1, get = 0; - osiSocklen_t len; - osiSockOptMcastLoop_t flag = 1; s = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); testOk(s != INVALID_SOCKET, "epicsSocketCreate INET, DGRAM, 0"); - status = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof(one)); - testOk(status >= 0, "setsockopt BROADCAST, 1"); + udpBroadcast(s, 1); + udpBroadcast(s, 0); - len = sizeof(get); - status = getsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&get, &len); - testOk(status >= 0 && len == sizeof(get) && get == 1, - "getsockopt BROADCAST == 1"); - - status = setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, - (char *)&flag, sizeof(flag)); - testOk(status >= 0, "setsockopt MULTICAST_LOOP, 1"); - - flag = 0; - len = sizeof(flag); - status = getsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&flag, &len); - testOk(status >= 0 && len == sizeof(flag) && flag == 1, - "getsockopt MULTICAST_LOOP == 1"); + multiCastLoop(s, 1); + multiCastLoop(s, 0); epicsSocketDestroy(s); } @@ -47,7 +62,7 @@ void udpSockTest(void) MAIN(osiSockTest) { int status; - testPlan(6); + testPlan(10); status = osiSockAttach(); testOk(status, "osiSockAttach"); From 5641afa0e2148eddf075125c2615b2e7d13f559a Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 19 Sep 2017 00:12:18 -0500 Subject: [PATCH 13/32] Change pvlOptTSELisTime to DBLINK_FLAG_TSELisTIME Renames recGblTSELwasModified() to TSEL_modified() in dbLink.c. Adds some tests for using JSON link types in dbCommon links. --- src/ioc/db/dbLink.c | 28 +++++++++++++++++++++++++--- src/ioc/db/recGbl.c | 30 +++++------------------------- src/ioc/db/recGbl.h | 3 +-- src/ioc/db/test/dbPutLinkTest.c | 19 ++++++++++++++----- src/ioc/db/test/dbPutLinkTestJ.db | 4 ++++ src/ioc/dbStatic/dbStaticLib.c | 2 +- src/ioc/dbStatic/link.h | 2 +- 7 files changed, 51 insertions(+), 37 deletions(-) diff --git a/src/ioc/db/dbLink.c b/src/ioc/db/dbLink.c index 9279b91fb..c90dcb3df 100644 --- a/src/ioc/db/dbLink.c +++ b/src/ioc/db/dbLink.c @@ -66,6 +66,26 @@ static const char * link_field_name(const struct link *plink) return "????"; } +/* Special TSEL handler for PV links */ +/* FIXME: Generalize for new link types... */ +static void TSEL_modified(struct link *plink) +{ + struct pv_link *ppv_link; + char *pfieldname; + + if (plink->type != PV_LINK) { + errlogPrintf("dbLink::TSEL_modified called for non PV_LINK\n"); + return; + } + /* If pvname contains .TIME truncate it to point to VAL instead */ + ppv_link = &plink->value.pv_link; + pfieldname = strstr(ppv_link->pvname, ".TIME"); + if (pfieldname) { + *pfieldname = 0; + plink->flags |= DBLINK_FLAG_TSELisTIME; + } +} + /***************************** Generic Link API *****************************/ @@ -93,7 +113,7 @@ void dbInitLink(struct link *plink, short dbfType) return; if (plink == &precord->tsel) - recGblTSELwasModified(plink); + TSEL_modified(plink); if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) { /* Make it a DB link if possible */ @@ -127,6 +147,9 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType, { struct dbCommon *precord = plink->precord; + /* Clear old TSELisTIME flag */ + plink->flags &= ~DBLINK_FLAG_TSELisTIME; + if (plink->type == CONSTANT) { dbConstAddLink(plink); return; @@ -145,7 +168,7 @@ void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType, return; if (plink == &precord->tsel) - recGblTSELwasModified(plink); + TSEL_modified(plink); if (ptarget) { /* It's a DB link */ @@ -470,4 +493,3 @@ long dbPutLinkLS(struct link *plink, char *pbuffer, epicsUInt32 len) return dbPutLink(plink, DBR_STRING, pbuffer, 1); } - diff --git a/src/ioc/db/recGbl.c b/src/ioc/db/recGbl.c index a614b5268..337ed7875 100644 --- a/src/ioc/db/recGbl.c +++ b/src/ioc/db/recGbl.c @@ -4,7 +4,7 @@ * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* recGbl.c */ /* @@ -259,15 +259,13 @@ void recGblGetTimeStamp(void *pvoid) struct link *plink = &prec->tsel; if (!dbLinkIsConstant(plink)) { - struct pv_link *ppv_link = &plink->value.pv_link; - - if (ppv_link->pvlMask & pvlOptTSELisTime) { + if (plink->flags & DBLINK_FLAG_TSELisTIME) { if (dbGetTimeStamp(plink, &prec->time)) - errlogPrintf("recGblGetTimeStamp: dbGetTimeStamp failed, %s.TSEL = %s\n", - prec->name, ppv_link->pvname); + errlogPrintf("recGblGetTimeStamp: dbGetTimeStamp failed for %s.TSEL", + prec->name); return; } - dbGetLink(&prec->tsel, DBR_SHORT, &prec->tse, 0, 0); + dbGetLink(plink, DBR_SHORT, &prec->tse, 0, 0); } if (prec->tse != epicsTimeEventDeviceTime) { if (epicsTimeGetEvent(&prec->time, prec->tse)) @@ -276,24 +274,6 @@ void recGblGetTimeStamp(void *pvoid) } } -void recGblTSELwasModified(struct link *plink) -{ - struct pv_link *ppv_link = &plink->value.pv_link; - char *pfieldname; - - if (plink->type != PV_LINK) { - errlogPrintf("recGblTSELwasModified called for non PV_LINK\n"); - return; - } - /*If pvname ends in .TIME then just ask for VAL*/ - /*Note that the VAL value will not be used*/ - pfieldname = strstr(ppv_link->pvname, ".TIME"); - if (pfieldname) { - *pfieldname = 0; - ppv_link->pvlMask |= pvlOptTSELisTime; - } -} - void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval, const epicsFloat64 deadband, unsigned *monitor_mask, const unsigned add_mask) { diff --git a/src/ioc/db/recGbl.h b/src/ioc/db/recGbl.h index 8eb589450..171c00964 100644 --- a/src/ioc/db/recGbl.h +++ b/src/ioc/db/recGbl.h @@ -4,7 +4,7 @@ * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* recGbl.h */ /* Record Global @@ -63,7 +63,6 @@ epicsShareFunc void recGblInheritSevr(int msMode, void *precord, epicsEnum16 sta epicsEnum16 sevr); epicsShareFunc void recGblFwdLink(void *precord); epicsShareFunc void recGblGetTimeStamp(void *precord); -epicsShareFunc void recGblTSELwasModified(struct link *plink); epicsShareFunc void recGblCheckDeadband(epicsFloat64 *poldval, const epicsFloat64 newval, const epicsFloat64 deadband, unsigned *monitor_mask, const unsigned add_mask); diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c index b39b98db2..8d2f1765a 100644 --- a/src/ioc/db/test/dbPutLinkTest.c +++ b/src/ioc/db/test/dbPutLinkTest.c @@ -565,7 +565,7 @@ void testJLink(void) testIocInitOk(); eltc(1); - testNumZ(3); + testNumZ(6); testdbPutFieldOk("j1.PROC", DBF_LONG, 1); testdbPutFieldOk("j2.PROC", DBF_LONG, 1); @@ -576,13 +576,16 @@ void testJLink(void) testdbGetFieldEqual("j2.VAL", DBF_LONG, 2); testdbGetFieldEqual("j3.VAL", DBF_LONG, 3); - testNumZ(3); + testNumZ(6); testdbPutFieldOk("j1.INP", DBF_STRING, "{\"z\":{\"good\":4}}"); testdbPutFieldOk("j1.PROC", DBF_LONG, 1); testdbGetFieldEqual("j1.VAL", DBF_LONG, 4); - testNumZ(3); + testdbPutFieldOk("j2.TSEL", DBF_STRING, "{\"z\":{\"good\":0}}"); + testdbPutFieldOk("j2.PROC", DBF_LONG, 1); + + testNumZ(7); testdbPutFieldFail(S_dbLib_badField, "j1.INP", DBF_STRING, "{\"z\":{\"fail\":5}}"); testdbPutFieldOk("j1.PROC", DBF_LONG, 1); @@ -590,7 +593,13 @@ void testJLink(void) /* put failure in parsing stage doesn't modify link */ testdbGetFieldEqual("j1.INP", DBF_STRING, "{\"z\":{\"good\":4}}"); - testNumZ(3); + testNumZ(7); + + /* Check SDIS using a JSON link prevents processing */ + testdbPutFieldOk("j1.SDIS", DBF_STRING, "{\"z\":{\"good\":1}}"); + testdbPutFieldOk("j1.INP", DBF_STRING, "{\"z\":{\"good\":1}}"); + testdbPutFieldOk("j1.PROC", DBF_LONG, 1); + testdbGetFieldEqual("j1.VAL", DBF_LONG, 4); testIocShutdownOk(); @@ -601,7 +610,7 @@ void testJLink(void) MAIN(dbPutLinkTest) { - testPlan(301); + testPlan(307); testLinkParse(); testLinkFailParse(); testCADBSet(); diff --git a/src/ioc/db/test/dbPutLinkTestJ.db b/src/ioc/db/test/dbPutLinkTestJ.db index 25cf4c822..621557c2c 100644 --- a/src/ioc/db/test/dbPutLinkTestJ.db +++ b/src/ioc/db/test/dbPutLinkTestJ.db @@ -1,10 +1,14 @@ record(x, "j1") { field(INP, {z:{good:1}}) + field(TSEL, {z:{good:0}}) + field(SDIS, {z:{good:0}}) + field(FLNK, {z:{good:0}}) } record(x, "j2") { field(INP, {z:{good:2}}) + field(TSEL, "j1.TIME") } record(x, "j3") { diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index d647f787d..bcfa93727 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -1940,7 +1940,7 @@ char * dbGetString(DBENTRY *pdbentry) else ppind=0; dbMsgPrint(pdbentry, "%s%s%s%s", plink->value.pv_link.pvname ? plink->value.pv_link.pvname : "", - (pvlMask & pvlOptTSELisTime) ? ".TIME" : "", + (plink->flags & DBLINK_FLAG_TSELisTIME) ? ".TIME" : "", ppstring[ppind], msstring[plink->value.pv_link.pvlMask&pvlOptMsMode]); break; diff --git a/src/ioc/dbStatic/link.h b/src/ioc/dbStatic/link.h index f2b426308..2e3c77820 100644 --- a/src/ioc/dbStatic/link.h +++ b/src/ioc/dbStatic/link.h @@ -67,10 +67,10 @@ epicsShareExtern maplinkType pamaplinkType[]; #define pvlOptInpString 0x100 /*Input as string*/ #define pvlOptOutNative 0x200 /*Output native*/ #define pvlOptOutString 0x400 /*Output as string*/ -#define pvlOptTSELisTime 0x800 /*Field TSEL is getting timeStamp*/ /* DBLINK Flag bits */ #define DBLINK_FLAG_INITIALIZED 1 /* dbInitLink() called */ +#define DBLINK_FLAG_TSELisTIME 2 /* Use TSEL to get timeStamp */ struct macro_link { char *macroStr; From 8f679e11335d4961aa25073f847fa0066096ee49 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 15 Sep 2017 17:54:48 -0500 Subject: [PATCH 14/32] yajl: missing LL defs --- src/libCom/yajl/yajl_parser.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libCom/yajl/yajl_parser.c b/src/libCom/yajl/yajl_parser.c index b1d75fe55..7e4da6924 100644 --- a/src/libCom/yajl/yajl_parser.c +++ b/src/libCom/yajl/yajl_parser.c @@ -30,6 +30,11 @@ #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 */ From 6f4e466989fc659fdf73d515c0761a3291e32751 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 27 Sep 2017 15:27:00 -0500 Subject: [PATCH 15/32] yajl: add EPICS_YAJL_API_VERSION macro --- src/libCom/Makefile | 1 + src/libCom/yajl/RULES | 17 +++++++++++++++++ src/libCom/yajl/yajl_common.h | 16 ++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/libCom/yajl/RULES diff --git a/src/libCom/Makefile b/src/libCom/Makefile index ee93ada0a..2ecd32b21 100644 --- a/src/libCom/Makefile +++ b/src/libCom/Makefile @@ -63,4 +63,5 @@ include $(LIBCOM)/error/RULES include $(LIBCOM)/flex/RULES include $(LIBCOM)/misc/RULES include $(LIBCOM)/osi/RULES +include $(LIBCOM)/yajl/RULES diff --git a/src/libCom/yajl/RULES b/src/libCom/yajl/RULES new file mode 100644 index 000000000..9cd228cbe --- /dev/null +++ b/src/libCom/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/libCom/yajl/yajl_common.h b/src/libCom/yajl/yajl_common.h index 096cf37a0..4bc63eead 100644 --- a/src/libCom/yajl/yajl_common.h +++ b/src/libCom/yajl/yajl_common.h @@ -20,10 +20,26 @@ #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 From cd14e2ee9fcd7faffd9b7134c762c67153807a03 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 30 Sep 2017 11:30:50 -0500 Subject: [PATCH 16/32] Add missing calls to yajl_complete_parse() Fixes leak when link parses OK but JSON errors follow. Includes regression test. --- src/ioc/db/dbChannel.c | 8 ++++++-- src/ioc/db/dbConvertJSON.c | 2 ++ src/ioc/db/dbJLink.c | 3 +++ src/ioc/db/test/dbPutLinkTest.c | 5 +++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ioc/db/dbChannel.c b/src/ioc/db/dbChannel.c index e16f8e740..92be08c77 100644 --- a/src/ioc/db/dbChannel.c +++ b/src/ioc/db/dbChannel.c @@ -267,7 +267,7 @@ static long chf_parse(dbChannel *chan, const char **pjson) { chan, NULL, 0 }; yajl_handle yh = yajl_alloc(&chf_callbacks, &chf_alloc, &parser); const char *json = *pjson; - size_t jlen = strlen(json); + size_t jlen = strlen(json), ylen; yajl_status ys; long status; @@ -275,11 +275,15 @@ static long chf_parse(dbChannel *chan, const char **pjson) return S_db_noMemory; ys = yajl_parse(yh, (const unsigned char *) json, jlen); + ylen = yajl_get_bytes_consumed(yh); + + if (ys == yajl_status_ok) + ys = yajl_complete_parse(yh); switch (ys) { case yajl_status_ok: + *pjson += ylen; status = 0; - *pjson += yajl_get_bytes_consumed(yh); break; case yajl_status_error: { diff --git a/src/ioc/db/dbConvertJSON.c b/src/ioc/db/dbConvertJSON.c index c9a7d449d..eb697eeda 100644 --- a/src/ioc/db/dbConvertJSON.c +++ b/src/ioc/db/dbConvertJSON.c @@ -171,6 +171,8 @@ long dbPutConvertJSON(const char *json, short dbrType, return S_db_noMemory; ys = yajl_parse(yh, (const unsigned char *) json, jlen); + if (ys == yajl_status_ok) + ys = yajl_complete_parse(yh); switch (ys) { case yajl_status_ok: diff --git a/src/ioc/db/dbJLink.c b/src/ioc/db/dbJLink.c index 109785b6d..ea054eee9 100644 --- a/src/ioc/db/dbJLink.c +++ b/src/ioc/db/dbJLink.c @@ -365,6 +365,8 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, return S_db_noMemory; ys = yajl_parse(yh, (const unsigned char *) json, jlen); + if (ys == yajl_status_ok) + ys = yajl_complete_parse(yh); switch (ys) { unsigned char *err; @@ -380,6 +382,7 @@ long dbJLinkParse(const char *json, size_t jlen, short dbfType, errlogPrintf("dbJLinkInit: %s\n", err); yajl_free_error(yh, err); dbJLinkFree(parser->pjlink); + dbJLinkFree(parser->product); /* fall through */ default: status = S_db_badField; diff --git a/src/ioc/db/test/dbPutLinkTest.c b/src/ioc/db/test/dbPutLinkTest.c index b39b98db2..e4a6ebc8e 100644 --- a/src/ioc/db/test/dbPutLinkTest.c +++ b/src/ioc/db/test/dbPutLinkTest.c @@ -585,9 +585,10 @@ void testJLink(void) testNumZ(3); testdbPutFieldFail(S_dbLib_badField, "j1.INP", DBF_STRING, "{\"z\":{\"fail\":5}}"); + testdbPutFieldFail(S_dbLib_badField, "j1.INP", DBF_STRING, "{\"z\":{\"good\":6}"); testdbPutFieldOk("j1.PROC", DBF_LONG, 1); testdbGetFieldEqual("j1.VAL", DBF_LONG, 4); - /* put failure in parsing stage doesn't modify link */ + /* put failures in parsing stage don't modify link */ testdbGetFieldEqual("j1.INP", DBF_STRING, "{\"z\":{\"good\":4}}"); testNumZ(3); @@ -601,7 +602,7 @@ void testJLink(void) MAIN(dbPutLinkTest) { - testPlan(301); + testPlan(302); testLinkParse(); testLinkFailParse(); testCADBSet(); From 9e75b8b32d1fbc18201b5252ab4598dbcb3f42a5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 13 Oct 2017 10:42:19 +0200 Subject: [PATCH 17/32] libcom/test: osiSockTest fix for RTEMS Instead of 0/1 RTEMS gives 0/32 (32==SO_BROADCAST). So switch the test to zero/non-zero. --- src/libCom/test/osiSockTest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/test/osiSockTest.c b/src/libCom/test/osiSockTest.c index 16a184afd..39eb0ba2b 100644 --- a/src/libCom/test/osiSockTest.c +++ b/src/libCom/test/osiSockTest.c @@ -23,7 +23,7 @@ void udpBroadcast(SOCKET s, int put) 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, + testOk(status >= 0 && len == sizeof(flag) && !flag == !put, "getsockopt BROADCAST => %d", flag); } @@ -38,7 +38,7 @@ void multiCastLoop(SOCKET s, int put) 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, + testOk(status >= 0 && len == sizeof(flag) && !flag == !put, "getsockopt MULTICAST_LOOP => %d", (int) flag); } From 58460d25b97eb316a376656f602b12c8a7c76aa3 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 13 Oct 2017 10:57:21 +0200 Subject: [PATCH 18/32] Release Notes --- documentation/RELEASE_NOTES.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 3be476cd9..33f12c441 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -16,6 +16,11 @@ +

Add osiSockOptMcastLoop_t and osiSockTest

+ +

Added a new OS-independent typedef for multicast socket options, and a test +file to check their correct operation.

+

Support for CONFIG_SITE.local in Base

This feature is mostly meant for use by developers; configuration From e3c9d5900ed27f13b341fee8f04e0c4507b90df1 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 18 Oct 2017 15:39:22 -0500 Subject: [PATCH 19/32] Added timestamp support to the lnkCalc link type. --- src/std/link/links.dbd.pod | 8 +++++ src/std/link/lnkCalc.c | 61 ++++++++++++++++++++++++++++---- src/std/rec/test/linkInitTest.db | 3 +- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod index ceb6ced77..d94e9e8f0 100644 --- a/src/std/link/links.dbd.pod +++ b/src/std/link/links.dbd.pod @@ -114,6 +114,14 @@ expression. Equivalent to the C field of a record. An optional integer specifying the numeric precision with which the calculation result should be displayed. Equivalent to the C field of a record. +=item time + +An optional string containing a single upper or lower-case letter C ... C +which must correspond to an input provided in the c parameter. When the +record containing such a link has C set to -2 (epicsTimeEventDeviceTime) +the record's timestamp field C