From 6c2b3aa1b95ee933dd81e9cb4cf8015e4f16a625 Mon Sep 17 00:00:00 2001 From: Rob Lemley Date: Tue, 14 Apr 2020 22:30:29 +0000 Subject: [PATCH] Bug 1621782 - Import json-c sources into comm-central. r=kaie JSON-C is a dependency of RNP. Differential Revision: https://phabricator.services.mozilla.com/D70736 --HG-- extra : moz-landing-system : lando --- third_party/README.json-c | 41 + third_party/json-c/AUTHORS | 5 + third_party/json-c/COPYING | 42 + third_party/json-c/ChangeLog | 382 +++++ third_party/json-c/INSTALL | 3 + third_party/json-c/NEWS | 1 + third_party/json-c/README.html | 42 + third_party/json-c/README.md | 173 ++ third_party/json-c/RELEASE_CHECKLIST.txt | 136 ++ third_party/json-c/STYLE.txt | 31 + third_party/json-c/arraylist.c | 146 ++ third_party/json-c/arraylist.h | 70 + third_party/json-c/bits.h | 36 + third_party/json-c/config.h.in | 196 +++ third_party/json-c/config.h.win32 | 205 +++ third_party/json-c/debug.c | 83 + third_party/json-c/debug.h | 75 + third_party/json-c/issues_closed_for_0.13.md | 267 +++ third_party/json-c/json.h | 38 + third_party/json-c/json_c_version.c | 20 + third_party/json-c/json_c_version.h | 40 + third_party/json-c/json_config.h.in | 3 + third_party/json-c/json_config.h.win32 | 5 + third_party/json-c/json_inttypes.h | 23 + third_party/json-c/json_object.c | 1493 +++++++++++++++++ third_party/json-c/json_object.h | 1034 ++++++++++++ third_party/json-c/json_object_iterator.c | 163 ++ third_party/json-c/json_object_iterator.h | 240 +++ third_party/json-c/json_object_private.h | 64 + third_party/json-c/json_pointer.c | 327 ++++ third_party/json-c/json_pointer.h | 120 ++ third_party/json-c/json_tokener.c | 997 +++++++++++ third_party/json-c/json_tokener.h | 216 +++ third_party/json-c/json_util.c | 243 +++ third_party/json-c/json_util.h | 106 ++ third_party/json-c/json_visit.c | 133 ++ third_party/json-c/json_visit.h | 95 ++ third_party/json-c/libjson.c | 26 + third_party/json-c/linkhash.c | 690 ++++++++ third_party/json-c/linkhash.h | 406 +++++ third_party/json-c/math_compat.h | 36 + third_party/json-c/printbuf.c | 155 ++ third_party/json-c/printbuf.h | 122 ++ third_party/json-c/random_seed.c | 238 +++ third_party/json-c/random_seed.h | 29 + third_party/json-c/snprintf_compat.h | 41 + third_party/json-c/strdup_compat.h | 16 + third_party/json-c/strerror_override.c | 101 ++ third_party/json-c/strerror_override.h | 30 + .../json-c/strerror_override_private.h | 12 + third_party/json-c/vasprintf_compat.h | 46 + 51 files changed, 9242 insertions(+) create mode 100644 third_party/README.json-c create mode 100644 third_party/json-c/AUTHORS create mode 100644 third_party/json-c/COPYING create mode 100644 third_party/json-c/ChangeLog create mode 100644 third_party/json-c/INSTALL create mode 100644 third_party/json-c/NEWS create mode 100644 third_party/json-c/README.html create mode 100644 third_party/json-c/README.md create mode 100644 third_party/json-c/RELEASE_CHECKLIST.txt create mode 100755 third_party/json-c/STYLE.txt create mode 100644 third_party/json-c/arraylist.c create mode 100644 third_party/json-c/arraylist.h create mode 100644 third_party/json-c/bits.h create mode 100644 third_party/json-c/config.h.in create mode 100644 third_party/json-c/config.h.win32 create mode 100644 third_party/json-c/debug.c create mode 100644 third_party/json-c/debug.h create mode 100644 third_party/json-c/issues_closed_for_0.13.md create mode 100644 third_party/json-c/json.h create mode 100644 third_party/json-c/json_c_version.c create mode 100644 third_party/json-c/json_c_version.h create mode 100644 third_party/json-c/json_config.h.in create mode 100644 third_party/json-c/json_config.h.win32 create mode 100644 third_party/json-c/json_inttypes.h create mode 100644 third_party/json-c/json_object.c create mode 100644 third_party/json-c/json_object.h create mode 100644 third_party/json-c/json_object_iterator.c create mode 100644 third_party/json-c/json_object_iterator.h create mode 100644 third_party/json-c/json_object_private.h create mode 100644 third_party/json-c/json_pointer.c create mode 100644 third_party/json-c/json_pointer.h create mode 100644 third_party/json-c/json_tokener.c create mode 100644 third_party/json-c/json_tokener.h create mode 100644 third_party/json-c/json_util.c create mode 100644 third_party/json-c/json_util.h create mode 100644 third_party/json-c/json_visit.c create mode 100644 third_party/json-c/json_visit.h create mode 100644 third_party/json-c/libjson.c create mode 100644 third_party/json-c/linkhash.c create mode 100644 third_party/json-c/linkhash.h create mode 100644 third_party/json-c/math_compat.h create mode 100644 third_party/json-c/printbuf.c create mode 100644 third_party/json-c/printbuf.h create mode 100644 third_party/json-c/random_seed.c create mode 100644 third_party/json-c/random_seed.h create mode 100644 third_party/json-c/snprintf_compat.h create mode 100644 third_party/json-c/strdup_compat.h create mode 100644 third_party/json-c/strerror_override.c create mode 100644 third_party/json-c/strerror_override.h create mode 100644 third_party/json-c/strerror_override_private.h create mode 100644 third_party/json-c/vasprintf_compat.h diff --git a/third_party/README.json-c b/third_party/README.json-c new file mode 100644 index 0000000000..216e8a1e04 --- /dev/null +++ b/third_party/README.json-c @@ -0,0 +1,41 @@ +Directory ./json-c contains a copy of version 0.13.1 of the json-c library, +which has been obtained from https://s3.amazonaws.com/json-c_releases/releases/json-c-0.13.1-nodoc.tar.gz . +(Link at https://github.com/json-c/json-c/wiki). + +For licensing information, please refer to the included documentation. + +The SHA256SUM of the imported file is: +94a26340c0785fcff4f46ff38609cf84ebcd670df0c8efd75d039cc951d80132 json-c-0.13.1-nodoc.tar.gz + +The following files and directories were removed from the source distribution's root: +autoconf-archive/ +fuzz/ +tests/ +.editorconfig +.gitignore +.travis.yml +Android.configure.mk +CMakeLists.txt +Doxyfile +Makefile.am +Makefile.in +README +aclocal.m4 +appveyor.yml +autogen.sh +compile +config.guess +config.sub +configure +configure.ac +depcomp +install-sh +json-c-uninstalled.pc.in +json-c.pc.in +ltmain.sh +missing +test-driver + +The following files were added to the source's root by MZLA Technologies: +moz.build + diff --git a/third_party/json-c/AUTHORS b/third_party/json-c/AUTHORS new file mode 100644 index 0000000000..b389989c45 --- /dev/null +++ b/third_party/json-c/AUTHORS @@ -0,0 +1,5 @@ +Michael Clark +Jehiah Czebotar +Eric Haszlakiewicz +C. Watford (christopher.watford@gmail.com) + diff --git a/third_party/json-c/COPYING b/third_party/json-c/COPYING new file mode 100644 index 0000000000..740d1258d4 --- /dev/null +++ b/third_party/json-c/COPYING @@ -0,0 +1,42 @@ + +Copyright (c) 2009-2012 Eric Haszlakiewicz + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------- + +Copyright (c) 2004, 2005 Metaparadigm Pte Ltd + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/json-c/ChangeLog b/third_party/json-c/ChangeLog new file mode 100644 index 0000000000..8681225689 --- /dev/null +++ b/third_party/json-c/ChangeLog @@ -0,0 +1,382 @@ + +0.13.1 (up to commit 0f814e5, 2018/03/04) +========================================= + +* Bump the major version of the .so library generated up to 4.0 to avoid + conflicts because some downstream packagers of json-c had already done + their own bump to ".so.3" for a much older 0.12 release. +* Add const size_t json_c_object_sizeof() +* Avoid invalid free (and thus a segfault) when ref_count gets < 0 +* PR#394: fix handling of custom double formats that include a ".0" +* Avoid uninitialized variable warnings in json_object_object_foreach +* Issue #396: fix build for certain uClibc based systems. +* Add a top level fuzz directory for fuzzers run by OSS-Fuzz + +0.13 (up to commit 5dae561, 2017/11/29) +================================= + +This release, being three and a half years after the 0.12 branch (f84d9c), + has quite a number of changes included. The following is a sampling of + the most significant ones. + +Since the 0.12 release, 250 issues and pull requests have been closed. +See issues_closed_for_0.13.md for a complete list. + + +Deprecated and removed features: +-------------------------------- +* All internal use of bits.h has been eliminated. The file will be removed. + Do not use: hexdigit(), error_ptr(), error_descrition() and it_error() +* lh_abort() is deprecated. It will be removed. + +Behavior changes: +----------------- +* Tighten the number parsing algorithm to raise errors instead of truncating + the results. For example 12.3.4 or 2015-01-15, which now return null. + See commit 99d8fc + +* Use size_t for array length and size. Platforms where sizeof(size_t) != sizeof(int) may not be backwards compatible + See commits 45c56b, 92e9a5 and others. + +* Check for failue when allocating memory, returning NULL and errno=ENOMEM. + See commit 2149a04. + +* Change json_object_object_add() return type from void to int, and will return -1 on failures, instead of exiting. (Note: this is not an ABI change) + +New features: +------------- +* We're aiming to follow RFC 7159 now. + +* Add a couple of additional option to json_object_to_json_string_ext: + JSON_C_TO_STRING_PRETTY_TAB + JSON_C_TO_STRING_NOSLASHESCAPE + +* Add a json_object_object_add_ex() function to allow for performance + improvements when certain constraints are known to be true. + +* Make serialization format of doubles configurable, in two different ways: + Call json_object_set_serializer with json_object_double_to_json_string and a custom + format on each double object, or + Call json_c_set_serialization_double_format() to set a global or thread-wide format. + +* Add utility function for comparing json_objects - json_object_equal() + +* Add a way to copy entire object trees: json_object_deep_copy() +* Add json_object_set_ function to modify the value of existing json_object's + without the need to recreate them. Also add a json_object_int_inc function to + adjust an int's value. +* Add support for JSON pointer, RFC 6901. See json_pointer.h +* Add a json_util_get_last_err() function to retrieve the string describing the + cause of errors, instead of printing to stderr. +* Add perllike hash function for strings, and json_global_set_string_hash() 8f8d03d +* Add a json_c_visit() function to provide a way to iterate over a tree of json-c objects. + +Notable bug fixes and other improvements: +----------------------------------------- +* Make reference increment and decrement atomic to allow passing json objects between threads. +* Fix json_object_object_foreach to avoid uninitialized variable warnings. +* Improve performance by removing unneeded data items from hashtable code and reducing duplicate hash computation. +* Improve performance by storing small strings inside json_object +* Improve performance of json_object_to_json_string by removing variadic printf. commit 9ff0f49 +* Issue #371: fix parsing of "-Infinity", and avoid needlessly copying the input when doing so. +* Fix stack buffer overflow in json_object_double_to_json_string_format() - commit 2c2deb87 +* Fix various potential null ptr deref and int32 overflows +* Issue #332: fix a long-standing bug in array_list_put_idx() where it would attempt to free previously free'd entries due to not checking the current array length. +* Issue #195: use uselocale() instead of setlocale() in json_tokener to behave better in threaded environments. +* Issue #275: fix out of bounds read when handling unicode surrogate pairs. +* Ensure doubles that happen to be a whole number are emitted with ".0" - commit ca7a19 +* PR#331: for Visual Studio, use a snprintf/vsnprintf wrapper that ensures the string is terminated. +* Fix double to int cast overflow in json_object_get_int64. +* Clamp double to int32 when narrowing in json_object_get_int. +* Use strtoll() to parse ints - instead of sscanf +* Miscellaneous smaller changes, including removing unused variables, fixing warning + about uninitialized variables adding const qualifiers, reformatting code, etc... + +Build changes: +-------------- +* Add Appveyor and Travis build support +* Switch to using CMake when building on Windows with Visual Studio. + A dynamic .dll is generated instead of a .lib + config.h is now generated, config.h.win32 should no longer be manually copied +* Add support for MacOS through CMake too. +* Enable silent build by default +* Link against libm when needed +* Add support for building with AddressSanitizer +* Add support for building with Clang +* Add a --enable-threading configure option, and only use the (slower) __sync_add_and_fetch()/__sync_sub_and_fetch() function when it is specified. + +List of new functions added: +---------------------------- +### json_object.h +* array_list_bsearch() +* array_list_del_idx() +* json_object_to_json_string_length() +* json_object_get_userdata() +* json_object_set_userdata() +* json_object_object_add_ex() +* json_object_array_bsearch() +* json_object_array_del_idx() +* json_object_set_boolean() +* json_object_set_int() +* json_object_int_inc() +* json_object_set_int64() +* json_c_set_serialization_double_format() +* json_object_double_to_json_string() +* json_object_set_double() +* json_object_set_string() +* json_object_set_string_len() +* json_object_equal() +* json_object_deep_copy() + +### json_pointer.h +* json_pointer_get() +* json_pointer_getf() +* json_pointer_set() +* json_pointer_setf() + +### json_util.h +* json_object_from_fd() +* json_object_to_fd() +* json_util_get_last_err() + +### json_visit.h +* json_c_visit() + +### linkhash.h +* json_global_set_string_hash() +* lh_table_resize() + +### printbuf.h +* printbuf_strappend() + + +0.12.1 +====== + + * Minimal changes to address compile issues. + +0.12 +==== + + * Address security issues: + * CVE-2013-6371: hash collision denial of service + * CVE-2013-6370: buffer overflow if size_t is larger than int + + * Avoid potential overflow in json_object_get_double + + * Eliminate the mc_abort() function and MC_ABORT macro. + + * Make the json_tokener_errors array local. It has been deprecated for + a while, and json_tokener_error_desc() should be used instead. + + * change the floating point output format to %.17g so values with + more than 6 digits show up in the output. + + * Remove the old libjson.so name compatibility support. The library is + only created as libjson-c.so now and headers are only installed + into the ${prefix}/json-c directory. + + * When supported by the linker, add the -Bsymbolic-functions flag. + + * Various changes to fix the build on MSVC. + + * Make strict mode more strict: + * number must not start with 0 + * no single-quote strings + * no comments + * trailing char not allowed + * only allow lowercase literals + + * Added a json_object_new_double_s() convenience function to allow + an exact string representation of a double to be specified when + creating the object and use it in json_tokener_parse_ex() so + a re-serialized object more exactly matches the input. + + * Add support NaN and Infinity + + +0.11 +==== + + * IMPORTANT: the name of the library has changed to libjson-c.so and + the header files are now in include/json-c. + The pkgconfig name has also changed from json to json-c. + You should change your build to use appropriate -I and -l options. + A compatibility shim is in place so builds using the old name will + continue to work, but that will be removed in the next release. + * Maximum recursion depth is now a runtime option. + json_tokener_new() is provided for compatibility. + json_tokener_new_ex(depth) + * Include json_object_iterator.h in the installed headers. + * Add support for building on Android. + * Rewrite json_object_object_add to replace just the value if the key already exists so keys remain valid. + * Make it safe to delete keys while iterating with the json_object_object_foreach macro. + * Add a json_set_serializer() function to allow the string output of a json_object to be customized. + * Make float parsing locale independent. + * Add a json_tokener_set_flags() function and a JSON_TOKENER_STRICT flag. + * Enable -Werror when building. + * speed improvements to parsing 64-bit integers on systems with working sscanf + * Add a json_object_object_length function. + * Fix a bug (buffer overrun) when expanding arrays to more than 64 entries. + +0.10 +==== + + * Add a json_object_to_json_string_ext() function to allow output to be + formatted in a more human readable form. + * Add json_object_object_get_ex(), a NULL-safe get object method, to be able + to distinguish between a key not present and the value being NULL. + * Add an alternative iterator implementation, see json_object_iterator.h + * Make json_object_iter public to enable external use of the + json_object_object_foreachC macro. + * Add a printbuf_memset() function to provide an effecient way to set and + append things like whitespace indentation. + * Adjust json_object_is_type and json_object_get_type so they return + json_type_null for NULL objects and handle NULL passed to + json_objct_object_get(). + * Rename boolean type to json_bool. + * Fix various compile issues for Visual Studio and MinGW. + * Allow json_tokener_parse_ex() to be re-used to parse multiple object. + Also, fix some parsing issues with capitalized hexadecimal numbers and + number in E notation. + * Add json_tokener_get_error() and json_tokener_error_desc() to better + encapsulate the process of retrieving errors while parsing. + * Various improvements to the documentation of many functions. + * Add new json_object_array_sort() function. + * Fix a bug in json_object_get_int(), which would incorrectly return 0 + when called on a string type object. + Eric Haszlakiewicz + * Add a json_type_to_name() function. + Eric Haszlakiewicz + * Add a json_tokener_parse_verbose() function. + Jehiah Czebotar + * Improve support for null bytes within JSON strings. + Jehiah Czebotar + * Fix file descriptor leak if memory allocation fails in json_util + Zachary Blair, zack_blair at hotmail dot com + * Add int64 support. Two new functions json_object_net_int64 and + json_object_get_int64. Binary compatibility preserved. + Eric Haszlakiewicz, EHASZLA at transunion com + Rui Miguel Silva Seabra, rms at 1407 dot org + * Fix subtle bug in linkhash where lookup could hang after all slots + were filled then successively freed. + Spotted by Jean-Marc Naud, j dash m at newtraxtech dot com + * Make json_object_from_file take const char *filename + Spotted by Vikram Raj V, vsagar at attinteractive dot com + * Add handling of surrogate pairs (json_tokener.c, test4.c, Makefile.am) + Brent Miller, bdmiller at yahoo dash inc dot com + * Correction to comment describing printbuf_memappend in printbuf.h + Brent Miller, bdmiller at yahoo dash inc dot com + +0.9 +=== + * Add README.html README-WIN32.html config.h.win32 to Makefile.am + Michael Clark, + * Add const qualifier to the json_tokener_parse functions + Eric Haszlakiewicz, EHASZLA at transunion dot com + * Rename min and max so we can never clash with C or C++ std library + Ian Atha, thatha at yahoo dash inc dot com + * Fix any noticeable spelling or grammar errors. + * Make sure every va_start has a va_end. + * Check all pointers for validity. + Erik Hovland, erik at hovland dot org + * Fix json_object_get_boolean to return false for empty string + Spotted by Vitaly Kruglikov, Vitaly dot Kruglikov at palm dot com + * optimizations to json_tokener_parse_ex(), printbuf_memappend() + Brent Miller, bdmiller at yahoo dash inc dot com + * Disable REFCOUNT_DEBUG by default in json_object.c + * Don't use this as a variable, so we can compile with a C++ compiler + * Add casts from void* to type of assignment when using malloc + * Add #ifdef __cplusplus guards to all of the headers + * Add typedefs for json_object, json_tokener, array_list, printbuf, lh_table + Michael Clark, + * Null pointer dereference fix. Fix json_object_get_boolean strlen test + to not return TRUE for zero length string. Remove redundant includes. + Erik Hovland, erik at hovland dot org + * Fixed warning reported by adding -Wstrict-prototypes + -Wold-style-definition to the compilatin flags. + Dotan Barak, dotanba at gmail dot com + * Add const correctness to public interfaces + Gerard Krol, g dot c dot krol at student dot tudelft dot nl + +0.8 +=== + * Add va_end for every va_start + Dotan Barak, dotanba at gmail dot com + * Add macros to enable compiling out debug code + Geoffrey Young, geoff at modperlcookbook dot org + * Fix bug with use of capital E in numbers with exponents + Mateusz Loskot, mateusz at loskot dot net + * Add stddef.h include + * Patch allows for json-c compile with -Werror and not fail due to + -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations + Geoffrey Young, geoff at modperlcookbook dot org + +0.7 +=== + * Add escaping of backslash to json output + * Add escaping of foward slash on tokenizing and output + * Changes to internal tokenizer from using recursion to + using a depth state structure to allow incremental parsing + +0.6 +=== + * Fix bug in escaping of control characters + Johan Björklund, johbjo09 at kth dot se + * Remove include "config.h" from headers (should only + be included from .c files) + Michael Clark + +0.5 +=== + * Make headers C++ compatible by change *this to *obj + * Add ifdef C++ extern "C" to headers + * Use simpler definition of min and max in bits.h + Larry Lansing, llansing at fuzzynerd dot com + + * Remove automake 1.6 requirement + * Move autogen commands into autogen.sh. Update README + * Remove error pointer special case for Windows + * Change license from LGPL to MIT + Michael Clark + +0.4 +=== + * Fix additional error case in object parsing + * Add back sign reversal in nested object parse as error pointer + value is negative, while error value is positive. + Michael Clark + +0.3 +=== + * fix pointer arithmetic bug for error pointer check in is_error() macro + * fix type passed to printbuf_memappend in json_tokener + * update autotools bootstrap instructions in README + Michael Clark + +0.2 +=== + * printbuf.c - C. Watford (christopher.watford@gmail.com) + Added a Win32/Win64 compliant implementation of vasprintf + * debug.c - C. Watford (christopher.watford@gmail.com) + Removed usage of vsyslog on Win32/Win64 systems, needs to be handled + by a configure script + * json_object.c - C. Watford (christopher.watford@gmail.com) + Added scope operator to wrap usage of json_object_object_foreach, this + needs to be rethought to be more ANSI C friendly + * json_object.h - C. Watford (christopher.watford@gmail.com) + Added Microsoft C friendly version of json_object_object_foreach + * json_tokener.c - C. Watford (christopher.watford@gmail.com) + Added a Win32/Win64 compliant implementation of strndup + * json_util.c - C. Watford (christopher.watford@gmail.com) + Added cast and mask to suffice size_t v. unsigned int conversion + correctness + * json_tokener.c - sign reversal issue on error info for nested object parse + spotted by Johan Björklund (johbjo09 at kth.se) + * json_object.c - escape " in json_escape_str + * Change to automake and libtool to build shared and static library + Michael Clark + +0.1 +=== + * initial release diff --git a/third_party/json-c/INSTALL b/third_party/json-c/INSTALL new file mode 100644 index 0000000000..5fb10a02cb --- /dev/null +++ b/third_party/json-c/INSTALL @@ -0,0 +1,3 @@ + +See README.md for installation instructions. + diff --git a/third_party/json-c/NEWS b/third_party/json-c/NEWS new file mode 100644 index 0000000000..5798fb41b9 --- /dev/null +++ b/third_party/json-c/NEWS @@ -0,0 +1 @@ +See the git repo. diff --git a/third_party/json-c/README.html b/third_party/json-c/README.html new file mode 100644 index 0000000000..d36156952b --- /dev/null +++ b/third_party/json-c/README.html @@ -0,0 +1,42 @@ + + + + JSON-C - A JSON implementation in C + + + +

JSON-C - A JSON implementation in C

+ +

Overview

+

JSON-C implements a reference counting object model that allows you to easily + construct JSON objects in C, output them as JSON formatted strings and parse + JSON formatted strings back into the C representation of JSON objects. + It aims to conform to RFC 7159. +

+ +

Building

+

To setup JSON-C to build on your system please run configure and make.

+

If you are on Win32 cmake is required, generally:

+
    +
  • mkdir build
  • +
  • cd build
  • +
  • cmake ..
  • +
  • msbuild "json-c.vcxproj" /m /verbosity:normal /p:OutDir=lib\
  • +
  • Or, open the project in Visual Studio
  • +
+ +

Documentation

+

Doxygen generated documentation exists here + and Win32 specific notes can be found here.

+ +

GIT Reposository

+

git clone https://github.com/json-c/json-c.git

+ +

Mailing List

+ Send email to json-c <at> googlegroups <dot> com

+ +

License

+

This program is free software; you can redistribute it and/or modify it under the terms of the MIT License.

+
+ + diff --git a/third_party/json-c/README.md b/third_party/json-c/README.md new file mode 100644 index 0000000000..1441e933eb --- /dev/null +++ b/third_party/json-c/README.md @@ -0,0 +1,173 @@ +`json-c` {#mainpage} +======== + +1. [Overview and Build Status](#overview) +2. [Building on Unix](#buildunix) +3. [Install Prerequisites](#installprereq) +4. [Building with partial threading support](#buildthreaded) +5. [Linking to libjson-c](#linking) +6. [Using json-c](#using) + +JSON-C - A JSON implementation in C +----------------------------------- + +Build Status +* [AppVeyor Build](https://ci.appveyor.com/project/hawicz/json-c) ![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/json-c/json-c?branch=master&svg=true) +* [Travis Build](https://travis-ci.org/json-c/json-c) ![Travis Build Status](https://travis-ci.org/json-c/json-c.svg?branch=master) + +JSON-C implements a reference counting object model that allows you to easily +construct JSON objects in C, output them as JSON formatted strings and parse +JSON formatted strings back into the C representation of JSON objects. +It aims to conform to [RFC 7159](https://tools.ietf.org/html/rfc7159). + + +Building on Unix with `git`, `gcc` and `autotools` +-------------------------------------------------- + +Home page for json-c: https://github.com/json-c/json-c/wiki + +### Prerequisites: + +See also the "Installing prerequisites" section below. + + - `gcc`, `clang`, or another C compiler + - `libtool>=2.2.6b` + +If you're not using a release tarball, you'll also need: + + - `autoconf>=2.64` (`autoreconf`) + - `automake>=1.13` + +Make sure you have a complete `libtool` install, including `libtoolize`. + +To generate docs (e.g. as part of make distcheck) you'll also need: + - `doxygen>=1.8.13` + +### Build instructions: + +`json-c` GitHub repo: https://github.com/json-c/json-c + +```sh +$ git clone https://github.com/json-c/json-c.git +$ cd json-c +$ sh autogen.sh +``` + +followed by + +```sh +$ ./configure # --enable-threading +$ make +$ make install +``` + +To build and run the test programs: + +```sh +$ make check +$ make USE_VALGRIND=0 check # optionally skip using valgrind +``` + +Install prerequisites +----------------------- + +If you are on a relatively modern system, you'll likely be able to install +the prerequisites using your OS's packaging system. + +### Install using apt (e.g. Ubuntu 16.04.2 LTS) +```sh +sudo apt install git +sudo apt install autoconf automake libtool +sudo apt install valgrind # optional +``` + +Then start from the "git clone" command, above. + +### Manually install and build autoconf, automake and libtool + +For older OS's that don't have up-to-date version of the packages will +require a bit more work. For example, CentOS release 5.11, etc... + +```sh +curl -O http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz +curl -O http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz +curl -O http://ftp.gnu.org/gnu/libtool/libtool-2.2.6b.tar.gz + +tar xzf autoconf-2.69.tar.gz +tar xzf automake-1.15.tar.gz +tar xzf libtool-2.2.6b.tar.gz + +export PATH=${HOME}/ac_install/bin:$PATH + +(cd autoconf-2.69 && \ + ./configure --prefix ${HOME}/ac_install && \ + make && \ + make install) + +(cd automake-1.15 && \ + ./configure --prefix ${HOME}/ac_install && \ + make && \ + make install) + +(cd libtool-2.2.6b && \ + ./configure --prefix ${HOME}/ac_install && \ + make && \ + make install) +``` + + +Building with partial threading support +---------------------------------------- + +Although json-c does not support fully multi-threaded access to +object trees, it has some code to help make use in threaded programs +a bit safer. Currently, this is limited to using atomic operations for +json_object_get() and json_object_put(). + +Since this may have a performance impact, of at least 3x slower +according to https://stackoverflow.com/a/11609063, it is disabled by +default. You may turn it on by adjusting your configure command with: + --enable-threading + +Separately, the default hash function used for object field keys, +lh_char_hash, uses a compare-and-swap operation to ensure the randomly +seed is only generated once. Because this is a one-time operation, it +is always compiled in when the compare-and-swap operation is available. + + +Linking to `libjson-c` +---------------------- + +If your system has `pkgconfig`, +then you can just add this to your `makefile`: + +```make +CFLAGS += $(shell pkg-config --cflags json-c) +LDFLAGS += $(shell pkg-config --libs json-c) +``` + +Without `pkgconfig`, you would do something like this: + +```make +JSON_C_DIR=/path/to/json_c/install +CFLAGS += -I$(JSON_C_DIR)/include/json-c +LDFLAGS+= -L$(JSON_C_DIR)/lib -ljson-c +``` + + +Using json-c +------------ + +To use json-c you can either include json.h, or preferrably, one of the +following more specific header files: + +* json_object.h - Core types and methods. +* json_tokener.h - Methods for parsing and serializing json-c object trees. +* json_pointer.h - JSON Pointer (RFC 6901) implementation for retrieving + objects from a json-c object tree. +* json_object_iterator.h - Methods for iterating over single json_object instances. +* json_visit.h - Methods for walking a tree of json-c objects. +* json_util.h - Miscelleanous utility functions. + +For a full list of headers see [files.html](files.html) + diff --git a/third_party/json-c/RELEASE_CHECKLIST.txt b/third_party/json-c/RELEASE_CHECKLIST.txt new file mode 100644 index 0000000000..28cb97304c --- /dev/null +++ b/third_party/json-c/RELEASE_CHECKLIST.txt @@ -0,0 +1,136 @@ + +Release checklist: + +release=0.13 +git clone https://github.com/json-c/json-c json-c-${release} +cd json-c-${release} + +Check that the compile works on Linux +Check that the compile works on NetBSD +Check that the compile works on Windows +Run "make distcheck" and fix any problems + (e.g. adding new files to SOURCES variables in Makefile.am) +Check ChangeLog to see if anything should be added. +Make any fixes/changes *before* branching. + + git branch json-c-${release} + git checkout json-c-${release} + +------------ + +Update the version in json_c_version.h +Update the version in Doxyfile +Update the version in configure.ac +Update the version in CMakeLists.txt + Use ${release}. + +Update the libjson_la_LDFLAGS line in Makefile.am to the new version. + Generally, unless we're doing a major release, change: + -version-info x:y:z + to + -version-info x:y+1:z + +------------ + +Generate the configure script and other files: + sh autogen.sh + git add -f Makefile.in aclocal.m4 config.guess config.h.in \ + config.sub configure depcomp install-sh \ + ltmain.sh missing tests/Makefile.in \ + INSTALL + + # check for anything else to be added: + git status --ignored + git commit + +------------ + +Generate the doxygen documentation: + doxygen + git add -f doc + git commit doc + +------------ + +cd .. +echo .git > excludes +echo autom4te.cache >> excludes +tar -czf json-c-${release}.tar.gz -X excludes json-c-${release} + +echo doc >> excludes +tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release} + +------------ + +Tag the branch: +cd json-c-${release} +git tag -a json-c-${release}-$(date +%Y%m%d) -m "Release json-c-${release}" + +git push origin json-c-${release} +git push --tags + +------------ + +Go to Amazon S3 service at: + https://console.aws.amazon.com/s3/ + +Upload the two tarballs in the json-c_releases folder. + When uploading, use "Reduced Redundancy", and make the uploaded files publicly accessible. + +Logout of Amazon S3, and verify that the files are visible. + https://s3.amazonaws.com/json-c_releases/releases/index.html + +=================================== + +Post-release checklist: + +git checkout master +Add new section to ChangeLog +Update the version in json_c_version.h +Update the version in Doxyfile +Update the version in configure.ac +Update the version in CMakeLists.txt + Use ${release}.99 to indicate a version "newer" than anything on the branch. + +Leave the libjson_la_LDFLAGS line in Makefile.am alone. + For more details see: + http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html + +------------ + +Update the gh-pages branch with new docs: + +cd json-c-${release} +git checkout json-c-${release} +cd .. + +git clone -b gh-pages https://github.com/json-c/json-c json-c-pages +cd json-c-pages +mkdir json-c-${release} +cp -R ../json-c-${release}/doc json-c-${release}/. +cp ../json-c-${release}/README-WIN32.html json-c-${release}/. +git add json-c-${release} +git commit + +vi index.html + Add/change links to current release. + +git commit index.html + +git push + +------------ + +Update checksums on wiki page. + +cd .. +openssl sha -sha256 json-c*gz +openssl md5 json-c*gz + +Copy and paste this output into the wiki page at: + https://github.com/json-c/json-c/wiki + +------------ + +Send an email to the mailing list. + diff --git a/third_party/json-c/STYLE.txt b/third_party/json-c/STYLE.txt new file mode 100755 index 0000000000..2dffbe7e02 --- /dev/null +++ b/third_party/json-c/STYLE.txt @@ -0,0 +1,31 @@ +In general: +For minor changes to a function, copy the existing formatting. +When changing the style, commit that separately from other changes. +For new code and major changes to a function, switch to the official json-c style. + +Official json-c style: +Aim for readability, not strict conformance to fixed style rules. +These rules are not comprehensive. Look to existing code for guidelines. +Indentation is tab based, with continuations of long lines starting with tabs then spaces for alignment. +Try to line up components of continuation lines with corresponding part of the line above (i.e. "indent -lp" effect), but avoid excessive identation tha causes extra line wraps. + e.g. (T=tab, S=space): +TTTTsome_long_func_call(arg1, arg2, +TTTTSSSSSSSSSSSSSSSSSSSarg3, arg4); +TTTTsome_reallly_really_long_func_name(arg1, +TTTTTarg2, arg3, arg4); +There should be a space between "if"/"while" and the following parenthesis. +"case" lines are indented at the same level as the "switch" statement. +Commas are followed by a single space. +Include spaces around most non-unary, non-postfix operators, "=", "==', "&", "||", etc... +Function calls have no space between the name and the parenthesis. +Curly braces go on their own line. +Curly braces may be omitted. + +Naming: +Words within function and variable names are separated with underscores. Avoid camel case. +Prefer longer, more descriptive names, but not excessively so. No single letter variable names. + +Other: +Variables should be defined for the smallest scope needed. +Functions should be defined static when possible. +When possible, avoid exposing internals in the public API. diff --git a/third_party/json-c/arraylist.c b/third_party/json-c/arraylist.c new file mode 100644 index 0000000000..ddeb8d4eb4 --- /dev/null +++ b/third_party/json-c/arraylist.c @@ -0,0 +1,146 @@ +/* + * $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include + +#ifdef STDC_HEADERS +# include +# include +#endif /* STDC_HEADERS */ + +#if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD) +# include +#endif /* HAVE_STRINGS_H */ + +#ifndef SIZE_T_MAX +#if SIZEOF_SIZE_T == SIZEOF_INT +#define SIZE_T_MAX UINT_MAX +#elif SIZEOF_SIZE_T == SIZEOF_LONG +#define SIZE_T_MAX ULONG_MAX +#elif SIZEOF_SIZE_T == SIZEOF_LONG_LONG +#define SIZE_T_MAX ULLONG_MAX +#else +#error Unable to determine size of size_t +#endif +#endif + +#include "arraylist.h" + +struct array_list* +array_list_new(array_list_free_fn *free_fn) +{ + struct array_list *arr; + + arr = (struct array_list*)calloc(1, sizeof(struct array_list)); + if(!arr) return NULL; + arr->size = ARRAY_LIST_DEFAULT_SIZE; + arr->length = 0; + arr->free_fn = free_fn; + if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) { + free(arr); + return NULL; + } + return arr; +} + +extern void +array_list_free(struct array_list *arr) +{ + size_t i; + for(i = 0; i < arr->length; i++) + if(arr->array[i]) arr->free_fn(arr->array[i]); + free(arr->array); + free(arr); +} + +void* +array_list_get_idx(struct array_list *arr, size_t i) +{ + if(i >= arr->length) return NULL; + return arr->array[i]; +} + +static int array_list_expand_internal(struct array_list *arr, size_t max) +{ + void *t; + size_t new_size; + + if(max < arr->size) return 0; + /* Avoid undefined behaviour on size_t overflow */ + if( arr->size >= SIZE_T_MAX / 2 ) + new_size = max; + else + { + new_size = arr->size << 1; + if (new_size < max) + new_size = max; + } + if (new_size > (~((size_t)0)) / sizeof(void*)) return -1; + if (!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1; + arr->array = (void**)t; + (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*)); + arr->size = new_size; + return 0; +} + +int +array_list_put_idx(struct array_list *arr, size_t idx, void *data) +{ + if (idx > SIZE_T_MAX - 1 ) return -1; + if(array_list_expand_internal(arr, idx+1)) return -1; + if(idx < arr->length && arr->array[idx]) + arr->free_fn(arr->array[idx]); + arr->array[idx] = data; + if(arr->length <= idx) arr->length = idx + 1; + return 0; +} + +int +array_list_add(struct array_list *arr, void *data) +{ + return array_list_put_idx(arr, arr->length, data); +} + +void +array_list_sort(struct array_list *arr, int(*sort_fn)(const void *, const void *)) +{ + qsort(arr->array, arr->length, sizeof(arr->array[0]), sort_fn); +} + +void* array_list_bsearch(const void **key, struct array_list *arr, + int (*sort_fn)(const void *, const void *)) +{ + return bsearch(key, arr->array, arr->length, sizeof(arr->array[0]), + sort_fn); +} + +size_t +array_list_length(struct array_list *arr) +{ + return arr->length; +} + +int +array_list_del_idx( struct array_list *arr, size_t idx, size_t count ) +{ + size_t i, stop; + + stop = idx + count; + if ( idx >= arr->length || stop > arr->length ) return -1; + for ( i = idx; i < stop; ++i ) { + if ( arr->array[i] ) arr->free_fn( arr->array[i] ); + } + memmove( arr->array + idx, arr->array + stop, (arr->length - stop) * sizeof(void*) ); + arr->length -= count; + return 0; +} diff --git a/third_party/json-c/arraylist.h b/third_party/json-c/arraylist.h new file mode 100644 index 0000000000..38603e8aa5 --- /dev/null +++ b/third_party/json-c/arraylist.h @@ -0,0 +1,70 @@ +/* + * $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Internal methods for working with json_type_array objects. + * Although this is exposed by the json_object_get_array() method, + * it is not recommended for direct use. + */ +#ifndef _arraylist_h_ +#define _arraylist_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARRAY_LIST_DEFAULT_SIZE 32 + +typedef void (array_list_free_fn) (void *data); + +struct array_list +{ + void **array; + size_t length; + size_t size; + array_list_free_fn *free_fn; +}; +typedef struct array_list array_list; + +extern struct array_list* +array_list_new(array_list_free_fn *free_fn); + +extern void +array_list_free(struct array_list *al); + +extern void* +array_list_get_idx(struct array_list *al, size_t i); + +extern int +array_list_put_idx(struct array_list *al, size_t i, void *data); + +extern int +array_list_add(struct array_list *al, void *data); + +extern size_t +array_list_length(struct array_list *al); + +extern void +array_list_sort(struct array_list *arr, int(*compar)(const void *, const void *)); + +extern void* array_list_bsearch(const void **key, + struct array_list *arr, + int (*sort_fn)(const void *, const void *)); + +extern int +array_list_del_idx(struct array_list *arr, size_t idx, size_t count); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/bits.h b/third_party/json-c/bits.h new file mode 100644 index 0000000000..14c1c132d3 --- /dev/null +++ b/third_party/json-c/bits.h @@ -0,0 +1,36 @@ +/** + * @file + * @brief Do not use, only contains deprecated defines. + * @deprecated Use json_util.h instead. + * + * $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#ifndef _bits_h_ +#define _bits_h_ + +/** + * @deprecated + */ +#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) +/** + * @deprecated + */ +#define error_ptr(error) ((void*)error) +/** + * @deprecated + */ +#define error_description(error) (json_tokener_get_error(error)) +/** + * @deprecated + */ +#define is_error(ptr) (ptr == NULL) + +#endif diff --git a/third_party/json-c/config.h.in b/third_party/json-c/config.h.in new file mode 100644 index 0000000000..363eb349c0 --- /dev/null +++ b/third_party/json-c/config.h.in @@ -0,0 +1,196 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Enable RDRAND Hardware RNG Hash Seed */ +#undef ENABLE_RDRAND + +/* Enable partial threading support */ +#undef ENABLE_THREADING + +/* Define if .gnu.warning accepts long strings. */ +#undef HAS_GNU_WARNING_LONG + +/* Has atomic builtins */ +#undef HAVE_ATOMIC_BUILTINS + +/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you + don't. */ +#undef HAVE_DECL_INFINITY + +/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. + */ +#undef HAVE_DECL_ISINF + +/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. + */ +#undef HAVE_DECL_ISNAN + +/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ +#undef HAVE_DECL_NAN + +/* Define to 1 if you have the declaration of `_finite', and to 0 if you + don't. */ +#undef HAVE_DECL__FINITE + +/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't. + */ +#undef HAVE_DECL__ISNAN + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `open' function. */ +#undef HAVE_OPEN + +/* Define to 1 if you have the `realloc' function. */ +#undef HAVE_REALLOC + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_CDEFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `uselocale' function. */ +#undef HAVE_USELOCALE + +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + +/* Define to 1 if you have the header file. */ +#undef HAVE_XLOCALE_H + +/* Have __thread */ +#undef HAVE___THREAD + +/* Public define for json_inttypes.h */ +#undef JSON_C_HAVE_INTTYPES_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The number of bytes in type int */ +#undef SIZEOF_INT + +/* The number of bytes in type int64_t */ +#undef SIZEOF_INT64_T + +/* The number of bytes in type long */ +#undef SIZEOF_LONG + +/* The number of bytes in type long long */ +#undef SIZEOF_LONG_LONG + +/* The number of bytes in type size_t */ +#undef SIZEOF_SIZE_T + +/* Specifier for __thread */ +#undef SPEC___THREAD + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/third_party/json-c/config.h.win32 b/third_party/json-c/config.h.win32 new file mode 100644 index 0000000000..eda08474f3 --- /dev/null +++ b/third_party/json-c/config.h.win32 @@ -0,0 +1,205 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Enable RDRANR Hardware RNG Hash Seed */ +#undef ENABLE_RDRAND + +/* Define if .gnu.warning accepts long strings. */ +#undef HAS_GNU_WARNING_LONG + +/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you + don't. */ +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) +#define HAVE_DECL_INFINITY 1 +#endif + +/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. + */ +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) +#define HAVE_DECL_ISINF 1 +#endif + +/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. + */ +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) +#define HAVE_DECL_ISNAN 1 +#endif + +/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ +#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) +#define HAVE_DECL_NAN 1 +#endif + +/* Define to 1 if you have the declaration of `_finite', and to 0 if you + don't. */ +#define HAVE_DECL__FINITE 1 + +/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't. + */ +#define HAVE_DECL__ISNAN 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#define HAVE_DOPRNT 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `open' function. */ +#define HAVE_OPEN 1 + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `snprintf' function. */ +#if defined(__MINGW32__) +#define HAVE_SNPRINTF 1 +#else +#undef HAVE_SNPRINTF +#endif + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 0 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#if defined(__MINGW32__) +#define HAVE_STRNCASECMP 1 +#else +#undef HAVE_STRNCASECMP +#endif + +#cmakedefine HAVE_STRTOLL +#cmakedefine strtoll @cmake_strtoll@ + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_CDEFS_H 1 + +/* Define to 1 if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_SYS_PARAM_H 1 +#else +#undef HAVE_SYS_PARAM_H +#endif + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#if defined(__MINGW32__) +#define HAVE_UNISTD_H 1 +#else +#undef HAVE_UNISTD_H +#endif + +/* Define to 1 if you have the `vasprintf' function. */ +#if defined(__MINGW32__) +#define HAVE_VASPRINTF 1 +#else +#undef HAVE_VASPRINTF +#endif + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "json-c" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "json-c@googlegroups.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "JSON C Library" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "JSON C Library 0.13.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "json-c" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "https://github.com/json-c/json-c" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.13.1" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.13.1" + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/third_party/json-c/debug.c b/third_party/json-c/debug.c new file mode 100644 index 0000000000..4b5140aec1 --- /dev/null +++ b/third_party/json-c/debug.c @@ -0,0 +1,83 @@ +/* + * $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include +#include +#include +#include + +#if HAVE_SYSLOG_H +# include +#endif /* HAVE_SYSLOG_H */ + +#if HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ + +#if HAVE_SYS_PARAM_H +#include +#endif /* HAVE_SYS_PARAM_H */ + +#include "debug.h" + +static int _syslog = 0; +static int _debug = 0; + +void mc_set_debug(int debug) { _debug = debug; } +int mc_get_debug(void) { return _debug; } + +extern void mc_set_syslog(int syslog) +{ + _syslog = syslog; +} + +void mc_debug(const char *msg, ...) +{ + va_list ap; + if(_debug) { + va_start(ap, msg); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_DEBUG, msg, ap); + } else +#endif + vprintf(msg, ap); + va_end(ap); + } +} + +void mc_error(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_ERR, msg, ap); + } else +#endif + vfprintf(stderr, msg, ap); + va_end(ap); +} + +void mc_info(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); +#if HAVE_VSYSLOG + if(_syslog) { + vsyslog(LOG_INFO, msg, ap); + } else +#endif + vfprintf(stderr, msg, ap); + va_end(ap); +} diff --git a/third_party/json-c/debug.h b/third_party/json-c/debug.h new file mode 100644 index 0000000000..07fcc380b3 --- /dev/null +++ b/third_party/json-c/debug.h @@ -0,0 +1,75 @@ +/* + * $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void mc_set_debug(int debug); +extern int mc_get_debug(void); + +extern void mc_set_syslog(int syslog); + +extern void mc_debug(const char *msg, ...); +extern void mc_error(const char *msg, ...); +extern void mc_info(const char *msg, ...); + +#ifndef __STRING +#define __STRING(x) #x +#endif + +#ifndef PARSER_BROKEN_FIXED + +#define JASSERT(cond) do {} while(0) + +#else + +#define JASSERT(cond) do { \ + if (!(cond)) { \ + mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \ + *(int *)0 = 1;\ + abort(); \ + }\ + } while(0) + +#endif + +#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) + +#ifdef MC_MAINTAINER_MODE +#define MC_SET_DEBUG(x) mc_set_debug(x) +#define MC_GET_DEBUG() mc_get_debug() +#define MC_SET_SYSLOG(x) mc_set_syslog(x) +#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__) +#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__) +#else +#define MC_SET_DEBUG(x) if (0) mc_set_debug(x) +#define MC_GET_DEBUG() (0) +#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x) +#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__) +#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/issues_closed_for_0.13.md b/third_party/json-c/issues_closed_for_0.13.md new file mode 100644 index 0000000000..a29e43705f --- /dev/null +++ b/third_party/json-c/issues_closed_for_0.13.md @@ -0,0 +1,267 @@ + +This list was created with: + +curl https://api.github.com/search/issues?q="repo%3Ajson-c%2Fjson-c+closed%3A>2014-04-10+created%3A<2017-12-01&sort=created&order=asc&per_page=400&page=1" > issues1.out +curl https://api.github.com/search/issues?q="repo%3Ajson-c%2Fjson-c+closed%3A>2014-04-10+created%3A<2017-12-01&sort=created&order=asc&per_page=400&page=2" > issues2.out +curl https://api.github.com/search/issues?q="repo%3Ajson-c%2Fjson-c+closed%3A>2014-04-10+created%3A<2017-12-01&sort=created&order=asc&per_page=400&page=3" > issues3.out +jq -r '.items[] | "[" + .title + "](" + .url + ")" | tostring' issues?.out > issues.md +#... manual editing ... + +---- + +Issues and Pull Requests closed for the 0.13 release +(since commit f84d9c, the 0.12 branch point, 2014-04-10) + +[Make json_object_object_add() indicate success or failure, test fix](https://api.github.com/repos/json-c/json-c/issues/61) +[Build fixes (make dist and make distcheck)](https://api.github.com/repos/json-c/json-c/issues/113) +[Fixing build](https://api.github.com/repos/json-c/json-c/issues/124) +[Fix compile error(variable size set but not used) on g++4.6](https://api.github.com/repos/json-c/json-c/issues/125) +[Removed unused size variable.](https://api.github.com/repos/json-c/json-c/issues/126) +[remove unused `size` variable](https://api.github.com/repos/json-c/json-c/issues/127) +[Remove unused variable from json_tokenizer.c](https://api.github.com/repos/json-c/json-c/issues/128) +[Failed to compile under Ubuntu 13.10 32bit](https://api.github.com/repos/json-c/json-c/issues/130) +[undefined symbol: __sync_val_compare_and_swap_4 ](https://api.github.com/repos/json-c/json-c/issues/131) +[Remove unused variable 'size'](https://api.github.com/repos/json-c/json-c/issues/132) +[Update and rename README to README.md](https://api.github.com/repos/json-c/json-c/issues/133) +[Must remove variable size...](https://api.github.com/repos/json-c/json-c/issues/134) +[bits.h uses removed json_tokener_errors\[error\]](https://api.github.com/repos/json-c/json-c/issues/135) +[Error when running make check](https://api.github.com/repos/json-c/json-c/issues/136) +[config.h.in should not be in git](https://api.github.com/repos/json-c/json-c/issues/137) +[Can't build on RHEL 6.5 due to dependency on automake-1.14](https://api.github.com/repos/json-c/json-c/issues/138) +[Code bug in random_test.c evaluating same expression twice ](https://api.github.com/repos/json-c/json-c/issues/140) +[Removed duplicate check in random_seed test - bug #140](https://api.github.com/repos/json-c/json-c/issues/141) +[Please undeprecate json_object_object_get](https://api.github.com/repos/json-c/json-c/issues/142) +[Introduce json_object_from_fd](https://api.github.com/repos/json-c/json-c/issues/144) +[Handle % character properly](https://api.github.com/repos/json-c/json-c/issues/145) +[TAGS rename](https://api.github.com/repos/json-c/json-c/issues/146) +[Bump the soname](https://api.github.com/repos/json-c/json-c/issues/148) +[SONAME bump](https://api.github.com/repos/json-c/json-c/issues/149) +[Fix build using MinGW.](https://api.github.com/repos/json-c/json-c/issues/150) +[Remove json_type enum trailing comma](https://api.github.com/repos/json-c/json-c/issues/151) +[error while compiling json-c library version 0.11](https://api.github.com/repos/json-c/json-c/issues/152) +[improve doc for json_object_to_json_string()](https://api.github.com/repos/json-c/json-c/issues/153) +[double precision](https://api.github.com/repos/json-c/json-c/issues/154) +[add bsearch for arrays](https://api.github.com/repos/json-c/json-c/issues/155) +[Remove trailing whitespaces](https://api.github.com/repos/json-c/json-c/issues/156) +[JSON-C shall not exit on calloc fail.](https://api.github.com/repos/json-c/json-c/issues/157) +[while using json-c 0.11, I am facing strange crash issue in json_object_put.](https://api.github.com/repos/json-c/json-c/issues/158) +[json_tokener.c compile error](https://api.github.com/repos/json-c/json-c/issues/159) +[missing header file on windows??](https://api.github.com/repos/json-c/json-c/issues/160) +[Is there a way to append to file?](https://api.github.com/repos/json-c/json-c/issues/161) +[json_util: add directory check for POSIX distros](https://api.github.com/repos/json-c/json-c/issues/162) +[Fix Win32 build problems](https://api.github.com/repos/json-c/json-c/issues/163) +[made it compile and link on Widnows (as static library)](https://api.github.com/repos/json-c/json-c/issues/164) +[json_object_to_json_string_ext length](https://api.github.com/repos/json-c/json-c/issues/165) +[Can't build on Windows with Visual Studio 2010](https://api.github.com/repos/json-c/json-c/issues/167) +[Tightening the number parsing algorithm](https://api.github.com/repos/json-c/json-c/issues/168) +[Doesn't compile on ubuntu 14.04, 64bit](https://api.github.com/repos/json-c/json-c/issues/169) +[Generated files in repository](https://api.github.com/repos/json-c/json-c/issues/170) +[Update configuration for VS2010 and win64](https://api.github.com/repos/json-c/json-c/issues/171) +[Adding support for parsing octal numbers](https://api.github.com/repos/json-c/json-c/issues/172) +[json_parse_int64 doesn't work correctly at illumos](https://api.github.com/repos/json-c/json-c/issues/173) +[Adding JSON_C_TO_STRING_PRETTY_TAB flag](https://api.github.com/repos/json-c/json-c/issues/174) +[make check fails 4 tests with overflows when built with ASAN](https://api.github.com/repos/json-c/json-c/issues/175) +[Possible to delete an array element at a given idx ?](https://api.github.com/repos/json-c/json-c/issues/176) +[Fix compiler warnings](https://api.github.com/repos/json-c/json-c/issues/177) +[Unable to compile on CentOS5](https://api.github.com/repos/json-c/json-c/issues/178) +[Added array_list_del_idx and json_object_array_del_idx](https://api.github.com/repos/json-c/json-c/issues/179) +[Enable silent build by default](https://api.github.com/repos/json-c/json-c/issues/180) +[json_tokener_parse_ex accepts invalid JSON](https://api.github.com/repos/json-c/json-c/issues/181) +[Link against libm when needed](https://api.github.com/repos/json-c/json-c/issues/182) +[Apply compile warning fix to master branch](https://api.github.com/repos/json-c/json-c/issues/183) +[Use only GCC-specific flags when compiling with GCC](https://api.github.com/repos/json-c/json-c/issues/184) +[compile error](https://api.github.com/repos/json-c/json-c/issues/185) +[Syntax error](https://api.github.com/repos/json-c/json-c/issues/186) +[array_list_get_idx and negative indexes.](https://api.github.com/repos/json-c/json-c/issues/187) +[json_object_object_foreach warnings](https://api.github.com/repos/json-c/json-c/issues/188) +[noisy json_object_from_file: error opening file](https://api.github.com/repos/json-c/json-c/issues/189) +[warning: initialization discards const qualifier from pointer target type \[enabled by default\]](https://api.github.com/repos/json-c/json-c/issues/190) +[json_tokener_parse accepts invalid JSON {"key": "value" , }](https://api.github.com/repos/json-c/json-c/issues/192) +[Make serialization format of doubles configurable](https://api.github.com/repos/json-c/json-c/issues/193) +[Add utility function for comparing json_objects](https://api.github.com/repos/json-c/json-c/issues/194) +[Call uselocale instead of setlocale](https://api.github.com/repos/json-c/json-c/issues/195) +[Performance improvements](https://api.github.com/repos/json-c/json-c/issues/196) +[Time for a new release?](https://api.github.com/repos/json-c/json-c/issues/197) +[Fix possible memory leak and remove superfluous NULL checks before free()](https://api.github.com/repos/json-c/json-c/issues/198) +[Fix build in Visual Studio](https://api.github.com/repos/json-c/json-c/issues/199) +[Add build scripts for CI platforms](https://api.github.com/repos/json-c/json-c/issues/200) +[disable forward-slash escaping?](https://api.github.com/repos/json-c/json-c/issues/201) +[Array with objects support](https://api.github.com/repos/json-c/json-c/issues/202) +[Add source position/coordinates to API](https://api.github.com/repos/json-c/json-c/issues/203) +[json-c/json.h not found ](https://api.github.com/repos/json-c/json-c/issues/204) +[json-c Compiled with Visual Studios](https://api.github.com/repos/json-c/json-c/issues/205) +[what do i use in place of json_object_object_get?](https://api.github.com/repos/json-c/json-c/issues/206) +[Add support for property pairs directly added to arrays](https://api.github.com/repos/json-c/json-c/issues/207) +[Performance enhancements (mainly) to json_object_to_json_string()](https://api.github.com/repos/json-c/json-c/issues/208) +[fix regression from 2d549662be832da838aa063da2efa78ee3b99668](https://api.github.com/repos/json-c/json-c/issues/209) +[Use size_t for arrays](https://api.github.com/repos/json-c/json-c/issues/210) +[Atomic updates for the refcount](https://api.github.com/repos/json-c/json-c/issues/211) +[Refcount doesn't work between threads](https://api.github.com/repos/json-c/json-c/issues/212) +[fix to compile with microsoft visual c++ 2010](https://api.github.com/repos/json-c/json-c/issues/213) +[Some non-GNU systems support __sync_val_compare_and_swap](https://api.github.com/repos/json-c/json-c/issues/214) +[Build json-c for window 64 bit.](https://api.github.com/repos/json-c/json-c/issues/215) +[configure: check realloc with AC_CHECK_FUNCS() to fix cross-compilation.](https://api.github.com/repos/json-c/json-c/issues/216) +[Checking for functions in float.h](https://api.github.com/repos/json-c/json-c/issues/217) +[Use a macro to indicate C99 to the compiler](https://api.github.com/repos/json-c/json-c/issues/218) +[Fix various potential null ptr deref and int32 overflows](https://api.github.com/repos/json-c/json-c/issues/219) +[Add utility function for comparing json_objects](https://api.github.com/repos/json-c/json-c/issues/220) +[JSON_C_TO_STRING_NOSLASHESCAPE works incorrectly](https://api.github.com/repos/json-c/json-c/issues/221) +[Fix issue #221: JSON_C_TO_STRING_NOSLASHESCAPE works incorrectly](https://api.github.com/repos/json-c/json-c/issues/222) +[Clarify json_object_get_string documentation of NULL handling & return](https://api.github.com/repos/json-c/json-c/issues/223) +[json_tokener.c - all warnings being treated as errors](https://api.github.com/repos/json-c/json-c/issues/224) +[Hi, will you support clib as a "registry"?](https://api.github.com/repos/json-c/json-c/issues/225) +[Bump SOVERSION to 3](https://api.github.com/repos/json-c/json-c/issues/227) +[avoid double slashes from json](https://api.github.com/repos/json-c/json-c/issues/228) +[configure fails: checking size of size_t... configure: error: cannot determine a size for size_t](https://api.github.com/repos/json-c/json-c/issues/229) +[Use stdint.h to check for size_t size](https://api.github.com/repos/json-c/json-c/issues/230) +[Fix size_t size check for first-time builds](https://api.github.com/repos/json-c/json-c/issues/231) +[tests/tests1: fix printf format for size_t arguments](https://api.github.com/repos/json-c/json-c/issues/232) +[Include stddef.h in json_object.h](https://api.github.com/repos/json-c/json-c/issues/233) +[Add public API to use userdata independently of custom serializer](https://api.github.com/repos/json-c/json-c/issues/234) +[Undefined symbols Error for architecture x86_64 on Mac ](https://api.github.com/repos/json-c/json-c/issues/235) +[Building a project which uses json-c with flag -Wcast-qual causes compilation errors](https://api.github.com/repos/json-c/json-c/issues/236) +[handle escaped utf-8](https://api.github.com/repos/json-c/json-c/issues/237) +[linkhash.c: optimised the table_free path](https://api.github.com/repos/json-c/json-c/issues/238) +[initialize null terminator of new printbuf](https://api.github.com/repos/json-c/json-c/issues/239) +[Compile error: Variable set but not used](https://api.github.com/repos/json-c/json-c/issues/240) +[getting error in date string 19\/07\/2016, fixed for error 19/07/2016](https://api.github.com/repos/json-c/json-c/issues/241) +[json_tokener_parse error](https://api.github.com/repos/json-c/json-c/issues/242) +[Fix #165](https://api.github.com/repos/json-c/json-c/issues/243) +[Error while compiling source from RHEL5, could you please help me to fix this ](https://api.github.com/repos/json-c/json-c/issues/244) +[json-c compile in window xp](https://api.github.com/repos/json-c/json-c/issues/245) +[Mac: uselocale failed to build](https://api.github.com/repos/json-c/json-c/issues/246) +[json_object_array_del_idx function has segment fault error?](https://api.github.com/repos/json-c/json-c/issues/247) +[Minor changes in C source code](https://api.github.com/repos/json-c/json-c/issues/248) +[Improving README](https://api.github.com/repos/json-c/json-c/issues/249) +[Improving .gitignore](https://api.github.com/repos/json-c/json-c/issues/250) +[Adding a file for EditorConfig](https://api.github.com/repos/json-c/json-c/issues/251) +[Very minor changes not related to C source code](https://api.github.com/repos/json-c/json-c/issues/252) +[Adding a test with cppcheck for Travis CI](https://api.github.com/repos/json-c/json-c/issues/253) +[Very minor changes to some tests](https://api.github.com/repos/json-c/json-c/issues/254) +[Minor changes in C source code](https://api.github.com/repos/json-c/json-c/issues/255) +[Mailing list dead?](https://api.github.com/repos/json-c/json-c/issues/256) +[Defining a coding style](https://api.github.com/repos/json-c/json-c/issues/257) +[Enable CI services](https://api.github.com/repos/json-c/json-c/issues/258) +[Fails to parse valid json](https://api.github.com/repos/json-c/json-c/issues/259) +[Adding an object to itself](https://api.github.com/repos/json-c/json-c/issues/260) +[Lack of proper documentation](https://api.github.com/repos/json-c/json-c/issues/261) +[Add Cmakefile and fix compiler warning.](https://api.github.com/repos/json-c/json-c/issues/262) +[Compiler Warnings with VS2015](https://api.github.com/repos/json-c/json-c/issues/263) +[successed in simple test while failed in my project](https://api.github.com/repos/json-c/json-c/issues/264) +[Conformance report for reference](https://api.github.com/repos/json-c/json-c/issues/265) +[crash perhaps related to reference counting](https://api.github.com/repos/json-c/json-c/issues/266) +[Removes me as Win32 maintainer, because I'm not.](https://api.github.com/repos/json-c/json-c/issues/267) +[Documentation of json_object_to_json_string gives no information about memory management](https://api.github.com/repos/json-c/json-c/issues/268) +[json_object__set(json_object *o, value) API for value setting in json object private structure](https://api.github.com/repos/json-c/json-c/issues/269) +[new API json_object_new_double_f(doubel d,const char * fmt);](https://api.github.com/repos/json-c/json-c/issues/270) +[Cannot compile using CMake on macOS](https://api.github.com/repos/json-c/json-c/issues/271) +[fixed wrong object name in json_object_all_values_equal](https://api.github.com/repos/json-c/json-c/issues/273) +[Support for 64 bit pointers on Windows](https://api.github.com/repos/json-c/json-c/issues/274) +[Out-of-bounds read in json_tokener_parse_ex](https://api.github.com/repos/json-c/json-c/issues/275) +[ ./configure for centos release 6.7(final) failure](https://api.github.com/repos/json-c/json-c/issues/276) +[Json object set xxx](https://api.github.com/repos/json-c/json-c/issues/277) +[Serialization of double with no fractional component drops trailing zero](https://api.github.com/repos/json-c/json-c/issues/278) +[Segmentation fault in array_list_length()](https://api.github.com/repos/json-c/json-c/issues/279) +[Should json_object_array_get_idx check whether input obj is array? ](https://api.github.com/repos/json-c/json-c/issues/280) +[how to pretty print json-c? ](https://api.github.com/repos/json-c/json-c/issues/281) +[ignore temporary files](https://api.github.com/repos/json-c/json-c/issues/282) +[json_pointer: add first revision based on RFC 6901](https://api.github.com/repos/json-c/json-c/issues/283) +[Resusing json_tokener object](https://api.github.com/repos/json-c/json-c/issues/284) +[Revert "compat/strdup.h: move common compat check for strdup() to own](https://api.github.com/repos/json-c/json-c/issues/285) +[json_tokener_parse_ex() returns json_tokener_continue on zero-length string](https://api.github.com/repos/json-c/json-c/issues/286) +[json_pointer: extend setter & getter with printf() style arguments](https://api.github.com/repos/json-c/json-c/issues/287) +[Fix _GNU_SOURCE define for vasprintf](https://api.github.com/repos/json-c/json-c/issues/288) +[bugfix: floating point representaion without fractional part ](https://api.github.com/repos/json-c/json-c/issues/289) +[duplicate an json_object](https://api.github.com/repos/json-c/json-c/issues/290) +[isspace assert error](https://api.github.com/repos/json-c/json-c/issues/291) +[configure error "./configure: line 13121: syntax error near unexpected token `-Wall'"](https://api.github.com/repos/json-c/json-c/issues/292) +[how to make with bitcode for ios](https://api.github.com/repos/json-c/json-c/issues/293) +[Adding UTF-8 validation. Fixes #122](https://api.github.com/repos/json-c/json-c/issues/294) +[cross compile w/ mingw](https://api.github.com/repos/json-c/json-c/issues/295) +[Missing functions header in json_object.h](https://api.github.com/repos/json-c/json-c/issues/296) +[could not parse string to Json object? Like string str=\"helloworld;E\\test\\log\\;end\"](https://api.github.com/repos/json-c/json-c/issues/297) +[Building using CMake doesn't work](https://api.github.com/repos/json-c/json-c/issues/298) +[Improve json_object -> string performance](https://api.github.com/repos/json-c/json-c/issues/299) +[Running tests with MinGW build](https://api.github.com/repos/json-c/json-c/issues/300) +[How to deep copy json_object in C++ ?](https://api.github.com/repos/json-c/json-c/issues/301) +[json_tokener_parse_ex doesn't parse JSON values](https://api.github.com/repos/json-c/json-c/issues/302) +[fix doc in tokener header file](https://api.github.com/repos/json-c/json-c/issues/303) +[(.text+0x72846): undefined reference to `is_error'](https://api.github.com/repos/json-c/json-c/issues/304) +[Fix compilation without C-99 option](https://api.github.com/repos/json-c/json-c/issues/305) +[./configure: line 12748 -error=deprecated-declarations](https://api.github.com/repos/json-c/json-c/issues/306) +[Memory leak in json_tokener_parse](https://api.github.com/repos/json-c/json-c/issues/307) +[AM_PROG_LIBTOOL not found on Linux](https://api.github.com/repos/json-c/json-c/issues/308) +[GCC 7 reports various -Wimplicit-fallthrough= errors](https://api.github.com/repos/json-c/json-c/issues/309) +[Add FALLTHRU comment to handle GCC7 warnings.](https://api.github.com/repos/json-c/json-c/issues/310) +[Fix error C3688 when compiling on Visual Studio 2015](https://api.github.com/repos/json-c/json-c/issues/311) +[Fix CMake Build process improved for MinGW and MSYS2](https://api.github.com/repos/json-c/json-c/issues/312) +[VERBOSE=1 make check; tests/test_util_file.test.c and tests/test_util_file.expected out of sync](https://api.github.com/repos/json-c/json-c/issues/313) +[Passing -1 to json_tokener_parse_ex is possibly unsafe](https://api.github.com/repos/json-c/json-c/issues/315) +[Memory Returned by json_object_to_json_string not freed](https://api.github.com/repos/json-c/json-c/issues/316) +[json_object_get_string gives segmentation error](https://api.github.com/repos/json-c/json-c/issues/317) +[PVS-Studio static analyzer analyze results](https://api.github.com/repos/json-c/json-c/issues/318) +[Windows: Fix dynamic library build with Visual Studio](https://api.github.com/repos/json-c/json-c/issues/319) +[Can't compile in Mac OS X El Capitan](https://api.github.com/repos/json-c/json-c/issues/320) +[build,cmake: fix vasprintf implicit definition and generate both static & shared libs](https://api.github.com/repos/json-c/json-c/issues/321) +[can not link with libjson-c.a](https://api.github.com/repos/json-c/json-c/issues/322) +[implicit fallthrough detected by gcc 7.1](https://api.github.com/repos/json-c/json-c/issues/323) +[JsonPath like function?](https://api.github.com/repos/json-c/json-c/issues/324) +[Fix stack buffer overflow in json_object_double_to_json_string_format()](https://api.github.com/repos/json-c/json-c/issues/325) +[why json-c so hard to compile](https://api.github.com/repos/json-c/json-c/issues/327) +[json_object: implement json_object_deep_copy() function](https://api.github.com/repos/json-c/json-c/issues/328) +[build,cmake: build,cmake: rename libjson-c-static.a to libjson-c.a](https://api.github.com/repos/json-c/json-c/issues/329) +[tests: symlink basic tests to a single file that has the common code](https://api.github.com/repos/json-c/json-c/issues/330) +[Safe use of snprintf() / vsnprintf() for Visual studio, and thread-safety fix](https://api.github.com/repos/json-c/json-c/issues/331) +[Valgrind: invalid read after json_object_array_del_idx.](https://api.github.com/repos/json-c/json-c/issues/332) +[Replace obsolete AM_PROG_LIBTOOL](https://api.github.com/repos/json-c/json-c/issues/333) +[README.md: show build status tag from travis-ci.org](https://api.github.com/repos/json-c/json-c/issues/335) +[tests: fix tests in travis-ci.org](https://api.github.com/repos/json-c/json-c/issues/336) +[Synchronize "potentially racy" random seed in lh_char_hash()](https://api.github.com/repos/json-c/json-c/issues/337) +[implement json_object_int_inc(json_object *, int64_t)](https://api.github.com/repos/json-c/json-c/issues/338) +[Json schema validation](https://api.github.com/repos/json-c/json-c/issues/339) +[strerror_override: add extern "C" and JSON_EXPORT specifiers for Visual C++ compilers](https://api.github.com/repos/json-c/json-c/issues/340) +[character "/" parse as "\/"](https://api.github.com/repos/json-c/json-c/issues/341) +[ No such file or directory "/usr/include/json.h"](https://api.github.com/repos/json-c/json-c/issues/342) +[Can't parse json](https://api.github.com/repos/json-c/json-c/issues/343) +[Fix Mingw build](https://api.github.com/repos/json-c/json-c/issues/344) +[Fix make dist and make distcheck](https://api.github.com/repos/json-c/json-c/issues/345) +[Clamp double to int32 when narrowing in json_object_get_int.](https://api.github.com/repos/json-c/json-c/issues/346) +[MSVC linker error json_c_strerror](https://api.github.com/repos/json-c/json-c/issues/347) +[why](https://api.github.com/repos/json-c/json-c/issues/348) +[`missing` is missing?](https://api.github.com/repos/json-c/json-c/issues/349) +[stderror-override and disable-shared](https://api.github.com/repos/json-c/json-c/issues/350) +[SIZE_T_MAX redefined from limits.h](https://api.github.com/repos/json-c/json-c/issues/351) +[`INSTALL` overrides an automake script.](https://api.github.com/repos/json-c/json-c/issues/352) +[Documentation issues](https://api.github.com/repos/json-c/json-c/issues/353) +[Fixes #351 #352 #353 ](https://api.github.com/repos/json-c/json-c/issues/354) +[1.make it can been compiled with Visual Studio 2010 by modify the CMakeList.txt and others](https://api.github.com/repos/json-c/json-c/issues/355) +[VS2008 test test_util_file.cpp err!](https://api.github.com/repos/json-c/json-c/issues/356) +[__json_c_strerror incompatibility with link-time optimization](https://api.github.com/repos/json-c/json-c/issues/357) +[make issue](https://api.github.com/repos/json-c/json-c/issues/358) +[update CMakeLists.txt for compile with visual studio at least 2010](https://api.github.com/repos/json-c/json-c/issues/359) +[Use strtoll() to parse ints](https://api.github.com/repos/json-c/json-c/issues/360) +[Fix double to int cast overflow in json_object_get_int64.](https://api.github.com/repos/json-c/json-c/issues/361) +[CMake Package Config](https://api.github.com/repos/json-c/json-c/issues/362) +[Issue #338, add json_object_add_int functions](https://api.github.com/repos/json-c/json-c/issues/363) +[Cmake is Errir](https://api.github.com/repos/json-c/json-c/issues/364) +[added fallthrough for gcc7](https://api.github.com/repos/json-c/json-c/issues/365) +[how to check the json string,crash!](https://api.github.com/repos/json-c/json-c/issues/366) +[Is json-c support "redirect" semantic?](https://api.github.com/repos/json-c/json-c/issues/367) +[Add examples](https://api.github.com/repos/json-c/json-c/issues/368) +[How to build json-c library for android?](https://api.github.com/repos/json-c/json-c/issues/369) +[Compiling using clang-cl](https://api.github.com/repos/json-c/json-c/issues/370) +[Invalid parsing for Infinity with json-c 0.12](https://api.github.com/repos/json-c/json-c/issues/371) +[Json-c 0.12: Fixed Infinity bug](https://api.github.com/repos/json-c/json-c/issues/372) +[build: fix build on appveyor CI](https://api.github.com/repos/json-c/json-c/issues/373) +[Undefined symbols for architecture x86_64:](https://api.github.com/repos/json-c/json-c/issues/374) +[what would happened when json_object_object_add add the same key](https://api.github.com/repos/json-c/json-c/issues/375) +[Eclipse error ](https://api.github.com/repos/json-c/json-c/issues/376) +[on gcc 7.2.0 on my linux distribution with json-c 2013-04-02 source](https://api.github.com/repos/json-c/json-c/issues/377) +[ Eclipse: library (libjson-c) not found, but configured](https://api.github.com/repos/json-c/json-c/issues/378) +[error: this statement may fall through \[-Werror=implicit-fallthrough=\]](https://api.github.com/repos/json-c/json-c/issues/379) +[Build on Windows](https://api.github.com/repos/json-c/json-c/issues/380) +[Fix makedist](https://api.github.com/repos/json-c/json-c/issues/381) +[Memory leak for json_tokener_parse_ex for version 0.12.1](https://api.github.com/repos/json-c/json-c/issues/382) +[Fix a compiler warning.](https://api.github.com/repos/json-c/json-c/issues/383) +[Fix a VS 2015 compiler warnings.](https://api.github.com/repos/json-c/json-c/issues/384) + diff --git a/third_party/json-c/json.h b/third_party/json-c/json.h new file mode 100644 index 0000000000..fc2daddee2 --- /dev/null +++ b/third_party/json-c/json.h @@ -0,0 +1,38 @@ +/* + * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief A convenience header that may be included instead of other individual ones. + */ +#ifndef _json_h_ +#define _json_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "debug.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_util.h" +#include "json_object.h" +#include "json_pointer.h" +#include "json_tokener.h" +#include "json_object_iterator.h" +#include "json_c_version.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/json_c_version.c b/third_party/json-c/json_c_version.c new file mode 100644 index 0000000000..13eb188554 --- /dev/null +++ b/third_party/json-c/json_c_version.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2012 Eric Haszlakiewicz + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ +#include "config.h" + +#include "json_c_version.h" + +const char *json_c_version(void) +{ + return JSON_C_VERSION; +} + +int json_c_version_num(void) +{ + return JSON_C_VERSION_NUM; +} + diff --git a/third_party/json-c/json_c_version.h b/third_party/json-c/json_c_version.h new file mode 100644 index 0000000000..98838be946 --- /dev/null +++ b/third_party/json-c/json_c_version.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012,2017 Eric Haszlakiewicz + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ + +/** + * @file + * @brief Methods for retrieving the json-c version. + */ +#ifndef _json_c_version_h_ +#define _json_c_version_h_ + +#define JSON_C_MAJOR_VERSION 0 +#define JSON_C_MINOR_VERSION 13 +#define JSON_C_MICRO_VERSION 01 +#define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \ + (JSON_C_MINOR_VERSION << 8) | \ + JSON_C_MICRO_VERSION) +#define JSON_C_VERSION "0.13.1" + +/** + * @see JSON_C_VERSION + * @return the version of the json-c library as a string + */ +const char *json_c_version(void); /* Returns JSON_C_VERSION */ + +/** + * The json-c version encoded into an int, with the low order 8 bits + * being the micro version, the next higher 8 bits being the minor version + * and the next higher 8 bits being the major version. + * For example, 7.12.99 would be 0x00070B63. + * + * @see JSON_C_VERSION_NUM + * @return the version of the json-c library as an int + */ +int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ + +#endif diff --git a/third_party/json-c/json_config.h.in b/third_party/json-c/json_config.h.in new file mode 100644 index 0000000000..7888e02170 --- /dev/null +++ b/third_party/json-c/json_config.h.in @@ -0,0 +1,3 @@ + +/* Define to 1 if you have the header file. */ +#undef JSON_C_HAVE_INTTYPES_H diff --git a/third_party/json-c/json_config.h.win32 b/third_party/json-c/json_config.h.win32 new file mode 100644 index 0000000000..9c542a4086 --- /dev/null +++ b/third_party/json-c/json_config.h.win32 @@ -0,0 +1,5 @@ + +/* Define to 1 if you have the header file. */ +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#define JSON_C_HAVE_INTTYPES_H 1 +#endif diff --git a/third_party/json-c/json_inttypes.h b/third_party/json-c/json_inttypes.h new file mode 100644 index 0000000000..3854913fc5 --- /dev/null +++ b/third_party/json-c/json_inttypes.h @@ -0,0 +1,23 @@ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ +#ifndef _json_inttypes_h_ +#define _json_inttypes_h_ + +#include "json_config.h" + +#ifdef JSON_C_HAVE_INTTYPES_H +/* inttypes.h includes stdint.h */ +#include + +#else +#include + +#define PRId64 "I64d" +#define SCNd64 "I64d" + +#endif + +#endif diff --git a/third_party/json-c/json_object.c b/third_party/json-c/json_object.c new file mode 100644 index 0000000000..458163c20d --- /dev/null +++ b/third_party/json-c/json_object.c @@ -0,0 +1,1493 @@ +/* + * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include "strerror_override.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "printbuf.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_object_private.h" +#include "json_util.h" +#include "math_compat.h" +#include "strdup_compat.h" +#include "snprintf_compat.h" + +#if SIZEOF_LONG_LONG != SIZEOF_INT64_T +#error "The long long type isn't 64-bits" +#endif + +// Don't define this. It's not thread-safe. +/* #define REFCOUNT_DEBUG 1 */ + +const char *json_number_chars = "0123456789.+-eE"; +const char *json_hex_chars = "0123456789abcdefABCDEF"; + +static void json_object_generic_delete(struct json_object* jso); +static struct json_object* json_object_new(enum json_type o_type); + +static json_object_to_json_string_fn json_object_object_to_json_string; +static json_object_to_json_string_fn json_object_boolean_to_json_string; +static json_object_to_json_string_fn json_object_double_to_json_string_default; +static json_object_to_json_string_fn json_object_int_to_json_string; +static json_object_to_json_string_fn json_object_string_to_json_string; +static json_object_to_json_string_fn json_object_array_to_json_string; + + +/* ref count debugging */ + +#ifdef REFCOUNT_DEBUG + +static struct lh_table *json_object_table; + +static void json_object_init(void) __attribute__ ((constructor)); +static void json_object_init(void) { + MC_DEBUG("json_object_init: creating object table\n"); + json_object_table = lh_kptr_table_new(128, NULL); +} + +static void json_object_fini(void) __attribute__ ((destructor)); +static void json_object_fini(void) +{ + struct lh_entry *ent; + if (MC_GET_DEBUG()) + { + if (json_object_table->count) + { + MC_DEBUG("json_object_fini: %d referenced objects at exit\n", + json_object_table->count); + lh_foreach(json_object_table, ent) + { + struct json_object* obj = + (struct json_object*) lh_entry_v(ent); + MC_DEBUG("\t%s:%p\n", + json_type_to_name(obj->o_type), obj); + } + } + } + MC_DEBUG("json_object_fini: freeing object table\n"); + lh_table_free(json_object_table); +} +#endif /* REFCOUNT_DEBUG */ + + +/* helper for accessing the optimized string data component in json_object + */ +static const char * +get_string_component(const struct json_object *jso) +{ + return (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) ? + jso->o.c_string.str.data : jso->o.c_string.str.ptr; +} + +/* string escaping */ + +static int json_escape_str(struct printbuf *pb, const char *str, int len, int flags) +{ + int pos = 0, start_offset = 0; + unsigned char c; + while (len--) + { + c = str[pos]; + switch(c) + { + case '\b': + case '\n': + case '\r': + case '\t': + case '\f': + case '"': + case '\\': + case '/': + if((flags & JSON_C_TO_STRING_NOSLASHESCAPE) && c == '/') + { + pos++; + break; + } + + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + + if(c == '\b') printbuf_memappend(pb, "\\b", 2); + else if(c == '\n') printbuf_memappend(pb, "\\n", 2); + else if(c == '\r') printbuf_memappend(pb, "\\r", 2); + else if(c == '\t') printbuf_memappend(pb, "\\t", 2); + else if(c == '\f') printbuf_memappend(pb, "\\f", 2); + else if(c == '"') printbuf_memappend(pb, "\\\"", 2); + else if(c == '\\') printbuf_memappend(pb, "\\\\", 2); + else if(c == '/') printbuf_memappend(pb, "\\/", 2); + + start_offset = ++pos; + break; + default: + if(c < ' ') + { + char sbuf[7]; + if(pos - start_offset > 0) + printbuf_memappend(pb, + str + start_offset, + pos - start_offset); + snprintf(sbuf, sizeof(sbuf), + "\\u00%c%c", + json_hex_chars[c >> 4], + json_hex_chars[c & 0xf]); + printbuf_memappend_fast(pb, sbuf, (int) sizeof(sbuf) - 1); + start_offset = ++pos; + } else + pos++; + } + } + if (pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + return 0; +} + + +/* reference counting */ + +extern struct json_object* json_object_get(struct json_object *jso) +{ + if (!jso) return jso; + +#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) + __sync_add_and_fetch(&jso->_ref_count, 1); +#else + ++jso->_ref_count; +#endif + + return jso; +} + +int json_object_put(struct json_object *jso) +{ + if(!jso) return 0; + + /* Avoid invalid free and crash explicitly instead of (silently) + * segfaulting. + */ + assert(jso->_ref_count > 0); + +#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) + /* Note: this only allow the refcount to remain correct + * when multiple threads are adjusting it. It is still an error + * for a thread to decrement the refcount if it doesn't "own" it, + * as that can result in the thread that loses the race to 0 + * operating on an already-freed object. + */ + if (__sync_sub_and_fetch(&jso->_ref_count, 1) > 0) return 0; +#else + if (--jso->_ref_count > 0) return 0; +#endif + + if (jso->_user_delete) + jso->_user_delete(jso, jso->_userdata); + jso->_delete(jso); + return 1; +} + + +/* generic object construction and destruction parts */ + +static void json_object_generic_delete(struct json_object* jso) +{ +#ifdef REFCOUNT_DEBUG + MC_DEBUG("json_object_delete_%s: %p\n", + json_type_to_name(jso->o_type), jso); + lh_table_delete(json_object_table, jso); +#endif /* REFCOUNT_DEBUG */ + printbuf_free(jso->_pb); + free(jso); +} + +static struct json_object* json_object_new(enum json_type o_type) +{ + struct json_object *jso; + + jso = (struct json_object*)calloc(sizeof(struct json_object), 1); + if (!jso) + return NULL; + jso->o_type = o_type; + jso->_ref_count = 1; + jso->_delete = &json_object_generic_delete; +#ifdef REFCOUNT_DEBUG + lh_table_insert(json_object_table, jso, jso); + MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); +#endif /* REFCOUNT_DEBUG */ + return jso; +} + + +/* type checking functions */ + +int json_object_is_type(const struct json_object *jso, enum json_type type) +{ + if (!jso) + return (type == json_type_null); + return (jso->o_type == type); +} + +enum json_type json_object_get_type(const struct json_object *jso) +{ + if (!jso) + return json_type_null; + return jso->o_type; +} + +void* json_object_get_userdata(json_object *jso) { + return jso ? jso->_userdata : NULL; +} + +void json_object_set_userdata(json_object *jso, void *userdata, + json_object_delete_fn *user_delete) +{ + // Can't return failure, so abort if we can't perform the operation. + assert(jso != NULL); + + // First, clean up any previously existing user info + if (jso->_user_delete) + jso->_user_delete(jso, jso->_userdata); + + jso->_userdata = userdata; + jso->_user_delete = user_delete; +} + +/* set a custom conversion to string */ + +void json_object_set_serializer(json_object *jso, + json_object_to_json_string_fn *to_string_func, + void *userdata, + json_object_delete_fn *user_delete) +{ + json_object_set_userdata(jso, userdata, user_delete); + + if (to_string_func == NULL) + { + // Reset to the standard serialization function + switch(jso->o_type) + { + case json_type_null: + jso->_to_json_string = NULL; + break; + case json_type_boolean: + jso->_to_json_string = &json_object_boolean_to_json_string; + break; + case json_type_double: + jso->_to_json_string = &json_object_double_to_json_string_default; + break; + case json_type_int: + jso->_to_json_string = &json_object_int_to_json_string; + break; + case json_type_object: + jso->_to_json_string = &json_object_object_to_json_string; + break; + case json_type_array: + jso->_to_json_string = &json_object_array_to_json_string; + break; + case json_type_string: + jso->_to_json_string = &json_object_string_to_json_string; + break; + } + return; + } + + jso->_to_json_string = to_string_func; +} + + +/* extended conversion to string */ + +const char* json_object_to_json_string_length(struct json_object *jso, int flags, size_t *length) +{ + const char *r = NULL; + size_t s = 0; + + if (!jso) + { + s = 4; + r = "null"; + } + else if ((jso->_pb) || (jso->_pb = printbuf_new())) + { + printbuf_reset(jso->_pb); + + if(jso->_to_json_string(jso, jso->_pb, 0, flags) >= 0) + { + s = (size_t)jso->_pb->bpos; + r = jso->_pb->buf; + } + } + + if (length) + *length = s; + return r; +} + +const char* json_object_to_json_string_ext(struct json_object *jso, int flags) +{ + return json_object_to_json_string_length(jso, flags, NULL); +} + +/* backwards-compatible conversion to string */ + +const char* json_object_to_json_string(struct json_object *jso) +{ + return json_object_to_json_string_ext(jso, JSON_C_TO_STRING_SPACED); +} + +static void indent(struct printbuf *pb, int level, int flags) +{ + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (flags & JSON_C_TO_STRING_PRETTY_TAB) + { + printbuf_memset(pb, -1, '\t', level); + } + else + { + printbuf_memset(pb, -1, ' ', level * 2); + } + } +} + +/* json_object_object */ + +static int json_object_object_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + int had_children = 0; + struct json_object_iter iter; + + printbuf_strappend(pb, "{" /*}*/); + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); + json_object_object_foreachC(jso, iter) + { + if (had_children) + { + printbuf_strappend(pb, ","); + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); + } + had_children = 1; + if (flags & JSON_C_TO_STRING_SPACED) + printbuf_strappend(pb, " "); + indent(pb, level+1, flags); + printbuf_strappend(pb, "\""); + json_escape_str(pb, iter.key, strlen(iter.key), flags); + if (flags & JSON_C_TO_STRING_SPACED) + printbuf_strappend(pb, "\": "); + else + printbuf_strappend(pb, "\":"); + if(iter.val == NULL) + printbuf_strappend(pb, "null"); + else + if (iter.val->_to_json_string(iter.val, pb, level+1,flags) < 0) + return -1; + } + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (had_children) + printbuf_strappend(pb, "\n"); + indent(pb,level,flags); + } + if (flags & JSON_C_TO_STRING_SPACED) + return printbuf_strappend(pb, /*{*/ " }"); + else + return printbuf_strappend(pb, /*{*/ "}"); +} + + +static void json_object_lh_entry_free(struct lh_entry *ent) +{ + if (!ent->k_is_constant) + free(lh_entry_k(ent)); + json_object_put((struct json_object*)lh_entry_v(ent)); +} + +static void json_object_object_delete(struct json_object* jso) +{ + lh_table_free(jso->o.c_object); + json_object_generic_delete(jso); +} + +struct json_object* json_object_new_object(void) +{ + struct json_object *jso = json_object_new(json_type_object); + if (!jso) + return NULL; + jso->_delete = &json_object_object_delete; + jso->_to_json_string = &json_object_object_to_json_string; + jso->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, + &json_object_lh_entry_free); + if (!jso->o.c_object) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + return jso; +} + +struct lh_table* json_object_get_object(const struct json_object *jso) +{ + if (!jso) + return NULL; + switch(jso->o_type) + { + case json_type_object: + return jso->o.c_object; + default: + return NULL; + } +} + +int json_object_object_add_ex(struct json_object* jso, + const char *const key, + struct json_object *const val, + const unsigned opts) +{ + struct json_object *existing_value = NULL; + struct lh_entry *existing_entry; + unsigned long hash; + + assert(json_object_get_type(jso) == json_type_object); + + // We lookup the entry and replace the value, rather than just deleting + // and re-adding it, so the existing key remains valid. + hash = lh_get_hash(jso->o.c_object, (const void *)key); + existing_entry = (opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) ? NULL : + lh_table_lookup_entry_w_hash(jso->o.c_object, + (const void *)key, hash); + + // The caller must avoid creating loops in the object tree, but do a + // quick check anyway to make sure we're not creating a trivial loop. + if (jso == val) + return -1; + + if (!existing_entry) + { + const void *const k = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT) ? + (const void *)key : strdup(key); + if (k == NULL) + return -1; + return lh_table_insert_w_hash(jso->o.c_object, k, val, hash, opts); + } + existing_value = (json_object *) lh_entry_v(existing_entry); + if (existing_value) + json_object_put(existing_value); + existing_entry->v = val; + return 0; +} + +int json_object_object_add(struct json_object* jso, const char *key, + struct json_object *val) +{ + return json_object_object_add_ex(jso, key, val, 0); +} + + +int json_object_object_length(const struct json_object *jso) +{ + assert(json_object_get_type(jso) == json_type_object); + return lh_table_length(jso->o.c_object); +} + +size_t json_c_object_sizeof(void) +{ + return sizeof(struct json_object); +} + +struct json_object* json_object_object_get(const struct json_object* jso, + const char *key) +{ + struct json_object *result = NULL; + json_object_object_get_ex(jso, key, &result); + return result; +} + +json_bool json_object_object_get_ex(const struct json_object* jso, const char *key, + struct json_object **value) +{ + if (value != NULL) + *value = NULL; + + if (NULL == jso) + return FALSE; + + switch(jso->o_type) + { + case json_type_object: + return lh_table_lookup_ex(jso->o.c_object, (const void *) key, + (void**) value); + default: + if (value != NULL) + *value = NULL; + return FALSE; + } +} + +void json_object_object_del(struct json_object* jso, const char *key) +{ + assert(json_object_get_type(jso) == json_type_object); + lh_table_delete(jso->o.c_object, key); +} + + +/* json_object_boolean */ + +static int json_object_boolean_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + if (jso->o.c_boolean) + return printbuf_strappend(pb, "true"); + return printbuf_strappend(pb, "false"); +} + +struct json_object* json_object_new_boolean(json_bool b) +{ + struct json_object *jso = json_object_new(json_type_boolean); + if (!jso) + return NULL; + jso->_to_json_string = &json_object_boolean_to_json_string; + jso->o.c_boolean = b; + return jso; +} + +json_bool json_object_get_boolean(const struct json_object *jso) +{ + if (!jso) + return FALSE; + switch(jso->o_type) + { + case json_type_boolean: + return jso->o.c_boolean; + case json_type_int: + return (jso->o.c_int64 != 0); + case json_type_double: + return (jso->o.c_double != 0); + case json_type_string: + return (jso->o.c_string.len != 0); + default: + return FALSE; + } +} + +int json_object_set_boolean(struct json_object *jso,json_bool new_value){ + if (!jso || jso->o_type!=json_type_boolean) + return 0; + jso->o.c_boolean=new_value; + return 1; +} + + +/* json_object_int */ + +static int json_object_int_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + /* room for 19 digits, the sign char, and a null term */ + char sbuf[21]; + snprintf(sbuf, sizeof(sbuf), "%" PRId64, jso->o.c_int64); + return printbuf_memappend (pb, sbuf, strlen(sbuf)); +} + +struct json_object* json_object_new_int(int32_t i) +{ + struct json_object *jso = json_object_new(json_type_int); + if (!jso) + return NULL; + jso->_to_json_string = &json_object_int_to_json_string; + jso->o.c_int64 = i; + return jso; +} + +int32_t json_object_get_int(const struct json_object *jso) +{ + int64_t cint64; + enum json_type o_type; + + if(!jso) return 0; + + o_type = jso->o_type; + cint64 = jso->o.c_int64; + + if (o_type == json_type_string) + { + /* + * Parse strings into 64-bit numbers, then use the + * 64-to-32-bit number handling below. + */ + if (json_parse_int64(get_string_component(jso), &cint64) != 0) + return 0; /* whoops, it didn't work. */ + o_type = json_type_int; + } + + switch(o_type) { + case json_type_int: + /* Make sure we return the correct values for out of range numbers. */ + if (cint64 <= INT32_MIN) + return INT32_MIN; + if (cint64 >= INT32_MAX) + return INT32_MAX; + return (int32_t) cint64; + case json_type_double: + if (jso->o.c_double <= INT32_MIN) + return INT32_MIN; + if (jso->o.c_double >= INT32_MAX) + return INT32_MAX; + return (int32_t)jso->o.c_double; + case json_type_boolean: + return jso->o.c_boolean; + default: + return 0; + } +} + +int json_object_set_int(struct json_object *jso,int new_value){ + if (!jso || jso->o_type!=json_type_int) + return 0; + jso->o.c_int64=new_value; + return 1; +} + +struct json_object* json_object_new_int64(int64_t i) +{ + struct json_object *jso = json_object_new(json_type_int); + if (!jso) + return NULL; + jso->_to_json_string = &json_object_int_to_json_string; + jso->o.c_int64 = i; + return jso; +} + +int64_t json_object_get_int64(const struct json_object *jso) +{ + int64_t cint; + + if (!jso) + return 0; + switch(jso->o_type) + { + case json_type_int: + return jso->o.c_int64; + case json_type_double: + if (jso->o.c_double >= INT64_MAX) + return INT64_MAX; + if (jso->o.c_double <= INT64_MIN) + return INT64_MIN; + return (int64_t)jso->o.c_double; + case json_type_boolean: + return jso->o.c_boolean; + case json_type_string: + if (json_parse_int64(get_string_component(jso), &cint) == 0) + return cint; + /* FALLTHRU */ + default: + return 0; + } +} + +int json_object_set_int64(struct json_object *jso,int64_t new_value){ + if (!jso || jso->o_type!=json_type_int) + return 0; + jso->o.c_int64=new_value; + return 1; +} + +int json_object_int_inc(struct json_object *jso, int64_t val) { + if (!jso || jso->o_type != json_type_int) + return 0; + if (val > 0 && jso->o.c_int64 > INT64_MAX - val) { + jso->o.c_int64 = INT64_MAX; + } else if (val < 0 && jso->o.c_int64 < INT64_MIN - val) { + jso->o.c_int64 = INT64_MIN; + } else { + jso->o.c_int64 += val; + } + return 1; +} + +/* json_object_double */ + +#if defined(HAVE___THREAD) +// i.e. __thread or __declspec(thread) +static SPEC___THREAD char *tls_serialization_float_format = NULL; +#endif +static char *global_serialization_float_format = NULL; + +int json_c_set_serialization_double_format(const char *double_format, int global_or_thread) +{ + if (global_or_thread == JSON_C_OPTION_GLOBAL) + { +#if defined(HAVE___THREAD) + if (tls_serialization_float_format) + { + free(tls_serialization_float_format); + tls_serialization_float_format = NULL; + } +#endif + if (global_serialization_float_format) + free(global_serialization_float_format); + global_serialization_float_format = double_format ? strdup(double_format) : NULL; + } + else if (global_or_thread == JSON_C_OPTION_THREAD) + { +#if defined(HAVE___THREAD) + if (tls_serialization_float_format) + { + free(tls_serialization_float_format); + tls_serialization_float_format = NULL; + } + tls_serialization_float_format = double_format ? strdup(double_format) : NULL; +#else + _json_c_set_last_err("json_c_set_option: not compiled with __thread support\n"); + return -1; +#endif + } + else + { + _json_c_set_last_err("json_c_set_option: invalid global_or_thread value: %d\n", global_or_thread); + return -1; + } + return 0; +} + + +static int json_object_double_to_json_string_format(struct json_object* jso, + struct printbuf *pb, + int level, + int flags, + const char *format) +{ + char buf[128], *p, *q; + int size; + /* Although JSON RFC does not support + NaN or Infinity as numeric values + ECMA 262 section 9.8.1 defines + how to handle these cases as strings */ + if (isnan(jso->o.c_double)) + { + size = snprintf(buf, sizeof(buf), "NaN"); + } + else if (isinf(jso->o.c_double)) + { + if(jso->o.c_double > 0) + size = snprintf(buf, sizeof(buf), "Infinity"); + else + size = snprintf(buf, sizeof(buf), "-Infinity"); + } + else + { + const char *std_format = "%.17g"; + int format_drops_decimals = 0; + + if (!format) + { +#if defined(HAVE___THREAD) + if (tls_serialization_float_format) + format = tls_serialization_float_format; + else +#endif + if (global_serialization_float_format) + format = global_serialization_float_format; + else + format = std_format; + } + size = snprintf(buf, sizeof(buf), format, jso->o.c_double); + + if (size < 0) + return -1; + + p = strchr(buf, ','); + if (p) + *p = '.'; + else + p = strchr(buf, '.'); + + if (format == std_format || strstr(format, ".0f") == NULL) + format_drops_decimals = 1; + + if (size < (int)sizeof(buf) - 2 && + isdigit((int)buf[0]) && /* Looks like *some* kind of number */ + !p && /* Has no decimal point */ + strchr(buf, 'e') == NULL && /* Not scientific notation */ + format_drops_decimals) + { + // Ensure it looks like a float, even if snprintf didn't, + // unless a custom format is set to omit the decimal. + strcat(buf, ".0"); + size += 2; + } + if (p && (flags & JSON_C_TO_STRING_NOZERO)) + { + /* last useful digit, always keep 1 zero */ + p++; + for (q=p ; *q ; q++) { + if (*q!='0') p=q; + } + /* drop trailing zeroes */ + *(++p) = 0; + size = p-buf; + } + } + // although unlikely, snprintf can fail + if (size < 0) + return -1; + + if (size >= (int)sizeof(buf)) + // The standard formats are guaranteed not to overrun the buffer, + // but if a custom one happens to do so, just silently truncate. + size = sizeof(buf) - 1; + printbuf_memappend(pb, buf, size); + return size; +} + +static int json_object_double_to_json_string_default(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + return json_object_double_to_json_string_format(jso, pb, level, flags, + NULL); +} + +int json_object_double_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + return json_object_double_to_json_string_format(jso, pb, level, flags, + (const char *)jso->_userdata); +} + +struct json_object* json_object_new_double(double d) +{ + struct json_object *jso = json_object_new(json_type_double); + if (!jso) + return NULL; + jso->_to_json_string = &json_object_double_to_json_string_default; + jso->o.c_double = d; + return jso; +} + +struct json_object* json_object_new_double_s(double d, const char *ds) +{ + char *new_ds; + struct json_object *jso = json_object_new_double(d); + if (!jso) + return NULL; + + new_ds = strdup(ds); + if (!new_ds) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + json_object_set_serializer(jso, json_object_userdata_to_json_string, + new_ds, json_object_free_userdata); + return jso; +} + +int json_object_userdata_to_json_string(struct json_object *jso, + struct printbuf *pb, int level, int flags) +{ + int userdata_len = strlen((const char *)jso->_userdata); + printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); + return userdata_len; +} + +void json_object_free_userdata(struct json_object *jso, void *userdata) +{ + free(userdata); +} + +double json_object_get_double(const struct json_object *jso) +{ + double cdouble; + char *errPtr = NULL; + + if(!jso) return 0.0; + switch(jso->o_type) { + case json_type_double: + return jso->o.c_double; + case json_type_int: + return jso->o.c_int64; + case json_type_boolean: + return jso->o.c_boolean; + case json_type_string: + errno = 0; + cdouble = strtod(get_string_component(jso), &errPtr); + + /* if conversion stopped at the first character, return 0.0 */ + if (errPtr == get_string_component(jso)) + return 0.0; + + /* + * Check that the conversion terminated on something sensible + * + * For example, { "pay" : 123AB } would parse as 123. + */ + if (*errPtr != '\0') + return 0.0; + + /* + * If strtod encounters a string which would exceed the + * capacity of a double, it returns +/- HUGE_VAL and sets + * errno to ERANGE. But +/- HUGE_VAL is also a valid result + * from a conversion, so we need to check errno. + * + * Underflow also sets errno to ERANGE, but it returns 0 in + * that case, which is what we will return anyway. + * + * See CERT guideline ERR30-C + */ + if ((HUGE_VAL == cdouble || -HUGE_VAL == cdouble) && + (ERANGE == errno)) + cdouble = 0.0; + return cdouble; + default: + return 0.0; + } +} + +int json_object_set_double(struct json_object *jso,double new_value){ + if (!jso || jso->o_type!=json_type_double) + return 0; + jso->o.c_double=new_value; + return 1; +} + +/* json_object_string */ + +static int json_object_string_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + printbuf_strappend(pb, "\""); + json_escape_str(pb, get_string_component(jso), jso->o.c_string.len, flags); + printbuf_strappend(pb, "\""); + return 0; +} + +static void json_object_string_delete(struct json_object* jso) +{ + if(jso->o.c_string.len >= LEN_DIRECT_STRING_DATA) + free(jso->o.c_string.str.ptr); + json_object_generic_delete(jso); +} + +struct json_object* json_object_new_string(const char *s) +{ + struct json_object *jso = json_object_new(json_type_string); + if (!jso) + return NULL; + jso->_delete = &json_object_string_delete; + jso->_to_json_string = &json_object_string_to_json_string; + jso->o.c_string.len = strlen(s); + if(jso->o.c_string.len < LEN_DIRECT_STRING_DATA) { + memcpy(jso->o.c_string.str.data, s, jso->o.c_string.len); + } else { + jso->o.c_string.str.ptr = strdup(s); + if (!jso->o.c_string.str.ptr) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + } + return jso; +} + +struct json_object* json_object_new_string_len(const char *s, int len) +{ + char *dstbuf; + struct json_object *jso = json_object_new(json_type_string); + if (!jso) + return NULL; + jso->_delete = &json_object_string_delete; + jso->_to_json_string = &json_object_string_to_json_string; + if(len < LEN_DIRECT_STRING_DATA) { + dstbuf = jso->o.c_string.str.data; + } else { + jso->o.c_string.str.ptr = (char*)malloc(len + 1); + if (!jso->o.c_string.str.ptr) + { + json_object_generic_delete(jso); + errno = ENOMEM; + return NULL; + } + dstbuf = jso->o.c_string.str.ptr; + } + memcpy(dstbuf, (const void *)s, len); + dstbuf[len] = '\0'; + jso->o.c_string.len = len; + return jso; +} + +const char* json_object_get_string(struct json_object *jso) +{ + if (!jso) + return NULL; + switch(jso->o_type) + { + case json_type_string: + return get_string_component(jso); + default: + return json_object_to_json_string(jso); + } +} + +int json_object_get_string_len(const struct json_object *jso) +{ + if (!jso) + return 0; + switch(jso->o_type) + { + case json_type_string: + return jso->o.c_string.len; + default: + return 0; + } +} + +int json_object_set_string(json_object* jso, const char* s) { + return json_object_set_string_len(jso, s, (int)(strlen(s))); +} + +int json_object_set_string_len(json_object* jso, const char* s, int len){ + char *dstbuf; + if (jso==NULL || jso->o_type!=json_type_string) return 0; + if (leno.c_string.str.data; + if (jso->o.c_string.len>=LEN_DIRECT_STRING_DATA) free(jso->o.c_string.str.ptr); + } else { + dstbuf=(char *)malloc(len+1); + if (dstbuf==NULL) return 0; + if (jso->o.c_string.len>=LEN_DIRECT_STRING_DATA) free(jso->o.c_string.str.ptr); + jso->o.c_string.str.ptr=dstbuf; + } + jso->o.c_string.len=len; + memcpy(dstbuf, (const void *)s, len); + dstbuf[len] = '\0'; + return 1; +} + +/* json_object_array */ + +static int json_object_array_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags) +{ + int had_children = 0; + size_t ii; + + printbuf_strappend(pb, "["); + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); + for(ii=0; ii < json_object_array_length(jso); ii++) + { + struct json_object *val; + if (had_children) + { + printbuf_strappend(pb, ","); + if (flags & JSON_C_TO_STRING_PRETTY) + printbuf_strappend(pb, "\n"); + } + had_children = 1; + if (flags & JSON_C_TO_STRING_SPACED) + printbuf_strappend(pb, " "); + indent(pb, level + 1, flags); + val = json_object_array_get_idx(jso, ii); + if(val == NULL) + printbuf_strappend(pb, "null"); + else + if (val->_to_json_string(val, pb, level+1, flags) < 0) + return -1; + } + if (flags & JSON_C_TO_STRING_PRETTY) + { + if (had_children) + printbuf_strappend(pb, "\n"); + indent(pb,level,flags); + } + + if (flags & JSON_C_TO_STRING_SPACED) + return printbuf_strappend(pb, " ]"); + return printbuf_strappend(pb, "]"); +} + +static void json_object_array_entry_free(void *data) +{ + json_object_put((struct json_object*)data); +} + +static void json_object_array_delete(struct json_object* jso) +{ + array_list_free(jso->o.c_array); + json_object_generic_delete(jso); +} + +struct json_object* json_object_new_array(void) +{ + struct json_object *jso = json_object_new(json_type_array); + if (!jso) + return NULL; + jso->_delete = &json_object_array_delete; + jso->_to_json_string = &json_object_array_to_json_string; + jso->o.c_array = array_list_new(&json_object_array_entry_free); + if(jso->o.c_array == NULL) + { + free(jso); + return NULL; + } + return jso; +} + +struct array_list* json_object_get_array(const struct json_object *jso) +{ + if (!jso) + return NULL; + switch(jso->o_type) + { + case json_type_array: + return jso->o.c_array; + default: + return NULL; + } +} + +void json_object_array_sort(struct json_object *jso, + int(*sort_fn)(const void *, const void *)) +{ + assert(json_object_get_type(jso) == json_type_array); + array_list_sort(jso->o.c_array, sort_fn); +} + +struct json_object* json_object_array_bsearch( + const struct json_object *key, + const struct json_object *jso, + int (*sort_fn)(const void *, const void *)) +{ + struct json_object **result; + + assert(json_object_get_type(jso) == json_type_array); + result = (struct json_object **)array_list_bsearch( + (const void **)(void *)&key, jso->o.c_array, sort_fn); + + if (!result) + return NULL; + return *result; +} + +size_t json_object_array_length(const struct json_object *jso) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_length(jso->o.c_array); +} + +int json_object_array_add(struct json_object *jso,struct json_object *val) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_add(jso->o.c_array, val); +} + +int json_object_array_put_idx(struct json_object *jso, size_t idx, + struct json_object *val) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_put_idx(jso->o.c_array, idx, val); +} + +int json_object_array_del_idx(struct json_object *jso, size_t idx, size_t count) +{ + assert(json_object_get_type(jso) == json_type_array); + return array_list_del_idx(jso->o.c_array, idx, count); +} + +struct json_object* json_object_array_get_idx(const struct json_object *jso, + size_t idx) +{ + assert(json_object_get_type(jso) == json_type_array); + return (struct json_object*)array_list_get_idx(jso->o.c_array, idx); +} + +static int json_array_equal(struct json_object* jso1, + struct json_object* jso2) +{ + size_t len, i; + + len = json_object_array_length(jso1); + if (len != json_object_array_length(jso2)) + return 0; + + for (i = 0; i < len; i++) { + if (!json_object_equal(json_object_array_get_idx(jso1, i), + json_object_array_get_idx(jso2, i))) + return 0; + } + return 1; +} + +static int json_object_all_values_equal(struct json_object* jso1, + struct json_object* jso2) +{ + struct json_object_iter iter; + struct json_object *sub; + + assert(json_object_get_type(jso1) == json_type_object); + assert(json_object_get_type(jso2) == json_type_object); + /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ + json_object_object_foreachC(jso1, iter) { + if (!lh_table_lookup_ex(jso2->o.c_object, (void*)iter.key, + (void**)(void *)&sub)) + return 0; + if (!json_object_equal(iter.val, sub)) + return 0; + } + + /* Iterate over jso2 keys to see if any exist that are not in jso1 */ + json_object_object_foreachC(jso2, iter) { + if (!lh_table_lookup_ex(jso1->o.c_object, (void*)iter.key, + (void**)(void *)&sub)) + return 0; + } + + return 1; +} + +int json_object_equal(struct json_object* jso1, struct json_object* jso2) +{ + if (jso1 == jso2) + return 1; + + if (!jso1 || !jso2) + return 0; + + if (jso1->o_type != jso2->o_type) + return 0; + + switch(jso1->o_type) { + case json_type_boolean: + return (jso1->o.c_boolean == jso2->o.c_boolean); + + case json_type_double: + return (jso1->o.c_double == jso2->o.c_double); + + case json_type_int: + return (jso1->o.c_int64 == jso2->o.c_int64); + + case json_type_string: + return (jso1->o.c_string.len == jso2->o.c_string.len && + memcmp(get_string_component(jso1), + get_string_component(jso2), + jso1->o.c_string.len) == 0); + + case json_type_object: + return json_object_all_values_equal(jso1, jso2); + + case json_type_array: + return json_array_equal(jso1, jso2); + + case json_type_null: + return 1; + }; + + return 0; +} + +static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) +{ + if (!src->_userdata && !src->_user_delete) + return 0; + + if (dst->_to_json_string == json_object_userdata_to_json_string) + { + dst->_userdata = strdup(src->_userdata); + } + // else if ... other supported serializers ... + else + { + _json_c_set_last_err("json_object_deep_copy: unable to copy unknown serializer data: %p\n", dst->_to_json_string); + return -1; + } + dst->_user_delete = src->_user_delete; + return 0; +} + + +/** + * The default shallow copy implementation. Simply creates a new object of the same + * type but does *not* copy over _userdata nor retain any custom serializer. + * If custom serializers are in use, json_object_deep_copy() must be passed a shallow copy + * implementation that is aware of how to copy them. + * + * This always returns -1 or 1. It will never return 2 since it does not copy the serializer. + */ +int json_c_shallow_copy_default(json_object *src, json_object *parent, const char *key, size_t index, json_object **dst) +{ + switch (src->o_type) { + case json_type_boolean: + *dst = json_object_new_boolean(src->o.c_boolean); + break; + + case json_type_double: + *dst = json_object_new_double(src->o.c_double); + break; + + case json_type_int: + *dst = json_object_new_int64(src->o.c_int64); + break; + + case json_type_string: + *dst = json_object_new_string(get_string_component(src)); + break; + + case json_type_object: + *dst = json_object_new_object(); + break; + + case json_type_array: + *dst = json_object_new_array(); + break; + + default: + errno = EINVAL; + return -1; + } + + if (!*dst) { + errno = ENOMEM; + return -1; + } + (*dst)->_to_json_string = src->_to_json_string; + // _userdata and _user_delete are copied later + return 1; +} + +/* + * The actual guts of json_object_deep_copy(), with a few additional args + * needed so we can keep track of where we are within the object tree. + * + * Note: caller is responsible for freeing *dst if this fails and returns -1. + */ +static int json_object_deep_copy_recursive(struct json_object *src, struct json_object *parent, const char *key_in_parent, size_t index_in_parent, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) +{ + struct json_object_iter iter; + size_t src_array_len, ii; + + int shallow_copy_rc = 0; + shallow_copy_rc = shallow_copy(src, parent, key_in_parent, index_in_parent, dst); + /* -1=error, 1=object created ok, 2=userdata set */ + if (shallow_copy_rc < 1) + { + errno = EINVAL; + return -1; + } + assert(*dst != NULL); + + switch (src->o_type) { + case json_type_object: + json_object_object_foreachC(src, iter) { + struct json_object *jso = NULL; + /* This handles the `json_type_null` case */ + if (!iter.val) + jso = NULL; + else if (json_object_deep_copy_recursive(iter.val, src, iter.key, -1, &jso, shallow_copy) < 0) + { + json_object_put(jso); + return -1; + } + + if (json_object_object_add(*dst, iter.key, jso) < 0) + { + json_object_put(jso); + return -1; + } + } + break; + + case json_type_array: + src_array_len = json_object_array_length(src); + for (ii = 0; ii < src_array_len; ii++) { + struct json_object *jso = NULL; + struct json_object *jso1 = json_object_array_get_idx(src, ii); + /* This handles the `json_type_null` case */ + if (!jso1) + jso = NULL; + else if (json_object_deep_copy_recursive(jso1, src, NULL, ii, &jso, shallow_copy) < 0) + { + json_object_put(jso); + return -1; + } + + if (json_object_array_add(*dst, jso) < 0) + { + json_object_put(jso); + return -1; + } + } + break; + + default: + break; + /* else, nothing to do, shallow_copy already did. */ + } + + if (shallow_copy_rc != 2) + return json_object_copy_serializer_data(src, *dst); + + return 0; +} + +int json_object_deep_copy(struct json_object *src, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) +{ + int rc; + + /* Check if arguments are sane ; *dst must not point to a non-NULL object */ + if (!src || !dst || *dst) { + errno = EINVAL; + return -1; + } + + if (shallow_copy == NULL) + shallow_copy = json_c_shallow_copy_default; + + rc = json_object_deep_copy_recursive(src, NULL, NULL, -1, dst, shallow_copy); + if (rc < 0) { + json_object_put(*dst); + *dst = NULL; + } + + return rc; +} + diff --git a/third_party/json-c/json_object.h b/third_party/json-c/json_object.h new file mode 100644 index 0000000000..073d80c617 --- /dev/null +++ b/third_party/json-c/json_object.h @@ -0,0 +1,1034 @@ +/* + * $Id: json_object.h,v 1.12 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Core json-c API. Start here, or with json_tokener.h + */ +#ifndef _json_object_h_ +#define _json_object_h_ + +#ifdef __GNUC__ +#define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__ ((deprecated)) +#elif defined(_MSC_VER) +#define THIS_FUNCTION_IS_DEPRECATED(func) __declspec(deprecated) func +#elif defined(__clang__) +#define THIS_FUNCTION_IS_DEPRECATED(func) func __deprecated +#else +#define THIS_FUNCTION_IS_DEPRECATED(func) func +#endif + +#ifdef __GNUC__ +#define JSON_C_CONST_FUNCTION(func) func __attribute__((const)) +#else +#define JSON_C_CONST_FUNCTION(func) func +#endif + +#if defined(_MSC_VER) +#define JSON_EXPORT __declspec(dllexport) +#else +#define JSON_EXPORT extern +#endif + +#include +#include "json_inttypes.h" +#include "printbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define JSON_OBJECT_DEF_HASH_ENTRIES 16 + +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes the output + * to have no extra whitespace or formatting applied. + */ +#define JSON_C_TO_STRING_PLAIN 0 +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes the output to have + * minimal whitespace inserted to make things slightly more readable. + */ +#define JSON_C_TO_STRING_SPACED (1<<0) +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes + * the output to be formatted. + * + * See the "Two Space Tab" option at http://jsonformatter.curiousconcept.com/ + * for an example of the format. + */ +#define JSON_C_TO_STRING_PRETTY (1<<1) +/** + * A flag for the json_object_to_json_string_ext() and + * json_object_to_file_ext() functions which causes + * the output to be formatted. + * + * Instead of a "Two Space Tab" this gives a single tab character. + */ +#define JSON_C_TO_STRING_PRETTY_TAB (1<<3) +/** + * A flag to drop trailing zero for float values + */ +#define JSON_C_TO_STRING_NOZERO (1<<2) + +/** + * Don't escape forward slashes. + */ +#define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4) + +/** + * A flag for the json_object_object_add_ex function which + * causes the value to be added without a check if it already exists. + * Note: it is the responsibilty of the caller to ensure that no + * key is added multiple times. If this is done, results are + * unpredictable. While this option is somewhat dangerous, it + * permits potentially large performance savings in code that + * knows for sure the key values are unique (e.g. because the + * code adds a well-known set of constant key values). + */ +#define JSON_C_OBJECT_ADD_KEY_IS_NEW (1<<1) +/** + * A flag for the json_object_object_add_ex function which + * flags the key as being constant memory. This means that + * the key will NOT be copied via strdup(), resulting in a + * potentially huge performance win (malloc, strdup and + * free are usually performance hogs). It is acceptable to + * use this flag for keys in non-constant memory blocks if + * the caller ensure that the memory holding the key lives + * longer than the corresponding json object. However, this + * is somewhat dangerous and should only be done if really + * justified. + * The general use-case for this flag is cases where the + * key is given as a real constant value in the function + * call, e.g. as in + * json_object_object_add_ex(obj, "ip", json, + * JSON_C_OBJECT_KEY_IS_CONSTANT); + */ +#define JSON_C_OBJECT_KEY_IS_CONSTANT (1<<2) + +#undef FALSE +#define FALSE ((json_bool)0) + +#undef TRUE +#define TRUE ((json_bool)1) + +/** + * Set the global value of an option, which will apply to all + * current and future threads that have not set a thread-local value. + * + * @see json_c_set_serialization_double_format + */ +#define JSON_C_OPTION_GLOBAL (0) +/** + * Set a thread-local value of an option, overriding the global value. + * This will fail if json-c is not compiled with threading enabled, and + * with the __thread specifier (or equivalent) available. + * + * @see json_c_set_serialization_double_format + */ +#define JSON_C_OPTION_THREAD (1) + +/** + * A structure to use with json_object_object_foreachC() loops. + * Contains key, val and entry members. + */ +struct json_object_iter +{ + char *key; + struct json_object *val; + struct lh_entry *entry; +}; +typedef struct json_object_iter json_object_iter; + +typedef int json_bool; + +/** + * @brief The core type for all type of JSON objects handled by json-c + */ +typedef struct json_object json_object; + +/** + * Type of custom user delete functions. See json_object_set_serializer. + */ +typedef void (json_object_delete_fn)(struct json_object *jso, void *userdata); + +/** + * Type of a custom serialization function. See json_object_set_serializer. + */ +typedef int (json_object_to_json_string_fn)(struct json_object *jso, + struct printbuf *pb, + int level, + int flags); + +/* supported object types */ + +typedef enum json_type { + /* If you change this, be sure to update json_type_to_name() too */ + json_type_null, + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string +} json_type; + +/* reference counting functions */ + +/** + * Increment the reference count of json_object, thereby grabbing shared + * ownership of obj. + * + * @param obj the json_object instance + */ +JSON_EXPORT struct json_object* json_object_get(struct json_object *obj); + +/** + * Decrement the reference count of json_object and free if it reaches zero. + * You must have ownership of obj prior to doing this or you will cause an + * imbalance in the reference count. + * + * @param obj the json_object instance + * @returns 1 if the object was freed. + */ +JSON_EXPORT int json_object_put(struct json_object *obj); + +/** + * Check if the json_object is of a given type + * @param obj the json_object instance + * @param type one of: + json_type_null (i.e. obj == NULL), + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string + */ +JSON_EXPORT int json_object_is_type(const struct json_object *obj, enum json_type type); + +/** + * Get the type of the json_object. See also json_type_to_name() to turn this + * into a string suitable, for instance, for logging. + * + * @param obj the json_object instance + * @returns type being one of: + json_type_null (i.e. obj == NULL), + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string + */ +JSON_EXPORT enum json_type json_object_get_type(const struct json_object *obj); + + +/** Stringify object to json format. + * Equivalent to json_object_to_json_string_ext(obj, JSON_C_TO_STRING_SPACED) + * The pointer you get is an internal of your json object. You don't + * have to free it, later use of json_object_put() should be sufficient. + * If you can not ensure there's no concurrent access to *obj use + * strdup(). + * @param obj the json_object instance + * @returns a string in JSON format + */ +JSON_EXPORT const char* json_object_to_json_string(struct json_object *obj); + +/** Stringify object to json format + * @see json_object_to_json_string() for details on how to free string. + * @param obj the json_object instance + * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants + * @returns a string in JSON format + */ +JSON_EXPORT const char* json_object_to_json_string_ext(struct json_object *obj, int +flags); + +/** Stringify object to json format + * @see json_object_to_json_string() for details on how to free string. + * @param obj the json_object instance + * @param flags formatting options, see JSON_C_TO_STRING_PRETTY and other constants + * @param length a pointer where, if not NULL, the length (without null) is stored + * @returns a string in JSON format and the length if not NULL + */ +JSON_EXPORT const char* json_object_to_json_string_length(struct json_object *obj, int +flags, size_t *length); + +/** + * Returns the userdata set by json_object_set_userdata() or + * json_object_set_serializer() + * + * @param jso the object to return the userdata for + */ +JSON_EXPORT void* json_object_get_userdata(json_object *jso); + +/** + * Set an opaque userdata value for an object + * + * The userdata can be retrieved using json_object_get_userdata(). + * + * If custom userdata is already set on this object, any existing user_delete + * function is called before the new one is set. + * + * The user_delete parameter is optional and may be passed as NULL, even if + * the userdata parameter is non-NULL. It will be called just before the + * json_object is deleted, after it's reference count goes to zero + * (see json_object_put()). + * If this is not provided, it is up to the caller to free the userdata at + * an appropriate time. (i.e. after the json_object is deleted) + * + * Note: Objects created by parsing strings may have custom serializers set + * which expect the userdata to contain specific data (due to use of + * json_object_new_double_s()). In this case, json_object_set_serialiser() with + * NULL as to_string_func should be used instead to set the userdata and reset + * the serializer to its default value. + * + * @param jso the object to set the userdata for + * @param userdata an optional opaque cookie + * @param user_delete an optional function from freeing userdata + */ +JSON_EXPORT void json_object_set_userdata(json_object *jso, void *userdata, + json_object_delete_fn *user_delete); + +/** + * Set a custom serialization function to be used when this particular object + * is converted to a string by json_object_to_json_string. + * + * If custom userdata is already set on this object, any existing user_delete + * function is called before the new one is set. + * + * If to_string_func is NULL the default behaviour is reset (but the userdata + * and user_delete fields are still set). + * + * The userdata parameter is optional and may be passed as NULL. It can be used + * to provide additional data for to_string_func to use. This parameter may + * be NULL even if user_delete is non-NULL. + * + * The user_delete parameter is optional and may be passed as NULL, even if + * the userdata parameter is non-NULL. It will be called just before the + * json_object is deleted, after it's reference count goes to zero + * (see json_object_put()). + * If this is not provided, it is up to the caller to free the userdata at + * an appropriate time. (i.e. after the json_object is deleted) + * + * Note that the userdata is the same as set by json_object_set_userdata(), so + * care must be taken not to overwrite the value when both a custom serializer + * and json_object_set_userdata() are used. + * + * @param jso the object to customize + * @param to_string_func the custom serialization function + * @param userdata an optional opaque cookie + * @param user_delete an optional function from freeing userdata + */ +JSON_EXPORT void json_object_set_serializer(json_object *jso, + json_object_to_json_string_fn *to_string_func, + void *userdata, + json_object_delete_fn *user_delete); + +#ifdef __clang__ +/* + * Clang doesn't pay attention to the parameters defined in the + * function typedefs used here, so turn off spurious doc warnings. + * { + */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#endif + +/** + * Simply call free on the userdata pointer. + * Can be used with json_object_set_serializer(). + * + * @param jso unused + * @param userdata the pointer that is passed to free(). + */ +json_object_delete_fn json_object_free_userdata; + +/** + * Copy the jso->_userdata string over to pb as-is. + * Can be used with json_object_set_serializer(). + * + * @param jso The object whose _userdata is used. + * @param pb The destination buffer. + * @param level Ignored. + * @param flags Ignored. + */ +json_object_to_json_string_fn json_object_userdata_to_json_string; + +#ifdef __clang__ +/* } */ +#pragma clang diagnostic pop +#endif + + +/* object type methods */ + +/** Create a new empty object with a reference count of 1. The caller of + * this object initially has sole ownership. Remember, when using + * json_object_object_add or json_object_array_put_idx, ownership will + * transfer to the object/array. Call json_object_get if you want to maintain + * shared ownership or also add this object as a child of multiple objects or + * arrays. Any ownerships you acquired but did not transfer must be released + * through json_object_put. + * + * @returns a json_object of type json_type_object + */ +JSON_EXPORT struct json_object* json_object_new_object(void); + +/** Get the hashtable of a json_object of type json_type_object + * @param obj the json_object instance + * @returns a linkhash + */ +JSON_EXPORT struct lh_table* json_object_get_object(const struct json_object *obj); + +/** Get the size of an object in terms of the number of fields it has. + * @param obj the json_object whose length to return + */ +JSON_EXPORT int json_object_object_length(const struct json_object* obj); + +/** Get the sizeof (struct json_object). + * @returns a size_t with the sizeof (struct json_object) + */ +JSON_C_CONST_FUNCTION(JSON_EXPORT size_t json_c_object_sizeof(void)); + +/** Add an object field to a json_object of type json_type_object + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object, independent of the lifetime of obj, you must wrap the + * passed object with json_object_get. + * + * Upon calling this, the ownership of val transfers to obj. Thus you must + * make sure that you do in fact have ownership over this object. For instance, + * json_object_new_object will give you ownership until you transfer it, + * whereas json_object_object_get does not. + * + * @param obj the json_object instance + * @param key the object field name (a private copy will be duplicated) + * @param val a json_object or NULL member to associate with the given field + * + * @return On success, 0 is returned. + * On error, a negative value is returned. + */ +JSON_EXPORT int json_object_object_add(struct json_object* obj, const char *key, + struct json_object *val); + +/** Add an object field to a json_object of type json_type_object + * + * The semantics are identical to json_object_object_add, except that an + * additional flag fields gives you more control over some detail aspects + * of processing. See the description of JSON_C_OBJECT_ADD_* flags for more + * details. + * + * @param obj the json_object instance + * @param key the object field name (a private copy will be duplicated) + * @param val a json_object or NULL member to associate with the given field + * @param opts process-modifying options. To specify multiple options, use + * arithmetic or (OPT1|OPT2) + */ +JSON_EXPORT int json_object_object_add_ex(struct json_object* obj, + const char *const key, + struct json_object *const val, + const unsigned opts); + +/** Get the json_object associate with a given object field. + * Deprecated/discouraged: used json_object_object_get_ex instead. + * + * This returns NULL if the field is found but its value is null, or if + * the field is not found, or if obj is not a json_type_object. If you + * need to distinguis between these cases, use json_object_object_get_ex(). + * + * *No* reference counts will be changed. There is no need to manually adjust + * reference counts through the json_object_put/json_object_get methods unless + * you need to have the child (value) reference maintain a different lifetime + * than the owning parent (obj). Ownership of the returned value is retained + * by obj (do not do json_object_put unless you have done a json_object_get). + * If you delete the value from obj (json_object_object_del) and wish to access + * the returned reference afterwards, make sure you have first gotten shared + * ownership through json_object_get (& don't forget to do a json_object_put + * or transfer ownership to prevent a memory leak). + * + * @param obj the json_object instance + * @param key the object field name + * @returns the json_object associated with the given field name + */ +JSON_EXPORT struct json_object* json_object_object_get(const struct json_object* obj, + const char *key); + +/** Get the json_object associated with a given object field. + * + * This returns true if the key is found, false in all other cases (including + * if obj isn't a json_type_object). + * + * *No* reference counts will be changed. There is no need to manually adjust + * reference counts through the json_object_put/json_object_get methods unless + * you need to have the child (value) reference maintain a different lifetime + * than the owning parent (obj). Ownership of value is retained by obj. + * + * @param obj the json_object instance + * @param key the object field name + * @param value a pointer where to store a reference to the json_object + * associated with the given field name. + * + * It is safe to pass a NULL value. + * @returns whether or not the key exists + */ +JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object* obj, + const char *key, + struct json_object **value); + +/** Delete the given json_object field + * + * The reference count will be decremented for the deleted object. If there + * are no more owners of the value represented by this key, then the value is + * freed. Otherwise, the reference to the value will remain in memory. + * + * @param obj the json_object instance + * @param key the object field name + */ +JSON_EXPORT void json_object_object_del(struct json_object* obj, const char *key); + +/** + * Iterate through all keys and values of an object. + * + * Adding keys to the object while iterating is NOT allowed. + * + * Deleting an existing key, or replacing an existing key with a + * new value IS allowed. + * + * @param obj the json_object instance + * @param key the local name for the char* key variable defined in the body + * @param val the local name for the json_object* object variable defined in + * the body + */ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L + +# define json_object_object_foreach(obj,key,val) \ + char *key = NULL; \ + struct json_object *val __attribute__((__unused__)) = NULL; \ + for(struct lh_entry *entry ## key = json_object_get_object(obj)->head, *entry_next ## key = NULL; \ + ({ if(entry ## key) { \ + key = (char*)lh_entry_k(entry ## key); \ + val = (struct json_object*)lh_entry_v(entry ## key); \ + entry_next ## key = entry ## key->next; \ + } ; entry ## key; }); \ + entry ## key = entry_next ## key ) + +#else /* ANSI C or MSC */ + +# define json_object_object_foreach(obj,key,val) \ + char *key = NULL;\ + struct json_object *val = NULL; \ + struct lh_entry *entry ## key; \ + struct lh_entry *entry_next ## key = NULL; \ + for(entry ## key = json_object_get_object(obj)->head; \ + (entry ## key ? ( \ + key = (char*)lh_entry_k(entry ## key), \ + val = (struct json_object*)lh_entry_v(entry ## key), \ + entry_next ## key = entry ## key->next, \ + entry ## key) : 0); \ + entry ## key = entry_next ## key) + +#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && __STDC_VERSION__ >= 199901L */ + +/** Iterate through all keys and values of an object (ANSI C Safe) + * @param obj the json_object instance + * @param iter the object iterator, use type json_object_iter + */ +#define json_object_object_foreachC(obj,iter) \ + for(iter.entry = json_object_get_object(obj)->head; \ + (iter.entry ? (iter.key = (char*)lh_entry_k(iter.entry), iter.val = (struct json_object*)lh_entry_v(iter.entry), iter.entry) : 0); \ + iter.entry = iter.entry->next) + +/* Array type methods */ + +/** Create a new empty json_object of type json_type_array + * @returns a json_object of type json_type_array + */ +JSON_EXPORT struct json_object* json_object_new_array(void); + +/** Get the arraylist of a json_object of type json_type_array + * @param obj the json_object instance + * @returns an arraylist + */ +JSON_EXPORT struct array_list* json_object_get_array(const struct json_object *obj); + +/** Get the length of a json_object of type json_type_array + * @param obj the json_object instance + * @returns an int + */ +JSON_EXPORT size_t json_object_array_length(const struct json_object *obj); + +/** Sorts the elements of jso of type json_type_array +* +* Pointers to the json_object pointers will be passed as the two arguments +* to sort_fn +* +* @param jso the json_object instance +* @param sort_fn a sorting function +*/ +JSON_EXPORT void json_object_array_sort(struct json_object *jso, int(*sort_fn)(const void *, const void *)); + +/** Binary search a sorted array for a specified key object. + * + * It depends on your compare function what's sufficient as a key. + * Usually you create some dummy object with the parameter compared in + * it, to identify the right item you're actually looking for. + * + * @see json_object_array_sort() for hints on the compare function. + * + * @param key a dummy json_object with the right key + * @param jso the array object we're searching + * @param sort_fn the sort/compare function + * + * @return the wanted json_object instance + */ +JSON_EXPORT struct json_object* json_object_array_bsearch( + const struct json_object *key, + const struct json_object *jso, + int (*sort_fn)(const void *, const void *)); + +/** Add an element to the end of a json_object of type json_type_array + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * @param obj the json_object instance + * @param val the json_object to be added + */ +JSON_EXPORT int json_object_array_add(struct json_object *obj, + struct json_object *val); + +/** Insert or replace an element at a specified index in an array (a json_object of type json_type_array) + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * The reference count of a replaced object will be decremented. + * + * The array size will be automatically be expanded to the size of the + * index if the index is larger than the current size. + * + * @param obj the json_object instance + * @param idx the index to insert the element at + * @param val the json_object to be added + */ +JSON_EXPORT int json_object_array_put_idx(struct json_object *obj, size_t idx, + struct json_object *val); + +/** Get the element at specificed index of the array (a json_object of type json_type_array) + * @param obj the json_object instance + * @param idx the index to get the element at + * @returns the json_object at the specified index (or NULL) + */ +JSON_EXPORT struct json_object* json_object_array_get_idx(const struct json_object *obj, + size_t idx); + +/** Delete an elements from a specified index in an array (a json_object of type json_type_array) + * + * The reference count will be decremented for each of the deleted objects. If there + * are no more owners of an element that is being deleted, then the value is + * freed. Otherwise, the reference to the value will remain in memory. + * + * @param obj the json_object instance + * @param idx the index to start deleting elements at + * @param count the number of elements to delete + * @returns 0 if the elements were successfully deleted + */ +JSON_EXPORT int json_object_array_del_idx(struct json_object *obj, size_t idx, size_t count); + +/* json_bool type methods */ + +/** Create a new empty json_object of type json_type_boolean + * @param b a json_bool TRUE or FALSE (1 or 0) + * @returns a json_object of type json_type_boolean + */ +JSON_EXPORT struct json_object* json_object_new_boolean(json_bool b); + +/** Get the json_bool value of a json_object + * + * The type is coerced to a json_bool if the passed object is not a json_bool. + * integer and double objects will return FALSE if there value is zero + * or TRUE otherwise. If the passed object is a string it will return + * TRUE if it has a non zero length. If any other object type is passed + * TRUE will be returned if the object is not NULL. + * + * @param obj the json_object instance + * @returns a json_bool + */ +JSON_EXPORT json_bool json_object_get_boolean(const struct json_object *obj); + + +/** Set the json_bool value of a json_object + * + * The type of obj is checked to be a json_type_boolean and 0 is returned + * if it is not without any further actions. If type of obj is json_type_boolean + * the obect value is chaned to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_boolean(struct json_object *obj,json_bool new_value); + + +/* int type methods */ + +/** Create a new empty json_object of type json_type_int + * Note that values are stored as 64-bit values internally. + * To ensure the full range is maintained, use json_object_new_int64 instead. + * @param i the integer + * @returns a json_object of type json_type_int + */ +JSON_EXPORT struct json_object* json_object_new_int(int32_t i); + + +/** Create a new empty json_object of type json_type_int + * @param i the integer + * @returns a json_object of type json_type_int + */ +JSON_EXPORT struct json_object* json_object_new_int64(int64_t i); + + +/** Get the int value of a json_object + * + * The type is coerced to a int if the passed object is not a int. + * double objects will return their integer conversion. Strings will be + * parsed as an integer. If no conversion exists then 0 is returned + * and errno is set to EINVAL. null is equivalent to 0 (no error values set) + * + * Note that integers are stored internally as 64-bit values. + * If the value of too big or too small to fit into 32-bit, INT32_MAX or + * INT32_MIN are returned, respectively. + * + * @param obj the json_object instance + * @returns an int + */ +JSON_EXPORT int32_t json_object_get_int(const struct json_object *obj); + +/** Set the int value of a json_object + * + * The type of obj is checked to be a json_type_int and 0 is returned + * if it is not without any further actions. If type of obj is json_type_int + * the obect value is changed to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_int(struct json_object *obj,int new_value); + +/** Increment a json_type_int object by the given amount, which may be negative. + * + * If the type of obj is not json_type_int then 0 is returned with no further + * action taken. + * If the addition would result in a overflow, the object value + * is set to INT64_MAX. + * If the addition would result in a underflow, the object value + * is set to INT64_MIN. + * Neither overflow nor underflow affect the return value. + * + * @param obj the json_object instance + * @param val the value to add + * @returns 1 if the increment succeded, 0 otherwise + */ +JSON_EXPORT int json_object_int_inc(struct json_object *obj, int64_t val); + + +/** Get the int value of a json_object + * + * The type is coerced to a int64 if the passed object is not a int64. + * double objects will return their int64 conversion. Strings will be + * parsed as an int64. If no conversion exists then 0 is returned. + * + * NOTE: Set errno to 0 directly before a call to this function to determine + * whether or not conversion was successful (it does not clear the value for + * you). + * + * @param obj the json_object instance + * @returns an int64 + */ +JSON_EXPORT int64_t json_object_get_int64(const struct json_object *obj); + + +/** Set the int64_t value of a json_object + * + * The type of obj is checked to be a json_type_int and 0 is returned + * if it is not without any further actions. If type of obj is json_type_int + * the obect value is chaned to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_int64(struct json_object *obj,int64_t new_value); + +/* double type methods */ + +/** Create a new empty json_object of type json_type_double + * + * @see json_object_double_to_json_string() for how to set a custom format string. + * + * @param d the double + * @returns a json_object of type json_type_double + */ +JSON_EXPORT struct json_object* json_object_new_double(double d); + +/** + * Create a new json_object of type json_type_double, using + * the exact serialized representation of the value. + * + * This allows for numbers that would otherwise get displayed + * inefficiently (e.g. 12.3 => "12.300000000000001") to be + * serialized with the more convenient form. + * + * Notes: + * + * This is used by json_tokener_parse_ex() to allow for + * an exact re-serialization of a parsed object. + * + * The userdata field is used to store the string representation, so it + * can't be used for other data if this function is used. + * + * An equivalent sequence of calls is: + * @code + * jso = json_object_new_double(d); + * json_object_set_serializer(jso, json_object_userdata_to_json_string, + * strdup(ds), json_object_free_userdata); + * @endcode + * + * @param d the numeric value of the double. + * @param ds the string representation of the double. This will be copied. + */ +JSON_EXPORT struct json_object* json_object_new_double_s(double d, const char *ds); + +/** + * Set a global or thread-local json-c option, depending on whether + * JSON_C_OPTION_GLOBAL or JSON_C_OPTION_THREAD is passed. + * Thread-local options default to undefined, and inherit from the global + * value, even if the global value is changed after the thread is created. + * Attempting to set thread-local options when threading is not compiled in + * will result in an error. Be sure to check the return value. + * + * double_format is a "%g" printf format, such as "%.20g" + * + * @return -1 on errors, 0 on success. + */ +int json_c_set_serialization_double_format(const char *double_format, int global_or_thread); + + + +/** Serialize a json_object of type json_type_double to a string. + * + * This function isn't meant to be called directly. Instead, you can set a + * custom format string for the serialization of this double using the + * following call (where "%.17g" actually is the default): + * + * @code + * jso = json_object_new_double(d); + * json_object_set_serializer(jso, json_object_double_to_json_string, + * "%.17g", NULL); + * @endcode + * + * @see printf(3) man page for format strings + * + * @param jso The json_type_double object that is serialized. + * @param pb The destination buffer. + * @param level Ignored. + * @param flags Ignored. + */ +JSON_EXPORT int json_object_double_to_json_string(struct json_object* jso, + struct printbuf *pb, + int level, + int flags); + +/** Get the double floating point value of a json_object + * + * The type is coerced to a double if the passed object is not a double. + * integer objects will return their double conversion. Strings will be + * parsed as a double. If no conversion exists then 0.0 is returned and + * errno is set to EINVAL. null is equivalent to 0 (no error values set) + * + * If the value is too big to fit in a double, then the value is set to + * the closest infinity with errno set to ERANGE. If strings cannot be + * converted to their double value, then EINVAL is set & NaN is returned. + * + * Arrays of length 0 are interpreted as 0 (with no error flags set). + * Arrays of length 1 are effectively cast to the equivalent object and + * converted using the above rules. All other arrays set the error to + * EINVAL & return NaN. + * + * NOTE: Set errno to 0 directly before a call to this function to + * determine whether or not conversion was successful (it does not clear + * the value for you). + * + * @param obj the json_object instance + * @returns a double floating point number + */ +JSON_EXPORT double json_object_get_double(const struct json_object *obj); + + +/** Set the double value of a json_object + * + * The type of obj is checked to be a json_type_double and 0 is returned + * if it is not without any further actions. If type of obj is json_type_double + * the obect value is chaned to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_double(struct json_object *obj,double new_value); + + + +/* string type methods */ + +/** Create a new empty json_object of type json_type_string + * + * A copy of the string is made and the memory is managed by the json_object + * + * @param s the string + * @returns a json_object of type json_type_string + */ +JSON_EXPORT struct json_object* json_object_new_string(const char *s); + +JSON_EXPORT struct json_object* json_object_new_string_len(const char *s, int len); + +/** Get the string value of a json_object + * + * If the passed object is of type json_type_null (i.e. obj == NULL), + * NULL is returned. + * + * If the passed object of type json_type_string, the string contents + * are returned. + * + * Otherwise the JSON representation of the object is returned. + * + * The returned string memory is managed by the json_object and will + * be freed when the reference count of the json_object drops to zero. + * + * @param obj the json_object instance + * @returns a string or NULL + */ +JSON_EXPORT const char* json_object_get_string(struct json_object *obj); + +/** Get the string length of a json_object + * + * If the passed object is not of type json_type_string then zero + * will be returned. + * + * @param obj the json_object instance + * @returns int + */ +JSON_EXPORT int json_object_get_string_len(const struct json_object *obj); + + +/** Set the string value of a json_object with zero terminated strings + * equivalent to json_object_set_string_len (obj, new_value, strlen(new_value)) + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_string(json_object* obj, const char* new_value); + +/** Set the string value of a json_object str + * + * The type of obj is checked to be a json_type_string and 0 is returned + * if it is not without any further actions. If type of obj is json_type_string + * the obect value is chaned to new_value + * + * @param obj the json_object instance + * @param new_value the value to be set; Since string legth is given in len this need not be zero terminated + * @param len the length of new_value + * @returns 1 if value is set correctly, 0 otherwise + */ +JSON_EXPORT int json_object_set_string_len(json_object* obj, const char* new_value, int len); + +/** Check if two json_object's are equal + * + * If the passed objects are equal 1 will be returned. + * Equality is defined as follows: + * - json_objects of different types are never equal + * - json_objects of the same primitive type are equal if the + * c-representation of their value is equal + * - json-arrays are considered equal if all values at the same + * indices are equal (same order) + * - Complex json_objects are considered equal if all + * contained objects referenced by their key are equal, + * regardless their order. + * + * @param obj1 the first json_object instance + * @param obj2 the second json_object instance + * @returns whether both objects are equal or not + */ +JSON_EXPORT int json_object_equal(struct json_object *obj1, + struct json_object *obj2); + +/** + * Perform a shallow copy of src into *dst as part of an overall json_object_deep_copy(). + * + * If src is part of a containing object or array, parent will be non-NULL, + * and key or index will be provided. + * When shallow_copy is called *dst will be NULL, and must be non-NULL when it returns. + * src will never be NULL. + * + * If shallow_copy sets the serializer on an object, return 2 to indicate to + * json_object_deep_copy that it should not attempt to use the standard userdata + * copy function. + * + * @return On success 1 or 2, -1 on errors + */ +typedef int (json_c_shallow_copy_fn)(json_object *src, json_object *parent, const char *key, size_t index, json_object **dst); + +/** + * The default shallow copy implementation for use with json_object_deep_copy(). + * This simply calls the appropriate json_object_new_() function and + * copies over the serializer function (_to_json_string internal field of + * the json_object structure) but not any _userdata or _user_delete values. + * + * If you're writing a custom shallow_copy function, perhaps because you're using + * your own custom serializer, you can call this first to create the new object + * before customizing it with json_object_set_serializer(). + * + * @return 1 on success, -1 on errors, but never 2. + */ +json_c_shallow_copy_fn json_c_shallow_copy_default; + +/** + * Copy the contents of the JSON object. + * The destination object must be initialized to NULL, + * to make sure this function won't overwrite an existing JSON object. + * + * This does roughly the same thing as + * `json_tokener_parse(json_object_get_string(src))`. + * + * @param src source JSON object whose contents will be copied + * @param dst pointer to the destination object where the contents of `src`; + * make sure this pointer is initialized to NULL + * @param shallow_copy an optional function to copy individual objects, needed + * when custom serializers are in use. See also + * json_object set_serializer. + * + * @returns 0 if the copy went well, -1 if an error occured during copy + * or if the destination pointer is non-NULL + */ + +JSON_EXPORT int json_object_deep_copy(struct json_object *src, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/json_object_iterator.c b/third_party/json-c/json_object_iterator.c new file mode 100644 index 0000000000..f8d69ab368 --- /dev/null +++ b/third_party/json-c/json_object_iterator.c @@ -0,0 +1,163 @@ +/** +******************************************************************************* +* @file json_object_iterator.c +* +* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. +* +* This library is free software; you can redistribute it and/or modify +* it under the terms of the MIT license. See COPYING for details. +* +******************************************************************************* +*/ + +#include + +#include "json.h" +#include "json_object_private.h" + +#include "json_object_iterator.h" + +/** + * How It Works + * + * For each JSON Object, json-c maintains a linked list of zero + * or more lh_entry (link-hash entry) structures inside the + * Object's link-hash table (lh_table). + * + * Each lh_entry structure on the JSON Object's linked list + * represents a single name/value pair. The "next" field of the + * last lh_entry in the list is set to NULL, which terminates + * the list. + * + * We represent a valid iterator that refers to an actual + * name/value pair via a pointer to the pair's lh_entry + * structure set as the iterator's opaque_ field. + * + * We follow json-c's current pair list representation by + * representing a valid "end" iterator (one that refers past the + * last pair) with a NULL value in the iterator's opaque_ field. + * + * A JSON Object without any pairs in it will have the "head" + * field of its lh_table structure set to NULL. For such an + * object, json_object_iter_begin will return an iterator with + * the opaque_ field set to NULL, which is equivalent to the + * "end" iterator. + * + * When iterating, we simply update the iterator's opaque_ field + * to point to the next lh_entry structure in the linked list. + * opaque_ will become NULL once we iterate past the last pair + * in the list, which makes the iterator equivalent to the "end" + * iterator. + */ + +/// Our current representation of the "end" iterator; +/// +/// @note May not always be NULL +static const void* kObjectEndIterValue = NULL; + +/** + * **************************************************************************** + */ +struct json_object_iterator +json_object_iter_begin(struct json_object* obj) +{ + struct json_object_iterator iter; + struct lh_table* pTable; + + /// @note json_object_get_object will return NULL if passed NULL + /// or a non-json_type_object instance + pTable = json_object_get_object(obj); + JASSERT(NULL != pTable); + + /// @note For a pair-less Object, head is NULL, which matches our + /// definition of the "end" iterator + iter.opaque_ = pTable->head; + return iter; +} + +/** + * **************************************************************************** + */ +struct json_object_iterator +json_object_iter_end(const struct json_object* obj) +{ + struct json_object_iterator iter; + + JASSERT(NULL != obj); + JASSERT(json_object_is_type(obj, json_type_object)); + + iter.opaque_ = kObjectEndIterValue; + + return iter; +} + +/** + * **************************************************************************** + */ +void +json_object_iter_next(struct json_object_iterator* iter) +{ + JASSERT(NULL != iter); + JASSERT(kObjectEndIterValue != iter->opaque_); + + iter->opaque_ = ((const struct lh_entry *)iter->opaque_)->next; +} + + +/** + * **************************************************************************** + */ +const char* +json_object_iter_peek_name(const struct json_object_iterator* iter) +{ + JASSERT(NULL != iter); + JASSERT(kObjectEndIterValue != iter->opaque_); + + return (const char*)(((const struct lh_entry *)iter->opaque_)->k); +} + + +/** + * **************************************************************************** + */ +struct json_object* +json_object_iter_peek_value(const struct json_object_iterator* iter) +{ + JASSERT(NULL != iter); + JASSERT(kObjectEndIterValue != iter->opaque_); + + return (struct json_object*)lh_entry_v((const struct lh_entry *)iter->opaque_); +} + + +/** + * **************************************************************************** + */ +json_bool +json_object_iter_equal(const struct json_object_iterator* iter1, + const struct json_object_iterator* iter2) +{ + JASSERT(NULL != iter1); + JASSERT(NULL != iter2); + + return (iter1->opaque_ == iter2->opaque_); +} + + +/** + * **************************************************************************** + */ +struct json_object_iterator +json_object_iter_init_default(void) +{ + struct json_object_iterator iter; + + /** + * @note Make this a negative, invalid value, such that + * accidental access to it would likely be trapped by the + * hardware as an invalid address. + */ + iter.opaque_ = NULL; + + return iter; +} diff --git a/third_party/json-c/json_object_iterator.h b/third_party/json-c/json_object_iterator.h new file mode 100644 index 0000000000..f226cbd524 --- /dev/null +++ b/third_party/json-c/json_object_iterator.h @@ -0,0 +1,240 @@ +/** +******************************************************************************* +* @file json_object_iterator.h +* +* Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. +* +* This library is free software; you can redistribute it and/or modify +* it under the terms of the MIT license. See COPYING for details. +* +* @brief An API for iterating over json_type_object objects, +* styled to be familiar to C++ programmers. +* Unlike json_object_object_foreach() and +* json_object_object_foreachC(), this avoids the need to expose +* json-c internals like lh_entry. +* +* API attributes:
+* * Thread-safe: NO
+* * Reentrant: NO +* +******************************************************************************* +*/ + + +#ifndef JSON_OBJECT_ITERATOR_H +#define JSON_OBJECT_ITERATOR_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Forward declaration for the opaque iterator information. + */ +struct json_object_iter_info_; + +/** + * The opaque iterator that references a name/value pair within + * a JSON Object instance or the "end" iterator value. + */ +struct json_object_iterator { + const void* opaque_; +}; + + +/** + * forward declaration of json-c's JSON value instance structure + */ +struct json_object; + + +/** + * Initializes an iterator structure to a "default" value that + * is convenient for initializing an iterator variable to a + * default state (e.g., initialization list in a class' + * constructor). + * + * @code + * struct json_object_iterator iter = json_object_iter_init_default(); + * MyClass() : iter_(json_object_iter_init_default()) + * @endcode + * + * @note The initialized value doesn't reference any specific + * pair, is considered an invalid iterator, and MUST NOT + * be passed to any json-c API that expects a valid + * iterator. + * + * @note User and internal code MUST NOT make any assumptions + * about and dependencies on the value of the "default" + * iterator value. + * + * @return json_object_iterator + */ +struct json_object_iterator +json_object_iter_init_default(void); + +/** Retrieves an iterator to the first pair of the JSON Object. + * + * @warning Any modification of the underlying pair invalidates all + * iterators to that pair. + * + * @param obj JSON Object instance (MUST be of type json_object) + * + * @return json_object_iterator If the JSON Object has at + * least one pair, on return, the iterator refers + * to the first pair. If the JSON Object doesn't + * have any pairs, the returned iterator is + * equivalent to the "end" iterator for the same + * JSON Object instance. + * + * @code + * struct json_object_iterator it; + * struct json_object_iterator itEnd; + * struct json_object* obj; + * + * obj = json_tokener_parse("{'first':'george', 'age':100}"); + * it = json_object_iter_begin(obj); + * itEnd = json_object_iter_end(obj); + * + * while (!json_object_iter_equal(&it, &itEnd)) { + * printf("%s\n", + * json_object_iter_peek_name(&it)); + * json_object_iter_next(&it); + * } + * + * @endcode + */ +struct json_object_iterator +json_object_iter_begin(struct json_object* obj); + +/** Retrieves the iterator that represents the position beyond the + * last pair of the given JSON Object instance. + * + * @warning Do NOT write code that assumes that the "end" + * iterator value is NULL, even if it is so in a + * particular instance of the implementation. + * + * @note The reason we do not (and MUST NOT) provide + * "json_object_iter_is_end(json_object_iterator* iter)" + * type of API is because it would limit the underlying + * representation of name/value containment (or force us + * to add additional, otherwise unnecessary, fields to + * the iterator structure). The "end" iterator and the + * equality test method, on the other hand, permit us to + * cleanly abstract pretty much any reasonable underlying + * representation without burdening the iterator + * structure with unnecessary data. + * + * @note For performance reasons, memorize the "end" iterator prior + * to any loop. + * + * @param obj JSON Object instance (MUST be of type json_object) + * + * @return json_object_iterator On return, the iterator refers + * to the "end" of the Object instance's pairs + * (i.e., NOT the last pair, but "beyond the last + * pair" value) + */ +struct json_object_iterator +json_object_iter_end(const struct json_object* obj); + +/** Returns an iterator to the next pair, if any + * + * @warning Any modification of the underlying pair + * invalidates all iterators to that pair. + * + * @param iter [IN/OUT] Pointer to iterator that references a + * name/value pair; MUST be a valid, non-end iterator. + * WARNING: bad things will happen if invalid or "end" + * iterator is passed. Upon return will contain the + * reference to the next pair if there is one; if there + * are no more pairs, will contain the "end" iterator + * value, which may be compared against the return value + * of json_object_iter_end() for the same JSON Object + * instance. + */ +void +json_object_iter_next(struct json_object_iterator* iter); + + +/** Returns a const pointer to the name of the pair referenced + * by the given iterator. + * + * @param iter pointer to iterator that references a name/value + * pair; MUST be a valid, non-end iterator. + * + * @warning bad things will happen if an invalid or + * "end" iterator is passed. + * + * @return const char* Pointer to the name of the referenced + * name/value pair. The name memory belongs to the + * name/value pair, will be freed when the pair is + * deleted or modified, and MUST NOT be modified or + * freed by the user. + */ +const char* +json_object_iter_peek_name(const struct json_object_iterator* iter); + + +/** Returns a pointer to the json-c instance representing the + * value of the referenced name/value pair, without altering + * the instance's reference count. + * + * @param iter pointer to iterator that references a name/value + * pair; MUST be a valid, non-end iterator. + * + * @warning bad things will happen if invalid or + * "end" iterator is passed. + * + * @return struct json_object* Pointer to the json-c value + * instance of the referenced name/value pair; the + * value's reference count is not changed by this + * function: if you plan to hold on to this json-c node, + * take a look at json_object_get() and + * json_object_put(). IMPORTANT: json-c API represents + * the JSON Null value as a NULL json_object instance + * pointer. + */ +struct json_object* +json_object_iter_peek_value(const struct json_object_iterator* iter); + + +/** Tests two iterators for equality. Typically used to test + * for end of iteration by comparing an iterator to the + * corresponding "end" iterator (that was derived from the same + * JSON Object instance). + * + * @note The reason we do not (and MUST NOT) provide + * "json_object_iter_is_end(json_object_iterator* iter)" + * type of API is because it would limit the underlying + * representation of name/value containment (or force us + * to add additional, otherwise unnecessary, fields to + * the iterator structure). The equality test method, on + * the other hand, permits us to cleanly abstract pretty + * much any reasonable underlying representation. + * + * @param iter1 Pointer to first valid, non-NULL iterator + * @param iter2 POinter to second valid, non-NULL iterator + * + * @warning if a NULL iterator pointer or an uninitialized + * or invalid iterator, or iterators derived from + * different JSON Object instances are passed, bad things + * will happen! + * + * @return json_bool non-zero if iterators are equal (i.e., both + * reference the same name/value pair or are both at + * "end"); zero if they are not equal. + */ +json_bool +json_object_iter_equal(const struct json_object_iterator* iter1, + const struct json_object_iterator* iter2); + + +#ifdef __cplusplus +} +#endif + + +#endif /* JSON_OBJECT_ITERATOR_H */ diff --git a/third_party/json-c/json_object_private.h b/third_party/json-c/json_object_private.h new file mode 100644 index 0000000000..53be70db08 --- /dev/null +++ b/third_party/json-c/json_object_private.h @@ -0,0 +1,64 @@ +/* + * $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ +#ifndef _json_object_private_h_ +#define _json_object_private_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define LEN_DIRECT_STRING_DATA 32 /**< how many bytes are directly stored in json_object for strings? */ + +typedef void (json_object_private_delete_fn)(struct json_object *o); + +struct json_object +{ + enum json_type o_type; + json_object_private_delete_fn *_delete; + json_object_to_json_string_fn *_to_json_string; + int _ref_count; + struct printbuf *_pb; + union data { + json_bool c_boolean; + double c_double; + int64_t c_int64; + struct lh_table *c_object; + struct array_list *c_array; + struct { + union { + /* optimize: if we have small strings, we can store them + * directly. This saves considerable CPU cycles AND memory. + */ + char *ptr; + char data[LEN_DIRECT_STRING_DATA]; + } str; + int len; + } c_string; + } o; + json_object_delete_fn *_user_delete; + void *_userdata; +}; + +void _json_c_set_last_err(const char *err_fmt, ...); + +extern const char *json_number_chars; +extern const char *json_hex_chars; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/json_pointer.c b/third_party/json-c/json_pointer.c new file mode 100644 index 0000000000..2b2a9ef507 --- /dev/null +++ b/third_party/json-c/json_pointer.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2016 Alexandru Ardelean. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include "strerror_override.h" + +#include +#include +#include +#include +#include + +#include "json_pointer.h" +#include "strdup_compat.h" +#include "vasprintf_compat.h" + +/** + * JavaScript Object Notation (JSON) Pointer + * RFC 6901 - https://tools.ietf.org/html/rfc6901 + */ + +static void string_replace_all_occurrences_with_char(char *s, const char *occur, char repl_char) +{ + int slen = strlen(s); + int skip = strlen(occur) - 1; /* length of the occurence, minus the char we're replacing */ + char *p = s; + while ((p = strstr(p, occur))) { + *p = repl_char; + p++; + slen -= skip; + memmove(p, (p + skip), slen - (p - s) + 1); /* includes null char too */ + } +} + +static int is_valid_index(struct json_object *jo, const char *path, int32_t *idx) +{ + int i, len = strlen(path); + /* this code-path optimizes a bit, for when we reference the 0-9 index range in a JSON array + and because leading zeros not allowed */ + if (len == 1) { + if (isdigit((int)path[0])) { + *idx = (path[0] - '0'); + goto check_oob; + } + errno = EINVAL; + return 0; + } + /* leading zeros not allowed per RFC */ + if (path[0] == '0') { + errno = EINVAL; + return 0; + } + /* RFC states base-10 decimals */ + for (i = 0; i < len; i++) { + if (!isdigit((int)path[i])) { + errno = EINVAL; + return 0; + } + } + + *idx = strtol(path, NULL, 10); + if (*idx < 0) { + errno = EINVAL; + return 0; + } +check_oob: + len = json_object_array_length(jo); + if (*idx >= len) { + errno = ENOENT; + return 0; + } + + return 1; +} + +static int json_pointer_get_single_path(struct json_object *obj, char *path, struct json_object **value) +{ + if (json_object_is_type(obj, json_type_array)) { + int32_t idx; + if (!is_valid_index(obj, path, &idx)) + return -1; + obj = json_object_array_get_idx(obj, idx); + if (obj) { + if (value) + *value = obj; + return 0; + } + /* Entry not found */ + errno = ENOENT; + return -1; + } + + /* RFC states that we first must eval all ~1 then all ~0 */ + string_replace_all_occurrences_with_char(path, "~1", '/'); + string_replace_all_occurrences_with_char(path, "~0", '~'); + + if (!json_object_object_get_ex(obj, path, value)) { + errno = ENOENT; + return -1; + } + + return 0; +} + +static int json_pointer_set_single_path( + struct json_object *parent, + const char *path, + struct json_object *value) +{ + if (json_object_is_type(parent, json_type_array)) { + int32_t idx; + /* RFC (Chapter 4) states that '-' may be used to add new elements to an array */ + if (path[0] == '-' && path[1] == '\0') + return json_object_array_add(parent, value); + if (!is_valid_index(parent, path, &idx)) + return -1; + return json_object_array_put_idx(parent, idx, value); + } + + /* path replacements should have been done in json_pointer_get_single_path(), + and we should still be good here */ + if (json_object_is_type(parent, json_type_object)) + return json_object_object_add(parent, path, value); + + /* Getting here means that we tried to "dereference" a primitive JSON type (like string, int, bool). + i.e. add a sub-object to it */ + errno = ENOENT; + return -1; +} + +static int json_pointer_get_recursive( + struct json_object *obj, + char *path, + struct json_object **value) +{ + char *endp; + int rc; + + /* All paths (on each recursion level must have a leading '/' */ + if (path[0] != '/') { + errno = EINVAL; + return -1; + } + path++; + + endp = strchr(path, '/'); + if (endp) + *endp = '\0'; + + /* If we err-ed here, return here */ + if ((rc = json_pointer_get_single_path(obj, path, &obj))) + return rc; + + if (endp) { + *endp = '/'; /* Put the slash back, so that the sanity check passes on next recursion level */ + return json_pointer_get_recursive(obj, endp, value); + } + + /* We should be at the end of the recursion here */ + if (value) + *value = obj; + + return 0; +} + +int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res) +{ + char *path_copy = NULL; + int rc; + + if (!obj || !path) { + errno = EINVAL; + return -1; + } + + if (path[0] == '\0') { + if (res) + *res = obj; + return 0; + } + + /* pass a working copy to the recursive call */ + if (!(path_copy = strdup(path))) { + errno = ENOMEM; + return -1; + } + rc = json_pointer_get_recursive(obj, path_copy, res); + free(path_copy); + + return rc; +} + +int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...) +{ + char *path_copy = NULL; + int rc = 0; + va_list args; + + if (!obj || !path_fmt) { + errno = EINVAL; + return -1; + } + + va_start(args, path_fmt); + rc = vasprintf(&path_copy, path_fmt, args); + va_end(args); + + if (rc < 0) + return rc; + + if (path_copy[0] == '\0') { + if (res) + *res = obj; + goto out; + } + + rc = json_pointer_get_recursive(obj, path_copy, res); +out: + free(path_copy); + + return rc; +} + +int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value) +{ + const char *endp; + char *path_copy = NULL; + struct json_object *set = NULL; + int rc; + + if (!obj || !path) { + errno = EINVAL; + return -1; + } + + if (path[0] == '\0') { + json_object_put(*obj); + *obj = value; + return 0; + } + + if (path[0] != '/') { + errno = EINVAL; + return -1; + } + + /* If there's only 1 level to set, stop here */ + if ((endp = strrchr(path, '/')) == path) { + path++; + return json_pointer_set_single_path(*obj, path, value); + } + + /* pass a working copy to the recursive call */ + if (!(path_copy = strdup(path))) { + errno = ENOMEM; + return -1; + } + path_copy[endp - path] = '\0'; + rc = json_pointer_get_recursive(*obj, path_copy, &set); + free(path_copy); + + if (rc) + return rc; + + endp++; + return json_pointer_set_single_path(set, endp, value); +} + +int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, ...) +{ + char *endp; + char *path_copy = NULL; + struct json_object *set = NULL; + va_list args; + int rc = 0; + + if (!obj || !path_fmt) { + errno = EINVAL; + return -1; + } + + /* pass a working copy to the recursive call */ + va_start(args, path_fmt); + rc = vasprintf(&path_copy, path_fmt, args); + va_end(args); + + if (rc < 0) + return rc; + + if (path_copy[0] == '\0') { + json_object_put(*obj); + *obj = value; + goto out; + } + + if (path_copy[0] != '/') { + errno = EINVAL; + rc = -1; + goto out; + } + + /* If there's only 1 level to set, stop here */ + if ((endp = strrchr(path_copy, '/')) == path_copy) { + set = *obj; + goto set_single_path; + } + + *endp = '\0'; + rc = json_pointer_get_recursive(*obj, path_copy, &set); + + if (rc) + goto out; + +set_single_path: + endp++; + rc = json_pointer_set_single_path(set, endp, value); +out: + free(path_copy); + return rc; +} + diff --git a/third_party/json-c/json_pointer.h b/third_party/json-c/json_pointer.h new file mode 100644 index 0000000000..b8746c0c97 --- /dev/null +++ b/third_party/json-c/json_pointer.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016 Alexadru Ardelean. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief JSON Pointer (RFC 6901) implementation for retrieving + * objects from a json-c object tree. + */ +#ifndef _json_pointer_h_ +#define _json_pointer_h_ + +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Retrieves a JSON sub-object from inside another JSON object + * using the JSON pointer notation as defined in RFC 6901 + * https://tools.ietf.org/html/rfc6901 + * + * The returned JSON sub-object is equivalent to parsing manually the + * 'obj' JSON tree ; i.e. it's not a new object that is created, but rather + * a pointer inside the JSON tree. + * + * Internally, this is equivalent to doing a series of 'json_object_object_get()' + * and 'json_object_array_get_idx()' along the given 'path'. + * + * Note that the 'path' string supports 'printf()' type arguments, so, whatever + * is added after the 'res' param will be treated as an argument for 'path' + * Example: json_pointer_get(obj, "/foo/%d/%s", &res, 0, bar) + * This means, that you need to escape '%' with '%%' (just like in printf()) + * + * @param obj the json_object instance/tree from where to retrieve sub-objects + * @param path a (RFC6901) string notation for the sub-object to retrieve + * @param res a pointer where to store a reference to the json_object + * associated with the given path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_get(struct json_object *obj, const char *path, struct json_object **res); + +/** + * This is a variant of 'json_pointer_get()' that supports printf() style arguments. + * + * Example: json_pointer_getf(obj, res, "/foo/%d/%s", 0, bak) + * This also means that you need to escape '%' with '%%' (just like in printf()) + * + * Please take into consideration all recommended 'printf()' format security + * aspects when using this function. + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param res a pointer where to store a reference to the json_object + * associated with the given path + * @param path_fmt a printf() style format for the path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_getf(struct json_object *obj, struct json_object **res, const char *path_fmt, ...); + +/** + * Sets JSON object 'value' in the 'obj' tree at the location specified + * by the 'path'. 'path' is JSON pointer notation as defined in RFC 6901 + * https://tools.ietf.org/html/rfc6901 + * + * Note that 'obj' is a double pointer, mostly for the "" (empty string) + * case, where the entire JSON object would be replaced by 'value'. + * In the case of the "" path, the object at '*obj' will have it's refcount + * decremented with 'json_object_put()' and the 'value' object will be assigned to it. + * + * For other cases (JSON sub-objects) ownership of 'value' will be transferred into + * '*obj' via 'json_object_object_add()' & 'json_object_array_put_idx()', so the + * only time the refcount should be decremented for 'value' is when the return value of + * 'json_pointer_set()' is negative (meaning the 'value' object did not get set into '*obj'). + * + * That also implies that 'json_pointer_set()' does not do any refcount incrementing. + * (Just that single decrement that was mentioned above). + * + * Note that the 'path' string supports 'printf()' type arguments, so, whatever + * is added after the 'value' param will be treated as an argument for 'path' + * Example: json_pointer_set(obj, "/foo/%d/%s", value, 0, bak) + * This means, that you need to escape '%' with '%%' (just like in printf()) + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param path a (RFC6901) string notation for the sub-object to set in the tree + * @param value object to set at path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_set(struct json_object **obj, const char *path, struct json_object *value); + +/** + * This is a variant of 'json_pointer_set()' that supports printf() style arguments. + * + * Example: json_pointer_setf(obj, value, "/foo/%d/%s", 0, bak) + * This also means that you need to escape '%' with '%%' (just like in printf()) + * + * Please take into consideration all recommended 'printf()' format security + * aspects when using this function. + * + * @param obj the json_object instance/tree to which to add a sub-object + * @param value object to set at path + * @param path_fmt a printf() style format for the path + * + * @return negative if an error (or not found), or 0 if succeeded + */ +int json_pointer_setf(struct json_object **obj, struct json_object *value, const char *path_fmt, ...); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/json_tokener.c b/third_party/json-c/json_tokener.c new file mode 100644 index 0000000000..449a82da6f --- /dev/null +++ b/third_party/json-c/json_tokener.c @@ -0,0 +1,997 @@ +/* + * $Id: json_tokener.c,v 1.20 2006/07/25 03:24:50 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + * + * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License + * (http://www.opensource.org/licenses/mit-license.php) + */ + +#include "config.h" + +#include +#include "math_compat.h" +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "printbuf.h" +#include "arraylist.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_object_private.h" +#include "json_tokener.h" +#include "json_util.h" +#include "strdup_compat.h" + +#ifdef HAVE_LOCALE_H +#include +#endif /* HAVE_LOCALE_H */ +#ifdef HAVE_XLOCALE_H +#include +#endif + +#define jt_hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) + +#if !HAVE_STRNCASECMP && defined(_MSC_VER) + /* MSC has the version as _strnicmp */ +# define strncasecmp _strnicmp +#elif !HAVE_STRNCASECMP +# error You do not have strncasecmp on your system. +#endif /* HAVE_STRNCASECMP */ + +/* Use C99 NAN by default; if not available, nan("") should work too. */ +#ifndef NAN +#define NAN nan("") +#endif /* !NAN */ + +static const char json_null_str[] = "null"; +static const int json_null_str_len = sizeof(json_null_str) - 1; +static const char json_inf_str[] = "Infinity"; +static const char json_inf_str_lower[] = "infinity"; +static const unsigned int json_inf_str_len = sizeof(json_inf_str) - 1; +static const char json_nan_str[] = "NaN"; +static const int json_nan_str_len = sizeof(json_nan_str) - 1; +static const char json_true_str[] = "true"; +static const int json_true_str_len = sizeof(json_true_str) - 1; +static const char json_false_str[] = "false"; +static const int json_false_str_len = sizeof(json_false_str) - 1; + +static const char* json_tokener_errors[] = { + "success", + "continue", + "nesting too deep", + "unexpected end of data", + "unexpected character", + "null expected", + "boolean expected", + "number expected", + "array value separator ',' expected", + "quoted object property name expected", + "object property name separator ':' expected", + "object value separator ',' expected", + "invalid string sequence", + "expected comment", + "buffer size overflow" +}; + +const char *json_tokener_error_desc(enum json_tokener_error jerr) +{ + int jerr_int = (int) jerr; + if (jerr_int < 0 || + jerr_int >= (int)(sizeof(json_tokener_errors) / sizeof(json_tokener_errors[0]))) + return "Unknown error, " + "invalid json_tokener_error value passed to json_tokener_error_desc()"; + return json_tokener_errors[jerr]; +} + +enum json_tokener_error json_tokener_get_error(struct json_tokener *tok) +{ + return tok->err; +} + +/* Stuff for decoding unicode sequences */ +#define IS_HIGH_SURROGATE(uc) (((uc) & 0xFC00) == 0xD800) +#define IS_LOW_SURROGATE(uc) (((uc) & 0xFC00) == 0xDC00) +#define DECODE_SURROGATE_PAIR(hi,lo) ((((hi) & 0x3FF) << 10) + ((lo) & 0x3FF) + 0x10000) +static unsigned char utf8_replacement_char[3] = { 0xEF, 0xBF, 0xBD }; + +struct json_tokener* json_tokener_new_ex(int depth) +{ + struct json_tokener *tok; + + tok = (struct json_tokener*)calloc(1, sizeof(struct json_tokener)); + if (!tok) return NULL; + tok->stack = (struct json_tokener_srec *) calloc(depth, + sizeof(struct json_tokener_srec)); + if (!tok->stack) { + free(tok); + return NULL; + } + tok->pb = printbuf_new(); + tok->max_depth = depth; + json_tokener_reset(tok); + return tok; +} + +struct json_tokener* json_tokener_new(void) +{ + return json_tokener_new_ex(JSON_TOKENER_DEFAULT_DEPTH); +} + +void json_tokener_free(struct json_tokener *tok) +{ + json_tokener_reset(tok); + if (tok->pb) printbuf_free(tok->pb); + free(tok->stack); + free(tok); +} + +static void json_tokener_reset_level(struct json_tokener *tok, int depth) +{ + tok->stack[depth].state = json_tokener_state_eatws; + tok->stack[depth].saved_state = json_tokener_state_start; + json_object_put(tok->stack[depth].current); + tok->stack[depth].current = NULL; + free(tok->stack[depth].obj_field_name); + tok->stack[depth].obj_field_name = NULL; +} + +void json_tokener_reset(struct json_tokener *tok) +{ + int i; + if (!tok) + return; + + for(i = tok->depth; i >= 0; i--) + json_tokener_reset_level(tok, i); + tok->depth = 0; + tok->err = json_tokener_success; +} + +struct json_object* json_tokener_parse(const char *str) +{ + enum json_tokener_error jerr_ignored; + struct json_object* obj; + obj = json_tokener_parse_verbose(str, &jerr_ignored); + return obj; +} + +struct json_object* json_tokener_parse_verbose(const char *str, + enum json_tokener_error *error) +{ + struct json_tokener* tok; + struct json_object* obj; + + tok = json_tokener_new(); + if (!tok) + return NULL; + obj = json_tokener_parse_ex(tok, str, -1); + *error = tok->err; + if(tok->err != json_tokener_success) { + if (obj != NULL) + json_object_put(obj); + obj = NULL; + } + + json_tokener_free(tok); + return obj; +} + +#define state tok->stack[tok->depth].state +#define saved_state tok->stack[tok->depth].saved_state +#define current tok->stack[tok->depth].current +#define obj_field_name tok->stack[tok->depth].obj_field_name + +/* Optimization: + * json_tokener_parse_ex() consumed a lot of CPU in its main loop, + * iterating character-by character. A large performance boost is + * achieved by using tighter loops to locally handle units such as + * comments and strings. Loops that handle an entire token within + * their scope also gather entire strings and pass them to + * printbuf_memappend() in a single call, rather than calling + * printbuf_memappend() one char at a time. + * + * PEEK_CHAR() and ADVANCE_CHAR() macros are used for code that is + * common to both the main loop and the tighter loops. + */ + +/* PEEK_CHAR(dest, tok) macro: + * Peeks at the current char and stores it in dest. + * Returns 1 on success, sets tok->err and returns 0 if no more chars. + * Implicit inputs: str, len vars + */ +#define PEEK_CHAR(dest, tok) \ + (((tok)->char_offset == len) ? \ + (((tok)->depth == 0 && \ + state == json_tokener_state_eatws && \ + saved_state == json_tokener_state_finish \ + ) ? \ + (((tok)->err = json_tokener_success), 0) \ + : \ + (((tok)->err = json_tokener_continue), 0) \ + ) : \ + (((dest) = *str), 1) \ + ) + +/* ADVANCE_CHAR() macro: + * Incrementes str & tok->char_offset. + * For convenience of existing conditionals, returns the old value of c (0 on eof) + * Implicit inputs: c var + */ +#define ADVANCE_CHAR(str, tok) \ + ( ++(str), ((tok)->char_offset)++, c) + + +/* End optimization macro defs */ + + +struct json_object* json_tokener_parse_ex(struct json_tokener *tok, + const char *str, int len) +{ + struct json_object *obj = NULL; + char c = '\1'; +#ifdef HAVE_USELOCALE + locale_t oldlocale = uselocale(NULL); + locale_t newloc; +#elif defined(HAVE_SETLOCALE) + char *oldlocale = NULL; +#endif + + tok->char_offset = 0; + tok->err = json_tokener_success; + + /* this interface is presently not 64-bit clean due to the int len argument + and the internal printbuf interface that takes 32-bit int len arguments + so the function limits the maximum string size to INT32_MAX (2GB). + If the function is called with len == -1 then strlen is called to check + the string length is less than INT32_MAX (2GB) */ + if ((len < -1) || (len == -1 && strlen(str) > INT32_MAX)) { + tok->err = json_tokener_error_size; + return NULL; + } + +#ifdef HAVE_USELOCALE + { + locale_t duploc = duplocale(oldlocale); + newloc = newlocale(LC_NUMERIC, "C", duploc); + // XXX at least Debian 8.4 has a bug in newlocale where it doesn't + // change the decimal separator unless you set LC_TIME! + if (newloc) + { + duploc = newloc; // original duploc has been freed by newlocale() + newloc = newlocale(LC_TIME, "C", duploc); + } + if (newloc == NULL) + { + freelocale(duploc); + return NULL; + } + uselocale(newloc); + } +#elif defined(HAVE_SETLOCALE) + { + char *tmplocale; + tmplocale = setlocale(LC_NUMERIC, NULL); + if (tmplocale) oldlocale = strdup(tmplocale); + setlocale(LC_NUMERIC, "C"); + } +#endif + + while (PEEK_CHAR(c, tok)) { + + redo_char: + switch(state) { + + case json_tokener_state_eatws: + /* Advance until we change state */ + while (isspace((int)c)) { + if ((!ADVANCE_CHAR(str, tok)) || (!PEEK_CHAR(c, tok))) + goto out; + } + if(c == '/' && !(tok->flags & JSON_TOKENER_STRICT)) { + printbuf_reset(tok->pb); + printbuf_memappend_fast(tok->pb, &c, 1); + state = json_tokener_state_comment_start; + } else { + state = saved_state; + goto redo_char; + } + break; + + case json_tokener_state_start: + switch(c) { + case '{': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_object_field_start; + current = json_object_new_object(); + if(current == NULL) + goto out; + break; + case '[': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_array; + current = json_object_new_array(); + if(current == NULL) + goto out; + break; + case 'I': + case 'i': + state = json_tokener_state_inf; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; + case 'N': + case 'n': + state = json_tokener_state_null; // or NaN + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; + case '\'': + if (tok->flags & JSON_TOKENER_STRICT) { + /* in STRICT mode only double-quote are allowed */ + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + /* FALLTHRU */ + case '"': + state = json_tokener_state_string; + printbuf_reset(tok->pb); + tok->quote_char = c; + break; + case 'T': + case 't': + case 'F': + case 'f': + state = json_tokener_state_boolean; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + state = json_tokener_state_number; + printbuf_reset(tok->pb); + tok->is_double = 0; + goto redo_char; + default: + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + break; + + case json_tokener_state_finish: + if(tok->depth == 0) goto out; + obj = json_object_get(current); + json_tokener_reset_level(tok, tok->depth); + tok->depth--; + goto redo_char; + + case json_tokener_state_inf: /* aka starts with 'i' (or 'I', or "-i", or "-I") */ + { + /* If we were guaranteed to have len set, then we could (usually) handle + * the entire "Infinity" check in a single strncmp (strncasecmp), but + * since len might be -1 (i.e. "read until \0"), we need to check it + * a character at a time. + * Trying to handle it both ways would make this code considerably more + * complicated with likely little performance benefit. + */ + int is_negative = 0; + const char *_json_inf_str = json_inf_str; + if (!(tok->flags & JSON_TOKENER_STRICT)) + _json_inf_str = json_inf_str_lower; + + /* Note: tok->st_pos must be 0 when state is set to json_tokener_state_inf */ + while (tok->st_pos < (int)json_inf_str_len) + { + char inf_char = *str; + if (!(tok->flags & JSON_TOKENER_STRICT)) + inf_char = tolower((int)*str); + if (inf_char != _json_inf_str[tok->st_pos]) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + tok->st_pos++; + (void)ADVANCE_CHAR(str, tok); + if (!PEEK_CHAR(c, tok)) + { + /* out of input chars, for now at least */ + goto out; + } + } + /* We checked the full length of "Infinity", so create the object. + * When handling -Infinity, the number parsing code will have dropped + * the "-" into tok->pb for us, so check it now. + */ + if (printbuf_length(tok->pb) > 0 && *(tok->pb->buf) == '-') + { + is_negative = 1; + } + current = json_object_new_double(is_negative + ? -INFINITY : INFINITY); + if (current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + + } + break; + case json_tokener_state_null: /* aka starts with 'n' */ + { + int size; + int size_nan; + printbuf_memappend_fast(tok->pb, &c, 1); + size = json_min(tok->st_pos+1, json_null_str_len); + size_nan = json_min(tok->st_pos+1, json_nan_str_len); + if((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_null_str, tok->pb->buf, size) == 0) + || (strncmp(json_null_str, tok->pb->buf, size) == 0) + ) { + if (tok->st_pos == json_null_str_len) { + current = NULL; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } + else if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_nan_str, tok->pb->buf, size_nan) == 0) || + (strncmp(json_nan_str, tok->pb->buf, size_nan) == 0) + ) + { + if (tok->st_pos == json_nan_str_len) + { + current = json_object_new_double(NAN); + if (current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else { + tok->err = json_tokener_error_parse_null; + goto out; + } + tok->st_pos++; + } + break; + + case json_tokener_state_comment_start: + if(c == '*') { + state = json_tokener_state_comment; + } else if(c == '/') { + state = json_tokener_state_comment_eol; + } else { + tok->err = json_tokener_error_parse_comment; + goto out; + } + printbuf_memappend_fast(tok->pb, &c, 1); + break; + + case json_tokener_state_comment: + { + /* Advance until we change state */ + const char *case_start = str; + while(c != '*') { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + goto out; + } + } + printbuf_memappend_fast(tok->pb, case_start, 1+str-case_start); + state = json_tokener_state_comment_end; + } + break; + + case json_tokener_state_comment_eol: + { + /* Advance until we change state */ + const char *case_start = str; + while(c != '\n') { + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + goto out; + } + } + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); + state = json_tokener_state_eatws; + } + break; + + case json_tokener_state_comment_end: + printbuf_memappend_fast(tok->pb, &c, 1); + if(c == '/') { + MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf); + state = json_tokener_state_eatws; + } else { + state = json_tokener_state_comment; + } + break; + + case json_tokener_state_string: + { + /* Advance until we change state */ + const char *case_start = str; + while(1) { + if(c == tok->quote_char) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos); + if(current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + break; + } else if(c == '\\') { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + saved_state = json_tokener_state_string; + state = json_tokener_state_string_escape; + break; + } + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + goto out; + } + } + } + break; + + case json_tokener_state_string_escape: + switch(c) { + case '"': + case '\\': + case '/': + printbuf_memappend_fast(tok->pb, &c, 1); + state = saved_state; + break; + case 'b': + case 'n': + case 'r': + case 't': + case 'f': + if(c == 'b') printbuf_memappend_fast(tok->pb, "\b", 1); + else if(c == 'n') printbuf_memappend_fast(tok->pb, "\n", 1); + else if(c == 'r') printbuf_memappend_fast(tok->pb, "\r", 1); + else if(c == 't') printbuf_memappend_fast(tok->pb, "\t", 1); + else if(c == 'f') printbuf_memappend_fast(tok->pb, "\f", 1); + state = saved_state; + break; + case 'u': + tok->ucs_char = 0; + tok->st_pos = 0; + state = json_tokener_state_escape_unicode; + break; + default: + tok->err = json_tokener_error_parse_string; + goto out; + } + break; + + case json_tokener_state_escape_unicode: + { + unsigned int got_hi_surrogate = 0; + + /* Handle a 4-byte sequence, or two sequences if a surrogate pair */ + while(1) { + if (c && strchr(json_hex_chars, c)) { + tok->ucs_char += ((unsigned int)jt_hexdigit(c) << ((3-tok->st_pos++)*4)); + if(tok->st_pos == 4) { + unsigned char unescaped_utf[4]; + + if (got_hi_surrogate) { + if (IS_LOW_SURROGATE(tok->ucs_char)) { + /* Recalculate the ucs_char, then fall thru to process normally */ + tok->ucs_char = DECODE_SURROGATE_PAIR(got_hi_surrogate, tok->ucs_char); + } else { + /* Hi surrogate was not followed by a low surrogate */ + /* Replace the hi and process the rest normally */ + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + } + got_hi_surrogate = 0; + } + + if (tok->ucs_char < 0x80) { + unescaped_utf[0] = tok->ucs_char; + printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 1); + } else if (tok->ucs_char < 0x800) { + unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6); + unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 2); + } else if (IS_HIGH_SURROGATE(tok->ucs_char)) { + /* Got a high surrogate. Remember it and look for the + * the beginning of another sequence, which should be the + * low surrogate. + */ + got_hi_surrogate = tok->ucs_char; + /* Not at end, and the next two chars should be "\u" */ + if ((len == -1 || len > (tok->char_offset + 2)) && + // str[0] != '0' && // implied by json_hex_chars, above. + (str[1] == '\\') && + (str[2] == 'u')) + { + /* Advance through the 16 bit surrogate, and move on to the + * next sequence. The next step is to process the following + * characters. + */ + if( !ADVANCE_CHAR(str, tok) || !ADVANCE_CHAR(str, tok) ) { + printbuf_memappend_fast(tok->pb, + (char*) utf8_replacement_char, 3); + } + /* Advance to the first char of the next sequence and + * continue processing with the next sequence. + */ + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, + (char*) utf8_replacement_char, 3); + goto out; + } + tok->ucs_char = 0; + tok->st_pos = 0; + continue; /* other json_tokener_state_escape_unicode */ + } else { + /* Got a high surrogate without another sequence following + * it. Put a replacement char in for the hi surrogate + * and pretend we finished. + */ + printbuf_memappend_fast(tok->pb, + (char*) utf8_replacement_char, 3); + } + } else if (IS_LOW_SURROGATE(tok->ucs_char)) { + /* Got a low surrogate not preceded by a high */ + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + } else if (tok->ucs_char < 0x10000) { + unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12); + unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 3); + } else if (tok->ucs_char < 0x110000) { + unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07); + unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f); + unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char*)unescaped_utf, 4); + } else { + /* Don't know what we got--insert the replacement char */ + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + } + state = saved_state; + break; + } + } else { + tok->err = json_tokener_error_parse_string; + goto out; + } + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + if (got_hi_surrogate) /* Clean up any pending chars */ + printbuf_memappend_fast(tok->pb, (char*)utf8_replacement_char, 3); + goto out; + } + } + } + break; + + case json_tokener_state_boolean: + { + int size1, size2; + printbuf_memappend_fast(tok->pb, &c, 1); + size1 = json_min(tok->st_pos+1, json_true_str_len); + size2 = json_min(tok->st_pos+1, json_false_str_len); + if((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_true_str, tok->pb->buf, size1) == 0) + || (strncmp(json_true_str, tok->pb->buf, size1) == 0) + ) { + if(tok->st_pos == json_true_str_len) { + current = json_object_new_boolean(1); + if(current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else if((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_false_str, tok->pb->buf, size2) == 0) + || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) { + if(tok->st_pos == json_false_str_len) { + current = json_object_new_boolean(0); + if(current == NULL) + goto out; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else { + tok->err = json_tokener_error_parse_boolean; + goto out; + } + tok->st_pos++; + } + break; + + case json_tokener_state_number: + { + /* Advance until we change state */ + const char *case_start = str; + int case_len=0; + int is_exponent=0; + int negativesign_next_possible_location=1; + while(c && strchr(json_number_chars, c)) { + ++case_len; + + /* non-digit characters checks */ + /* note: since the main loop condition to get here was + an input starting with 0-9 or '-', we are + protected from input starting with '.' or + e/E. */ + if (c == '.') { + if (tok->is_double != 0) { + /* '.' can only be found once, and out of the exponent part. + Thus, if the input is already flagged as double, it + is invalid. */ + tok->err = json_tokener_error_parse_number; + goto out; + } + tok->is_double = 1; + } + if (c == 'e' || c == 'E') { + if (is_exponent != 0) { + /* only one exponent possible */ + tok->err = json_tokener_error_parse_number; + goto out; + } + is_exponent = 1; + tok->is_double = 1; + /* the exponent part can begin with a negative sign */ + negativesign_next_possible_location = case_len + 1; + } + if (c == '-' && case_len != negativesign_next_possible_location) { + /* If the negative sign is not where expected (ie + start of input or start of exponent part), the + input is invalid. */ + tok->err = json_tokener_error_parse_number; + goto out; + } + + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, case_len); + goto out; + } + } + if (case_len>0) + printbuf_memappend_fast(tok->pb, case_start, case_len); + + // Check for -Infinity + if (tok->pb->buf[0] == '-' && case_len <= 1 && + (c == 'i' || c == 'I')) + { + state = json_tokener_state_inf; + tok->st_pos = 0; + goto redo_char; + } + } + { + int64_t num64; + double numd; + if (!tok->is_double && json_parse_int64(tok->pb->buf, &num64) == 0) { + if (num64 && tok->pb->buf[0]=='0' && + (tok->flags & JSON_TOKENER_STRICT)) { + /* in strict mode, number must not start with 0 */ + tok->err = json_tokener_error_parse_number; + goto out; + } + current = json_object_new_int64(num64); + if(current == NULL) + goto out; + } + else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) + { + current = json_object_new_double_s(numd, tok->pb->buf); + if(current == NULL) + goto out; + } else { + tok->err = json_tokener_error_parse_number; + goto out; + } + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + break; + + case json_tokener_state_array_after_sep: + case json_tokener_state_array: + if(c == ']') { + if (state == json_tokener_state_array_after_sep && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + if(tok->depth >= tok->max_depth-1) { + tok->err = json_tokener_error_depth; + goto out; + } + state = json_tokener_state_array_add; + tok->depth++; + json_tokener_reset_level(tok, tok->depth); + goto redo_char; + } + break; + + case json_tokener_state_array_add: + if( json_object_array_add(current, obj) != 0 ) + goto out; + saved_state = json_tokener_state_array_sep; + state = json_tokener_state_eatws; + goto redo_char; + + case json_tokener_state_array_sep: + if(c == ']') { + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == ',') { + saved_state = json_tokener_state_array_after_sep; + state = json_tokener_state_eatws; + } else { + tok->err = json_tokener_error_parse_array; + goto out; + } + break; + + case json_tokener_state_object_field_start: + case json_tokener_state_object_field_start_after_sep: + if(c == '}') { + if (state == json_tokener_state_object_field_start_after_sep && + (tok->flags & JSON_TOKENER_STRICT)) + { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if (c == '"' || c == '\'') { + tok->quote_char = c; + printbuf_reset(tok->pb); + state = json_tokener_state_object_field; + } else { + tok->err = json_tokener_error_parse_object_key_name; + goto out; + } + break; + + case json_tokener_state_object_field: + { + /* Advance until we change state */ + const char *case_start = str; + while(1) { + if(c == tok->quote_char) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + obj_field_name = strdup(tok->pb->buf); + saved_state = json_tokener_state_object_field_end; + state = json_tokener_state_eatws; + break; + } else if(c == '\\') { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + saved_state = json_tokener_state_object_field; + state = json_tokener_state_string_escape; + break; + } + if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { + printbuf_memappend_fast(tok->pb, case_start, str-case_start); + goto out; + } + } + } + break; + + case json_tokener_state_object_field_end: + if(c == ':') { + saved_state = json_tokener_state_object_value; + state = json_tokener_state_eatws; + } else { + tok->err = json_tokener_error_parse_object_key_sep; + goto out; + } + break; + + case json_tokener_state_object_value: + if(tok->depth >= tok->max_depth-1) { + tok->err = json_tokener_error_depth; + goto out; + } + state = json_tokener_state_object_value_add; + tok->depth++; + json_tokener_reset_level(tok, tok->depth); + goto redo_char; + + case json_tokener_state_object_value_add: + json_object_object_add(current, obj_field_name, obj); + free(obj_field_name); + obj_field_name = NULL; + saved_state = json_tokener_state_object_sep; + state = json_tokener_state_eatws; + goto redo_char; + + case json_tokener_state_object_sep: + /* { */ + if(c == '}') { + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == ',') { + saved_state = json_tokener_state_object_field_start_after_sep; + state = json_tokener_state_eatws; + } else { + tok->err = json_tokener_error_parse_object_value_sep; + goto out; + } + break; + + } + if (!ADVANCE_CHAR(str, tok)) + goto out; + } /* while(PEEK_CHAR) */ + + out: + if (c && + (state == json_tokener_state_finish) && + (tok->depth == 0) && + (tok->flags & JSON_TOKENER_STRICT)) { + /* unexpected char after JSON data */ + tok->err = json_tokener_error_parse_unexpected; + } + if (!c) { /* We hit an eof char (0) */ + if(state != json_tokener_state_finish && + saved_state != json_tokener_state_finish) + tok->err = json_tokener_error_parse_eof; + } + +#ifdef HAVE_USELOCALE + uselocale(oldlocale); + freelocale(newloc); +#elif defined(HAVE_SETLOCALE) + setlocale(LC_NUMERIC, oldlocale); + free(oldlocale); +#endif + + if (tok->err == json_tokener_success) + { + json_object *ret = json_object_get(current); + int ii; + + /* Partially reset, so we parse additional objects on subsequent calls. */ + for(ii = tok->depth; ii >= 0; ii--) + json_tokener_reset_level(tok, ii); + return ret; + } + + MC_DEBUG("json_tokener_parse_ex: error %s at offset %d\n", + json_tokener_errors[tok->err], tok->char_offset); + return NULL; +} + +void json_tokener_set_flags(struct json_tokener *tok, int flags) +{ + tok->flags = flags; +} diff --git a/third_party/json-c/json_tokener.h b/third_party/json-c/json_tokener.h new file mode 100644 index 0000000000..ed272b673d --- /dev/null +++ b/third_party/json-c/json_tokener.h @@ -0,0 +1,216 @@ +/* + * $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Methods to parse an input string into a tree of json_object objects. + */ +#ifndef _json_tokener_h_ +#define _json_tokener_h_ + +#include +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum json_tokener_error { + json_tokener_success, + json_tokener_continue, + json_tokener_error_depth, + json_tokener_error_parse_eof, + json_tokener_error_parse_unexpected, + json_tokener_error_parse_null, + json_tokener_error_parse_boolean, + json_tokener_error_parse_number, + json_tokener_error_parse_array, + json_tokener_error_parse_object_key_name, + json_tokener_error_parse_object_key_sep, + json_tokener_error_parse_object_value_sep, + json_tokener_error_parse_string, + json_tokener_error_parse_comment, + json_tokener_error_size +}; + +enum json_tokener_state { + json_tokener_state_eatws, + json_tokener_state_start, + json_tokener_state_finish, + json_tokener_state_null, + json_tokener_state_comment_start, + json_tokener_state_comment, + json_tokener_state_comment_eol, + json_tokener_state_comment_end, + json_tokener_state_string, + json_tokener_state_string_escape, + json_tokener_state_escape_unicode, + json_tokener_state_boolean, + json_tokener_state_number, + json_tokener_state_array, + json_tokener_state_array_add, + json_tokener_state_array_sep, + json_tokener_state_object_field_start, + json_tokener_state_object_field, + json_tokener_state_object_field_end, + json_tokener_state_object_value, + json_tokener_state_object_value_add, + json_tokener_state_object_sep, + json_tokener_state_array_after_sep, + json_tokener_state_object_field_start_after_sep, + json_tokener_state_inf +}; + +struct json_tokener_srec +{ + enum json_tokener_state state, saved_state; + struct json_object *obj; + struct json_object *current; + char *obj_field_name; +}; + +#define JSON_TOKENER_DEFAULT_DEPTH 32 + +struct json_tokener +{ + char *str; + struct printbuf *pb; + int max_depth, depth, is_double, st_pos, char_offset; + enum json_tokener_error err; + unsigned int ucs_char; + char quote_char; + struct json_tokener_srec *stack; + int flags; +}; +/** + * @deprecated Unused in json-c code + */ +typedef struct json_tokener json_tokener; + +/** + * Be strict when parsing JSON input. Use caution with + * this flag as what is considered valid may become more + * restrictive from one release to the next, causing your + * code to fail on previously working input. + * + * This flag is not set by default. + * + * @see json_tokener_set_flags() + */ +#define JSON_TOKENER_STRICT 0x01 + +/** + * Given an error previously returned by json_tokener_get_error(), + * return a human readable description of the error. + * + * @return a generic error message is returned if an invalid error value is provided. + */ +const char *json_tokener_error_desc(enum json_tokener_error jerr); + +/** + * Retrieve the error caused by the last call to json_tokener_parse_ex(), + * or json_tokener_success if there is no error. + * + * When parsing a JSON string in pieces, if the tokener is in the middle + * of parsing this will return json_tokener_continue. + * + * See also json_tokener_error_desc(). + */ +JSON_EXPORT enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); + +JSON_EXPORT struct json_tokener* json_tokener_new(void); +JSON_EXPORT struct json_tokener* json_tokener_new_ex(int depth); +JSON_EXPORT void json_tokener_free(struct json_tokener *tok); +JSON_EXPORT void json_tokener_reset(struct json_tokener *tok); +JSON_EXPORT struct json_object* json_tokener_parse(const char *str); +JSON_EXPORT struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); + +/** + * Set flags that control how parsing will be done. + */ +JSON_EXPORT void json_tokener_set_flags(struct json_tokener *tok, int flags); + +/** + * Parse a string and return a non-NULL json_object if a valid JSON value + * is found. The string does not need to be a JSON object or array; + * it can also be a string, number or boolean value. + * + * A partial JSON string can be parsed. If the parsing is incomplete, + * NULL will be returned and json_tokener_get_error() will return + * json_tokener_continue. + * json_tokener_parse_ex() can then be called with additional bytes in str + * to continue the parsing. + * + * If json_tokener_parse_ex() returns NULL and the error is anything other than + * json_tokener_continue, a fatal error has occurred and parsing must be + * halted. Then, the tok object must not be reused until json_tokener_reset() is + * called. + * + * When a valid JSON value is parsed, a non-NULL json_object will be + * returned. Also, json_tokener_get_error() will return json_tokener_success. + * Be sure to check the type with json_object_is_type() or + * json_object_get_type() before using the object. + * + * @b XXX this shouldn't use internal fields: + * Trailing characters after the parsed value do not automatically cause an + * error. It is up to the caller to decide whether to treat this as an + * error or to handle the additional characters, perhaps by parsing another + * json value starting from that point. + * + * Extra characters can be detected by comparing the tok->char_offset against + * the length of the last len parameter passed in. + * + * The tokener does \b not maintain an internal buffer so the caller is + * responsible for calling json_tokener_parse_ex with an appropriate str + * parameter starting with the extra characters. + * + * This interface is presently not 64-bit clean due to the int len argument + * so the function limits the maximum string size to INT32_MAX (2GB). + * If the function is called with len == -1 then strlen is called to check + * the string length is less than INT32_MAX (2GB) + * + * Example: + * @code +json_object *jobj = NULL; +const char *mystring = NULL; +int stringlen = 0; +enum json_tokener_error jerr; +do { + mystring = ... // get JSON string, e.g. read from file, etc... + stringlen = strlen(mystring); + jobj = json_tokener_parse_ex(tok, mystring, stringlen); +} while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue); +if (jerr != json_tokener_success) +{ + fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr)); + // Handle errors, as appropriate for your application. +} +if (tok->char_offset < stringlen) // XXX shouldn't access internal fields +{ + // Handle extra characters after parsed object as desired. + // e.g. issue an error, parse another object from that point, etc... +} +// Success, use jobj here. + +@endcode + * + * @param tok a json_tokener previously allocated with json_tokener_new() + * @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated. + * @param len the length of str + */ +JSON_EXPORT struct json_object* json_tokener_parse_ex(struct json_tokener *tok, + const char *str, int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/json_util.c b/third_party/json-c/json_util.c new file mode 100644 index 0000000000..ad7704a945 --- /dev/null +++ b/third_party/json-c/json_util.c @@ -0,0 +1,243 @@ +/* + * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" +#undef realloc + +#include "strerror_override.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif /* HAVE_SYS_TYPES_H */ + +#ifdef HAVE_SYS_STAT_H +#include +#endif /* HAVE_SYS_STAT_H */ + +#ifdef HAVE_FCNTL_H +#include +#endif /* HAVE_FCNTL_H */ + +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ + +#ifdef WIN32 +# if MSC_VER < 1800 +/* strtoll is available only since Visual Studio 2013 */ +# define strtoll _strtoi64 +# endif +# define WIN32_LEAN_AND_MEAN +# include +# include +#endif /* defined(WIN32) */ + +#if !defined(HAVE_OPEN) && defined(WIN32) +# define open _open +#endif + +#include "snprintf_compat.h" + +#include "debug.h" +#include "printbuf.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_tokener.h" +#include "json_util.h" + +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename); + +static char _last_err[256] = ""; + +const char *json_util_get_last_err() +{ + if (_last_err[0] == '\0') + return NULL; + return _last_err; +} + +void _json_c_set_last_err(const char *err_fmt, ...) +{ + va_list ap; + va_start(ap, err_fmt); + // Ignore (attempted) overruns from snprintf + (void)vsnprintf(_last_err, sizeof(_last_err), err_fmt, ap); + va_end(ap); +} + +struct json_object* json_object_from_fd(int fd) +{ + struct printbuf *pb; + struct json_object *obj; + char buf[JSON_FILE_BUF_SIZE]; + int ret; + + if(!(pb = printbuf_new())) { + _json_c_set_last_err("json_object_from_file: printbuf_new failed\n"); + return NULL; + } + while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { + printbuf_memappend(pb, buf, ret); + } + if(ret < 0) { + _json_c_set_last_err("json_object_from_fd: error reading fd %d: %s\n", fd, strerror(errno)); + printbuf_free(pb); + return NULL; + } + obj = json_tokener_parse(pb->buf); + printbuf_free(pb); + return obj; +} + +struct json_object* json_object_from_file(const char *filename) +{ + struct json_object *obj; + int fd; + + if((fd = open(filename, O_RDONLY)) < 0) { + _json_c_set_last_err("json_object_from_file: error opening file %s: %s\n", + filename, strerror(errno)); + return NULL; + } + obj = json_object_from_fd(fd); + close(fd); + return obj; +} + +/* extended "format and write to file" function */ + +int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags) +{ + int fd, ret; + int saved_errno; + + if (!obj) { + _json_c_set_last_err("json_object_to_file: object is null\n"); + return -1; + } + + if ((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { + _json_c_set_last_err("json_object_to_file: error opening file %s: %s\n", + filename, strerror(errno)); + return -1; + } + ret = _json_object_to_fd(fd, obj, flags, filename); + saved_errno = errno; + close(fd); + errno = saved_errno; + return ret; +} + +int json_object_to_fd(int fd, struct json_object *obj, int flags) +{ + if (!obj) { + _json_c_set_last_err("json_object_to_fd: object is null\n"); + return -1; + } + + return _json_object_to_fd(fd, obj, flags, NULL); +} +static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename) +{ + int ret; + const char *json_str; + unsigned int wpos, wsize; + + filename = filename ? filename : "(fd)"; + + if (!(json_str = json_object_to_json_string_ext(obj,flags))) { + return -1; + } + + wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ + wpos = 0; + while(wpos < wsize) { + if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { + _json_c_set_last_err("json_object_to_file: error writing file %s: %s\n", + filename, strerror(errno)); + return -1; + } + + /* because of the above check for ret < 0, we can safely cast and add */ + wpos += (unsigned int)ret; + } + + return 0; +} + +// backwards compatible "format and write to file" function + +int json_object_to_file(const char *filename, struct json_object *obj) +{ + return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); +} + +int json_parse_double(const char *buf, double *retval) +{ + char *end; + *retval = strtod(buf, &end); + return end == buf ? 1 : 0; +} + +int json_parse_int64(const char *buf, int64_t *retval) +{ + char *end = NULL; + int64_t val; + + errno = 0; + val = strtoll(buf, &end, 10); + if (end != buf) + *retval = val; + return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0; +} + +#ifndef HAVE_REALLOC +void* rpl_realloc(void* p, size_t n) +{ + if (n == 0) + n = 1; + if (p == 0) + return malloc(n); + return realloc(p, n); +} +#endif + +#define NELEM(a) (sizeof(a) / sizeof(a[0])) +static const char* json_type_name[] = { + /* If you change this, be sure to update the enum json_type definition too */ + "null", + "boolean", + "double", + "int", + "object", + "array", + "string", +}; + +const char *json_type_to_name(enum json_type o_type) +{ + int o_type_int = (int)o_type; + if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name)) + { + _json_c_set_last_err("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name)); + return NULL; + } + return json_type_name[o_type]; +} + diff --git a/third_party/json-c/json_util.h b/third_party/json-c/json_util.h new file mode 100644 index 0000000000..e065f60c66 --- /dev/null +++ b/third_party/json-c/json_util.h @@ -0,0 +1,106 @@ +/* + * $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Miscllaneous utility functions and macros. + */ +#ifndef _json_util_h_ +#define _json_util_h_ + +#include "json_object.h" + +#ifndef json_min +#define json_min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef json_max +#define json_max(a,b) ((a) > (b) ? (a) : (b)) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#define JSON_FILE_BUF_SIZE 4096 + +/* utility functions */ +/** + * Read the full contents of the given file, then convert it to a + * json_object using json_tokener_parse(). + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +extern struct json_object* json_object_from_file(const char *filename); + +/** + * Create a JSON object from already opened file descriptor. + * + * This function can be helpful, when you opened the file already, + * e.g. when you have a temp file. + * Note, that the fd must be readable at the actual position, i.e. + * use lseek(fd, 0, SEEK_SET) before. + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +extern struct json_object* json_object_from_fd(int fd); + +/** + * Equivalent to: + * json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +extern int json_object_to_file(const char *filename, struct json_object *obj); + +/** + * Open and truncate the given file, creating it if necessary, then + * convert the json_object to a string and write it to the file. + * + * Returns -1 if something fails. See json_util_get_last_err() for details. + */ +extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); + +/** + * Convert the json_object to a string and write it to the file descriptor. + * Handles partial writes and will keep writing until done, or an error + * occurs. + * + * @param fd an open, writable file descriptor to write to + * @param obj the object to serializer and write + * @param flags flags to pass to json_object_to_json_string_ext() + * @return -1 if something fails. See json_util_get_last_err() for details. + */ +extern int json_object_to_fd(int fd, struct json_object *obj, int flags); + +/** + * Return the last error from various json-c functions, including: + * json_object_to_file{,_ext}, json_object_to_fd() or + * json_object_from_{file,fd}, or NULL if there is none. + */ +const char *json_util_get_last_err(void); + + +extern int json_parse_int64(const char *buf, int64_t *retval); +extern int json_parse_double(const char *buf, double *retval); + +/** + * Return a string describing the type of the object. + * e.g. "int", or "object", etc... + */ +extern const char *json_type_to_name(enum json_type o_type); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/json_visit.c b/third_party/json-c/json_visit.c new file mode 100644 index 0000000000..1126ff8d7b --- /dev/null +++ b/third_party/json-c/json_visit.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2016 Eric Haszlakiewicz + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + */ + +#include + +#include "config.h" +#include "json_inttypes.h" +#include "json_object.h" +#include "json_visit.h" +#include "linkhash.h" + +static int _json_c_visit(json_object *jso, json_object *parent_jso, + const char *jso_key, size_t *jso_index, + json_c_visit_userfunc *userfunc, void *userarg); + +int json_c_visit(json_object *jso, int future_flags, + json_c_visit_userfunc *userfunc, void *userarg) +{ + int ret = _json_c_visit(jso, NULL, NULL, NULL, userfunc, userarg); + switch(ret) + { + case JSON_C_VISIT_RETURN_CONTINUE: + case JSON_C_VISIT_RETURN_SKIP: + case JSON_C_VISIT_RETURN_POP: + case JSON_C_VISIT_RETURN_STOP: + return 0; + default: + return JSON_C_VISIT_RETURN_ERROR; + } +} +static int _json_c_visit(json_object *jso, json_object *parent_jso, + const char *jso_key, size_t *jso_index, + json_c_visit_userfunc *userfunc, void *userarg) +{ + int userret = userfunc(jso, 0, parent_jso, jso_key, jso_index, userarg); + switch(userret) + { + case JSON_C_VISIT_RETURN_CONTINUE: + break; + case JSON_C_VISIT_RETURN_SKIP: + case JSON_C_VISIT_RETURN_POP: + case JSON_C_VISIT_RETURN_STOP: + case JSON_C_VISIT_RETURN_ERROR: + return userret; + default: + fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", userret); + return JSON_C_VISIT_RETURN_ERROR; + } + + switch(json_object_get_type(jso)) + { + case json_type_null: + case json_type_boolean: + case json_type_double: + case json_type_int: + case json_type_string: + // we already called userfunc above, move on to the next object + return JSON_C_VISIT_RETURN_CONTINUE; + + case json_type_object: + { + json_object_object_foreach(jso, key, child) + { + userret = _json_c_visit(child, jso, key, NULL, userfunc, userarg); + if (userret == JSON_C_VISIT_RETURN_POP) + break; + if (userret == JSON_C_VISIT_RETURN_STOP || + userret == JSON_C_VISIT_RETURN_ERROR) + return userret; + if (userret != JSON_C_VISIT_RETURN_CONTINUE && + userret != JSON_C_VISIT_RETURN_SKIP) + { + fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", userret); + return JSON_C_VISIT_RETURN_ERROR; + } + } + break; + } + case json_type_array: + { + size_t array_len = json_object_array_length(jso); + size_t ii; + for (ii = 0; ii < array_len; ii++) + { + json_object *child = json_object_array_get_idx(jso, ii); + userret = _json_c_visit(child, jso, NULL, &ii, userfunc, userarg); + if (userret == JSON_C_VISIT_RETURN_POP) + break; + if (userret == JSON_C_VISIT_RETURN_STOP || + userret == JSON_C_VISIT_RETURN_ERROR) + return userret; + if (userret != JSON_C_VISIT_RETURN_CONTINUE && + userret != JSON_C_VISIT_RETURN_SKIP) + { + fprintf(stderr, "INTERNAL ERROR: _json_c_visit returned %d\n", userret); + return JSON_C_VISIT_RETURN_ERROR; + } + } + break; + } + default: + fprintf(stderr, "INTERNAL ERROR: _json_c_visit found object of unknown type: %d\n", json_object_get_type(jso)); + return JSON_C_VISIT_RETURN_ERROR; + } + + // Call userfunc for the second type on container types, after all + // members of the container have been visited. + // Non-container types will have already returned before this point. + + userret = userfunc(jso, JSON_C_VISIT_SECOND, parent_jso, jso_key, jso_index, userarg); + switch(userret) + { + case JSON_C_VISIT_RETURN_SKIP: + case JSON_C_VISIT_RETURN_POP: + // These are not really sensible during JSON_C_VISIT_SECOND, + // but map them to JSON_C_VISIT_CONTINUE anyway. + // FALLTHROUGH + case JSON_C_VISIT_RETURN_CONTINUE: + return JSON_C_VISIT_RETURN_CONTINUE; + case JSON_C_VISIT_RETURN_STOP: + case JSON_C_VISIT_RETURN_ERROR: + return userret; + default: + fprintf(stderr, "ERROR: invalid return value from json_c_visit userfunc: %d\n", userret); + return JSON_C_VISIT_RETURN_ERROR; + } + // NOTREACHED +} + diff --git a/third_party/json-c/json_visit.h b/third_party/json-c/json_visit.h new file mode 100644 index 0000000000..b147d99ebc --- /dev/null +++ b/third_party/json-c/json_visit.h @@ -0,0 +1,95 @@ + +#ifndef _json_c_json_visit_h_ +#define _json_c_json_visit_h_ + +/** + * @file + * @brief Methods for walking a tree of objects. + */ +#include "json_object.h" + +typedef int (json_c_visit_userfunc)(json_object *jso, int flags, + json_object *parent_jso, const char *jso_key, + size_t *jso_index, void *userarg); + +/** + * Visit each object in the JSON hierarchy starting at jso. + * For each object, userfunc is called, passing the object and userarg. + * If the object has a parent (i.e. anything other than jso itself) + * its parent will be passed as parent_jso, and either jso_key or jso_index + * will be set, depending on whether the parent is an object or an array. + * + * Nodes will be visited depth first, but containers (arrays and objects) + * will be visited twice, the second time with JSON_C_VISIT_SECOND set in + * flags. + * + * userfunc must return one of the defined return values, to indicate + * whether and how to continue visiting nodes, or one of various ways to stop. + * + * Returns 0 if nodes were visited successfully, even if some were + * intentionally skipped due to what userfunc returned. + * Returns <0 if an error occurred during iteration, including if + * userfunc returned JSON_C_VISIT_RETURN_ERROR. + */ +int json_c_visit(json_object *jso, int future_flags, + json_c_visit_userfunc *userfunc, void *userarg); + +/** + * Passed to json_c_visit_userfunc as one of the flags values to indicate + * that this is the second time a container (array or object) is being + * called, after all of it's members have been iterated over. + */ +#define JSON_C_VISIT_SECOND 0x02 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * should proceed normally. + */ +#define JSON_C_VISIT_RETURN_CONTINUE 0 + + +/** + * This json_c_visit_userfunc return value indicates that iteration + * over the members of the current object should be skipped. + * If the current object isn't a container (array or object), this + * is no different than JSON_C_VISIT_RETURN_CONTINUE. + */ +#define JSON_C_VISIT_RETURN_SKIP 7547 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * of the fields/elements of the containing object should stop + * and continue "popped up" a level of the object hierarchy. + * For example, returning this when handling arg will result in + * arg3 and any other fields being skipped. The next call to userfunc + * will be the JSON_C_VISIT_SECOND call on "foo", followed by a userfunc + * call on "bar". + *
+ * {
+ *   "foo": {
+ *     "arg1": 1,
+ *     "arg2": 2,
+ *     "arg3": 3,
+ *     ...
+ *   },
+ *   "bar": {
+ *     ...
+ *   }
+ * }
+ * 
+ */ +#define JSON_C_VISIT_RETURN_POP 767 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * should stop immediately, and cause json_c_visit to return success. + */ +#define JSON_C_VISIT_RETURN_STOP 7867 + +/** + * This json_c_visit_userfunc return value indicates that iteration + * should stop immediately, and cause json_c_visit to return an error. + */ +#define JSON_C_VISIT_RETURN_ERROR -1 + +#endif /* _json_c_json_visit_h_ */ diff --git a/third_party/json-c/libjson.c b/third_party/json-c/libjson.c new file mode 100644 index 0000000000..b19df42f72 --- /dev/null +++ b/third_party/json-c/libjson.c @@ -0,0 +1,26 @@ + +/* dummy source file for compatibility purposes */ + +#if defined(HAVE_CDEFS_H) +#include +#endif + +#ifndef __warn_references + +#if defined(__GNUC__) && defined (HAS_GNU_WARNING_LONG) + +#define __warn_references(sym,msg) \ + __asm__(".section .gnu" #sym ",\n\t.ascii \"" msg "\"\n\t.text"); + +#else +#define __warn_references(sym,msg) /* nothing */ +#endif + +#endif + +#include "json_object.h" + +__warn_references(json_object_get, "Warning: please link against libjson-c instead of libjson"); + +/* __asm__(".section .gnu.warning." __STRING(sym) \ + " ; .ascii \"" msg "\" ; .text") */ diff --git a/third_party/json-c/linkhash.c b/third_party/json-c/linkhash.c new file mode 100644 index 0000000000..5497061a8a --- /dev/null +++ b/third_party/json-c/linkhash.c @@ -0,0 +1,690 @@ +/* + * $Id: linkhash.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_ENDIAN_H +# include /* attempt to define endianness */ +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) +# define WIN32_LEAN_AND_MEAN +# include /* Get InterlockedCompareExchange */ +#endif + +#include "random_seed.h" +#include "linkhash.h" + +/* hash functions */ +static unsigned long lh_char_hash(const void *k); +static unsigned long lh_perllike_str_hash(const void *k); +static lh_hash_fn *char_hash_fn = lh_char_hash; + +int +json_global_set_string_hash(const int h) +{ + switch(h) { + case JSON_C_STR_HASH_DFLT: + char_hash_fn = lh_char_hash; + break; + case JSON_C_STR_HASH_PERLLIKE: + char_hash_fn = lh_perllike_str_hash; + break; + default: + return -1; + } + return 0; +} + +void lh_abort(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); + exit(1); +} + +static unsigned long lh_ptr_hash(const void *k) +{ + /* CAW: refactored to be 64bit nice */ + return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); +} + +int lh_ptr_equal(const void *k1, const void *k2) +{ + return (k1 == k2); +} + +/* + * hashlittle from lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * http://burtleburtle.net/bob/c/lookup3.c + * minor modifications to make functions static so no symbols are exported + * minor mofifications to compile with -Werror + */ + +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + * AddressSanitizer is similarly picky about overrunning + * the buffer. (http://clang.llvm.org/docs/AddressSanitizer.html + */ +#ifdef VALGRIND +# define PRECISE_MEMORY_ACCESS 1 +#elif defined(__SANITIZE_ADDRESS__) /* GCC's ASAN */ +# define PRECISE_MEMORY_ACCESS 1 +#elif defined(__has_feature) +# if __has_feature(address_sanitizer) /* Clang's ASAN */ +# define PRECISE_MEMORY_ACCESS 1 +# endif +#endif +#ifndef PRECISE_MEMORY_ACCESS + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + const uint8_t *k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; /* FALLTHRU */ + case 11: c+=((uint32_t)k[10])<<16; /* FALLTHRU */ + case 10: c+=((uint32_t)k[9])<<8; /* FALLTHRU */ + case 9 : c+=k[8]; /* FALLTHRU */ + case 8 : b+=((uint32_t)k[7])<<24; /* FALLTHRU */ + case 7 : b+=((uint32_t)k[6])<<16; /* FALLTHRU */ + case 6 : b+=((uint32_t)k[5])<<8; /* FALLTHRU */ + case 5 : b+=k[4]; /* FALLTHRU */ + case 4 : a+=((uint32_t)k[3])<<24; /* FALLTHRU */ + case 3 : a+=((uint32_t)k[2])<<16; /* FALLTHRU */ + case 2 : a+=((uint32_t)k[1])<<8; /* FALLTHRU */ + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + +/* a simple hash function similiar to what perl does for strings. + * for good results, the string should not be excessivly large. + */ +static unsigned long lh_perllike_str_hash(const void *k) +{ + const char *rkey = (const char *)k; + unsigned hashval = 1; + + while (*rkey) + hashval = hashval * 33 + *rkey++; + + return hashval; +} + +static unsigned long lh_char_hash(const void *k) +{ +#if defined _MSC_VER || defined __MINGW32__ +#define RANDOM_SEED_TYPE LONG +#else +#define RANDOM_SEED_TYPE int +#endif + static volatile RANDOM_SEED_TYPE random_seed = -1; + + if (random_seed == -1) { + RANDOM_SEED_TYPE seed; + /* we can't use -1 as it is the unitialized sentinel */ + while ((seed = json_c_get_random_seed()) == -1); +#if SIZEOF_INT == 8 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 +#define USE_SYNC_COMPARE_AND_SWAP 1 +#endif +#if SIZEOF_INT == 4 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 +#define USE_SYNC_COMPARE_AND_SWAP 1 +#endif +#if SIZEOF_INT == 2 && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 +#define USE_SYNC_COMPARE_AND_SWAP 1 +#endif +#if defined USE_SYNC_COMPARE_AND_SWAP + (void)__sync_val_compare_and_swap(&random_seed, -1, seed); +#elif defined _MSC_VER || defined __MINGW32__ + InterlockedCompareExchange(&random_seed, seed, -1); +#else +//#warning "racy random seed initializtion if used by multiple threads" + random_seed = seed; /* potentially racy */ +#endif + } + + return hashlittle((const char*)k, strlen((const char*)k), random_seed); +} + +int lh_char_equal(const void *k1, const void *k2) +{ + return (strcmp((const char*)k1, (const char*)k2) == 0); +} + +struct lh_table* lh_table_new(int size, + lh_entry_free_fn *free_fn, + lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn) +{ + int i; + struct lh_table *t; + + t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); + if (!t) + return NULL; + + t->count = 0; + t->size = size; + t->table = (struct lh_entry*)calloc(size, sizeof(struct lh_entry)); + if (!t->table) + { + free(t); + return NULL; + } + t->free_fn = free_fn; + t->hash_fn = hash_fn; + t->equal_fn = equal_fn; + for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY; + return t; +} + +struct lh_table* lh_kchar_table_new(int size, + lh_entry_free_fn *free_fn) +{ + return lh_table_new(size, free_fn, char_hash_fn, lh_char_equal); +} + +struct lh_table* lh_kptr_table_new(int size, + lh_entry_free_fn *free_fn) +{ + return lh_table_new(size, free_fn, lh_ptr_hash, lh_ptr_equal); +} + +int lh_table_resize(struct lh_table *t, int new_size) +{ + struct lh_table *new_t; + struct lh_entry *ent; + + new_t = lh_table_new(new_size, NULL, t->hash_fn, t->equal_fn); + if (new_t == NULL) + return -1; + + for (ent = t->head; ent != NULL; ent = ent->next) + { + unsigned long h = lh_get_hash(new_t, ent->k); + unsigned int opts = 0; + if (ent->k_is_constant) + opts = JSON_C_OBJECT_KEY_IS_CONSTANT; + if (lh_table_insert_w_hash(new_t, ent->k, ent->v, h, opts) != 0) + { + lh_table_free(new_t); + return -1; + } + } + free(t->table); + t->table = new_t->table; + t->size = new_size; + t->head = new_t->head; + t->tail = new_t->tail; + free(new_t); + + return 0; +} + +void lh_table_free(struct lh_table *t) +{ + struct lh_entry *c; + if(t->free_fn) { + for(c = t->head; c != NULL; c = c->next) + t->free_fn(c); + } + free(t->table); + free(t); +} + + +int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, const unsigned long h, const unsigned opts) +{ + unsigned long n; + + if (t->count >= t->size * LH_LOAD_FACTOR) + if (lh_table_resize(t, t->size * 2) != 0) + return -1; + + n = h % t->size; + + while( 1 ) { + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; + if ((int)++n == t->size) n = 0; + } + + t->table[n].k = k; + t->table[n].k_is_constant = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT); + t->table[n].v = v; + t->count++; + + if(t->head == NULL) { + t->head = t->tail = &t->table[n]; + t->table[n].next = t->table[n].prev = NULL; + } else { + t->tail->next = &t->table[n]; + t->table[n].prev = t->tail; + t->table[n].next = NULL; + t->tail = &t->table[n]; + } + + return 0; +} +int lh_table_insert(struct lh_table *t, const void *k, const void *v) +{ + return lh_table_insert_w_hash(t, k, v, lh_get_hash(t, k), 0); +} + + +struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h) +{ + unsigned long n = h % t->size; + int count = 0; + + while( count < t->size ) { + if(t->table[n].k == LH_EMPTY) return NULL; + if(t->table[n].k != LH_FREED && + t->equal_fn(t->table[n].k, k)) return &t->table[n]; + if ((int)++n == t->size) n = 0; + count++; + } + return NULL; +} + +struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) +{ + return lh_table_lookup_entry_w_hash(t, k, lh_get_hash(t, k)); +} + +const void* lh_table_lookup(struct lh_table *t, const void *k) +{ + void *result; + lh_table_lookup_ex(t, k, &result); + return result; +} + +json_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v) +{ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if (e != NULL) { + if (v != NULL) *v = lh_entry_v(e); + return TRUE; /* key found */ + } + if (v != NULL) *v = NULL; + return FALSE; /* key not found */ +} + +int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) +{ + ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */ + + /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */ + if(n < 0) { return -2; } + + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1; + t->count--; + if(t->free_fn) t->free_fn(e); + t->table[n].v = NULL; + t->table[n].k = LH_FREED; + if(t->tail == &t->table[n] && t->head == &t->table[n]) { + t->head = t->tail = NULL; + } else if (t->head == &t->table[n]) { + t->head->next->prev = NULL; + t->head = t->head->next; + } else if (t->tail == &t->table[n]) { + t->tail->prev->next = NULL; + t->tail = t->tail->prev; + } else { + t->table[n].prev->next = t->table[n].next; + t->table[n].next->prev = t->table[n].prev; + } + t->table[n].next = t->table[n].prev = NULL; + return 0; +} + + +int lh_table_delete(struct lh_table *t, const void *k) +{ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if(!e) return -1; + return lh_table_delete_entry(t, e); +} + +int lh_table_length(struct lh_table *t) +{ + return t->count; +} diff --git a/third_party/json-c/linkhash.h b/third_party/json-c/linkhash.h new file mode 100644 index 0000000000..9c2f5c1b25 --- /dev/null +++ b/third_party/json-c/linkhash.h @@ -0,0 +1,406 @@ +/* + * $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Internal methods for working with json_type_object objects. Although + * this is exposed by the json_object_get_object() function and within the + * json_object_iter type, it is not recommended for direct use. + */ +#ifndef _linkhash_h_ +#define _linkhash_h_ + +#include "json_object.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * golden prime used in hash functions + */ +#define LH_PRIME 0x9e370001UL + +/** + * The fraction of filled hash buckets until an insert will cause the table + * to be resized. + * This can range from just above 0 up to 1.0. + */ +#define LH_LOAD_FACTOR 0.66 + +/** + * sentinel pointer value for empty slots + */ +#define LH_EMPTY (void*)-1 + +/** + * sentinel pointer value for freed slots + */ +#define LH_FREED (void*)-2 + +/** + * default string hash function + */ +#define JSON_C_STR_HASH_DFLT 0 + +/** + * perl-like string hash function + */ +#define JSON_C_STR_HASH_PERLLIKE 1 + +/** + * This function sets the hash function to be used for strings. + * Must be one of the JSON_C_STR_HASH_* values. + * @returns 0 - ok, -1 if parameter was invalid + */ +int json_global_set_string_hash(const int h); + +struct lh_entry; + +/** + * callback function prototypes + */ +typedef void (lh_entry_free_fn) (struct lh_entry *e); +/** + * callback function prototypes + */ +typedef unsigned long (lh_hash_fn) (const void *k); +/** + * callback function prototypes + */ +typedef int (lh_equal_fn) (const void *k1, const void *k2); + +/** + * An entry in the hash table + */ +struct lh_entry { + /** + * The key. Use lh_entry_k() instead of accessing this directly. + */ + const void *k; + /** + * A flag for users of linkhash to know whether or not they + * need to free k. + */ + int k_is_constant; + /** + * The value. Use lh_entry_v() instead of accessing this directly. + */ + const void *v; + /** + * The next entry + */ + struct lh_entry *next; + /** + * The previous entry. + */ + struct lh_entry *prev; +}; + + +/** + * The hash table structure. + */ +struct lh_table { + /** + * Size of our hash. + */ + int size; + /** + * Numbers of entries. + */ + int count; + + /** + * The first entry. + */ + struct lh_entry *head; + + /** + * The last entry. + */ + struct lh_entry *tail; + + struct lh_entry *table; + + /** + * A pointer onto the function responsible for freeing an entry. + */ + lh_entry_free_fn *free_fn; + lh_hash_fn *hash_fn; + lh_equal_fn *equal_fn; +}; +typedef struct lh_table lh_table; + + +/** + * Convenience list iterator. + */ +#define lh_foreach(table, entry) \ +for(entry = table->head; entry; entry = entry->next) + +/** + * lh_foreach_safe allows calling of deletion routine while iterating. + * + * @param table a struct lh_table * to iterate over + * @param entry a struct lh_entry * variable to hold each element + * @param tmp a struct lh_entry * variable to hold a temporary pointer to the next element + */ +#define lh_foreach_safe(table, entry, tmp) \ +for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) + + + +/** + * Create a new linkhash table. + * + * @param size initial table size. The table is automatically resized + * although this incurs a performance penalty. + * @param free_fn callback function used to free memory for entries + * when lh_table_free or lh_table_delete is called. + * If NULL is provided, then memory for keys and values + * must be freed by the caller. + * @param hash_fn function used to hash keys. 2 standard ones are defined: + * lh_ptr_hash and lh_char_hash for hashing pointer values + * and C strings respectively. + * @param equal_fn comparison function to compare keys. 2 standard ones defined: + * lh_ptr_hash and lh_char_hash for comparing pointer values + * and C strings respectively. + * @return On success, a pointer to the new linkhash table is returned. + * On error, a null pointer is returned. + */ +extern struct lh_table* lh_table_new(int size, + lh_entry_free_fn *free_fn, + lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn); + +/** + * Convenience function to create a new linkhash table with char keys. + * + * @param size initial table size. + * @param free_fn callback function used to free memory for entries. + * @return On success, a pointer to the new linkhash table is returned. + * On error, a null pointer is returned. + */ +extern struct lh_table* lh_kchar_table_new(int size, + lh_entry_free_fn *free_fn); + + +/** + * Convenience function to create a new linkhash table with ptr keys. + * + * @param size initial table size. + * @param free_fn callback function used to free memory for entries. + * @return On success, a pointer to the new linkhash table is returned. + * On error, a null pointer is returned. + */ +extern struct lh_table* lh_kptr_table_new(int size, + lh_entry_free_fn *free_fn); + + +/** + * Free a linkhash table. + * + * If a lh_entry_free_fn callback free function was provided then it is + * called for all entries in the table. + * + * @param t table to free. + */ +extern void lh_table_free(struct lh_table *t); + + +/** + * Insert a record into the table. + * + * @param t the table to insert into. + * @param k a pointer to the key to insert. + * @param v a pointer to the value to insert. + * + * @return On success, 0 is returned. + * On error, a negative value is returned. + */ +extern int lh_table_insert(struct lh_table *t, const void *k, const void *v); + + +/** + * Insert a record into the table using a precalculated key hash. + * + * The hash h, which should be calculated with lh_get_hash() on k, is provided by + * the caller, to allow for optimization when multiple operations with the same + * key are known to be needed. + * + * @param t the table to insert into. + * @param k a pointer to the key to insert. + * @param v a pointer to the value to insert. + * @param h hash value of the key to insert + * @param opts if set to JSON_C_OBJECT_KEY_IS_CONSTANT, sets lh_entry.k_is_constant + * so t's free function knows to avoid freeing the key. + */ +extern int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, const unsigned long h, const unsigned opts); + + +/** + * Lookup a record in the table. + * + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @return a pointer to the record structure of the value or NULL if it does not exist. + */ +extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k); + +/** + * Lookup a record in the table using a precalculated key hash. + * + * The hash h, which should be calculated with lh_get_hash() on k, is provided by + * the caller, to allow for optimization when multiple operations with the same + * key are known to be needed. + * + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @param h hash value of the key to lookup + * @return a pointer to the record structure of the value or NULL if it does not exist. + */ +extern struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h); + +/** + * Lookup a record into the table. + * + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @return a pointer to the found value or NULL if it does not exist. + * @deprecated Use lh_table_lookup_ex() instead. + */ +THIS_FUNCTION_IS_DEPRECATED(extern const void* lh_table_lookup(struct lh_table *t, const void *k)); + +/** + * Lookup a record in the table. + * + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @param v a pointer to a where to store the found value (set to NULL if it doesn't exist). + * @return whether or not the key was found + */ +extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v); + +/** + * Delete a record from the table. + * + * If a callback free function is provided then it is called for the + * for the item being deleted. + * @param t the table to delete from. + * @param e a pointer to the entry to delete. + * @return 0 if the item was deleted. + * @return -1 if it was not found. + */ +extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); + + +/** + * Delete a record from the table. + * + * If a callback free function is provided then it is called for the + * for the item being deleted. + * @param t the table to delete from. + * @param k a pointer to the key to delete. + * @return 0 if the item was deleted. + * @return -1 if it was not found. + */ +extern int lh_table_delete(struct lh_table *t, const void *k); + +extern int lh_table_length(struct lh_table *t); + +/** + * Prints a message to stdout, + * then exits the program with an exit code of 1. + * + * @param msg Message format string, like for printf. + * @param ... Format args. + * + * @deprecated Since it is not a good idea to exit the entire program + * because of an internal library failure, json-c will no longer + * use this function internally. + * However, because its interface is public, it will remain part of + * the API on the off chance of legacy software using it externally. + */ +THIS_FUNCTION_IS_DEPRECATED(void lh_abort(const char *msg, ...)); + +/** + * Resizes the specified table. + * + * @param t Pointer to table to resize. + * @param new_size New table size. Must be positive. + * + * @return On success, 0 is returned. + * On error, a negative value is returned. + */ +int lh_table_resize(struct lh_table *t, int new_size); + + +/** + * @deprecated Don't use this outside of linkhash.h: + */ +#if !defined(_MSC_VER) || (_MSC_VER > 1800) +/* VS2010 can't handle inline funcs, so skip it there */ +#define _LH_INLINE inline +#else +#define _LH_INLINE +#endif + +/** + * Calculate the hash of a key for a given table. + * + * This is an exension to support functions that need to calculate + * the hash several times and allows them to do it just once and then pass + * in the hash to all utility functions. Depending on use case, this can be a + * considerable performance improvement. + * @param t the table (used to obtain hash function) + * @param k a pointer to the key to lookup + * @return the key's hash + */ +static _LH_INLINE unsigned long lh_get_hash(const struct lh_table *t, const void *k) +{ + return t->hash_fn(k); +} + +#undef _LH_INLINE + +/** + * @deprecated Don't use this outside of linkhash.h: + */ +#ifdef __UNCONST +#define _LH_UNCONST(a) __UNCONST(a) +#else +#define _LH_UNCONST(a) ((void *)(uintptr_t)(const void *)(a)) +#endif + +/** + * Return a non-const version of lh_entry.k. + * + * lh_entry.k is const to indicate and help ensure that linkhash itself doesn't modify + * it, but callers are allowed to do what they want with it. + * See also lh_entry.k_is_constant + */ +#define lh_entry_k(entry) _LH_UNCONST((entry)->k) + +/** + * Return a non-const version of lh_entry.v. + * + * v is const to indicate and help ensure that linkhash itself doesn't modify + * it, but callers are allowed to do what they want with it. + */ +#define lh_entry_v(entry) _LH_UNCONST((entry)->v) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/math_compat.h b/third_party/json-c/math_compat.h new file mode 100644 index 0000000000..d530537b94 --- /dev/null +++ b/third_party/json-c/math_compat.h @@ -0,0 +1,36 @@ +#ifndef __math_compat_h +#define __math_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +/* Define isnan, isinf, infinity and nan on Windows/MSVC */ + +#ifndef HAVE_DECL_ISNAN +# ifdef HAVE_DECL__ISNAN +#include +#define isnan(x) _isnan(x) +# endif +#endif + +#ifndef HAVE_DECL_ISINF +# ifdef HAVE_DECL__FINITE +#include +#define isinf(x) (!_finite(x)) +# endif +#endif + +#ifndef HAVE_DECL_INFINITY +#include +#define INFINITY (DBL_MAX + DBL_MAX) +#define HAVE_DECL_INFINITY +#endif + +#ifndef HAVE_DECL_NAN +#define NAN (INFINITY - INFINITY) +#define HAVE_DECL_NAN +#endif + +#endif diff --git a/third_party/json-c/printbuf.c b/third_party/json-c/printbuf.c new file mode 100644 index 0000000000..6c77b5defd --- /dev/null +++ b/third_party/json-c/printbuf.c @@ -0,0 +1,155 @@ +/* + * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + * + * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License + * (http://www.opensource.org/licenses/mit-license.php) + */ + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_STDARG_H +# include +#else /* !HAVE_STDARG_H */ +# error Not enough var arg support! +#endif /* HAVE_STDARG_H */ + +#include "debug.h" +#include "printbuf.h" +#include "snprintf_compat.h" +#include "vasprintf_compat.h" + +static int printbuf_extend(struct printbuf *p, int min_size); + +struct printbuf* printbuf_new(void) +{ + struct printbuf *p; + + p = (struct printbuf*)calloc(1, sizeof(struct printbuf)); + if(!p) return NULL; + p->size = 32; + p->bpos = 0; + if(!(p->buf = (char*)malloc(p->size))) { + free(p); + return NULL; + } + p->buf[0]= '\0'; + return p; +} + + +/** + * Extend the buffer p so it has a size of at least min_size. + * + * If the current size is large enough, nothing is changed. + * + * Note: this does not check the available space! The caller + * is responsible for performing those calculations. + */ +static int printbuf_extend(struct printbuf *p, int min_size) +{ + char *t; + int new_size; + + if (p->size >= min_size) + return 0; + + new_size = p->size * 2; + if (new_size < min_size + 8) + new_size = min_size + 8; +#ifdef PRINTBUF_DEBUG + MC_DEBUG("printbuf_memappend: realloc " + "bpos=%d min_size=%d old_size=%d new_size=%d\n", + p->bpos, min_size, p->size, new_size); +#endif /* PRINTBUF_DEBUG */ + if(!(t = (char*)realloc(p->buf, new_size))) + return -1; + p->size = new_size; + p->buf = t; + return 0; +} + +int printbuf_memappend(struct printbuf *p, const char *buf, int size) +{ + if (p->size <= p->bpos + size + 1) { + if (printbuf_extend(p, p->bpos + size + 1) < 0) + return -1; + } + memcpy(p->buf + p->bpos, buf, size); + p->bpos += size; + p->buf[p->bpos]= '\0'; + return size; +} + +int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) +{ + int size_needed; + + if (offset == -1) + offset = pb->bpos; + size_needed = offset + len; + if (pb->size < size_needed) + { + if (printbuf_extend(pb, size_needed) < 0) + return -1; + } + + memset(pb->buf + offset, charvalue, len); + if (pb->bpos < size_needed) + pb->bpos = size_needed; + + return 0; +} + +int sprintbuf(struct printbuf *p, const char *msg, ...) +{ + va_list ap; + char *t; + int size; + char buf[128]; + + /* user stack buffer first */ + va_start(ap, msg); + size = vsnprintf(buf, 128, msg, ap); + va_end(ap); + /* if string is greater than stack buffer, then use dynamic string + with vasprintf. Note: some implementation of vsnprintf return -1 + if output is truncated whereas some return the number of bytes that + would have been written - this code handles both cases. */ + if(size == -1 || size > 127) { + va_start(ap, msg); + if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; } + va_end(ap); + printbuf_memappend(p, t, size); + free(t); + return size; + } else { + printbuf_memappend(p, buf, size); + return size; + } +} + +void printbuf_reset(struct printbuf *p) +{ + p->buf[0] = '\0'; + p->bpos = 0; +} + +void printbuf_free(struct printbuf *p) +{ + if(p) { + free(p->buf); + free(p); + } +} diff --git a/third_party/json-c/printbuf.h b/third_party/json-c/printbuf.h new file mode 100644 index 0000000000..567a6a08bb --- /dev/null +++ b/third_party/json-c/printbuf.h @@ -0,0 +1,122 @@ +/* + * $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ + * + * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + * + * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. + * The copyrights to the contents of this file are licensed under the MIT License + * (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * @file + * @brief Internal string buffer handing. Unless you're writing a + * json_object_to_json_string_fn implementation for use with + * json_object_set_serializer() direct use of this is not + * recommended. + */ +#ifndef _printbuf_h_ +#define _printbuf_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct printbuf { + char *buf; + int bpos; + int size; +}; +typedef struct printbuf printbuf; + +extern struct printbuf* +printbuf_new(void); + +/* As an optimization, printbuf_memappend_fast() is defined as a macro + * that handles copying data if the buffer is large enough; otherwise + * it invokes printbuf_memappend() which performs the heavy + * lifting of realloc()ing the buffer and copying data. + * + * Your code should not use printbuf_memappend() directly unless it + * checks the return code. Use printbuf_memappend_fast() instead. + */ +extern int +printbuf_memappend(struct printbuf *p, const char *buf, int size); + +#define printbuf_memappend_fast(p, bufptr, bufsize) \ +do { \ + if ((p->size - p->bpos) > bufsize) { \ + memcpy(p->buf + p->bpos, (bufptr), bufsize); \ + p->bpos += bufsize; \ + p->buf[p->bpos]= '\0'; \ + } else { printbuf_memappend(p, (bufptr), bufsize); } \ +} while (0) + +#define printbuf_length(p) ((p)->bpos) + +/** + * Results in a compile error if the argument is not a string literal. + */ +#define _printbuf_check_literal(mystr) ("" mystr) + +/** + * This is an optimization wrapper around printbuf_memappend() that is useful + * for appending string literals. Since the size of string constants is known + * at compile time, using this macro can avoid a costly strlen() call. This is + * especially helpful when a constant string must be appended many times. If + * you got here because of a compilation error caused by passing something + * other than a string literal, use printbuf_memappend_fast() in conjunction + * with strlen(). + * + * See also: + * printbuf_memappend_fast() + * printbuf_memappend() + * sprintbuf() + */ +#define printbuf_strappend(pb, str) \ + printbuf_memappend ((pb), _printbuf_check_literal(str), sizeof(str) - 1) + +/** + * Set len bytes of the buffer to charvalue, starting at offset offset. + * Similar to calling memset(x, charvalue, len); + * + * The memory allocated for the buffer is extended as necessary. + * + * If offset is -1, this starts at the end of the current data in the buffer. + */ +extern int +printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len); + +/** + * Formatted print to printbuf. + * + * This function is the most expensive of the available functions for appending + * string data to a printbuf and should be used only where convenience is more + * important than speed. Avoid using this function in high performance code or + * tight loops; in these scenarios, consider using snprintf() with a static + * buffer in conjunction with one of the printbuf_*append() functions. + * + * See also: + * printbuf_memappend_fast() + * printbuf_memappend() + * printbuf_strappend() + */ +extern int +sprintbuf(struct printbuf *p, const char *msg, ...); + +extern void +printbuf_reset(struct printbuf *p); + +extern void +printbuf_free(struct printbuf *p); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/random_seed.c b/third_party/json-c/random_seed.c new file mode 100644 index 0000000000..32327774ad --- /dev/null +++ b/third_party/json-c/random_seed.c @@ -0,0 +1,238 @@ +/* + * random_seed.c + * + * Copyright (c) 2013 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +#include "strerror_override.h" +#include +#include "config.h" +#include "random_seed.h" + +#define DEBUG_SEED(s) + + +#if defined ENABLE_RDRAND + +/* cpuid */ + +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) +#define HAS_X86_CPUID 1 + +static void do_cpuid(int regs[], int h) +{ + __asm__ __volatile__( +#if defined __x86_64__ + "pushq %%rbx;\n" +#else + "pushl %%ebx;\n" +#endif + "cpuid;\n" +#if defined __x86_64__ + "popq %%rbx;\n" +#else + "popl %%ebx;\n" +#endif + : "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) + : "a"(h)); +} + +#elif defined _MSC_VER + +#define HAS_X86_CPUID 1 +#define do_cpuid __cpuid + +#endif + +/* has_rdrand */ + +#if HAS_X86_CPUID + +static int has_rdrand() +{ + // CPUID.01H:ECX.RDRAND[bit 30] == 1 + int regs[4]; + do_cpuid(regs, 1); + return (regs[2] & (1 << 30)) != 0; +} + +#endif + +/* get_rdrand_seed - GCC x86 and X64 */ + +#if defined __GNUC__ && (defined __i386__ || defined __x86_64__) + +#define HAVE_RDRAND 1 + +static int get_rdrand_seed() +{ + DEBUG_SEED("get_rdrand_seed"); + int _eax; + // rdrand eax + __asm__ __volatile__("1: .byte 0x0F\n" + " .byte 0xC7\n" + " .byte 0xF0\n" + " jnc 1b;\n" + : "=a" (_eax)); + return _eax; +} + +#endif + +#if defined _MSC_VER + +#if _MSC_VER >= 1700 +#define HAVE_RDRAND 1 + +/* get_rdrand_seed - Visual Studio 2012 and above */ + +static int get_rdrand_seed() +{ + DEBUG_SEED("get_rdrand_seed"); + int r; + while (_rdrand32_step(&r) == 0); + return r; +} + +#elif defined _M_IX86 +#define HAVE_RDRAND 1 + +/* get_rdrand_seed - Visual Studio 2010 and below - x86 only */ + +static int get_rdrand_seed() +{ + DEBUG_SEED("get_rdrand_seed"); + int _eax; +retry: + // rdrand eax + __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 + __asm jnc retry + __asm mov _eax, eax + return _eax; +} + +#endif +#endif + +#endif /* defined ENABLE_RDRAND */ + + +/* has_dev_urandom */ + +#if defined (__APPLE__) || defined(__unix__) || defined(__linux__) + +#include +#include +#include +#include +#include + +#define HAVE_DEV_RANDOM 1 + +static const char *dev_random_file = "/dev/urandom"; + +static int has_dev_urandom() +{ + struct stat buf; + if (stat(dev_random_file, &buf)) { + return 0; + } + return ((buf.st_mode & S_IFCHR) != 0); +} + + +/* get_dev_random_seed */ + +static int get_dev_random_seed() +{ + DEBUG_SEED("get_dev_random_seed"); + + int fd = open(dev_random_file, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno)); + exit(1); + } + + int r; + ssize_t nread = read(fd, &r, sizeof(r)); + if (nread != sizeof(r)) { + fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno)); + exit(1); + } + + close(fd); + return r; +} + +#endif + + +/* get_cryptgenrandom_seed */ + +#ifdef WIN32 + +#define HAVE_CRYPTGENRANDOM 1 + +#include +#include +#ifndef __GNUC__ +#pragma comment(lib, "advapi32.lib") +#endif + +static int get_cryptgenrandom_seed() +{ + HCRYPTPROV hProvider = 0; + int r; + + DEBUG_SEED("get_cryptgenrandom_seed"); + + if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + fprintf(stderr, "error CryptAcquireContextW"); + exit(1); + } + + if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) { + fprintf(stderr, "error CryptGenRandom"); + exit(1); + } + + CryptReleaseContext(hProvider, 0); + + return r; +} + +#endif + + +/* get_time_seed */ + +#include + +static int get_time_seed() +{ + DEBUG_SEED("get_time_seed"); + + return (int)time(NULL) * 433494437; +} + + +/* json_c_get_random_seed */ + +int json_c_get_random_seed() +{ +#if HAVE_RDRAND + if (has_rdrand()) return get_rdrand_seed(); +#endif +#if HAVE_DEV_RANDOM + if (has_dev_urandom()) return get_dev_random_seed(); +#endif +#if HAVE_CRYPTGENRANDOM + return get_cryptgenrandom_seed(); +#endif + return get_time_seed(); +} diff --git a/third_party/json-c/random_seed.h b/third_party/json-c/random_seed.h new file mode 100644 index 0000000000..2f43dad1f3 --- /dev/null +++ b/third_party/json-c/random_seed.h @@ -0,0 +1,29 @@ +/* + * random_seed.h + * + * Copyright (c) 2013 Metaparadigm Pte. Ltd. + * Michael Clark + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See COPYING for details. + * + */ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ +#ifndef seed_h +#define seed_h + +#ifdef __cplusplus +extern "C" { +#endif + +extern int json_c_get_random_seed(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/json-c/snprintf_compat.h b/third_party/json-c/snprintf_compat.h new file mode 100644 index 0000000000..8ca9b31c6f --- /dev/null +++ b/third_party/json-c/snprintf_compat.h @@ -0,0 +1,41 @@ +#ifndef __snprintf_compat_h +#define __snprintf_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +/* + * Microsoft's _vsnprintf and _snprint don't always terminate + * the string, so use wrappers that ensure that. + */ + +#include + +#if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) +static int json_c_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + int ret; + ret = _vsnprintf(str, size, format, ap); + str[size - 1] = '\0'; + return ret; +} +#define vsnprintf json_c_vsnprintf + +static int json_c_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int ret; + va_start(ap, format); + ret = json_c_vsnprintf(str, size, format, ap); + va_end(ap); + return ret; +} +#define snprintf json_c_snprintf + +#elif !defined(HAVE_SNPRINTF) /* !HAVE_SNPRINTF */ +# error Need vsnprintf! +#endif /* !HAVE_SNPRINTF && defined(WIN32) */ + +#endif /* __snprintf_compat_h */ diff --git a/third_party/json-c/strdup_compat.h b/third_party/json-c/strdup_compat.h new file mode 100644 index 0000000000..9c523596e3 --- /dev/null +++ b/third_party/json-c/strdup_compat.h @@ -0,0 +1,16 @@ +#ifndef __strdup_compat_h +#define __strdup_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#if !defined(HAVE_STRDUP) && defined(_MSC_VER) + /* MSC has the version as _strdup */ +# define strdup _strdup +#elif !defined(HAVE_STRDUP) +# error You do not have strdup on your system. +#endif /* HAVE_STRDUP */ + +#endif diff --git a/third_party/json-c/strerror_override.c b/third_party/json-c/strerror_override.c new file mode 100644 index 0000000000..90a15814cf --- /dev/null +++ b/third_party/json-c/strerror_override.c @@ -0,0 +1,101 @@ +#define STRERROR_OVERRIDE_IMPL 1 +#include "strerror_override.h" + +/* + * Override strerror() to get consistent output across platforms. + */ + +static struct { + int errno_value; + const char *errno_str; +} errno_list[] = { +#define STRINGIFY(x) #x +#define ENTRY(x) {x, &STRINGIFY(undef_ ## x)[6]} + ENTRY(EPERM), + ENTRY(ENOENT), + ENTRY(ESRCH), + ENTRY(EINTR), + ENTRY(EIO), + ENTRY(ENXIO), + ENTRY(E2BIG), + ENTRY(ENOEXEC), + ENTRY(EBADF), + ENTRY(ECHILD), + ENTRY(EDEADLK), + ENTRY(ENOMEM), + ENTRY(EACCES), + ENTRY(EFAULT), +#ifdef ENOTBLK + ENTRY(ENOTBLK), +#endif + ENTRY(EBUSY), + ENTRY(EEXIST), + ENTRY(EXDEV), + ENTRY(ENODEV), + ENTRY(ENOTDIR), + ENTRY(EISDIR), + ENTRY(EINVAL), + ENTRY(ENFILE), + ENTRY(EMFILE), + ENTRY(ENOTTY), +#ifdef ETXTBSY + ENTRY(ETXTBSY), +#endif + ENTRY(EFBIG), + ENTRY(ENOSPC), + ENTRY(ESPIPE), + ENTRY(EROFS), + ENTRY(EMLINK), + ENTRY(EPIPE), + ENTRY(EDOM), + ENTRY(ERANGE), + ENTRY(EAGAIN), + { 0, (char *)0 } +}; + +// Enabled during tests +int _json_c_strerror_enable = 0; + +#define PREFIX "ERRNO=" +static char errno_buf[128] = PREFIX; +char *_json_c_strerror(int errno_in) +{ + int start_idx; + char digbuf[20]; + int ii, jj; + + if (!_json_c_strerror_enable) + return strerror(errno_in); + + // Avoid standard functions, so we don't need to include any + // headers, or guess at signatures. + + for (ii = 0; errno_list[ii].errno_str != (char *)0; ii++) + { + const char *errno_str = errno_list[ii].errno_str; + if (errno_list[ii].errno_value != errno_in) + continue; + + for (start_idx = sizeof(PREFIX) - 1, jj = 0; errno_str[jj] != '\0'; jj++, start_idx++) + { + errno_buf[start_idx] = errno_str[jj]; + } + errno_buf[start_idx] = '\0'; + return errno_buf; + } + + // It's not one of the known errno values, return the numeric value. + for (ii = 0; errno_in > 10; errno_in /= 10, ii++) + { + digbuf[ii] = "0123456789"[(errno_in % 10)]; + } + digbuf[ii] = "0123456789"[(errno_in % 10)]; + + // Reverse the digits + for (start_idx = sizeof(PREFIX) - 1 ; ii >= 0; ii--, start_idx++) + { + errno_buf[start_idx] = digbuf[ii]; + } + return errno_buf; +} + diff --git a/third_party/json-c/strerror_override.h b/third_party/json-c/strerror_override.h new file mode 100644 index 0000000000..5674381804 --- /dev/null +++ b/third_party/json-c/strerror_override.h @@ -0,0 +1,30 @@ +#ifndef _json_strerror_override_h_ +#define _json_strerror_override_h_ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#include "config.h" +#include + +#include "json_object.h" /* for JSON_EXPORT */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +JSON_EXPORT char *_json_c_strerror(int errno_in); + +#ifndef STRERROR_OVERRIDE_IMPL +#define strerror _json_c_strerror +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _json_strerror_override_h_ */ diff --git a/third_party/json-c/strerror_override_private.h b/third_party/json-c/strerror_override_private.h new file mode 100644 index 0000000000..5180b4f307 --- /dev/null +++ b/third_party/json-c/strerror_override_private.h @@ -0,0 +1,12 @@ +#ifndef __json_strerror_override_private_h__ +#define __json_strerror_override_private_h__ + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +/* Used by tests to get consistent output */ +extern int _json_c_strerror_enable; + +#endif diff --git a/third_party/json-c/vasprintf_compat.h b/third_party/json-c/vasprintf_compat.h new file mode 100644 index 0000000000..43dbf8939c --- /dev/null +++ b/third_party/json-c/vasprintf_compat.h @@ -0,0 +1,46 @@ +#ifndef __vasprintf_compat_h +#define __vasprintf_compat_h + +/** + * @file + * @brief Do not use, json-c internal, may be changed or removed at any time. + */ + +#include "snprintf_compat.h" + +#if !defined(HAVE_VASPRINTF) +/* CAW: compliant version of vasprintf */ +static int vasprintf(char **buf, const char *fmt, va_list ap) +{ +#ifndef WIN32 + static char _T_emptybuffer = '\0'; +#endif /* !defined(WIN32) */ + int chars; + char *b; + + if(!buf) { return -1; } + +#ifdef WIN32 + chars = _vscprintf(fmt, ap)+1; +#else /* !defined(WIN32) */ + /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite + our buffer like on some 64bit sun systems.... but hey, its time to move on */ + chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1; + if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */ +#endif /* defined(WIN32) */ + + b = (char*)malloc(sizeof(char)*chars); + if(!b) { return -1; } + + if((chars = vsprintf(b, fmt, ap)) < 0) + { + free(b); + } else { + *buf = b; + } + + return chars; +} +#endif /* !HAVE_VASPRINTF */ + +#endif /* __vasprintf_compat_h */