diff options
Diffstat (limited to 'src/fluent-bit/lib/jansson-e23f558')
357 files changed, 19378 insertions, 0 deletions
diff --git a/src/fluent-bit/lib/jansson-e23f558/.gitignore b/src/fluent-bit/lib/jansson-e23f558/.gitignore new file mode 100644 index 000000000..1a028d295 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/.gitignore @@ -0,0 +1,37 @@ +*~ +*.o +*.a +.libs +.deps +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +libtool +ltmain.sh +missing +compile +test-driver +*.lo +*.la +stamp-h1 +*.pyc +*.pc +/src/jansson_config.h +/jansson_private_config.h.in +/jansson_private_config.h +/build +*.exe +.idea +cmake-build-debug/ +*.log +*.trs diff --git a/src/fluent-bit/lib/jansson-e23f558/Android.mk b/src/fluent-bit/lib/jansson-e23f558/Android.mk new file mode 100644 index 000000000..e3b09e72c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/Android.mk @@ -0,0 +1,30 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_ARM_MODE := arm + +LOCAL_SRC_FILES := \ + src/dump.c \ + src/error.c \ + src/hashtable.c \ + src/hashtable_seed.c \ + src/load.c \ + src/memory.c \ + src/pack_unpack.c \ + src/strbuffer.c \ + src/strconv.c \ + src/utf.c \ + src/value.c + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/android \ + $(LOCAL_PATH)/src + +LOCAL_MODULE_TAGS := optional +LOCAL_SHARED_LIBRARIES := libc +LOCAL_CFLAGS += -O3 -DHAVE_STDINT_H=1 + +LOCAL_MODULE:= libjansson + +include $(BUILD_SHARED_LIBRARY) diff --git a/src/fluent-bit/lib/jansson-e23f558/CHANGES b/src/fluent-bit/lib/jansson-e23f558/CHANGES new file mode 100644 index 000000000..cb6ff07cb --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/CHANGES @@ -0,0 +1,986 @@ +Version 2.14 +============ + +Released 2021-09-09 + +* New Features: + + - Add `json_object_getn`, `json_object_setn`, `json_object_deln`, and the + corresponding `nocheck` functions. (#520, by Maxim Zhukov) + +* Fixes: + + - Handle `sprintf` corner cases (#537, by Tobias Stoeckmann) + +* Build: + + - Symbol versioning for all exported symbols (#540, by Simon McVittie) + - Fix compiler warnings (#555, by Kelvin Lee) + +* Documentation: + + - Small fixes (#544, #546, by @i-ky) + - Sphinx 3 compatibility (#543, by Pierce Lopez) + + +Version 2.13.1 +============== + +Released 2020-05-07 + +* Build: + + - Include `jansson_version_str()` and `jansson_version_cmp()` in + shared library. (#534) + + - Include ``scripts/`` in tarball. (#535) + + +Version 2.13 +============ + +Released 2020-05-05 + +* New Features: + + - Add `jansson_version_str()` and `jansson_version_cmp()` for runtime + version checking (#465). + + - Add `json_object_update_new()`, `json_object_update_existing_new()` + and `json_object_update_missing_new()` functions (#499). + + - Add `json_object_update_recursive()` (#505). + +* Build: + + - Add ``-Wno-format-truncation`` to suppress format truncation warnings (#489). + +* Bug fixes: + + - Remove ``strtod`` macro definition for MinGW (#498). + + - Add infinite loop check in `json_deep_copy()` (#490). + + - Add ``pipe`` macro definition for MinGW (#500). + + - Enhance ``JANSSON_ATTRS`` macro to support earlier C standard(C89) (#501). + + - Update version detection for sphinx-build (#502). + +* Documentation: + + - Fix typos (#483, #494). + + - Document that call the custom free function to free the return value + of `json_dumps()` if you have a custom malloc/free (#490). + + - Add vcpkg installation instructions (#496). + + - Document that non-blocking file descriptor is not supported on + `json_loadfd()` (#503). + + +Version 2.12 +============ + +Released 2018-11-26 + +* Bug fixes: + + - Fix error message in `json_pack()` for NULL object (#409). + + - Avoid invalid memory read in `json_pack()` (#421). + + - Call va_end after va_copy in `json_vsprintf()` (#427). + + - Improve handling of formats with '?' and '*' in `json_pack()` (#438). + + - Remove inappropriate `jsonp_free()` which caused segmentation fault in + error handling (#444). + +* Build: + + - Add function attributes for GCC and CLANG to provide warnings on improper + use of jansson routines (#404). + + - Many CMake fixes (#408, #412, #415). + + - Enable -Bsymbolic-functions linker flag whenever possible. + + - Resolve various compiler warnings (#423, #430, #435, #436). + + - Fix code coverage ignored paths (#439). + +* Other: + + - Test coverage improvements (#398, #400). + + - Add VS 2017 to appveyor, update Visual Studio documentation (#417). + + - Update copyright for 2018 (#424). + + - Update install instructions in README (#401). + +Version 2.11 +============ + +Released 2018-02-09 + +* New features: + + - Add `json_pack()` format specifiers s*, o* and O* for values that + can be omitted if null (#339). + + - Add `json_error_code()` to retrieve numeric error codes (#365, #380, + #381). + + - Enable thread safety for `json_dump()` on all systems. Enable thread + safe `json_decref()` and `json_incref()` for modern compilers (#389). + + - Add `json_sprintf()` and `json_vsprintf()` (#393). + +* Bug Fixes: + + - Fix incorrect report of success from `json_dump_file()` when an error + is returned by `fclose()` (#359). + + - Make json_equal() const-correct (#344). + + - Fix incomplete stealing of references by `json_pack()` (#374). + +* Build: + + - Work around gcc's -Wimplicit-fallthrough. + + - Fix CMake detection of ``sys/types.h`` header (#375). + + - Fix `jansson.pc` generated by CMake to be more consistent with the one + generated using GNU Autotools (#368). + +* Other: + + - Miscellaneous documentation fixes (#356, #378, #395). + + - Remove unnecessary reference actions from parsers (#377). + +Version 2.10 +============ + +Released 2017-03-02 + +* New features: + + - Add JSON_EMBED encoding flag allowing arrays and objects to be encoded + into existing streams (#329). + + - Add `json_dumpb()` function for dumping to a pre-allocated buffer (#328). + + - Add `json_dumpfd()` and `json_loadfd()` functions for dumping to streaming + file descriptors (#328). + + - Add support for parsing buffers larger than 2GB (#309). + +* Build: + + - Fix CMake build when LONG_LONG_INT is defined as "" (#321) + +* Other: + + - Internal code cleanup (#311, #314) + +Version 2.9 +=========== + +Released 2016-09-18 + +* New features: + + - Add ``json_auto_t`` to automatically decref a value that goes out + of scope. Available only on GCC and Clang. (#301) + +* Build: + + - Fix CMake build (at least on Linux) by removing conflicting + jansson_config.h from the distribution (#306) + + - Change CMake install target generation to be optional (#305) + +* Documentation: + + - Small documentation fixes. + + +Version 2.8 +=========== + +Released 2016-08-30 + +* New features: + + - Always preserve insertion order of object items. + `json_object_iter()` and friends, `json_object_foreach()` and + `json_dumps()` and friends now always work in the insertion order of + object items (#293). + + - Add `json_object_foreach_safe()` macro that allows + `json_object_del()` calls during iteration (#230). + + - Add `json_get_alloc_funcs()` to allow reading the allocation + functions set by `json_set_alloc_funcs()` (#262, #264). + + - Add `json_pack()` format specifiers s?, o? and O? for values that + can be null (#261, #270). + +* Bug fixes: + + - Fix a crash when parsing inputs consisting of very deeply nested + arrays or objects (#282, #284). + + - Never convert numbers to integers in the parser when + JSON_DECODE_INT_AS_REAL is set. This fixes error messages for + overflowing numbers when JSON_DECODE_INT_AS_REAL is set (#212). + + - Fix a use-after-free in `json_pack()` error handling. + + - Fix subnormal number parsing on mingw32. + + - Handle out-of-memory situations gracefully in the hashtable + implementation (#298). + +* Build: + + - Fix build with CMake on all versions of Visual Studio up to 2015 + (#262, #289). + + - Fix pkgconfig libdir when using CMake (#268). + + - Fix CMake config for static CRT builds on Windows (#206). + + - Fix warnings on LLVM 6.0 targeting iOS arm64 (#208). + + - Add coverlls.io support via Travis for a nice test coverage badge + (#211). + + - Don't expect ``jansson_config.h`` to be in the compiler's include + path (#209). + + - Add a build-time option to set initial hashtable size (#213). + + - Use snprintf and strncpy in place of sprintf and strcpy to silence + linker warnings on OpenBSD (#233). + +* Documentation: + + - Fix various typos in documentation, and a broken link (#258). + + - Add an example program in ``examples/`` (#214, #217). + + - Fix building of documentation man pages (#207). + + - Document the fact that copying objects doesn't preserve the + insertion order of keys (#237). + +* Tests: + + - Don't use the nonstandard __FUNCTION__ macro in tests. + + - Use expr instead of $((...)) in shell scripts for Solaris 10 + compatibility. + + - Disable Visual Studio warning C4756 when triggered deliberately in + tests (#216). + + - Other minor fixes (#221, #248). + +* Other changes: + + - List all unrecognized object keys when strict unpacking fails + (#263). + + - Alter the order of the members of the hashtable_pair struct for + easier debugging. + + - Minor performance improvement to `json_dump()` and friends (#234). + + - Minor style fixes (#255, #257). + + +Version 2.7 +=========== + +Released 2014-10-02 + +* New features: + + - `json_pack()` and friends: Add format specifiers ``s%`` and ``+%`` + for a size_t string length (#141). + + - `json_unpack()` and friends: Add format specifier ``s%`` for + unpacking the string length along with the string itself (#141). + + - Add length-aware string constructors `json_stringn()` and + `json_stringn_nocheck()`, length-aware string mutators + `json_string_setn()` and `json_string_setn_nocheck()`, and a + function for getting string's length `json_string_length()` (#141, + #143). + + - Support ``\u0000`` escapes in the decoder. The support can be + enabled by using the ``JSON_ALLOW_NUL`` decoding flag (#141). + + - Add `json_boolean_value()` as an alias for `json_is_true()` + (#146). + + - Add JSON_REAL_PRECISION encoding flag/macro for controlling real + number precision (#178). + + - Define the maximum indentation as JSON_MAX_INDENT (#191). + +* Bug fixes: + + - Some malformed ``\uNNNN`` escapes could crash the decoder with an + assertion failure. + + - Avoid integer overflows with very long strings in UTF-8 decoder and + hashtable. + + - Check for *NULL* key in `json_object_get()` and + `json_object_del()` (#151). + + - Enhance hashtable seeding on Windows (#162). + + - `json_unpack()`: Allow mixing JSON_STRICT with optional keys + (#162, #163). + + - Fix int/int32 mismatch (#142). + + - Parse subnormal numbers correctly (#202). + +* Build: + + - Remove VS2010 build files. CMake should be used on Windows instead + (#165). + + - Fix CMake build flags for MinGW (#193). + + - Add CMake config files for find_package. Rename config.h to + jansson_private_config.h (#157, #159). + + - Make Valgrind checks work with CMake (#160). + + - Fix feature checks to use correct __ATOMIC flags. + + - Fix CMake checks for uint16_t and uint8_t support (#177). + + - Make Jansson build on SmartOS/Solaris (#171). + + - Work around a GCC bug on Solaris (#175). + + - Fix autoreconf on Debian (#182). + + - Don't use GNU make specific export for global AM_CFLAGS (#203, + #204). + + - Fix building on Android using the supplied Android.mk (#166, + #174). + + - Android.mk: Add -DHAVE_STDINT_H to LOCAL_CFLAGS (#200). + +* Documentation: + + - Document JANSSON_BUILD_SHARED_LIBS CMake option (#187). + +* Tests: + + - Close file handles correctly (#198). + +* Other changes: + + - ``\uNNNN`` escapes are now encoded in upper case for better + readability. + + - Enable usage of AddressSanitizer (#180). + + +Version 2.6 +=========== + +Released 2014-02-11 + +* Security: + + - CVE-2013-6401: The hash function used by the hashtable + implementation has been changed, and is automatically seeded with + random data when the first JSON object is created. This prevents + an attacker from causing large JSON objects with specially crafted + keys perform poorly. + +* New features: + + - `json_object_seed()`: Set the seed value of the hash function. + +* Bug fixes: + + - Include CMake specific files in the release tarball. + +* Documentation: + + - Fix tutorial source to send a User-Agent header, which is now + required by the GitHub API. + + - Set all memory to zero in secure_free() example. + + +Version 2.5 +=========== + +Released 2013-09-19 + +* New features: + + - `json_pack()` and friends: Add format specifiers ``s#``, ``+`` and + ``+#``. + + - Add ``JSON_DECODE_INT_AS_REAL`` decoding flag to treat all numbers + as real in the decoder (#123). + + - Add `json_array_foreach()`, paralleling `json_object_foreach()` + (#118). + +* Bug fixes: + + - `json_dumps()` and friends: Don't crash if json is *NULL* and + ``JSON_ENCODE_ANY`` is set. + + - Fix a theoretical integer overflow in `jsonp_strdup()`. + + - Fix `l_isxdigit()` macro (#97). + + - Fix an off-by-one error in `json_array_remove()`. + +* Build: + + - Support CMake in addition to GNU Autotools (#106, #107, #112, + #115, #120, #127). + + - Support building for Android (#109). + + - Don't use ``-Werror`` by default. + + - Support building and testing with VPATH (#93). + + - Fix compilation when ``NDEBUG`` is defined (#128) + +* Tests: + + - Fix a refleak in ``test/bin/json_process.c``. + +* Documentation: + + - Clarify the return value of `json_load_callback_t`. + + - Document how to circumvent problems with separate heaps on Windows. + + - Fix memory leaks and warnings in ``github_commits.c``. + + - Use `json_decref()` properly in tutorial. + +* Other: + + - Make it possible to forward declare ``struct json_t``. + + +Version 2.4 +=========== + +Released 2012-09-23 + +* New features: + + - Add `json_boolean()` macro that returns the JSON true or false + value based on its argument (#86). + + - Add `json_load_callback()` that calls a callback function + repeatedly to read the JSON input (#57). + + - Add JSON_ESCAPE_SLASH encoding flag to escape all occurences of + ``/`` with ``\/``. + +* Bug fixes: + + - Check for and reject NaN and Inf values for reals. Encoding these + values resulted in invalid JSON. + + - Fix `json_real_set()` to return -1 on error. + +* Build: + + - Jansson now builds on Windows with Visual Studio 2010, and + includes solution and project files in ``win32/vs2010/`` + directory. + + - Fix build warnings (#77, #78). + + - Add ``-no-undefined`` to LDFLAGS (#90). + +* Tests: + + - Fix the symbol exports test on Linux/PPC64 (#88). + +* Documentation: + + - Fix typos (#73, #84). + + +Version 2.3.1 +============= + +Released 2012-04-20 + +* Build issues: + + - Only use ``long long`` if ``strtoll()`` is also available. + +* Documentation: + + - Fix the names of library version constants in documentation. (#52) + + - Change the tutorial to use GitHub API v3. (#65) + +* Tests: + + - Make some tests locale independent. (#51) + + - Distribute the library exports test in the tarball. + + - Make test run on shells that don't support the ``export FOO=bar`` + syntax. + + +Version 2.3 +=========== + +Released 2012-01-27 + +* New features: + + - `json_unpack()` and friends: Add support for optional object keys + with the ``{s?o}`` syntax. + + - Add `json_object_update_existing()` and + `json_object_update_missing()`, for updating only existing keys or + only adding missing keys to an object. (#37) + + - Add `json_object_foreach()` for more convenient iteration over + objects. (#45, #46) + + - When decoding JSON, write the number of bytes that were read from + input to ``error.position`` also on success. This is handy with + ``JSON_DISABLE_EOF_CHECK``. + + - Add support for decoding any JSON value, not just arrays or + objects. The support is enabled with the new ``JSON_DECODE_ANY`` + flag. Patch by Andrea Marchesini. (#4) + +* Bug fixes + + - Avoid problems with object's serial number growing too big. (#40, + #41) + + - Decoding functions now return NULL if the first argument is NULL. + Patch by Andrea Marchesini. + + - Include ``jansson_config.h.win32`` in the distribution tarball. + + - Remove ``+`` and leading zeros from exponents in the encoder. + (#39) + + - Make Jansson build and work on MinGW. (#39, #38) + +* Documentation + + - Note that the same JSON values must not be encoded in parallel by + separate threads. (#42) + + - Document MinGW support. + + +Version 2.2.1 +============= + +Released 2011-10-06 + +* Bug fixes: + + - Fix real number encoding and decoding under non-C locales. (#32) + + - Fix identifier decoding under non-UTF-8 locales. (#35) + + - `json_load_file()`: Open the input file in binary mode for maximum + compatiblity. + +* Documentation: + + - Clarify the lifecycle of the result of the ``s`` fromat of + `json_unpack()`. (#31) + + - Add some portability info. (#36) + + - Little clarifications here and there. + +* Other: + + - Some style fixes, issues detected by static analyzers. + + +Version 2.2 +=========== + +Released 2011-09-03 + +* New features: + + - `json_dump_callback()`: Pass the encoder output to a callback + function in chunks. + +* Bug fixes: + + - `json_string_set()`: Check that target is a string and value is + not NULL. + +* Other: + + - Documentation typo fixes and clarifications. + + +Version 2.1 +=========== + +Released 2011-06-10 + +* New features: + + - `json_loadb()`: Decode a string with a given size, useful if the + string is not null terminated. + + - Add ``JSON_ENCODE_ANY`` encoding flag to allow encoding any JSON + value. By default, only arrays and objects can be encoded. (#19) + + - Add ``JSON_REJECT_DUPLICATES`` decoding flag to issue a decoding + error if any JSON object in the input contins duplicate keys. (#3) + + - Add ``JSON_DISABLE_EOF_CHECK`` decoding flag to stop decoding after a + valid JSON input. This allows other data after the JSON data. + +* Bug fixes: + + - Fix an additional memory leak when memory allocation fails in + `json_object_set()` and friends. + + - Clear errno before calling `strtod()` for better portability. (#27) + +* Building: + + - Avoid set-but-not-used warning/error in a test. (#20) + +* Other: + + - Minor clarifications to documentation. + + +Version 2.0.1 +============= + +Released 2011-03-31 + +* Bug fixes: + + - Replace a few `malloc()` and `free()` calls with their + counterparts that support custom memory management. + + - Fix object key hashing in json_unpack() strict checking mode. + + - Fix the parentheses in ``JANSSON_VERSION_HEX`` macro. + + - Fix `json_object_size()` return value. + + - Fix a few compilation issues. + +* Portability: + + - Enhance portability of `va_copy()`. + + - Test framework portability enhancements. + +* Documentation: + + - Distribute ``doc/upgrading.rst`` with the source tarball. + + - Build documentation in strict mode in ``make distcheck``. + + +Version 2.0 +=========== + +Released 2011-02-28 + +This release is backwards incompatible with the 1.x release series. +See the chapter "Upgrading from older versions" in documentation for +details. + +* Backwards incompatible changes: + + - Unify unsigned integer usage in the API: All occurences of + unsigned int and unsigned long have been replaced with size_t. + + - Change JSON integer's underlying type to the widest signed integer + type available, i.e. long long if it's supported, otherwise long. + Add a typedef json_int_t that defines the type. + + - Change the maximum indentation depth to 31 spaces in encoder. This + frees up bits from the flags parameter of encoding functions + `json_dumpf()`, `json_dumps()` and `json_dump_file()`. + + - For future needs, add a flags parameter to all decoding functions + `json_loadf()`, `json_loads()` and `json_load_file()`. + +* New features + + - `json_pack()`, `json_pack_ex()`, `json_vpack_ex()`: Create JSON + values based on a format string. + + - `json_unpack()`, `json_unpack_ex()`, `json_vunpack_ex()`: Simple + value extraction and validation functionality based on a format + string. + + - Add column, position and source fields to the ``json_error_t`` + struct. + + - Enhance error reporting in the decoder. + + - ``JANSSON_VERSION`` et al.: Preprocessor constants that define the + library version. + + - `json_set_alloc_funcs()`: Set custom memory allocation functions. + +* Fix many portability issues, especially on Windows. + +* Configuration + + - Add file ``jansson_config.h`` that contains site specific + configuration. It's created automatically by the configure script, + or can be created by hand if the configure script cannot be used. + The file ``jansson_config.h.win32`` can be used without + modifications on Windows systems. + + - Add a section to documentation describing how to build Jansson on + Windows. + + - Documentation now requires Sphinx 1.0 or newer. + + +Version 1.3 +=========== + +Released 2010-06-13 + +* New functions: + + - `json_object_iter_set()`, `json_object_iter_set_new()`: Change + object contents while iterating over it. + + - `json_object_iter_at()`: Return an iterator that points to a + specific object item. + +* New encoding flags: + + - ``JSON_PRESERVE_ORDER``: Preserve the insertion order of object + keys. + +* Bug fixes: + + - Fix an error that occured when an array or object was first + encoded as empty, then populated with some data, and then + re-encoded + + - Fix the situation like above, but when the first encoding resulted + in an error + +* Documentation: + + - Clarify the documentation on reference stealing, providing an + example usage pattern + + +Version 1.2.1 +============= + +Released 2010-04-03 + +* Bug fixes: + + - Fix reference counting on ``true``, ``false`` and ``null`` + - Estimate real number underflows in decoder with 0.0 instead of + issuing an error + +* Portability: + + - Make ``int32_t`` available on all systems + - Support compilers that don't have the ``inline`` keyword + - Require Autoconf 2.60 (for ``int32_t``) + +* Tests: + + - Print test names correctly when ``VERBOSE=1`` + - ``test/suites/api``: Fail when a test fails + - Enhance tests for iterators + - Enhance tests for decoding texts that contain null bytes + +* Documentation: + + - Don't remove ``changes.rst`` in ``make clean`` + - Add a chapter on RFC conformance + + +Version 1.2 +=========== + +Released 2010-01-21 + +* New functions: + + - `json_equal()`: Test whether two JSON values are equal + - `json_copy()` and `json_deep_copy()`: Make shallow and deep copies + of JSON values + - Add a version of all functions taking a string argument that + doesn't check for valid UTF-8: `json_string_nocheck()`, + `json_string_set_nocheck()`, `json_object_set_nocheck()`, + `json_object_set_new_nocheck()` + +* New encoding flags: + + - ``JSON_SORT_KEYS``: Sort objects by key + - ``JSON_ENSURE_ASCII``: Escape all non-ASCII Unicode characters + - ``JSON_COMPACT``: Use a compact representation with all unneeded + whitespace stripped + +* Bug fixes: + + - Revise and unify whitespace usage in encoder: Add spaces between + array and object items, never append newline to output. + - Remove const qualifier from the ``json_t`` parameter in + `json_string_set()`, `json_integer_set()` and `json_real_set`. + - Use ``int32_t`` internally for representing Unicode code points + (int is not enough on all platforms) + +* Other changes: + + - Convert ``CHANGES`` (this file) to reStructured text and add it to + HTML documentation + - The test system has been refactored. Python is no longer required + to run the tests. + - Documentation can now be built by invoking ``make html`` + - Support for pkg-config + + +Version 1.1.3 +============= + +Released 2009-12-18 + +* Encode reals correctly, so that first encoding and then decoding a + real always produces the same value +* Don't export private symbols in ``libjansson.so`` + + +Version 1.1.2 +============= + +Released 2009-11-08 + +* Fix a bug where an error message was not produced if the input file + could not be opened in `json_load_file()` +* Fix an assertion failure in decoder caused by a minus sign without a + digit after it +* Remove an unneeded include of ``stdint.h`` in ``jansson.h`` + + +Version 1.1.1 +============= + +Released 2009-10-26 + +* All documentation files were not distributed with v1.1; build + documentation in make distcheck to prevent this in the future +* Fix v1.1 release date in ``CHANGES`` + + +Version 1.1 +=========== + +Released 2009-10-20 + +* API additions and improvements: + + - Extend array and object APIs + - Add functions to modify integer, real and string values + - Improve argument validation + - Use unsigned int instead of ``uint32_t`` for encoding flags + +* Enhance documentation + + - Add getting started guide and tutorial + - Fix some typos + - General clarifications and cleanup + +* Check for integer and real overflows and underflows in decoder +* Make singleton values thread-safe (``true``, ``false`` and ``null``) +* Enhance circular reference handling +* Don't define ``-std=c99`` in ``AM_CFLAGS`` +* Add C++ guards to ``jansson.h`` +* Minor performance and portability improvements +* Expand test coverage + + +Version 1.0.4 +============= + +Released 2009-10-11 + +* Relax Autoconf version requirement to 2.59 +* Make Jansson compile on platforms where plain ``char`` is unsigned +* Fix API tests for object + + +Version 1.0.3 +============= + +Released 2009-09-14 + +* Check for integer and real overflows and underflows in decoder +* Use the Python json module for tests, or simplejson if the json + module is not found +* Distribute changelog (this file) + + +Version 1.0.2 +============= + +Released 2009-09-08 + +* Handle EOF correctly in decoder + + +Version 1.0.1 +============= + +Released 2009-09-04 + +* Fixed broken `json_is_boolean()` + + +Version 1.0 +=========== + +Released 2009-08-25 + +* Initial release diff --git a/src/fluent-bit/lib/jansson-e23f558/CMakeLists.txt b/src/fluent-bit/lib/jansson-e23f558/CMakeLists.txt new file mode 100644 index 000000000..ed33e3c47 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/CMakeLists.txt @@ -0,0 +1,662 @@ +cmake_minimum_required (VERSION 3.1) +project(jansson C) + +# Options +option(JANSSON_BUILD_SHARED_LIBS "Build shared libraries." OFF) +option(USE_URANDOM "Use /dev/urandom to seed the hash function." ON) +option(USE_WINDOWS_CRYPTOAPI "Use CryptGenRandom to seed the hash function." ON) + +if (MSVC) + # This option must match the settings used in your program, in particular if you + # are linking statically + option(JANSSON_STATIC_CRT "Link the static CRT libraries" OFF ) +endif () + +option(JANSSON_EXAMPLES "Compile example applications" ON) + +if (UNIX) + option(JANSSON_COVERAGE "(GCC Only! Requires gcov/lcov to be installed). Include target for doing coverage analysis for the test suite. Note that -DCMAKE_BUILD_TYPE=Debug must be set" OFF) +endif () + +# Set some nicer output dirs. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(JANSSON_TEMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/tmp) + +# Give the debug version a different postfix for windows, +# so both the debug and release version can be built in the +# same build-tree on Windows (MSVC). +if (WIN32 AND NOT CMAKE_DEBUG_POSTFIX) + set(CMAKE_DEBUG_POSTFIX "_d") +endif() + +# This is how I thought it should go +# set (JANSSON_VERSION "2.3.1") +# set (JANSSON_SOVERSION 2) + +set(JANSSON_DISPLAY_VERSION "2.14") + +# This is what is required to match the same numbers as automake's +set(JANSSON_VERSION "4.14.0") +set(JANSSON_SOVERSION 4) + +# for CheckFunctionKeywords +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include (CheckCSourceCompiles) +include (CheckFunctionExists) +include (CheckFunctionKeywords) +include (CheckIncludeFiles) +include (CheckTypeSize) + +# suppress format-truncation warning +include (CheckCCompilerFlag) +check_c_compiler_flag(-Wno-format-truncation HAS_NO_FORMAT_TRUNCATION) +if (HAS_NO_FORMAT_TRUNCATION) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-truncation") +endif() + +if (MSVC) + # Turn off Microsofts "security" warnings. + add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo" ) + + if (JANSSON_STATIC_CRT) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") + endif() +endif() + +message("C compiler: ${CMAKE_C_COMPILER_ID}") + +if (JANSSON_COVERAGE) + include(CodeCoverage) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") +endif() + +check_include_files (endian.h HAVE_ENDIAN_H) +check_include_files (fcntl.h HAVE_FCNTL_H) +check_include_files (sched.h HAVE_SCHED_H) +check_include_files (unistd.h HAVE_UNISTD_H) +check_include_files (sys/param.h HAVE_SYS_PARAM_H) +check_include_files (sys/stat.h HAVE_SYS_STAT_H) +check_include_files (sys/time.h HAVE_SYS_TIME_H) +check_include_files (sys/types.h HAVE_SYS_TYPES_H) + +check_function_exists (close HAVE_CLOSE) +check_function_exists (getpid HAVE_GETPID) +check_function_exists (gettimeofday HAVE_GETTIMEOFDAY) +check_function_exists (open HAVE_OPEN) +check_function_exists (read HAVE_READ) +check_function_exists (sched_yield HAVE_SCHED_YIELD) + +# Check for the int-type includes +check_include_files (stdint.h HAVE_STDINT_H) + +# Check our 64 bit integer sizes +check_type_size (__int64 __INT64) +check_type_size (int64_t INT64_T) +check_type_size ("long long" LONG_LONG_INT) + +# Check our 32 bit integer sizes +check_type_size (int32_t INT32_T) +check_type_size (__int32 __INT32) +check_type_size ("long" LONG_INT) +check_type_size ("int" INT) +if (HAVE_INT32_T) + set (JSON_INT32 int32_t) +elseif (HAVE___INT32) + set (JSON_INT32 __int32) +elseif (HAVE_LONG_INT AND (LONG_INT EQUAL 4)) + set (JSON_INT32 long) +elseif (HAVE_INT AND (INT EQUAL 4)) + set (JSON_INT32 int) +else () + message (FATAL_ERROR "Could not detect a valid 32-bit integer type") +endif () + +check_type_size ("unsigned long" UNSIGNED_LONG_INT) +check_type_size ("unsigned int" UNSIGNED_INT) +check_type_size ("unsigned short" UNSIGNED_SHORT) + +check_type_size (uint32_t UINT32_T) +check_type_size (__uint32 __UINT32) +if (HAVE_UINT32_T) + set (JSON_UINT32 uint32_t) +elseif (HAVE___UINT32) + set (JSON_UINT32 __uint32) +elseif (HAVE_UNSIGNED_LONG_INT AND (UNSIGNED_LONG_INT EQUAL 4)) + set (JSON_UINT32 "unsigned long") +elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 4)) + set (JSON_UINT32 "unsigned int") +else () + message (FATAL_ERROR "Could not detect a valid unsigned 32-bit integer type") +endif () + +check_type_size (uint16_t UINT16_T) +check_type_size (__uint16 __UINT16) +if (HAVE_UINT16_T) + set (JSON_UINT16 uint16_t) +elseif (HAVE___UINT16) + set (JSON_UINT16 __uint16) +elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 2)) + set (JSON_UINT16 "unsigned int") +elseif (HAVE_UNSIGNED_SHORT AND (UNSIGNED_SHORT EQUAL 2)) + set (JSON_UINT16 "unsigned short") +else () + message (FATAL_ERROR "Could not detect a valid unsigned 16-bit integer type") +endif () + +check_type_size (uint8_t UINT8_T) +check_type_size (__uint8 __UINT8) +if (HAVE_UINT8_T) + set (JSON_UINT8 uint8_t) +elseif (HAVE___UINT8) + set (JSON_UINT8 __uint8) +else () + set (JSON_UINT8 "unsigned char") +endif () + +# Check for ssize_t and SSIZE_T existence. +check_type_size(ssize_t SSIZE_T) +check_type_size(SSIZE_T UPPERCASE_SSIZE_T) +if(NOT HAVE_SSIZE_T) + if(HAVE_UPPERCASE_SSIZE_T) + set(JSON_SSIZE SSIZE_T) + else() + set(JSON_SSIZE int) + endif() +endif() +set(CMAKE_EXTRA_INCLUDE_FILES "") + +# Check for all the variants of strtoll +check_function_exists (strtoll HAVE_STRTOLL) +check_function_exists (strtoq HAVE_STRTOQ) +check_function_exists (_strtoi64 HAVE__STRTOI64) + +# Figure out what variant we should use +if (HAVE_STRTOLL) + set (JSON_STRTOINT strtoll) +elseif (HAVE_STRTOQ) + set (JSON_STRTOINT strtoq) +elseif (HAVE__STRTOI64) + set (JSON_STRTOINT _strtoi64) +else () + # fallback to strtol (32 bit) + # this will set all the required variables + set (JSON_STRTOINT strtol) + set (JSON_INT_T long) + set (JSON_INTEGER_FORMAT "\"ld\"") +endif () + +# if we haven't defined JSON_INT_T, then we have a 64 bit conversion function. +# detect what to use for the 64 bit type. +# Note: I will prefer long long if I can get it, as that is what the automake system aimed for. +if (NOT DEFINED JSON_INT_T) + if (HAVE_LONG_LONG_INT AND (LONG_LONG_INT EQUAL 8)) + set (JSON_INT_T "long long") + elseif (HAVE_INT64_T) + set (JSON_INT_T int64_t) + elseif (HAVE___INT64) + set (JSON_INT_T __int64) + else () + message (FATAL_ERROR "Could not detect 64 bit type, although I detected the strtoll equivalent") + endif () + + # Apparently, Borland BCC and MSVC wants I64d, + # Borland BCC could also accept LD + # and gcc wants ldd, + # I am not sure what cygwin will want, so I will assume I64d + + if (WIN32) # matches both msvc and cygwin + set (JSON_INTEGER_FORMAT "\"I64d\"") + else () + set (JSON_INTEGER_FORMAT "\"lld\"") + endif () +endif () + + +# If locale.h and localeconv() are available, define to 1, otherwise to 0. +check_include_files (locale.h HAVE_LOCALE_H) +check_function_exists (localeconv HAVE_LOCALECONV) + +if (HAVE_LOCALECONV AND HAVE_LOCALE_H) + set (JSON_HAVE_LOCALECONV 1) +else () + set (JSON_HAVE_LOCALECONV 0) +endif() + +# check if we have setlocale +check_function_exists(setlocale HAVE_SETLOCALE) + +# Check what the inline keyword is. +# Note that the original JSON_INLINE was always set to just 'inline', so this goes further. +check_function_keywords("inline") +check_function_keywords("__inline") +check_function_keywords("__inline__") + +if (HAVE_INLINE) + set(JSON_INLINE inline) +elseif (HAVE___INLINE) + set(JSON_INLINE __inline) +elseif (HAVE___INLINE__) + set(JSON_INLINE __inline__) +else() + # no inline on this platform + set (JSON_INLINE) +endif() + +check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1); return 0; } " HAVE_SYNC_BUILTINS) +check_c_source_compiles ("int main() { char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE); return 0; }" HAVE_ATOMIC_BUILTINS) + +if (HAVE_SYNC_BUILTINS) + set(JSON_HAVE_SYNC_BUILTINS 1) +else() + set(JSON_HAVE_SYNC_BUILTINS 0) +endif() + +if (HAVE_ATOMIC_BUILTINS) + set(JSON_HAVE_ATOMIC_BUILTINS 1) +else() + set(JSON_HAVE_ATOMIC_BUILTINS 0) +endif() + +set (JANSSON_INITIAL_HASHTABLE_ORDER 3 CACHE STRING "Number of buckets new object hashtables contain is 2 raised to this power. The default is 3, so empty hashtables contain 2^3 = 8 buckets.") + +# configure the public config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h) + +# Copy the jansson.h file to the public include folder +file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + +add_definitions(-DJANSSON_USING_CMAKE) + +# configure the private config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_private_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h) + +# and tell the source code to include it +add_definitions(-DHAVE_CONFIG_H) + +include_directories (${CMAKE_CURRENT_BINARY_DIR}/include) +include_directories (${CMAKE_CURRENT_BINARY_DIR}/private_include) + +# Add the lib sources. +file(GLOB JANSSON_SRC src/*.c) + +set(JANSSON_HDR_PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src/hashtable.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson_private.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/strbuffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/utf.h + ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h) + +set(JANSSON_HDR_PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h) + +source_group("Library Sources" FILES ${JANSSON_SRC}) +source_group("Library Private Headers" FILES ${JANSSON_HDR_PRIVATE}) +source_group("Library Public Headers" FILES ${JANSSON_HDR_PUBLIC}) + +if(JANSSON_BUILD_SHARED_LIBS) + add_library(jansson SHARED + ${JANSSON_SRC} + ${JANSSON_HDR_PRIVATE} + ${JANSSON_HDR_PUBLIC} + src/jansson.def) + +# check if linker support --default-symver + list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,--default-symver") + check_c_source_compiles( + " + int main (void) + { + return 0; + } + " + DSYMVER_WORKS + ) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,--default-symver") + + if (SYMVER_WORKS) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--default-symver") + else() +# some linkers may only support --version-script + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/jansson.sym" "JANSSON_${JANSSON_SOVERSION} { + global: + *; +}; +") + list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym") + check_c_source_compiles( + " + int main (void) + { + return 0; + } + " + VSCRIPT_WORKS + ) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym") + if (VSCRIPT_WORKS) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/jansson.sym") + endif() + endif() + + set_target_properties(jansson PROPERTIES + VERSION ${JANSSON_VERSION} + SOVERSION ${JANSSON_SOVERSION}) +else() + add_library(jansson STATIC + ${JANSSON_SRC} + ${JANSSON_HDR_PRIVATE} + ${JANSSON_HDR_PUBLIC}) + set_target_properties(jansson PROPERTIES + POSITION_INDEPENDENT_CODE true) +endif() + +if (JANSSON_EXAMPLES) + add_executable(simple_parse "${CMAKE_CURRENT_SOURCE_DIR}/examples/simple_parse.c") + target_link_libraries(simple_parse jansson) +endif() + +# For building Documentation (uses Sphinx) +option(JANSSON_BUILD_DOCS "Build documentation (uses python-sphinx)." ON) +if (JANSSON_BUILD_DOCS) + find_package(Sphinx) + + if (NOT SPHINX_FOUND) + message(WARNING "Sphinx not found. Cannot generate documentation! + Set -DJANSSON_BUILD_DOCS=OFF to get rid of this message.") + else() + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Your Sphinx version is too old! + This project requires Sphinx v1.0 or above to produce + proper documentation (you have v${Sphinx_VERSION_STRING}). + You will get output but it will have errors.") + endif() + + # configured documentation tools and intermediate build results + set(BINARY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_build") + + # Sphinx cache with pickled ReST documents + set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees") + + # CMake could be used to build the conf.py file too, + # eg it could automatically write the version of the program or change the theme. + # if(NOT DEFINED SPHINX_THEME) + # set(SPHINX_THEME default) + # endif() + # + # if(NOT DEFINED SPHINX_THEME_DIR) + # set(SPHINX_THEME_DIR) + # endif() + # + # configure_file( + # "${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" + # "${BINARY_BUILD_DIR}/conf.py" + # @ONLY) + + # TODO: Add support for all sphinx builders: http://sphinx-doc.org/builders.html + + # Add documentation targets. + set(DOC_TARGETS html) + + option(JANSSON_BUILD_MAN "Create a target for building man pages." ON) + + if (JANSSON_BUILD_MAN) + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Sphinx version 1.0 > is required to build man pages. You have v${Sphinx_VERSION_STRING}.") + else() + list(APPEND DOC_TARGETS man) + endif() + endif() + + option(JANSSON_BUILD_LATEX "Create a target for building latex docs (to create PDF)." OFF) + + if (JANSSON_BUILD_LATEX) + find_package(LATEX) + + if (NOT LATEX_COMPILER) + message("Couldn't find Latex, can't build latex docs using Sphinx") + else() + message("Latex found! If you have problems building, see Sphinx documentation for required Latex packages.") + list(APPEND DOC_TARGETS latex) + endif() + endif() + + # The doc target will build all documentation targets. + add_custom_target(doc) + + foreach (DOC_TARGET ${DOC_TARGETS}) + add_custom_target(${DOC_TARGET} + ${SPHINX_EXECUTABLE} + # -q # Enable for quiet mode + -b ${DOC_TARGET} + -d "${SPHINX_CACHE_DIR}" + # -c "${BINARY_BUILD_DIR}" # enable if using cmake-generated conf.py + "${CMAKE_CURRENT_SOURCE_DIR}/doc" + "${CMAKE_CURRENT_BINARY_DIR}/doc/${DOC_TARGET}" + COMMENT "Building ${DOC_TARGET} documentation with Sphinx") + + add_dependencies(doc ${DOC_TARGET}) + endforeach() + + message("Building documentation enabled for: ${DOC_TARGETS}") + endif() +endif () + + +option(JANSSON_WITHOUT_TESTS "Don't build tests ('make test' to execute tests)" OFF) + +if (NOT JANSSON_WITHOUT_TESTS) + option(JANSSON_TEST_WITH_VALGRIND "Enable valgrind tests." OFF) + + ENABLE_TESTING() + + if (JANSSON_TEST_WITH_VALGRIND) + # TODO: Add FindValgrind.cmake instead of having a hardcoded path. + + add_definitions(-DVALGRIND) + + # enable valgrind + set(CMAKE_MEMORYCHECK_COMMAND valgrind) + set(CMAKE_MEMORYCHECK_COMMAND_OPTIONS + "--error-exitcode=1 --leak-check=full --show-reachable=yes --track-origins=yes -q") + + set(MEMCHECK_COMMAND + "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}") + separate_arguments(MEMCHECK_COMMAND) + endif () + + # + # Test suites. + # + if (CMAKE_COMPILER_IS_GNUCC) + add_definitions(-Wall -Wextra -Wdeclaration-after-statement) + endif () + + set(api_tests + test_array + test_chaos + test_copy + test_dump + test_dump_callback + test_equal + test_fixed_size + test_load + test_load_callback + test_loadb + test_number + test_object + test_pack + test_simple + test_sprintf + test_unpack) + + # Doing arithmetic on void pointers is not allowed by Microsofts compiler + # such as secure_malloc and secure_free is doing, so exclude it for now. + if (NOT MSVC) + list(APPEND api_tests test_memory_funcs) + endif() + + # Helper macro for building and linking a test program. + macro(build_testprog name dir) + add_executable(${name} ${dir}/${name}.c) + add_dependencies(${name} jansson) + target_link_libraries(${name} jansson) + endmacro(build_testprog) + + # Create executables and tests/valgrind tests for API tests. + foreach (test ${api_tests}) + build_testprog(${test} ${CMAKE_CURRENT_SOURCE_DIR}/test/suites/api) + + if (JANSSON_TEST_WITH_VALGRIND) + add_test(memcheck__${test} + ${MEMCHECK_COMMAND} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test} + WORKING_DIRECTORY ${JANSSON_TEMP_DIR}) + else() + add_test(${test} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test} + WORKING_DIRECTORY ${JANSSON_TEMP_DIR}) + endif () + endforeach () + + # Test harness for the suites tests. + build_testprog(json_process ${CMAKE_CURRENT_SOURCE_DIR}/test/bin) + + set(SUITE_TEST_CMD ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process) + set(SUITES encoding-flags valid invalid invalid-unicode) + foreach (SUITE ${SUITES}) + file(GLOB TESTDIRS test/suites/${SUITE}/*) + + foreach (TESTDIR ${TESTDIRS}) + if (IS_DIRECTORY ${TESTDIR}) + get_filename_component(TNAME ${TESTDIR} NAME) + + if (JANSSON_TEST_WITH_VALGRIND) + add_test(memcheck__${SUITE}__${TNAME} + ${MEMCHECK_COMMAND} ${SUITE_TEST_CMD} ${TESTDIR}) + else() + add_test(${SUITE}__${TNAME} + ${SUITE_TEST_CMD} ${TESTDIR}) + endif() + + if ((${SUITE} STREQUAL "valid" OR ${SUITE} STREQUAL "invalid") AND NOT EXISTS ${TESTDIR}/nostrip) + if (JANSSON_TEST_WITH_VALGRIND) + add_test(memcheck__${SUITE}__${TNAME}__strip + ${MEMCHECK_COMMAND} ${SUITE_TEST_CMD} --strip ${TESTDIR}) + else() + add_test(${SUITE}__${TNAME}__strip + ${SUITE_TEST_CMD} --strip ${TESTDIR}) + endif() + endif () + endif () + endforeach () + endforeach () + + if (JANSSON_COVERAGE) + SETUP_TARGET_FOR_COVERAGE(coverage coverage ctest) + endif () + + # Enable using "make check" just like the autotools project. + # By default cmake creates a target "make test" + add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} + DEPENDS json_process ${api_tests}) +endif () + +# +# Installation preparation. +# + +# Allow the user to override installation directories. +set(JANSSON_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") +set(JANSSON_INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") +set(JANSSON_INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") + +if(WIN32 AND NOT CYGWIN) + set(DEF_INSTALL_CMAKE_DIR cmake) +else() + set(DEF_INSTALL_CMAKE_DIR lib/cmake/jansson) +endif() + +set(JANSSON_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") + +# Create pkg-conf file. +# (We use the same files as ./configure does, so we +# have to defined the same variables used there). +set(prefix ${CMAKE_INSTALL_PREFIX}) +set(exec_prefix "\${prefix}") +set(libdir "\${exec_prefix}/${JANSSON_INSTALL_LIB_DIR}") +set(includedir "\${prefix}/${JANSSON_INSTALL_INCLUDE_DIR}") +set(VERSION ${JANSSON_DISPLAY_VERSION}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jansson.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc @ONLY) + +# Make sure the paths are relative. +foreach(p LIB BIN INCLUDE CMAKE) + set(var JANSSON_INSTALL_${p}_DIR) +endforeach() + +# Generate the config file for the build-tree. +set(JANSSON__INCLUDE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_BINARY_DIR}/include") +set(JANSSON_INCLUDE_DIRS ${JANSSON__INCLUDE_DIRS} CACHE PATH "Jansson include directories") +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/janssonConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/janssonConfig.cmake + @ONLY) + + +# Generate the config file for the installation tree. +include(CMakePackageConfigHelpers) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake" + VERSION ${JANSSON_VERSION} + COMPATIBILITY ExactVersion +) + +configure_package_config_file( + "cmake/janssonConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake" + INSTALL_DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}" +) + +# +# Install targets. +# +option(JANSSON_INSTALL "Generate installation target" ON) +if (JANSSON_INSTALL) + install(TARGETS jansson + EXPORT janssonTargets + LIBRARY DESTINATION "lib" + ARCHIVE DESTINATION "lib" + RUNTIME DESTINATION "bin" + INCLUDES DESTINATION "include") + + install(FILES ${JANSSON_HDR_PUBLIC} + DESTINATION "include") + + # Install the pkg-config. + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc + DESTINATION lib/pkgconfig) + + # Install the configs. + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake + DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}") + + # Install exports for the install-tree. + install(EXPORT janssonTargets + NAMESPACE jansson:: + DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}") +endif() + +# For use when simply using add_library from a parent project to build jansson. +set(JANSSON_LIBRARIES jansson CACHE STRING "jansson libraries") diff --git a/src/fluent-bit/lib/jansson-e23f558/CleanSpec.mk b/src/fluent-bit/lib/jansson-e23f558/CleanSpec.mk new file mode 100644 index 000000000..b84e1b65e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/CleanSpec.mk @@ -0,0 +1,49 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ diff --git a/src/fluent-bit/lib/jansson-e23f558/LICENSE b/src/fluent-bit/lib/jansson-e23f558/LICENSE new file mode 100644 index 000000000..483459ca9 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2009-2020 Petri Lehtinen <petri@digip.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/fluent-bit/lib/jansson-e23f558/Makefile.am b/src/fluent-bit/lib/jansson-e23f558/Makefile.am new file mode 100644 index 000000000..a6f9192d8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/Makefile.am @@ -0,0 +1,12 @@ +EXTRA_DIST = CHANGES LICENSE README.rst CMakeLists.txt cmake android examples scripts +SUBDIRS = doc src test + +# "make distcheck" builds the dvi target, so use it to check that the +# documentation is built correctly. +dvi: + $(MAKE) SPHINXOPTS_EXTRA=-W html + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = jansson.pc + +TESTS = scripts/clang-format-check diff --git a/src/fluent-bit/lib/jansson-e23f558/README.rst b/src/fluent-bit/lib/jansson-e23f558/README.rst new file mode 100644 index 000000000..4a307dc15 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/README.rst @@ -0,0 +1,74 @@ +Jansson README +============== + +.. image:: https://github.com/akheron/jansson/workflows/tests/badge.svg + :target: https://github.com/akheron/jansson/actions + +.. image:: https://ci.appveyor.com/api/projects/status/lmhkkc4q8cwc65ko + :target: https://ci.appveyor.com/project/akheron/jansson + +.. image:: https://coveralls.io/repos/akheron/jansson/badge.png?branch=master + :target: https://coveralls.io/r/akheron/jansson?branch=master + +Jansson_ is a C library for encoding, decoding and manipulating JSON +data. Its main features and design principles are: + +- Simple and intuitive API and data model + +- `Comprehensive documentation`_ + +- No dependencies on other libraries + +- Full Unicode support (UTF-8) + +- Extensive test suite + +Jansson is licensed under the `MIT license`_; see LICENSE in the +source distribution for details. + +Compilation and Installation +---------------------------- + +If you obtained a ``jansson-X.Y.tar.*`` tarball from GitHub Releases, just use +the standard autotools commands:: + + $ ./configure + $ make + $ make install + +To run the test suite, invoke:: + + $ make check + +If the source has been checked out from a Git repository, the ``configure`` +script has to be generated first. The easiest way is to use autoreconf:: + + $ autoreconf -i + + +Documentation +------------- + +Documentation is available at http://jansson.readthedocs.io/en/latest/. + +The documentation source is in the ``doc/`` subdirectory. To generate +HTML documentation, invoke:: + + $ make html + +Then, point your browser to ``doc/_build/html/index.html``. Sphinx_ +1.0 or newer is required to generate the documentation. + + +Community +--------- + +* `Documentation <http://jansson.readthedocs.io/en/latest/>`_ +* `Issue tracker <https://github.com/akheron/jansson/issues>`_ +* `Mailing list <http://groups.google.com/group/jansson-users>`_ +* `Wiki <https://github.com/akheron/jansson/wiki>`_ contains some development documentation + +.. _Jansson: http://www.digip.org/jansson/ +.. _`Comprehensive documentation`: http://jansson.readthedocs.io/en/latest/ +.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php +.. _Sphinx: http://sphinx.pocoo.org/ diff --git a/src/fluent-bit/lib/jansson-e23f558/android/jansson_config.h b/src/fluent-bit/lib/jansson-e23f558/android/jansson_config.h new file mode 100644 index 000000000..618a0da73 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/android/jansson_config.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE inline +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG 1 + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV 0 + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/appveyor.yml b/src/fluent-bit/lib/jansson-e23f558/appveyor.yml new file mode 100644 index 000000000..e2bdad7fc --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/appveyor.yml @@ -0,0 +1,18 @@ +environment: + matrix: + - VS: Visual Studio 9 2008 + - VS: Visual Studio 10 2010 + - VS: Visual Studio 11 2012 + - VS: Visual Studio 12 2013 + - VS: Visual Studio 14 2015 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + VS: Visual Studio 15 2017 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + VS: Visual Studio 16 2019 + +build_script: + - md build + - cd build + - cmake -G "%VS%" .. + - cmake --build . --config Release + - ctest --output-on-failure diff --git a/src/fluent-bit/lib/jansson-e23f558/cmake/CheckFunctionKeywords.cmake b/src/fluent-bit/lib/jansson-e23f558/cmake/CheckFunctionKeywords.cmake new file mode 100644 index 000000000..44601fd4e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/cmake/CheckFunctionKeywords.cmake @@ -0,0 +1,15 @@ +include(CheckCSourceCompiles) + +macro(check_function_keywords _wordlist) + set(${_result} "") + foreach(flag ${_wordlist}) + string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${flagname}") + check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag}) + if(${have_flag} AND NOT ${_result}) + set(${_result} "${flag}") +# break() + endif(${have_flag} AND NOT ${_result}) + endforeach(flag) +endmacro(check_function_keywords) diff --git a/src/fluent-bit/lib/jansson-e23f558/cmake/CodeCoverage.cmake b/src/fluent-bit/lib/jansson-e23f558/cmake/CodeCoverage.cmake new file mode 100644 index 000000000..3a21d3d4e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/cmake/CodeCoverage.cmake @@ -0,0 +1,163 @@ +# +# Boost Software License - Version 1.0 - August 17th, 2003 +# +# Permission is hereby granted, free of charge, to any person or organization +# obtaining a copy of the software and accompanying documentation covered by +# this license (the "Software") to use, reproduce, display, distribute, +# execute, and transmit the Software, and to prepare derivative works of the +# Software, and to permit third-parties to whom the Software is furnished to +# do so, all subject to the following: +# +# The copyright notices in the Software and this entire statement, including +# the above license grant, this restriction and the following disclaimer, +# must be included in all copies of the Software, in whole or in part, and +# all derivative works of the Software, unless such copies or derivative +# works are solely in the form of machine-executable object code generated by +# a source language processor. +# +# 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +# SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +# FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# 2012-01-31, Lars Bilke +# - Enable Code Coverage +# +# 2013-09-17, Joakim Söderberg +# - Added support for Clang. +# - Some additional usage instructions. +# +# USAGE: +# 1. Copy this file into your cmake modules path. +# +# 2. Add the following line to your CMakeLists.txt: +# INCLUDE(CodeCoverage) +# +# 3. Set compiler flags to turn off optimization and enable coverage: +# SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") +# SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") +# +# 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target +# which runs your test executable and produces a lcov code coverage report: +# Example: +# SETUP_TARGET_FOR_COVERAGE( +# my_coverage_target # Name for custom target. +# test_driver # Name of the test driver executable that runs the tests. +# # NOTE! This should always have a ZERO as exit code +# # otherwise the coverage generation will not complete. +# coverage # Name of output directory. +# ) +# +# 4. Build a Debug build: +# cmake -DCMAKE_BUILD_TYPE=Debug .. +# make +# make my_coverage_target +# +# + +# Check prereqs +FIND_PROGRAM( GCOV_PATH gcov ) +FIND_PROGRAM( LCOV_PATH lcov ) +FIND_PROGRAM( GENHTML_PATH genhtml ) +FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests) + +IF(NOT GCOV_PATH) + MESSAGE(FATAL_ERROR "gcov not found! Aborting...") +ENDIF() # NOT GCOV_PATH + +IF(NOT (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC)) + # Clang version 3.0.0 and greater now supports gcov as well. + MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.") + + IF(NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) + MESSAGE(FATAL_ERROR "Compiler is not GNU gcc or Clang! Aborting...") + ENDIF() +ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX + +IF ( NOT CMAKE_BUILD_TYPE STREQUAL "Debug" ) + MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" ) +ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" + + +# Param _targetname The name of new the custom make target +# Param _outputname lcov output is generated as _outputname.info +# HTML report is generated in _outputname/index.html +# Param _testrunner The name of the target which runs the tests. +# MUST return ZERO always, even on errors. +# If not, no coverage report will be created! +# Optional fourth parameter is passed as arguments to _testrunner +# Pass them in list form, e.g.: "-j;2" for -j 2 +FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _outputname _testrunner) + + IF(NOT LCOV_PATH) + MESSAGE(FATAL_ERROR "lcov not found! Aborting...") + ENDIF() # NOT LCOV_PATH + + IF(NOT GENHTML_PATH) + MESSAGE(FATAL_ERROR "genhtml not found! Aborting...") + ENDIF() # NOT GENHTML_PATH + + # Setup target + ADD_CUSTOM_TARGET(${_targetname} + + # Cleanup lcov + ${LCOV_PATH} --directory . --zerocounters + + # Run tests + COMMAND ${_testrunner} ${ARGV3} + + # Capturing lcov counters and generating report + COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info --rc lcov_branch_coverage=1 + COMMAND ${LCOV_PATH} --remove ${_outputname}.info '*/build/include/*' '*/test/*' '/usr/include/*' --output-file ${_outputname}.info --rc lcov_branch_coverage=1 + # COMMAND ${GENHTML_PATH} --branch-coverage -o ${_outputname} ${_outputname}.info.cleaned + # COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned + + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." + ) + + # Show info where to find the report + ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD + COMMAND ; + COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report." + ) + +ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE + +# Param _targetname The name of new the custom make target +# Param _testrunner The name of the target which runs the tests +# Param _outputname cobertura output is generated as _outputname.xml +# Optional fourth parameter is passed as arguments to _testrunner +# Pass them in list form, e.g.: "-j;2" for -j 2 +FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname) + + IF(NOT PYTHON_EXECUTABLE) + MESSAGE(FATAL_ERROR "Python not found! Aborting...") + ENDIF() # NOT PYTHON_EXECUTABLE + + IF(NOT GCOVR_PATH) + MESSAGE(FATAL_ERROR "gcovr not found! Aborting...") + ENDIF() # NOT GCOVR_PATH + + ADD_CUSTOM_TARGET(${_targetname} + + # Run tests + ${_testrunner} ${ARGV3} + + # Running gcovr + COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Running gcovr to produce Cobertura code coverage report." + ) + + # Show info where to find the report + ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD + COMMAND ; + COMMENT "Cobertura code coverage report saved in ${_outputname}.xml." + ) + +ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA + diff --git a/src/fluent-bit/lib/jansson-e23f558/cmake/Coveralls.cmake b/src/fluent-bit/lib/jansson-e23f558/cmake/Coveralls.cmake new file mode 100644 index 000000000..29221c917 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/cmake/Coveralls.cmake @@ -0,0 +1,111 @@ +# +# 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) 2014 Joakim Söderberg <joakim.soderberg@gmail.com> +# + + +# +# Param _COVERAGE_SRCS A list of source files that coverage should be collected for. +# Param _COVERALLS_UPLOAD Upload the result to coveralls? +# +function(coveralls_setup _COVERAGE_SRCS _COVERALLS_UPLOAD) + # When passing a CMake list to an external process, the list + # will be converted from the format "1;2;3" to "1 2 3". + # This means the script we're calling won't see it as a list + # of sources, but rather just one long path. We remedy this + # by replacing ";" with "*" and then reversing that in the script + # that we're calling. + # http://cmake.3232098.n2.nabble.com/Passing-a-CMake-list-quot-as-is-quot-to-a-custom-target-td6505681.html + set(COVERAGE_SRCS_TMP ${_COVERAGE_SRCS}) + set(COVERAGE_SRCS "") + foreach (COVERAGE_SRC ${COVERAGE_SRCS_TMP}) + set(COVERAGE_SRCS "${COVERAGE_SRCS}*${COVERAGE_SRC}") + endforeach() + + #message("Coverage sources: ${COVERAGE_SRCS}") + set(COVERALLS_FILE ${PROJECT_BINARY_DIR}/coveralls.json) + + add_custom_target(coveralls_generate + + # Zero the coverage counters. + COMMAND ${CMAKE_COMMAND} + -P "${PROJECT_SOURCE_DIR}/cmake/CoverallsClear.cmake" + + # Run regress tests. + COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + + # Generate Gcov and translate it into coveralls JSON. + # We do this by executing an external CMake script. + # (We don't want this to run at CMake generation time, but after compilation and everything has run). + COMMAND ${CMAKE_COMMAND} + -DCOVERAGE_SRCS="${COVERAGE_SRCS}" # TODO: This is passed like: "a b c", not "a;b;c" + -DCOVERALLS_OUTPUT_FILE="${COVERALLS_FILE}" + -DCOV_PATH="${PROJECT_BINARY_DIR}" + -DPROJECT_ROOT="${PROJECT_SOURCE_DIR}" + -P "${PROJECT_SOURCE_DIR}/cmake/CoverallsGenerateGcov.cmake" + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Generating coveralls output..." + ) + + if (_COVERALLS_UPLOAD) + message("COVERALLS UPLOAD: ON") + + find_program(CURL_EXECUTABLE curl) + + if (NOT CURL_EXECUTABLE) + message(FATAL_ERROR "Coveralls: curl not found! Aborting") + endif() + + add_custom_target(coveralls_upload + # Upload the JSON to coveralls. + COMMAND ${CURL_EXECUTABLE} + -S -F json_file=@${COVERALLS_FILE} + https://coveralls.io/api/v1/jobs + + DEPENDS coveralls_generate + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Uploading coveralls output...") + + add_custom_target(coveralls DEPENDS coveralls_upload) + else() + message("COVERALLS UPLOAD: OFF") + add_custom_target(coveralls DEPENDS coveralls_generate) + endif() + +endfunction() + +macro(coveralls_turn_on_coverage) + if(NOT (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + AND (NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) + message(FATAL_ERROR "Coveralls: Compiler ${CMAKE_C_COMPILER_ID} is not GNU gcc! Aborting... You can set this on the command line using CC=/usr/bin/gcc CXX=/usr/bin/g++ cmake <options> ..") + endif() + + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(FATAL_ERROR "Coveralls: Code coverage results with an optimised (non-Debug) build may be misleading! Add -DCMAKE_BUILD_TYPE=Debug") + endif() + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") +endmacro() + + + diff --git a/src/fluent-bit/lib/jansson-e23f558/cmake/CoverallsClear.cmake b/src/fluent-bit/lib/jansson-e23f558/cmake/CoverallsClear.cmake new file mode 100644 index 000000000..eb68695a2 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/cmake/CoverallsClear.cmake @@ -0,0 +1,24 @@ +# +# 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) 2014 Joakim Söderberg <joakim.soderberg@gmail.com> +# + +file(REMOVE_RECURSE ${PROJECT_BINARY_DIR}/*.gcda) + diff --git a/src/fluent-bit/lib/jansson-e23f558/cmake/CoverallsGenerateGcov.cmake b/src/fluent-bit/lib/jansson-e23f558/cmake/CoverallsGenerateGcov.cmake new file mode 100644 index 000000000..c4da8fbdf --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/cmake/CoverallsGenerateGcov.cmake @@ -0,0 +1,380 @@ +# +# 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) 2014 Joakim Söderberg <joakim.soderberg@gmail.com> +# +# This is intended to be run by a custom target in a CMake project like this. +# 0. Compile program with coverage support. +# 1. Clear coverage data. (Recursively delete *.gcda in build dir) +# 2. Run the unit tests. +# 3. Run this script specifying which source files the coverage should be performed on. +# +# This script will then use gcov to generate .gcov files in the directory specified +# via the COV_PATH var. This should probably be the same as your cmake build dir. +# +# It then parses the .gcov files to convert them into the Coveralls JSON format: +# https://coveralls.io/docs/api +# +# Example for running as standalone CMake script from the command line: +# (Note it is important the -P is at the end...) +# $ cmake -DCOV_PATH=$(pwd) +# -DCOVERAGE_SRCS="catcierge_rfid.c;catcierge_timer.c" +# -P ../cmake/CoverallsGcovUpload.cmake +# +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + + +# +# Make sure we have the needed arguments. +# +if (NOT COVERALLS_OUTPUT_FILE) + message(FATAL_ERROR "Coveralls: No coveralls output file specified. Please set COVERALLS_OUTPUT_FILE") +endif() + +if (NOT COV_PATH) + message(FATAL_ERROR "Coveralls: Missing coverage directory path where gcov files will be generated. Please set COV_PATH") +endif() + +if (NOT COVERAGE_SRCS) + message(FATAL_ERROR "Coveralls: Missing the list of source files that we should get the coverage data for COVERAGE_SRCS") +endif() + +if (NOT PROJECT_ROOT) + message(FATAL_ERROR "Coveralls: Missing PROJECT_ROOT.") +endif() + +# Since it's not possible to pass a CMake list properly in the +# "1;2;3" format to an external process, we have replaced the +# ";" with "*", so reverse that here so we get it back into the +# CMake list format. +string(REGEX REPLACE "\\*" ";" COVERAGE_SRCS ${COVERAGE_SRCS}) + +find_program(GCOV_EXECUTABLE gcov) + +if (NOT GCOV_EXECUTABLE) + message(FATAL_ERROR "gcov not found! Aborting...") +endif() + +find_package(Git) + +# TODO: Add these git things to the coveralls json. +if (GIT_FOUND) + # Branch. + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + macro (git_log_format FORMAT_CHARS VAR_NAME) + execute_process( + COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%${FORMAT_CHARS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${VAR_NAME} + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endmacro() + + git_log_format(an GIT_AUTHOR_EMAIL) + git_log_format(ae GIT_AUTHOR_EMAIL) + git_log_format(cn GIT_COMMITTER_NAME) + git_log_format(ce GIT_COMMITTER_EMAIL) + git_log_format(B GIT_COMMIT_MESSAGE) + + message("Git exe: ${GIT_EXECUTABLE}") + message("Git branch: ${GIT_BRANCH}") + message("Git author: ${GIT_AUTHOR_NAME}") + message("Git e-mail: ${GIT_AUTHOR_EMAIL}") + message("Git committer name: ${GIT_COMMITTER_NAME}") + message("Git committer e-mail: ${GIT_COMMITTER_EMAIL}") + message("Git commit message: ${GIT_COMMIT_MESSAGE}") + +endif() + +############################# Macros ######################################### + +# +# This macro converts from the full path format gcov outputs: +# +# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov +# +# to the original source file path the .gcov is for: +# +# /path/to/project/root/subdir/the_file.c +# +macro(get_source_path_from_gcov_filename _SRC_FILENAME _GCOV_FILENAME) + + # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov + # -> + # #path#to#project#root#subdir#the_file.c.gcov + get_filename_component(_GCOV_FILENAME_WEXT ${_GCOV_FILENAME} NAME) + + # #path#to#project#root#subdir#the_file.c.gcov -> /path/to/project/root/subdir/the_file.c + string(REGEX REPLACE "\\.gcov$" "" SRC_FILENAME_TMP ${_GCOV_FILENAME_WEXT}) + string(REGEX REPLACE "\#" "/" SRC_FILENAME_TMP ${SRC_FILENAME_TMP}) + set(${_SRC_FILENAME} "${SRC_FILENAME_TMP}") +endmacro() + +############################################################################## + +# Get the coverage data. +file(GLOB_RECURSE GCDA_FILES "${COV_PATH}/*.gcda") +message("GCDA files:") + +# Get a list of all the object directories needed by gcov +# (The directories the .gcda files and .o files are found in) +# and run gcov on those. +foreach(GCDA ${GCDA_FILES}) + message("Process: ${GCDA}") + message("------------------------------------------------------------------------------") + get_filename_component(GCDA_DIR ${GCDA} PATH) + + # + # The -p below refers to "Preserve path components", + # This means that the generated gcov filename of a source file will + # keep the original files entire filepath, but / is replaced with #. + # Example: + # + # /path/to/project/root/build/CMakeFiles/the_file.dir/subdir/the_file.c.gcda + # ------------------------------------------------------------------------------ + # File '/path/to/project/root/subdir/the_file.c' + # Lines executed:68.34% of 199 + # /path/to/project/root/subdir/the_file.c:creating '#path#to#project#root#subdir#the_file.c.gcov' + # + # If -p is not specified then the file is named only "the_file.c.gcov" + # + execute_process( + COMMAND ${GCOV_EXECUTABLE} -p -o ${GCDA_DIR} ${GCDA} + WORKING_DIRECTORY ${COV_PATH} + ) +endforeach() + +# TODO: Make these be absolute path +file(GLOB ALL_GCOV_FILES ${COV_PATH}/*.gcov) + +# Get only the filenames to use for filtering. +#set(COVERAGE_SRCS_NAMES "") +#foreach (COVSRC ${COVERAGE_SRCS}) +# get_filename_component(COVSRC_NAME ${COVSRC} NAME) +# message("${COVSRC} -> ${COVSRC_NAME}") +# list(APPEND COVERAGE_SRCS_NAMES "${COVSRC_NAME}") +#endforeach() + +# +# Filter out all but the gcov files we want. +# +# We do this by comparing the list of COVERAGE_SRCS filepaths that the +# user wants the coverage data for with the paths of the generated .gcov files, +# so that we only keep the relevant gcov files. +# +# Example: +# COVERAGE_SRCS = +# /path/to/project/root/subdir/the_file.c +# +# ALL_GCOV_FILES = +# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov +# /path/to/project/root/build/#path#to#project#root#subdir#other_file.c.gcov +# +# Result should be: +# GCOV_FILES = +# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov +# +set(GCOV_FILES "") +#message("Look in coverage sources: ${COVERAGE_SRCS}") +message("\nFilter out unwanted GCOV files:") +message("===============================") + +set(COVERAGE_SRCS_REMAINING ${COVERAGE_SRCS}) + +foreach (GCOV_FILE ${ALL_GCOV_FILES}) + + # + # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov + # -> + # /path/to/project/root/subdir/the_file.c + get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) + + # Is this in the list of source files? + # TODO: We want to match against relative path filenames from the source file root... + list(FIND COVERAGE_SRCS ${GCOV_SRC_PATH} WAS_FOUND) + + if (NOT WAS_FOUND EQUAL -1) + message("YES: ${GCOV_FILE}") + list(APPEND GCOV_FILES ${GCOV_FILE}) + + # We remove it from the list, so we don't bother searching for it again. + # Also files left in COVERAGE_SRCS_REMAINING after this loop ends should + # have coverage data generated from them (no lines are covered). + list(REMOVE_ITEM COVERAGE_SRCS_REMAINING ${GCOV_SRC_PATH}) + else() + message("NO: ${GCOV_FILE}") + endif() +endforeach() + +# TODO: Enable setting these +set(JSON_SERVICE_NAME "travis-ci") +set(JSON_SERVICE_JOB_ID $ENV{TRAVIS_JOB_ID}) + +set(JSON_TEMPLATE +"{ + \"service_name\": \"\@JSON_SERVICE_NAME\@\", + \"service_job_id\": \"\@JSON_SERVICE_JOB_ID\@\", + \"source_files\": \@JSON_GCOV_FILES\@ +}" +) + +set(SRC_FILE_TEMPLATE +"{ + \"name\": \"\@GCOV_SRC_REL_PATH\@\", + \"source\": \"\@GCOV_FILE_SOURCE\@\", + \"coverage\": \@GCOV_FILE_COVERAGE\@ +}" +) + +message("\nGenerate JSON for files:") +message("=========================") + +set(JSON_GCOV_FILES "[") + +# Read the GCOV files line by line and get the coverage data. +foreach (GCOV_FILE ${GCOV_FILES}) + + get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) + file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") + + # Loads the gcov file as a list of lines. + file(STRINGS ${GCOV_FILE} GCOV_LINES) + + # Instead of trying to parse the source from the + # gcov file, simply read the file contents from the source file. + # (Parsing it from the gcov is hard because C-code uses ; in many places + # which also happens to be the same as the CMake list delimiter). + file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE) + + string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REGEX REPLACE "\"" "\\\\\"" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REPLACE "\t" "\\\\t" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REPLACE "\r" "\\\\r" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REPLACE "\n" "\\\\n" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + # According to http://json.org/ these should be escaped as well. + # Don't know how to do that in CMake however... + #string(REPLACE "\b" "\\\\b" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + #string(REPLACE "\f" "\\\\f" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + #string(REGEX REPLACE "\u([a-fA-F0-9]{4})" "\\\\u\\1" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + + # We want a json array of coverage data as a single string + # start building them from the contents of the .gcov + set(GCOV_FILE_COVERAGE "[") + + foreach (GCOV_LINE ${GCOV_LINES}) + # Example of what we're parsing: + # Hitcount |Line | Source + # " 8: 26: if (!allowed || (strlen(allowed) == 0))" + string(REGEX REPLACE + "^([^:]*):([^:]*):(.*)$" + "\\1;\\2;\\3" + RES + "${GCOV_LINE}") + + list(LENGTH RES RES_COUNT) + if (RES_COUNT GREATER 2) + list(GET RES 0 HITCOUNT) + list(GET RES 1 LINE) + list(GET RES 2 SOURCE) + + string(STRIP ${HITCOUNT} HITCOUNT) + string(STRIP ${LINE} LINE) + + # Lines with 0 line numbers are metadata and can be ignored. + if (NOT ${LINE} EQUAL 0) + + # Translate the hitcount into valid JSON values. + if (${HITCOUNT} STREQUAL "#####") + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") + elseif (${HITCOUNT} STREQUAL "-") + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") + else() + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}${HITCOUNT}, ") + endif() + # TODO: Look for LCOV_EXCL_LINE in SOURCE to get rid of false positives. + endif() + else() + message(WARNING "Failed to properly parse line --> ${GCOV_LINE}") + endif() + endforeach() + + # Advanced way of removing the trailing comma in the JSON array. + # "[1, 2, 3, " -> "[1, 2, 3" + string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) + + # Append the trailing ] to complete the JSON array. + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") + + # Generate the final JSON for this file. + message("Generate JSON for file: ${GCOV_SRC_REL_PATH}...") + string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) + + set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") +endforeach() + +# Loop through all files we couldn't find any coverage for +# as well, and generate JSON for those as well with 0% coverage. +foreach(NOT_COVERED_SRC ${COVERAGE_SRCS_REMAINING}) + + # Loads the source file as a list of lines. + file(STRINGS ${NOT_COVERED_SRC} SRC_LINES) + + set(GCOV_FILE_COVERAGE "[") + set(GCOV_FILE_SOURCE "") + + foreach (SOURCE ${SRC_LINES}) + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") + + string(REPLACE "\\" "\\\\" SOURCE "${SOURCE}") + string(REGEX REPLACE "\"" "\\\\\"" SOURCE "${SOURCE}") + string(REPLACE "\t" "\\\\t" SOURCE "${SOURCE}") + string(REPLACE "\r" "\\\\r" SOURCE "${SOURCE}") + set(GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}${SOURCE}\\n") + endforeach() + + # Remove trailing comma, and complete JSON array with ] + string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") + + # Generate the final JSON for this file. + message("Generate JSON for non-gcov file: ${NOT_COVERED_SRC}...") + string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) + set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") +endforeach() + +# Get rid of trailing comma. +string(REGEX REPLACE ",[ ]*$" "" JSON_GCOV_FILES ${JSON_GCOV_FILES}) +set(JSON_GCOV_FILES "${JSON_GCOV_FILES}]") + +# Generate the final complete JSON! +message("Generate final JSON...") +string(CONFIGURE ${JSON_TEMPLATE} JSON) + +file(WRITE "${COVERALLS_OUTPUT_FILE}" "${JSON}") +message("###########################################################################") +message("Generated coveralls JSON containing coverage data:") +message("${COVERALLS_OUTPUT_FILE}") +message("###########################################################################") + diff --git a/src/fluent-bit/lib/jansson-e23f558/cmake/FindSphinx.cmake b/src/fluent-bit/lib/jansson-e23f558/cmake/FindSphinx.cmake new file mode 100644 index 000000000..3bf0a5d4d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/cmake/FindSphinx.cmake @@ -0,0 +1,315 @@ +# +# PART B. DOWNLOADING AGREEMENT - LICENSE FROM SBIA WITH RIGHT TO SUBLICENSE ("SOFTWARE LICENSE"). +# ------------------------------------------------------------------------------------------------ +# +# 1. As used in this Software License, "you" means the individual downloading and/or +# using, reproducing, modifying, displaying and/or distributing the Software and +# the institution or entity which employs or is otherwise affiliated with such +# individual in connection therewith. The Section of Biomedical Image Analysis, +# Department of Radiology at the Universiy of Pennsylvania ("SBIA") hereby grants +# you, with right to sublicense, with respect to SBIA's rights in the software, +# and data, if any, which is the subject of this Software License (collectively, +# the "Software"), a royalty-free, non-exclusive license to use, reproduce, make +# derivative works of, display and distribute the Software, provided that: +# (a) you accept and adhere to all of the terms and conditions of this Software +# License; (b) in connection with any copy of or sublicense of all or any portion +# of the Software, all of the terms and conditions in this Software License shall +# appear in and shall apply to such copy and such sublicense, including without +# limitation all source and executable forms and on any user documentation, +# prefaced with the following words: "All or portions of this licensed product +# (such portions are the "Software") have been obtained under license from the +# Section of Biomedical Image Analysis, Department of Radiology at the University +# of Pennsylvania and are subject to the following terms and conditions:" +# (c) you preserve and maintain all applicable attributions, copyright notices +# and licenses included in or applicable to the Software; (d) modified versions +# of the Software must be clearly identified and marked as such, and must not +# be misrepresented as being the original Software; and (e) you consider making, +# but are under no obligation to make, the source code of any of your modifications +# to the Software freely available to others on an open source basis. +# +# 2. The license granted in this Software License includes without limitation the +# right to (i) incorporate the Software into proprietary programs (subject to +# any restrictions applicable to such programs), (ii) add your own copyright +# statement to your modifications of the Software, and (iii) provide additional +# or different license terms and conditions in your sublicenses of modifications +# of the Software; provided that in each case your use, reproduction or +# distribution of such modifications otherwise complies with the conditions +# stated in this Software License. +# +# 3. This Software License does not grant any rights with respect to third party +# software, except those rights that SBIA has been authorized by a third +# party to grant to you, and accordingly you are solely responsible for +# (i) obtaining any permissions from third parties that you need to use, +# reproduce, make derivative works of, display and distribute the Software, +# and (ii) informing your sublicensees, including without limitation your +# end-users, of their obligations to secure any such required permissions. +# +# 4. The Software has been designed for research purposes only and has not been +# reviewed or approved by the Food and Drug Administration or by any other +# agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL APPLICATIONS ARE NEITHER +# RECOMMENDED NOR ADVISED. Any commercialization of the Software is at the +# sole risk of the party or parties engaged in such commercialization. +# You further agree to use, reproduce, make derivative works of, display +# and distribute the Software in compliance with all applicable governmental +# laws, regulations and orders, including without limitation those relating +# to export and import control. +# +# 5. The Software is provided "AS IS" and neither SBIA nor any contributor to +# the software (each a "Contributor") shall have any obligation to provide +# maintenance, support, updates, enhancements or modifications thereto. +# SBIA AND ALL CONTRIBUTORS SPECIFICALLY DISCLAIM ALL EXPRESS AND IMPLIED +# WARRANTIES OF ANY KIND INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL SBIA OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR +# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY RELATED +# TO THE SOFTWARE, EVEN IF SBIA OR ANY CONTRIBUTOR HAS BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM EXTENT NOT PROHIBITED BY LAW OR +# REGULATION, YOU FURTHER ASSUME ALL LIABILITY FOR YOUR USE, REPRODUCTION, +# MAKING OF DERIVATIVE WORKS, DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE +# AND AGREE TO INDEMNIFY AND HOLD HARMLESS SBIA AND ALL CONTRIBUTORS FROM +# AND AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS ARISING +# THEREFROM. +# +# 6. None of the names, logos or trademarks of SBIA or any of SBIA's affiliates +# or any of the Contributors, or any funding agency, may be used to endorse +# or promote products produced in whole or in part by operation of the Software +# or derived from or based on the Software without specific prior written +# permission from the applicable party. +# +# 7. Any use, reproduction or distribution of the Software which is not in accordance +# with this Software License shall automatically revoke all rights granted to you +# under this Software License and render Paragraphs 1 and 2 of this Software +# License null and void. +# +# 8. This Software License does not grant any rights in or to any intellectual +# property owned by SBIA or any Contributor except those rights expressly +# granted hereunder. +# +# +# PART C. MISCELLANEOUS +# --------------------- +# +# This Agreement shall be governed by and construed in accordance with the laws +# of The Commonwealth of Pennsylvania without regard to principles of conflicts +# of law. This Agreement shall supercede and replace any license terms that you +# may have agreed to previously with respect to Software from SBIA. +# +############################################################################## +# @file FindSphinx.cmake +# @brief Find Sphinx documentation build tools. +# +# @par Input variables: +# <table border="0"> +# <tr> +# @tp @b Sphinx_DIR @endtp +# <td>Installation directory of Sphinx tools. Can also be set as environment variable.</td> +# </tr> +# <tr> +# @tp @b SPHINX_DIR @endtp +# <td>Alternative environment variable for @c Sphinx_DIR.</td> +# </tr> +# <tr> +# @tp @b Sphinx_FIND_COMPONENTS @endtp +# <td>Sphinx build tools to look for, i.e., 'apidoc' and/or 'build'.</td> +# </tr> +# </table> +# +# @par Output variables: +# <table border="0"> +# <tr> +# @tp @b Sphinx_FOUND @endtp +# <td>Whether all or only the requested Sphinx build tools were found.</td> +# </tr> +# <tr> +# @tp @b SPHINX_FOUND @endtp +# <td>Alias for @c Sphinx_FOUND.<td> +# </tr> +# <tr> +# @tp @b SPHINX_EXECUTABLE @endtp +# <td>Non-cached alias for @c Sphinx-build_EXECUTABLE.</td> +# </tr> +# <tr> +# @tp @b Sphinx_PYTHON_EXECUTABLE @endtp +# <td>Python executable used to run sphinx-build. This is either the +# by default found Python interpreter or a specific version as +# specified by the shebang (#!) of the sphinx-build script.</td> +# </tr> +# <tr> +# @tp @b Sphinx_PYTHON_OPTIONS @endtp +# <td>A list of Python options extracted from the shebang (#!) of the +# sphinx-build script. The -E option is added by this module +# if the Python executable is not the system default to avoid +# problems with a differing setting of the @c PYTHONHOME.</td> +# </tr> +# <tr> +# @tp @b Sphinx-build_EXECUTABLE @endtp +# <td>Absolute path of the found sphinx-build tool.</td> +# </tr> +# <tr> +# @tp @b Sphinx-apidoc_EXECUTABLE @endtp +# <td>Absolute path of the found sphinx-apidoc tool.</td> +# </tr> +# <tr> +# @tp @b Sphinx_VERSION_STRING @endtp +# <td>Sphinx version found e.g. 1.1.2.</td> +# </tr> +# <tr> +# @tp @b Sphinx_VERSION_MAJOR @endtp +# <td>Sphinx major version found e.g. 1.</td> +# </tr> +# <tr> +# @tp @b Sphinx_VERSION_MINOR @endtp +# <td>Sphinx minor version found e.g. 1.</td> +# </tr> +# <tr> +# @tp @b Sphinx_VERSION_PATCH @endtp +# <td>Sphinx patch version found e.g. 2.</td> +# </tr> +# </table> +# +# @ingroup CMakeFindModules +############################################################################## + +set (_Sphinx_REQUIRED_VARS) + +# ---------------------------------------------------------------------------- +# initialize search +if (NOT Sphinx_DIR) + if (NOT $ENV{Sphinx_DIR} STREQUAL "") + set (Sphinx_DIR "$ENV{Sphinx_DIR}" CACHE PATH "Installation prefix of Sphinx (docutils)." FORCE) + else () + set (Sphinx_DIR "$ENV{SPHINX_DIR}" CACHE PATH "Installation prefix of Sphinx (docutils)." FORCE) + endif () +endif () + +# ---------------------------------------------------------------------------- +# default components to look for +if (NOT Sphinx_FIND_COMPONENTS) + set (Sphinx_FIND_COMPONENTS "build") +elseif (NOT Sphinx_FIND_COMPONENTS MATCHES "^(build|apidoc)$") + message (FATAL_ERROR "Invalid Sphinx component in: ${Sphinx_FIND_COMPONENTS}") +endif () + +# ---------------------------------------------------------------------------- +# find components, i.e., build tools +foreach (_Sphinx_TOOL IN LISTS Sphinx_FIND_COMPONENTS) + if (Sphinx_DIR) + find_program ( + Sphinx-${_Sphinx_TOOL}_EXECUTABLE + NAMES sphinx-${_Sphinx_TOOL} sphinx-${_Sphinx_TOOL}.py + HINTS "${Sphinx_DIR}" + PATH_SUFFIXES bin + DOC "The sphinx-${_Sphinx_TOOL} Python script." + NO_DEFAULT_PATH + ) + else () + find_program ( + Sphinx-${_Sphinx_TOOL}_EXECUTABLE + NAMES sphinx-${_Sphinx_TOOL} sphinx-${_Sphinx_TOOL}.py + DOC "The sphinx-${_Sphinx_TOOL} Python script." + ) + endif () + mark_as_advanced (Sphinx-${_Sphinx_TOOL}_EXECUTABLE) + list (APPEND _Sphinx_REQUIRED_VARS Sphinx-${_Sphinx_TOOL}_EXECUTABLE) +endforeach () + +# ---------------------------------------------------------------------------- +# determine Python executable used by Sphinx +if (Sphinx-build_EXECUTABLE) + # extract python executable from shebang of sphinx-build + find_package (PythonInterp QUIET) + set (Sphinx_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}") + set (Sphinx_PYTHON_OPTIONS) + file (STRINGS "${Sphinx-build_EXECUTABLE}" FIRST_LINE LIMIT_COUNT 1) + if (FIRST_LINE MATCHES "^#!(.*/python.*)") # does not match "#!/usr/bin/env python" ! + string (REGEX REPLACE "^ +| +$" "" Sphinx_PYTHON_EXECUTABLE "${CMAKE_MATCH_1}") + if (Sphinx_PYTHON_EXECUTABLE MATCHES "([^ ]+) (.*)") + set (Sphinx_PYTHON_EXECUTABLE "${CMAKE_MATCH_1}") + string (REGEX REPLACE " +" ";" Sphinx_PYTHON_OPTIONS "${CMAKE_MATCH_2}") + endif () + endif () + # this is done to avoid problems with multiple Python versions being installed + # remember: CMake command if(STR EQUAL STR) is bad and may cause many troubles ! + string (REGEX REPLACE "([.+*?^$])" "\\\\\\1" _Sphinx_PYTHON_EXECUTABLE_RE "${PYTHON_EXECUTABLE}") + list (FIND Sphinx_PYTHON_OPTIONS -E IDX) + if (IDX EQUAL -1 AND NOT Sphinx_PYTHON_EXECUTABLE MATCHES "^${_Sphinx_PYTHON_EXECUTABLE_RE}$") + list (INSERT Sphinx_PYTHON_OPTIONS 0 -E) + endif () + unset (_Sphinx_PYTHON_EXECUTABLE_RE) +endif () + +# ---------------------------------------------------------------------------- +# determine Sphinx version +# some quick experiments by @ploxiln +# - sphinx 1.7 and later have the version output format like "sphinx-build 1.7.2" +# - sphinx 1.2 through 1.6 have the version output format like "Sphinx (sphinx-build) 1.2.2" +# - sphinx 1.1 and before do not have a "--version" flag, but it causes the help output like "-h" does which includes version like "Sphinx v1.0.2" +if (Sphinx-build_EXECUTABLE) + # intentionally use invalid -h option here as the help that is shown then + # will include the Sphinx version information + if (Sphinx_PYTHON_EXECUTABLE) + execute_process ( + COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" --version + OUTPUT_VARIABLE _Sphinx_VERSION + ERROR_VARIABLE _Sphinx_VERSION + ) + elseif (UNIX) + execute_process ( + COMMAND "${Sphinx-build_EXECUTABLE}" --version + OUTPUT_VARIABLE _Sphinx_VERSION + ERROR_VARIABLE _Sphinx_VERSION + ) + endif () + + # The sphinx version can also contain a "b" instead of the last dot. + # For example "Sphinx v1.2b1" or "Sphinx 1.7.0b2" so we cannot just split on "." + if (_Sphinx_VERSION MATCHES "sphinx-build ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))") + set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}") + set (_SPHINX_VERSION_FOUND) + elseif (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b?)([0-9]*)(b?)([0-9]*))") + set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}") + set (_SPHINX_VERSION_FOUND) + elseif (_Sphinx_VERSION MATCHES "Sphinx \\(sphinx-build\\) ([0-9]+\\.[0-9]+(\\.|a?|b?)([0-9]*)(b?)([0-9]*))") + set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}") + set (_SPHINX_VERSION_FOUND) + endif () +endif () + +if(_SPHINX_VERSION_FOUND) + string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MAJOR ${Sphinx_VERSION_STRING}) + string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MINOR ${Sphinx_VERSION_STRING}) + string(REGEX REPLACE "[0-9]+\\.[0-9]+(\\.|b)([0-9]+)" "\\1" Sphinx_VERSION_PATCH ${Sphinx_VERSION_STRING}) + + # v1.2.0 -> v1.2 + if (Sphinx_VERSION_PATCH EQUAL 0) + string (REGEX REPLACE "\\.0$" "" Sphinx_VERSION_STRING "${Sphinx_VERSION_STRING}") + endif () +endif () + +# ---------------------------------------------------------------------------- +# compatibility with FindPythonInterp.cmake and FindPerl.cmake +set (SPHINX_EXECUTABLE "${Sphinx-build_EXECUTABLE}") + +# ---------------------------------------------------------------------------- +# handle the QUIETLY and REQUIRED arguments and set SPHINX_FOUND to TRUE if +# all listed variables are TRUE +include (FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS ( + Sphinx + REQUIRED_VARS + ${_Sphinx_REQUIRED_VARS} +# VERSION_VAR # This isn't available until CMake 2.8.8 so don't use it. + Sphinx_VERSION_STRING +) + +# ---------------------------------------------------------------------------- +# set Sphinx_DIR +if (NOT Sphinx_DIR AND Sphinx-build_EXECUTABLE) + get_filename_component (Sphinx_DIR "${Sphinx-build_EXECUTABLE}" PATH) + string (REGEX REPLACE "/bin/?" "" Sphinx_DIR "${Sphinx_DIR}") + set (Sphinx_DIR "${Sphinx_DIR}" CACHE PATH "Installation directory of Sphinx tools." FORCE) +endif () + +unset (_Sphinx_VERSION) +unset (_Sphinx_REQUIRED_VARS)
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/cmake/janssonConfig.cmake.in b/src/fluent-bit/lib/jansson-e23f558/cmake/janssonConfig.cmake.in new file mode 100644 index 000000000..abd6793c5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/cmake/janssonConfig.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/janssonTargets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/src/fluent-bit/lib/jansson-e23f558/cmake/jansson_config.h.cmake b/src/fluent-bit/lib/jansson-e23f558/cmake/jansson_config.h.cmake new file mode 100644 index 000000000..2f248cbcb --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/cmake/jansson_config.h.cmake @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The CMake system will generate the jansson_config.h file and + * copy it to the build and install directories. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* Define this so that we can disable scattered automake configuration in source files */ +#ifndef JANSSON_USING_CMAKE +#define JANSSON_USING_CMAKE +#endif + +/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used, + * as we will also check for __int64 etc types. + * (the definition was used in the automake system) */ + +/* Bring in the cmake-detected defines */ +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Include our standard type header for the integer typedef */ + +#if defined(HAVE_STDINT_H) +# include <stdint.h> +#elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +#elif defined(HAVE_SYS_TYPES_H) +# include <sys/types.h> +#endif + + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @JSON_INLINE@ +#endif + + +#define json_int_t @JSON_INT_T@ +#define json_strtoint @JSON_STRTOINT@ +#define JSON_INTEGER_FORMAT @JSON_INTEGER_FORMAT@ + + +/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @JSON_HAVE_LOCALECONV@ + +/* If __atomic builtins are available they will be used to manage + reference counts of json_t. */ +#define JSON_HAVE_ATOMIC_BUILTINS @JSON_HAVE_ATOMIC_BUILTINS@ + +/* If __atomic builtins are not available we try using __sync builtins + to manage reference counts of json_t. */ +#define JSON_HAVE_SYNC_BUILTINS @JSON_HAVE_SYNC_BUILTINS@ + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/cmake/jansson_private_config.h.cmake b/src/fluent-bit/lib/jansson-e23f558/cmake/jansson_private_config.h.cmake new file mode 100644 index 000000000..b7c451497 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/cmake/jansson_private_config.h.cmake @@ -0,0 +1,53 @@ +#cmakedefine HAVE_ENDIAN_H 1 +#cmakedefine HAVE_FCNTL_H 1 +#cmakedefine HAVE_SCHED_H 1 +#cmakedefine HAVE_UNISTD_H 1 +#cmakedefine HAVE_SYS_PARAM_H 1 +#cmakedefine HAVE_SYS_STAT_H 1 +#cmakedefine HAVE_SYS_TIME_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 +#cmakedefine HAVE_STDINT_H 1 + +#cmakedefine HAVE_CLOSE 1 +#cmakedefine HAVE_GETPID 1 +#cmakedefine HAVE_GETTIMEOFDAY 1 +#cmakedefine HAVE_OPEN 1 +#cmakedefine HAVE_READ 1 +#cmakedefine HAVE_SCHED_YIELD 1 + +#cmakedefine HAVE_SYNC_BUILTINS 1 +#cmakedefine HAVE_ATOMIC_BUILTINS 1 + +#cmakedefine HAVE_LOCALE_H 1 +#cmakedefine HAVE_SETLOCALE 1 + +#cmakedefine HAVE_INT32_T 1 +#ifndef HAVE_INT32_T +# define int32_t @JSON_INT32@ +#endif + +#cmakedefine HAVE_UINT32_T 1 +#ifndef HAVE_UINT32_T +# define uint32_t @JSON_UINT32@ +#endif + +#cmakedefine HAVE_UINT16_T 1 +#ifndef HAVE_UINT16_T +# define uint16_t @JSON_UINT16@ +#endif + +#cmakedefine HAVE_UINT8_T 1 +#ifndef HAVE_UINT8_T +# define uint8_t @JSON_UINT8@ +#endif + +#cmakedefine HAVE_SSIZE_T 1 + +#ifndef HAVE_SSIZE_T +# define ssize_t @JSON_SSIZE@ +#endif + +#cmakedefine USE_URANDOM 1 +#cmakedefine USE_WINDOWS_CRYPTOAPI 1 + +#define INITIAL_HASHTABLE_ORDER @JANSSON_INITIAL_HASHTABLE_ORDER@ diff --git a/src/fluent-bit/lib/jansson-e23f558/configure.ac b/src/fluent-bit/lib/jansson-e23f558/configure.ac new file mode 100644 index 000000000..f022eb72a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/configure.ac @@ -0,0 +1,181 @@ +AC_PREREQ([2.60]) +AC_INIT([jansson], [2.14], [https://github.com/akheron/jansson/issues]) + +AC_CONFIG_AUX_DIR([.]) +AM_INIT_AUTOMAKE([1.10 foreign]) + +AC_CONFIG_SRCDIR([src/value.c]) +AC_CONFIG_HEADERS([jansson_private_config.h]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_CXX +AC_PROG_LIBTOOL +AM_CONDITIONAL([GCC], [test x$GCC = xyes]) + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([endian.h fcntl.h locale.h sched.h unistd.h sys/param.h sys/stat.h sys/time.h sys/types.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_INT32_T +AC_TYPE_UINT32_T +AC_TYPE_UINT16_T +AC_TYPE_UINT8_T +AC_TYPE_LONG_LONG_INT + +AC_C_INLINE +case $ac_cv_c_inline in + yes) json_inline=inline;; + no) json_inline=;; + *) json_inline=$ac_cv_c_inline;; +esac +AC_SUBST([json_inline]) + +# Checks for library functions. +AC_CHECK_FUNCS([close getpid gettimeofday localeconv open read sched_yield strtoll]) + +AC_MSG_CHECKING([for gcc __sync builtins]) +have_sync_builtins=no +AC_TRY_LINK( + [], [unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1);], + [have_sync_builtins=yes], +) +if test "x$have_sync_builtins" = "xyes"; then + AC_DEFINE([HAVE_SYNC_BUILTINS], [1], + [Define to 1 if gcc's __sync builtins are available]) + json_have_sync_builtins=1 +else + json_have_sync_builtins=0 +fi +AC_SUBST([json_have_sync_builtins]) +AC_MSG_RESULT([$have_sync_builtins]) + +AC_MSG_CHECKING([for gcc __atomic builtins]) +have_atomic_builtins=no +AC_TRY_LINK( + [], [char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE);], + [have_atomic_builtins=yes], +) +if test "x$have_atomic_builtins" = "xyes"; then + AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1], + [Define to 1 if gcc's __atomic builtins are available]) + json_have_atomic_builtins=1 +else + json_have_atomic_builtins=0 +fi +AC_SUBST([json_have_atomic_builtins]) +AC_MSG_RESULT([$have_atomic_builtins]) + +case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in + yesyes) json_have_long_long=1;; + *) json_have_long_long=0;; +esac +AC_SUBST([json_have_long_long]) + +case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in + yesyes) json_have_localeconv=1;; + *) json_have_localeconv=0;; +esac +AC_SUBST([json_have_localeconv]) + +# Features +AC_ARG_ENABLE([urandom], + [AS_HELP_STRING([--disable-urandom], + [Don't use /dev/urandom to seed the hash function])], + [use_urandom=$enableval], [use_urandom=yes]) + +if test "x$use_urandom" = xyes; then +AC_DEFINE([USE_URANDOM], [1], + [Define to 1 if /dev/urandom should be used for seeding the hash function]) +fi + +AC_ARG_ENABLE([windows-cryptoapi], + [AS_HELP_STRING([--disable-windows-cryptoapi], + [Don't use CryptGenRandom to seed the hash function])], + [use_windows_cryptoapi=$enableval], [use_windows_cryptoapi=yes]) + +if test "x$use_windows_cryptoapi" = xyes; then +AC_DEFINE([USE_WINDOWS_CRYPTOAPI], [1], + [Define to 1 if CryptGenRandom should be used for seeding the hash function]) +fi + +AC_ARG_ENABLE([initial-hashtable-order], + [AS_HELP_STRING([--enable-initial-hashtable-order=VAL], + [Number of buckets new object hashtables contain is 2 raised to this power. The default is 3, so empty hashtables contain 2^3 = 8 buckets.])], + [initial_hashtable_order=$enableval], [initial_hashtable_order=3]) +AC_DEFINE_UNQUOTED([INITIAL_HASHTABLE_ORDER], [$initial_hashtable_order], + [Number of buckets new object hashtables contain is 2 raised to this power. E.g. 3 -> 2^3 = 8.]) + +AC_ARG_ENABLE([Bsymbolic], + [AS_HELP_STRING([--disable-Bsymbolic], + [Avoid linking with -Bsymbolic-function])], + [], [with_Bsymbolic=check]) + +if test "x$with_Bsymbolic" != "xno" ; then + AC_MSG_CHECKING([for -Bsymbolic-functions linker flag]) + saved_LDFLAGS="${LDFLAGS}" + LDFLAGS=-Wl,-Bsymbolic-functions + AC_TRY_LINK( + [], [int main (void) { return 0; }], + [AC_MSG_RESULT([yes]) + have_Bsymbolic=yes], + [AC_MSG_RESULT([no]) + have_Bsymbolic=no] + ) + LDFLAGS="${saved_LDFLAGS}" + + if test "x$with_Bsymbolic" = "xcheck" ; then + with_Bsymbolic=$have_Bsymbolic; + fi + if test "x$with_Bsymbolic:x$have_Bsymbolic" = "xyes:xno" ; then + AC_MSG_ERROR([linker support is required for -Bsymbolic]) + fi +fi + +AS_IF([test "x$with_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions]) +AC_SUBST(JSON_BSYMBOLIC_LDFLAGS) + +# Enable symbol versioning on GNU libc +JSON_SYMVER_LDFLAGS= +AC_CHECK_DECL([__GLIBC__], [JSON_SYMVER_LDFLAGS=-Wl,--default-symver]) +AC_SUBST([JSON_SYMVER_LDFLAGS]) + +AC_ARG_ENABLE([ossfuzzers], + [AS_HELP_STRING([--enable-ossfuzzers], + [Whether to generate the fuzzers for OSS-Fuzz])], + [have_ossfuzzers=yes], [have_ossfuzzers=no]) +AM_CONDITIONAL([USE_OSSFUZZERS], [test "x$have_ossfuzzers" = "xyes"]) + + +AC_SUBST([LIB_FUZZING_ENGINE]) +AM_CONDITIONAL([USE_OSSFUZZ_FLAG], [test "x$LIB_FUZZING_ENGINE" = "x-fsanitize=fuzzer"]) +AM_CONDITIONAL([USE_OSSFUZZ_STATIC], [test -f "$LIB_FUZZING_ENGINE"]) + + +if test x$GCC = xyes; then + AC_MSG_CHECKING(for -Wno-format-truncation) + wnoformat_truncation="-Wno-format-truncation" + AS_IF([${CC} -Wno-format-truncation -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1], + [AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no) + wnoformat_truncation=""]) + + AM_CFLAGS="-Wall -Wextra -Wdeclaration-after-statement -Wshadow ${wnoformat_truncation}" +fi +AC_SUBST([AM_CFLAGS]) + +AC_CONFIG_FILES([ + jansson.pc + Makefile + doc/Makefile + src/Makefile + src/jansson_config.h + test/Makefile + test/bin/Makefile + test/ossfuzz/Makefile + test/suites/Makefile + test/suites/api/Makefile +]) +AC_OUTPUT diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/.gitignore b/src/fluent-bit/lib/jansson-e23f558/doc/.gitignore new file mode 100644 index 000000000..69fa449dd --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/.gitignore @@ -0,0 +1 @@ +_build/ diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/Makefile.am b/src/fluent-bit/lib/jansson-e23f558/doc/Makefile.am new file mode 100644 index 000000000..8186a7db8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/Makefile.am @@ -0,0 +1,20 @@ +EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst \ + gettingstarted.rst github_commits.c index.rst threadsafety.rst \ + tutorial.rst upgrading.rst ext/refcounting.py + +SPHINXBUILD = sphinx-build +SPHINXOPTS = -d _build/doctrees $(SPHINXOPTS_EXTRA) + +html-local: + $(SPHINXBUILD) -b html $(SPHINXOPTS) $(srcdir) _build/html + +install-html-local: html + mkdir -p $(DESTDIR)$(htmldir) + cp -r _build/html $(DESTDIR)$(htmldir) + +uninstall-local: + rm -rf $(DESTDIR)$(htmldir) + +clean-local: + rm -rf _build + rm -f ext/refcounting.pyc diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/README b/src/fluent-bit/lib/jansson-e23f558/doc/README new file mode 100644 index 000000000..930b3bf0c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/README @@ -0,0 +1,5 @@ +To build the documentation, invoke + + make html + +Then point your browser to _build/html/index.html. diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/apiref.rst b/src/fluent-bit/lib/jansson-e23f558/doc/apiref.rst new file mode 100644 index 000000000..4bfb68799 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/apiref.rst @@ -0,0 +1,2064 @@ +.. _apiref: + +************* +API Reference +************* + +.. highlight:: c + +Preliminaries +============= + +All declarations are in :file:`jansson.h`, so it's enough to + +:: + + #include <jansson.h> + +in each source file. + +All constants are prefixed with ``JSON_`` (except for those describing +the library version, prefixed with ``JANSSON_``). Other identifiers +are prefixed with ``json_``. Type names are suffixed with ``_t`` and +``typedef``\ 'd so that the ``struct`` keyword need not be used. + + +Library Version +=============== + +The Jansson version is of the form *A.B.C*, where *A* is the major +version, *B* is the minor version and *C* is the micro version. If the +micro version is zero, it's omitted from the version string, i.e. the +version string is just *A.B*. + +When a new release only fixes bugs and doesn't add new features or +functionality, the micro version is incremented. When new features are +added in a backwards compatible way, the minor version is incremented +and the micro version is set to zero. When there are backwards +incompatible changes, the major version is incremented and others are +set to zero. + +The following preprocessor constants specify the current version of +the library: + +``JANSSON_MAJOR_VERSION``, ``JANSSON_MINOR_VERSION``, ``JANSSON_MICRO_VERSION`` + Integers specifying the major, minor and micro versions, + respectively. + +``JANSSON_VERSION`` + A string representation of the current version, e.g. ``"1.2.1"`` or + ``"1.3"``. + +``JANSSON_VERSION_HEX`` + A 3-byte hexadecimal representation of the version, e.g. + ``0x010201`` for version 1.2.1 and ``0x010300`` for version 1.3. + This is useful in numeric comparisons, e.g.:: + + #if JANSSON_VERSION_HEX >= 0x010300 + /* Code specific to version 1.3 and above */ + #endif + +Additionally, there are functions to determine the version of Jansson at +runtime: + +.. function:: const char *jansson_version_str() + + Return the version of the Jansson library, in the same format as + the ``JANSSON_VERSION`` preprocessor constant. + + .. versionadded:: 2.13 + +.. function:: int jansson_version_cmp(int major, int minor, int micro) + + Returns an integer less than, equal to, or greater than zero if + the runtime version of Jansson is found, respectively, to be less + than, to match, or be greater than the provided *major*, *minor*, and + *micro*. + + .. versionadded:: 2.13 + +``JANSSON_THREAD_SAFE_REFCOUNT`` + If this value is defined all read-only operations and reference counting in + Jansson are thread safe. This value is not defined for versions older than + ``2.11`` or when the compiler does not provide built-in atomic functions. + + +Value Representation +==================== + +The JSON specification (:rfc:`4627`) defines the following data types: +*object*, *array*, *string*, *number*, *boolean*, and *null*. JSON +types are used dynamically; arrays and objects can hold any other data +type, including themselves. For this reason, Jansson's type system is +also dynamic in nature. There's one C type to represent all JSON +values, and this structure knows the type of the JSON value it holds. + +.. type:: json_t + + This data structure is used throughout the library to represent all + JSON values. It always contains the type of the JSON value it holds + and the value's reference count. The rest depends on the type of the + value. + +Objects of :type:`json_t` are always used through a pointer. There +are APIs for querying the type, manipulating the reference count, and +for constructing and manipulating values of different types. + +Unless noted otherwise, all API functions return an error value if an +error occurs. Depending on the function's signature, the error value +is either *NULL* or -1. Invalid arguments or invalid input are +apparent sources for errors. Memory allocation and I/O operations may +also cause errors. + + +Type +---- + +.. c:enum:: json_type + + The type of a JSON value. The following members are defined: + + +--------------------+ + | ``JSON_OBJECT`` | + +--------------------+ + | ``JSON_ARRAY`` | + +--------------------+ + | ``JSON_STRING`` | + +--------------------+ + | ``JSON_INTEGER`` | + +--------------------+ + | ``JSON_REAL`` | + +--------------------+ + | ``JSON_TRUE`` | + +--------------------+ + | ``JSON_FALSE`` | + +--------------------+ + | ``JSON_NULL`` | + +--------------------+ + + These correspond to JSON object, array, string, number, boolean and + null. A number is represented by either a value of the type + ``JSON_INTEGER`` or of the type ``JSON_REAL``. A true boolean value + is represented by a value of the type ``JSON_TRUE`` and false by a + value of the type ``JSON_FALSE``. + +.. function:: int json_typeof(const json_t *json) + + Return the type of the JSON value (a :type:`json_type` cast to + ``int``). *json* MUST NOT be *NULL*. This function is actually + implemented as a macro for speed. + +.. function:: int json_is_object(const json_t *json) + int json_is_array(const json_t *json) + int json_is_string(const json_t *json) + int json_is_integer(const json_t *json) + int json_is_real(const json_t *json) + int json_is_true(const json_t *json) + int json_is_false(const json_t *json) + int json_is_null(const json_t *json) + + These functions (actually macros) return true (non-zero) for values + of the given type, and false (zero) for values of other types and + for *NULL*. + +.. function:: int json_is_number(const json_t *json) + + Returns true for values of types ``JSON_INTEGER`` and + ``JSON_REAL``, and false for other types and for *NULL*. + +.. function:: int json_is_boolean(const json_t *json) + + Returns true for types ``JSON_TRUE`` and ``JSON_FALSE``, and false + for values of other types and for *NULL*. + +.. function:: int json_boolean_value(const json_t *json) + + Alias of :func:`json_is_true()`, i.e. returns 1 for ``JSON_TRUE`` + and 0 otherwise. + + .. versionadded:: 2.7 + + +.. _apiref-reference-count: + +Reference Count +--------------- + +The reference count is used to track whether a value is still in use +or not. When a value is created, it's reference count is set to 1. If +a reference to a value is kept (e.g. a value is stored somewhere for +later use), its reference count is incremented, and when the value is +no longer needed, the reference count is decremented. When the +reference count drops to zero, there are no references left, and the +value can be destroyed. + +.. function:: json_t *json_incref(json_t *json) + + Increment the reference count of *json* if it's not *NULL*. + Returns *json*. + +.. function:: void json_decref(json_t *json) + + Decrement the reference count of *json*. As soon as a call to + :func:`json_decref()` drops the reference count to zero, the value + is destroyed and it can no longer be used. + +Functions creating new JSON values set the reference count to 1. These +functions are said to return a **new reference**. Other functions +returning (existing) JSON values do not normally increase the +reference count. These functions are said to return a **borrowed +reference**. So, if the user will hold a reference to a value returned +as a borrowed reference, he must call :func:`json_incref`. As soon as +the value is no longer needed, :func:`json_decref` should be called +to release the reference. + +Normally, all functions accepting a JSON value as an argument will +manage the reference, i.e. increase and decrease the reference count +as needed. However, some functions **steal** the reference, i.e. they +have the same result as if the user called :func:`json_decref()` on +the argument right after calling the function. These functions are +suffixed with ``_new`` or have ``_new_`` somewhere in their name. + +For example, the following code creates a new JSON array and appends +an integer to it:: + + json_t *array, *integer; + + array = json_array(); + integer = json_integer(42); + + json_array_append(array, integer); + json_decref(integer); + +Note how the caller has to release the reference to the integer value +by calling :func:`json_decref()`. By using a reference stealing +function :func:`json_array_append_new()` instead of +:func:`json_array_append()`, the code becomes much simpler:: + + json_t *array = json_array(); + json_array_append_new(array, json_integer(42)); + +In this case, the user doesn't have to explicitly release the +reference to the integer value, as :func:`json_array_append_new()` +steals the reference when appending the value to the array. + +In the following sections it is clearly documented whether a function +will return a new or borrowed reference or steal a reference to its +argument. + + +Circular References +------------------- + +A circular reference is created when an object or an array is, +directly or indirectly, inserted inside itself. The direct case is +simple:: + + json_t *obj = json_object(); + json_object_set(obj, "foo", obj); + +Jansson will refuse to do this, and :func:`json_object_set()` (and +all the other such functions for objects and arrays) will return with +an error status. The indirect case is the dangerous one:: + + json_t *arr1 = json_array(), *arr2 = json_array(); + json_array_append(arr1, arr2); + json_array_append(arr2, arr1); + +In this example, the array ``arr2`` is contained in the array +``arr1``, and vice versa. Jansson cannot check for this kind of +indirect circular references without a performance hit, so it's up to +the user to avoid them. + +If a circular reference is created, the memory consumed by the values +cannot be freed by :func:`json_decref()`. The reference counts never +drops to zero because the values are keeping the references to each +other. Moreover, trying to encode the values with any of the encoding +functions will fail. The encoder detects circular references and +returns an error status. + +Scope Dereferencing +------------------- + +.. versionadded:: 2.9 + +It is possible to use the ``json_auto_t`` type to automatically +dereference a value at the end of a scope. For example:: + + void function(void) { + json_auto_t *value = NULL; + value = json_string("foo"); + /* json_decref(value) is automatically called. */ + } + +This feature is only available on GCC and Clang. So if your project +has a portability requirement for other compilers, you should avoid +this feature. + +Additionally, as always, care should be taken when passing values to +functions that steal references. + +True, False and Null +==================== + +These three values are implemented as singletons, so the returned +pointers won't change between invocations of these functions. + +.. function:: json_t *json_true(void) + + .. refcounting:: new + + Returns the JSON true value. + +.. function:: json_t *json_false(void) + + .. refcounting:: new + + Returns the JSON false value. + +.. function:: json_t *json_boolean(val) + + .. refcounting:: new + + Returns JSON false if ``val`` is zero, and JSON true otherwise. + This is a macro, and equivalent to ``val ? json_true() : + json_false()``. + + .. versionadded:: 2.4 + + +.. function:: json_t *json_null(void) + + .. refcounting:: new + + Returns the JSON null value. + + +String +====== + +Jansson uses UTF-8 as the character encoding. All JSON strings must be +valid UTF-8 (or ASCII, as it's a subset of UTF-8). All Unicode +codepoints U+0000 through U+10FFFF are allowed, but you must use +length-aware functions if you wish to embed null bytes in strings. + +.. function:: json_t *json_string(const char *value) + + .. refcounting:: new + + Returns a new JSON string, or *NULL* on error. *value* must be a + valid null terminated UTF-8 encoded Unicode string. + +.. function:: json_t *json_stringn(const char *value, size_t len) + + .. refcounting:: new + + Like :func:`json_string`, but with explicit length, so *value* may + contain null characters or not be null terminated. + + .. versionadded:: 2.7 + +.. function:: json_t *json_string_nocheck(const char *value) + + .. refcounting:: new + + Like :func:`json_string`, but doesn't check that *value* is valid + UTF-8. Use this function only if you are certain that this really + is the case (e.g. you have already checked it by other means). + +.. function:: json_t *json_stringn_nocheck(const char *value, size_t len) + + .. refcounting:: new + + Like :func:`json_string_nocheck`, but with explicit length, so + *value* may contain null characters or not be null terminated. + + .. versionadded:: 2.7 + +.. function:: const char *json_string_value(const json_t *string) + + Returns the associated value of *string* as a null terminated UTF-8 + encoded string, or *NULL* if *string* is not a JSON string. + + The returned value is read-only and must not be modified or freed by + the user. It is valid as long as *string* exists, i.e. as long as + its reference count has not dropped to zero. + +.. function:: size_t json_string_length(const json_t *string) + + Returns the length of *string* in its UTF-8 presentation, or zero + if *string* is not a JSON string. + + .. versionadded:: 2.7 + +.. function:: int json_string_set(json_t *string, const char *value) + + Sets the associated value of *string* to *value*. *value* must be a + valid UTF-8 encoded Unicode string. Returns 0 on success and -1 on + error. + +.. function:: int json_string_setn(json_t *string, const char *value, size_t len) + + Like :func:`json_string_set`, but with explicit length, so *value* + may contain null characters or not be null terminated. + + .. versionadded:: 2.7 + +.. function:: int json_string_set_nocheck(json_t *string, const char *value) + + Like :func:`json_string_set`, but doesn't check that *value* is + valid UTF-8. Use this function only if you are certain that this + really is the case (e.g. you have already checked it by other + means). + +.. function:: int json_string_setn_nocheck(json_t *string, const char *value, size_t len) + + Like :func:`json_string_set_nocheck`, but with explicit length, + so *value* may contain null characters or not be null terminated. + + .. versionadded:: 2.7 + +.. function:: json_t *json_sprintf(const char *format, ...) + json_t *json_vsprintf(const char *format, va_list ap) + + .. refcounting:: new + + Construct a JSON string from a format string and varargs, just like + :func:`printf()`. + + .. versionadded:: 2.11 + + +Number +====== + +The JSON specification only contains one numeric type, "number". The C +programming language has distinct types for integer and floating-point +numbers, so for practical reasons Jansson also has distinct types for +the two. They are called "integer" and "real", respectively. For more +information, see :ref:`rfc-conformance`. + +.. type:: json_int_t + + This is the C type that is used to store JSON integer values. It + represents the widest integer type available on your system. In + practice it's just a typedef of ``long long`` if your compiler + supports it, otherwise ``long``. + + Usually, you can safely use plain ``int`` in place of + ``json_int_t``, and the implicit C integer conversion handles the + rest. Only when you know that you need the full 64-bit range, you + should use ``json_int_t`` explicitly. + +``JSON_INTEGER_IS_LONG_LONG`` + This is a preprocessor variable that holds the value 1 if + :type:`json_int_t` is ``long long``, and 0 if it's ``long``. It + can be used as follows:: + + #if JSON_INTEGER_IS_LONG_LONG + /* Code specific for long long */ + #else + /* Code specific for long */ + #endif + +``JSON_INTEGER_FORMAT`` + This is a macro that expands to a :func:`printf()` conversion + specifier that corresponds to :type:`json_int_t`, without the + leading ``%`` sign, i.e. either ``"lld"`` or ``"ld"``. This macro + is required because the actual type of :type:`json_int_t` can be + either ``long`` or ``long long``, and :func:`printf()` requires + different length modifiers for the two. + + Example:: + + json_int_t x = 123123123; + printf("x is %" JSON_INTEGER_FORMAT "\n", x); + + +.. function:: json_t *json_integer(json_int_t value) + + .. refcounting:: new + + Returns a new JSON integer, or *NULL* on error. + +.. function:: json_int_t json_integer_value(const json_t *integer) + + Returns the associated value of *integer*, or 0 if *json* is not a + JSON integer. + +.. function:: int json_integer_set(const json_t *integer, json_int_t value) + + Sets the associated value of *integer* to *value*. Returns 0 on + success and -1 if *integer* is not a JSON integer. + +.. function:: json_t *json_real(double value) + + .. refcounting:: new + + Returns a new JSON real, or *NULL* on error. + +.. function:: double json_real_value(const json_t *real) + + Returns the associated value of *real*, or 0.0 if *real* is not a + JSON real. + +.. function:: int json_real_set(const json_t *real, double value) + + Sets the associated value of *real* to *value*. Returns 0 on + success and -1 if *real* is not a JSON real. + +.. function:: double json_number_value(const json_t *json) + + Returns the associated value of the JSON integer or JSON real + *json*, cast to double regardless of the actual type. If *json* is + neither JSON real nor JSON integer, 0.0 is returned. + + +Array +===== + +A JSON array is an ordered collection of other JSON values. + +.. function:: json_t *json_array(void) + + .. refcounting:: new + + Returns a new JSON array, or *NULL* on error. Initially, the array + is empty. + +.. function:: size_t json_array_size(const json_t *array) + + Returns the number of elements in *array*, or 0 if *array* is NULL + or not a JSON array. + +.. function:: json_t *json_array_get(const json_t *array, size_t index) + + .. refcounting:: borrow + + Returns the element in *array* at position *index*. The valid range + for *index* is from 0 to the return value of + :func:`json_array_size()` minus 1. If *array* is not a JSON array, + if *array* is *NULL*, or if *index* is out of range, *NULL* is + returned. + +.. function:: int json_array_set(json_t *array, size_t index, json_t *value) + + Replaces the element in *array* at position *index* with *value*. + The valid range for *index* is from 0 to the return value of + :func:`json_array_size()` minus 1. Returns 0 on success and -1 on + error. + +.. function:: int json_array_set_new(json_t *array, size_t index, json_t *value) + + Like :func:`json_array_set()` but steals the reference to *value*. + This is useful when *value* is newly created and not used after + the call. + +.. function:: int json_array_append(json_t *array, json_t *value) + + Appends *value* to the end of *array*, growing the size of *array* + by 1. Returns 0 on success and -1 on error. + +.. function:: int json_array_append_new(json_t *array, json_t *value) + + Like :func:`json_array_append()` but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: int json_array_insert(json_t *array, size_t index, json_t *value) + + Inserts *value* to *array* at position *index*, shifting the + elements at *index* and after it one position towards the end of + the array. Returns 0 on success and -1 on error. + +.. function:: int json_array_insert_new(json_t *array, size_t index, json_t *value) + + Like :func:`json_array_insert()` but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: int json_array_remove(json_t *array, size_t index) + + Removes the element in *array* at position *index*, shifting the + elements after *index* one position towards the start of the array. + Returns 0 on success and -1 on error. The reference count of the + removed value is decremented. + +.. function:: int json_array_clear(json_t *array) + + Removes all elements from *array*. Returns 0 on success and -1 on + error. The reference count of all removed values are decremented. + +.. function:: int json_array_extend(json_t *array, json_t *other_array) + + Appends all elements in *other_array* to the end of *array*. + Returns 0 on success and -1 on error. + +.. function:: void json_array_foreach(array, index, value) + + Iterate over every element of ``array``, running the block + of code that follows each time with the proper values set to + variables ``index`` and ``value``, of types :type:`size_t` and + :type:`json_t` pointer respectively. Example:: + + /* array is a JSON array */ + size_t index; + json_t *value; + + json_array_foreach(array, index, value) { + /* block of code that uses index and value */ + } + + The items are returned in increasing index order. + + This macro expands to an ordinary ``for`` statement upon + preprocessing, so its performance is equivalent to that of + hand-written code using the array access functions. + The main advantage of this macro is that it abstracts + away the complexity, and makes for more concise and readable code. + + .. versionadded:: 2.5 + + +Object +====== + +A JSON object is a dictionary of key-value pairs, where the key is a +Unicode string and the value is any JSON value. + +Even though null bytes are allowed in string values, they are not +allowed in object keys. + +.. function:: json_t *json_object(void) + + .. refcounting:: new + + Returns a new JSON object, or *NULL* on error. Initially, the + object is empty. + +.. function:: size_t json_object_size(const json_t *object) + + Returns the number of elements in *object*, or 0 if *object* is not + a JSON object. + +.. function:: json_t *json_object_get(const json_t *object, const char *key) + + .. refcounting:: borrow + + Get a value corresponding to *key* from *object*. Returns *NULL* if + *key* is not found and on error. + +.. function:: json_t *json_object_getn(const json_t *object, const char *key, size_t key_len) + + .. refcounting:: borrow + + Like :func:`json_object_get`, but give the fixed-length *key* with length *key_len*. + See :ref:`fixed_length_keys` for details. + + .. versionadded:: 2.14 + +.. function:: int json_object_set(json_t *object, const char *key, json_t *value) + + Set the value of *key* to *value* in *object*. *key* must be a + valid null terminated UTF-8 encoded Unicode string. If there + already is a value for *key*, it is replaced by the new value. + Returns 0 on success and -1 on error. + +.. function:: int json_object_setn(json_t *object, const char *key, size_t key_len, json_t *value) + + Like :func:`json_object_set`, but give the fixed-length *key* with length *key_len*. + See :ref:`fixed_length_keys` for details. + + .. versionadded:: 2.14 + +.. function:: int json_object_set_nocheck(json_t *object, const char *key, json_t *value) + + Like :func:`json_object_set`, but doesn't check that *key* is + valid UTF-8. Use this function only if you are certain that this + really is the case (e.g. you have already checked it by other + means). + +.. function:: int json_object_setn_nocheck(json_t *object, const char *key, size_t key_len, json_t *value) + + Like :func:`json_object_set_nocheck`, but give the fixed-length *key* with length *key_len*. + See :ref:`fixed_length_keys` for details. + + .. versionadded:: 2.14 + +.. function:: int json_object_set_new(json_t *object, const char *key, json_t *value) + + Like :func:`json_object_set()` but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: int json_object_setn_new(json_t *object, const char *key, size_t key_len, json_t *value) + + Like :func:`json_object_set_new`, but give the fixed-length *key* with length *key_len*. + See :ref:`fixed_length_keys` for details. + + .. versionadded:: 2.14 + +.. function:: int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value) + + Like :func:`json_object_set_new`, but doesn't check that *key* is + valid UTF-8. Use this function only if you are certain that this + really is the case (e.g. you have already checked it by other + means). + +.. function:: int json_object_setn_new_nocheck(json_t *object, const char *key, size_t key_len, json_t *value) + + Like :func:`json_object_set_new_nocheck`, but give the fixed-length *key* with length *key_len*. + See :ref:`fixed_length_keys` for details. + + .. versionadded:: 2.14 + +.. function:: int json_object_del(json_t *object, const char *key) + + Delete *key* from *object* if it exists. Returns 0 on success, or + -1 if *key* was not found. The reference count of the removed value + is decremented. + +.. function:: int json_object_deln(json_t *object, const char *key, size_t key_len) + + Like :func:`json_object_del`, but give the fixed-length *key* with length *key_len*. + See :ref:`fixed_length_keys` for details. + + .. versionadded:: 2.14 + +.. function:: int json_object_clear(json_t *object) + + Remove all elements from *object*. Returns 0 on success and -1 if + *object* is not a JSON object. The reference count of all removed + values are decremented. + +.. function:: int json_object_update(json_t *object, json_t *other) + + Update *object* with the key-value pairs from *other*, overwriting + existing keys. Returns 0 on success or -1 on error. + +.. function:: int json_object_update_existing(json_t *object, json_t *other) + + Like :func:`json_object_update()`, but only the values of existing + keys are updated. No new keys are created. Returns 0 on success or + -1 on error. + + .. versionadded:: 2.3 + +.. function:: int json_object_update_missing(json_t *object, json_t *other) + + Like :func:`json_object_update()`, but only new keys are created. + The value of any existing key is not changed. Returns 0 on success + or -1 on error. + + .. versionadded:: 2.3 + +.. function:: int json_object_update_new(json_t *object, json_t *other) + + Like :func:`json_object_update()`, but steals the reference to + *other*. This is useful when *other* is newly created and not used + after the call. + +.. function:: int json_object_update_existing_new(json_t *object, json_t *other) + + Like :func:`json_object_update_new()`, but only the values of existing + keys are updated. No new keys are created. Returns 0 on success or + -1 on error. + +.. function:: int json_object_update_missing_new(json_t *object, json_t *other) + + Like :func:`json_object_update_new()`, but only new keys are created. + The value of any existing key is not changed. Returns 0 on success + or -1 on error. + +.. function:: int json_object_update_recursive(json_t *object, json_t *other) + + Like :func:`json_object_update()`, but object values in *other* are + recursively merged with the corresponding values in *object* if they are also + objects, instead of overwriting them. Returns 0 on success or -1 on error. + +.. function:: void json_object_foreach(object, key, value) + + Iterate over every key-value pair of ``object``, running the block + of code that follows each time with the proper values set to + variables ``key`` and ``value``, of types ``const char *`` and + :type:`json_t` pointer respectively. Example:: + + /* obj is a JSON object */ + const char *key; + json_t *value; + + json_object_foreach(obj, key, value) { + /* block of code that uses key and value */ + } + + The items are returned in the order they were inserted to the + object. + + **Note:** It's not safe to call ``json_object_del(object, key)`` or ``json_object_deln(object, key, key_len)`` + during iteration. If you need to, use + :func:`json_object_foreach_safe` instead. + + This macro expands to an ordinary ``for`` statement upon + preprocessing, so its performance is equivalent to that of + hand-written iteration code using the object iteration protocol + (see below). The main advantage of this macro is that it abstracts + away the complexity behind iteration, and makes for more concise and + readable code. + + .. versionadded:: 2.3 + + +.. function:: void json_object_foreach_safe(object, tmp, key, value) + + Like :func:`json_object_foreach()`, but it's safe to call + ``json_object_del(object, key)`` or ``json_object_deln(object, key, key_len)`` during iteration. + You need to pass an extra ``void *`` parameter ``tmp`` that is used for temporary storage. + + .. versionadded:: 2.8 + +.. function:: void json_object_keylen_foreach(object, key, key_len, value) + + Like :c:func:`json_object_foreach`, but in *key_len* stored length of the *key*. + Example:: + + /* obj is a JSON object */ + const char *key; + json_t *value; + size_t len; + + json_object_keylen_foreach(obj, key, len, value) { + printf("got key %s with length %zu\n", key, len); + } + + **Note:** It's not safe to call ``json_object_deln(object, key, key_len)`` + during iteration. If you need to, use + :func:`json_object_keylen_foreach_safe` instead. + + .. versionadded:: 2.14 + + +.. function:: void json_object_keylen_foreach_safe(object, tmp, key, key_len, value) + + Like :func:`json_object_keylen_foreach()`, but it's safe to call + ``json_object_deln(object, key, key_len)`` during iteration. + You need to pass an extra ``void *`` parameter ``tmp`` that is used for temporary storage. + + .. versionadded:: 2.14 + +The following functions can be used to iterate through all key-value +pairs in an object. The items are returned in the order they were +inserted to the object. + +.. function:: void *json_object_iter(json_t *object) + + Returns an opaque iterator which can be used to iterate over all + key-value pairs in *object*, or *NULL* if *object* is empty. + +.. function:: void *json_object_iter_at(json_t *object, const char *key) + + Like :func:`json_object_iter()`, but returns an iterator to the + key-value pair in *object* whose key is equal to *key*, or NULL if + *key* is not found in *object*. Iterating forward to the end of + *object* only yields all key-value pairs of the object if *key* + happens to be the first key in the underlying hash table. + +.. function:: void *json_object_iter_next(json_t *object, void *iter) + + Returns an iterator pointing to the next key-value pair in *object* + after *iter*, or *NULL* if the whole object has been iterated + through. + +.. function:: const char *json_object_iter_key(void *iter) + + Extract the associated key from *iter*. + +.. function:: size_t json_object_iter_key_len(void *iter) + + Extract the associated key length from *iter*. + + .. versionadded:: 2.14 + +.. function:: json_t *json_object_iter_value(void *iter) + + .. refcounting:: borrow + + Extract the associated value from *iter*. + +.. function:: int json_object_iter_set(json_t *object, void *iter, json_t *value) + + Set the value of the key-value pair in *object*, that is pointed to + by *iter*, to *value*. + +.. function:: int json_object_iter_set_new(json_t *object, void *iter, json_t *value) + + Like :func:`json_object_iter_set()`, but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: void *json_object_key_to_iter(const char *key) + + Like :func:`json_object_iter_at()`, but much faster. Only works for + values returned by :func:`json_object_iter_key()`. Using other keys + will lead to segfaults. This function is used internally to + implement :func:`json_object_foreach`. Example:: + + /* obj is a JSON object */ + const char *key; + json_t *value; + + void *iter = json_object_iter(obj); + while(iter) + { + key = json_object_iter_key(iter); + value = json_object_iter_value(iter); + /* use key and value ... */ + iter = json_object_iter_next(obj, iter); + } + + .. versionadded:: 2.3 + +.. function:: void json_object_seed(size_t seed) + + Seed the hash function used in Jansson's hashtable implementation. + The seed is used to randomize the hash function so that an + attacker cannot control its output. + + If *seed* is 0, Jansson generates the seed itself by reading + random data from the operating system's entropy sources. If no + entropy sources are available, falls back to using a combination + of the current timestamp (with microsecond precision if possible) + and the process ID. + + If called at all, this function must be called before any calls to + :func:`json_object()`, either explicit or implicit. If this + function is not called by the user, the first call to + :func:`json_object()` (either explicit or implicit) seeds the hash + function. See :ref:`thread-safety` for notes on thread safety. + + If repeatable results are required, for e.g. unit tests, the hash + function can be "unrandomized" by calling :func:`json_object_seed` + with a constant value on program startup, e.g. + ``json_object_seed(1)``. + + .. versionadded:: 2.6 + + +Error reporting +=============== + +Jansson uses a single struct type to pass error information to the +user. See sections :ref:`apiref-decoding`, :ref:`apiref-pack` and +:ref:`apiref-unpack` for functions that pass error information using +this struct. + +.. type:: json_error_t + + .. member:: char text[] + + The error message (in UTF-8), or an empty string if a message is + not available. + + The last byte of this array contains a numeric error code. Use + :func:`json_error_code()` to extract this code. + + .. member:: char source[] + + Source of the error. This can be (a part of) the file name or a + special identifier in angle brackets (e.g. ``<string>``). + + .. member:: int line + + The line number on which the error occurred. + + .. member:: int column + + The column on which the error occurred. Note that this is the + *character column*, not the byte column, i.e. a multibyte UTF-8 + character counts as one column. + + .. member:: int position + + The position in bytes from the start of the input. This is + useful for debugging Unicode encoding problems. + +The normal use of :type:`json_error_t` is to allocate it on the stack, +and pass a pointer to a function. Example:: + + int main() { + json_t *json; + json_error_t error; + + json = json_load_file("/path/to/file.json", 0, &error); + if(!json) { + /* the error variable contains error information */ + } + ... + } + +Also note that if the call succeeded (``json != NULL`` in the above +example), the contents of ``error`` are generally left unspecified. +The decoding functions write to the ``position`` member also on +success. See :ref:`apiref-decoding` for more info. + +All functions also accept *NULL* as the :type:`json_error_t` pointer, +in which case no error information is returned to the caller. + +.. c:enum:: json_error_code + + An enumeration containing numeric error codes. The following errors are + currently defined: + + ``json_error_unknown`` + + Unknown error. This should only be returned for non-errorneous + :type:`json_error_t` structures. + + ``json_error_out_of_memory`` + + The library couldn’t allocate any heap memory. + + ``json_error_stack_overflow`` + + Nesting too deep. + + ``json_error_cannot_open_file`` + + Couldn’t open input file. + + ``json_error_invalid_argument`` + + A function argument was invalid. + + ``json_error_invalid_utf8`` + + The input string isn’t valid UTF-8. + + ``json_error_premature_end_of_input`` + + The input ended in the middle of a JSON value. + + ``json_error_end_of_input_expected`` + + There was some text after the end of a JSON value. See the + ``JSON_DISABLE_EOF_CHECK`` flag. + + ``json_error_invalid_syntax`` + + JSON syntax error. + + ``json_error_invalid_format`` + + Invalid format string for packing or unpacking. + + ``json_error_wrong_type`` + + When packing or unpacking, the actual type of a value differed from the + one specified in the format string. + + ``json_error_null_character`` + + A null character was detected in a JSON string. See the + ``JSON_ALLOW_NUL`` flag. + + ``json_error_null_value`` + + When packing or unpacking, some key or value was ``NULL``. + + ``json_error_null_byte_in_key`` + + An object key would contain a null byte. Jansson can’t represent such + keys; see :ref:`rfc-conformance`. + + ``json_error_duplicate_key`` + + Duplicate key in object. See the ``JSON_REJECT_DUPLICATES`` flag. + + ``json_error_numeric_overflow`` + + When converting a JSON number to a C numeric type, a numeric overflow + was detected. + + ``json_error_item_not_found`` + + Key in object not found. + + ``json_error_index_out_of_range`` + + Array index is out of range. + + .. versionadded:: 2.11 + +.. function:: enum json_error_code json_error_code(const json_error_t *error) + + Returns the error code embedded in ``error->text``. + + .. versionadded:: 2.11 + + +Encoding +======== + +This section describes the functions that can be used to encode +values to JSON. By default, only objects and arrays can be encoded +directly, since they are the only valid *root* values of a JSON text. +To encode any JSON value, use the ``JSON_ENCODE_ANY`` flag (see +below). + +By default, the output has no newlines, and spaces are used between +array and object elements for a readable output. This behavior can be +altered by using the ``JSON_INDENT`` and ``JSON_COMPACT`` flags +described below. A newline is never appended to the end of the encoded +JSON data. + +Each function takes a *flags* parameter that controls some aspects of +how the data is encoded. Its default value is 0. The following macros +can be ORed together to obtain *flags*. + +``JSON_INDENT(n)`` + Pretty-print the result, using newlines between array and object + items, and indenting with *n* spaces. The valid range for *n* is + between 0 and 31 (inclusive), other values result in an undefined + output. If ``JSON_INDENT`` is not used or *n* is 0, no newlines are + inserted between array and object items. + + The ``JSON_MAX_INDENT`` constant defines the maximum indentation + that can be used, and its value is 31. + + .. versionchanged:: 2.7 + Added ``JSON_MAX_INDENT``. + +``JSON_COMPACT`` + This flag enables a compact representation, i.e. sets the separator + between array and object items to ``","`` and between object keys + and values to ``":"``. Without this flag, the corresponding + separators are ``", "`` and ``": "`` for more readable output. + +``JSON_ENSURE_ASCII`` + If this flag is used, the output is guaranteed to consist only of + ASCII characters. This is achieved by escaping all Unicode + characters outside the ASCII range. + +``JSON_SORT_KEYS`` + If this flag is used, all the objects in output are sorted by key. + This is useful e.g. if two JSON texts are diffed or visually + compared. + +``JSON_PRESERVE_ORDER`` + **Deprecated since version 2.8:** Order of object keys + is always preserved. + + Prior to version 2.8: If this flag is used, object keys in the + output are sorted into the same order in which they were first + inserted to the object. For example, decoding a JSON text and then + encoding with this flag preserves the order of object keys. + +``JSON_ENCODE_ANY`` + Specifying this flag makes it possible to encode any JSON value on + its own. Without it, only objects and arrays can be passed as the + *json* value to the encoding functions. + + **Note:** Encoding any value may be useful in some scenarios, but + it's generally discouraged as it violates strict compatibility with + :rfc:`4627`. If you use this flag, don't expect interoperability + with other JSON systems. + + .. versionadded:: 2.1 + +``JSON_ESCAPE_SLASH`` + Escape the ``/`` characters in strings with ``\/``. + + .. versionadded:: 2.4 + +``JSON_REAL_PRECISION(n)`` + Output all real numbers with at most *n* digits of precision. The + valid range for *n* is between 0 and 31 (inclusive), and other + values result in an undefined behavior. + + By default, the precision is 17, to correctly and losslessly encode + all IEEE 754 double precision floating point numbers. + + .. versionadded:: 2.7 + +``JSON_EMBED`` + If this flag is used, the opening and closing characters of the top-level + array ('[', ']') or object ('{', '}') are omitted during encoding. This + flag is useful when concatenating multiple arrays or objects into a stream. + + .. versionadded:: 2.10 + +These functions output UTF-8: + +.. function:: char *json_dumps(const json_t *json, size_t flags) + + Returns the JSON representation of *json* as a string, or *NULL* on + error. *flags* is described above. The return value must be freed + by the caller using :func:`free()`. Note that if you have called + :func:`json_set_alloc_funcs()` to override :func:`free()`, you should + call your custom free function instead to free the return value. + +.. function:: size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) + + Writes the JSON representation of *json* to the *buffer* of + *size* bytes. Returns the number of bytes that would be written + or 0 on error. *flags* is described above. *buffer* is not + null-terminated. + + This function never writes more than *size* bytes. If the return + value is greater than *size*, the contents of the *buffer* are + undefined. This behavior enables you to specify a NULL *buffer* + to determine the length of the encoding. For example:: + + size_t size = json_dumpb(json, NULL, 0, 0); + if (size == 0) + return -1; + + char *buf = alloca(size); + + size = json_dumpb(json, buf, size, 0); + + .. versionadded:: 2.10 + +.. function:: int json_dumpf(const json_t *json, FILE *output, size_t flags) + + Write the JSON representation of *json* to the stream *output*. + *flags* is described above. Returns 0 on success and -1 on error. + If an error occurs, something may have already been written to + *output*. In this case, the output is undefined and most likely not + valid JSON. + +.. function:: int json_dumpfd(const json_t *json, int output, size_t flags) + + Write the JSON representation of *json* to the stream *output*. + *flags* is described above. Returns 0 on success and -1 on error. + If an error occurs, something may have already been written to + *output*. In this case, the output is undefined and most likely not + valid JSON. + + It is important to note that this function can only succeed on stream + file descriptors (such as SOCK_STREAM). Using this function on a + non-stream file descriptor will result in undefined behavior. For + non-stream file descriptors, see instead :func:`json_dumpb()`. + + This function requires POSIX and fails on all non-POSIX systems. + + .. versionadded:: 2.10 + +.. function:: int json_dump_file(const json_t *json, const char *path, size_t flags) + + Write the JSON representation of *json* to the file *path*. If + *path* already exists, it is overwritten. *flags* is described + above. Returns 0 on success and -1 on error. + +.. type:: json_dump_callback_t + + A typedef for a function that's called by + :func:`json_dump_callback()`:: + + typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + + *buffer* points to a buffer containing a chunk of output, *size* is + the length of the buffer, and *data* is the corresponding + :func:`json_dump_callback()` argument passed through. + + *buffer* is guaranteed to be a valid UTF-8 string (i.e. multi-byte + code unit sequences are preserved). *buffer* never contains + embedded null bytes. + + On error, the function should return -1 to stop the encoding + process. On success, it should return 0. + + .. versionadded:: 2.2 + +.. function:: int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) + + Call *callback* repeatedly, passing a chunk of the JSON + representation of *json* each time. *flags* is described above. + Returns 0 on success and -1 on error. + + .. versionadded:: 2.2 + + +.. _apiref-decoding: + +Decoding +======== + +This section describes the functions that can be used to decode JSON +text to the Jansson representation of JSON data. The JSON +specification requires that a JSON text is either a serialized array +or object, and this requirement is also enforced with the following +functions. In other words, the top level value in the JSON text being +decoded must be either array or object. To decode any JSON value, use +the ``JSON_DECODE_ANY`` flag (see below). + +See :ref:`rfc-conformance` for a discussion on Jansson's conformance +to the JSON specification. It explains many design decisions that +affect especially the behavior of the decoder. + +Each function takes a *flags* parameter that can be used to control +the behavior of the decoder. Its default value is 0. The following +macros can be ORed together to obtain *flags*. + +``JSON_REJECT_DUPLICATES`` + Issue a decoding error if any JSON object in the input text + contains duplicate keys. Without this flag, the value of the last + occurrence of each key ends up in the result. Key equivalence is + checked byte-by-byte, without special Unicode comparison + algorithms. + + .. versionadded:: 2.1 + +``JSON_DECODE_ANY`` + By default, the decoder expects an array or object as the input. + With this flag enabled, the decoder accepts any valid JSON value. + + **Note:** Decoding any value may be useful in some scenarios, but + it's generally discouraged as it violates strict compatibility with + :rfc:`4627`. If you use this flag, don't expect interoperability + with other JSON systems. + + .. versionadded:: 2.3 + +``JSON_DISABLE_EOF_CHECK`` + By default, the decoder expects that its whole input constitutes a + valid JSON text, and issues an error if there's extra data after + the otherwise valid JSON input. With this flag enabled, the decoder + stops after decoding a valid JSON array or object, and thus allows + extra data after the JSON text. + + Normally, reading will stop when the last ``]`` or ``}`` in the + JSON input is encountered. If both ``JSON_DISABLE_EOF_CHECK`` and + ``JSON_DECODE_ANY`` flags are used, the decoder may read one extra + UTF-8 code unit (up to 4 bytes of input). For example, decoding + ``4true`` correctly decodes the integer 4, but also reads the + ``t``. For this reason, if reading multiple consecutive values that + are not arrays or objects, they should be separated by at least one + whitespace character. + + .. versionadded:: 2.1 + +``JSON_DECODE_INT_AS_REAL`` + JSON defines only one number type. Jansson distinguishes between + ints and reals. For more information see :ref:`real-vs-integer`. + With this flag enabled the decoder interprets all numbers as real + values. Integers that do not have an exact double representation + will silently result in a loss of precision. Integers that cause + a double overflow will cause an error. + + .. versionadded:: 2.5 + +``JSON_ALLOW_NUL`` + Allow ``\u0000`` escape inside string values. This is a safety + measure; If you know your input can contain null bytes, use this + flag. If you don't use this flag, you don't have to worry about null + bytes inside strings unless you explicitly create themselves by + using e.g. :func:`json_stringn()` or ``s#`` format specifier for + :func:`json_pack()`. + + Object keys cannot have embedded null bytes even if this flag is + used. + + .. versionadded:: 2.6 + +Each function also takes an optional :type:`json_error_t` parameter +that is filled with error information if decoding fails. It's also +updated on success; the number of bytes of input read is written to +its ``position`` field. This is especially useful when using +``JSON_DISABLE_EOF_CHECK`` to read multiple consecutive JSON texts. + +.. versionadded:: 2.3 + Number of bytes of input read is written to the ``position`` field + of the :type:`json_error_t` structure. + +If no error or position information is needed, you can pass *NULL*. + +.. function:: json_t *json_loads(const char *input, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON string *input* and returns the array or object it + contains, or *NULL* on error, in which case *error* is filled with + information about the error. *flags* is described above. + +.. function:: json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON string *buffer*, whose length is *buflen*, and + returns the array or object it contains, or *NULL* on error, in + which case *error* is filled with information about the error. This + is similar to :func:`json_loads()` except that the string doesn't + need to be null-terminated. *flags* is described above. + + .. versionadded:: 2.1 + +.. function:: json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in stream *input* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. *flags* is described + above. + + This function will start reading the input from whatever position + the input file was in, without attempting to seek first. If an error + occurs, the file position will be left indeterminate. On success, + the file position will be at EOF, unless ``JSON_DISABLE_EOF_CHECK`` + flag was used. In this case, the file position will be at the first + character after the last ``]`` or ``}`` in the JSON input. This + allows calling :func:`json_loadf()` on the same ``FILE`` object + multiple times, if the input consists of consecutive JSON texts, + possibly separated by whitespace. + +.. function:: json_t *json_loadfd(int input, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in stream *input* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. *flags* is described + above. + + This function will start reading the input from whatever position + the input file descriptor was in, without attempting to seek first. + If an error occurs, the file position will be left indeterminate. + On success, the file position will be at EOF, unless + ``JSON_DISABLE_EOF_CHECK`` flag was used. In this case, the file + descriptor's position will be at the first character after the last + ``]`` or ``}`` in the JSON input. This allows calling + :func:`json_loadfd()` on the same file descriptor multiple times, + if the input consists of consecutive JSON texts, possibly separated + by whitespace. + + It is important to note that this function can only succeed on stream + file descriptors (such as SOCK_STREAM). Using this function on a + non-stream file descriptor will result in undefined behavior. For + non-stream file descriptors, see instead :func:`json_loadb()`. In + addition, please note that this function cannot be used on non-blocking + file descriptors (such as a non-blocking socket). Using this function + on non-blocking file descriptors has a high risk of data loss because + it does not support resuming. + + This function requires POSIX and fails on all non-POSIX systems. + + .. versionadded:: 2.10 + +.. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in file *path* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. *flags* is described + above. + +.. type:: json_load_callback_t + + A typedef for a function that's called by + :func:`json_load_callback()` to read a chunk of input data:: + + typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + + *buffer* points to a buffer of *buflen* bytes, and *data* is the + corresponding :func:`json_load_callback()` argument passed through. + + On success, the function should write at most *buflen* bytes to + *buffer*, and return the number of bytes written; a returned value + of 0 indicates that no data was produced and that the end of file + has been reached. On error, the function should return + ``(size_t)-1`` to abort the decoding process. + + In UTF-8, some code points are encoded as multi-byte sequences. The + callback function doesn't need to worry about this, as Jansson + handles it at a higher level. For example, you can safely read a + fixed number of bytes from a network connection without having to + care about code unit sequences broken apart by the chunk + boundaries. + + .. versionadded:: 2.4 + +.. function:: json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text produced by repeated calls to *callback*, and + returns the array or object it contains, or *NULL* on error, in + which case *error* is filled with information about the error. + *data* is passed through to *callback* on each call. *flags* is + described above. + + .. versionadded:: 2.4 + + +.. _apiref-pack: + +Building Values +=============== + +This section describes functions that help to create, or *pack*, +complex JSON values, especially nested objects and arrays. Value +building is based on a *format string* that is used to tell the +functions about the expected arguments. + +For example, the format string ``"i"`` specifies a single integer +value, while the format string ``"[ssb]"`` or the equivalent ``"[s, s, +b]"`` specifies an array value with two strings and a boolean as its +items:: + + /* Create the JSON integer 42 */ + json_pack("i", 42); + + /* Create the JSON array ["foo", "bar", true] */ + json_pack("[ssb]", "foo", "bar", 1); + +Here's the full list of format specifiers. The type in parentheses +denotes the resulting JSON type, and the type in brackets (if any) +denotes the C type that is expected as the corresponding argument or +arguments. + +``s`` (string) [const char \*] + Convert a null terminated UTF-8 string to a JSON string. + +``s?`` (string) [const char \*] + Like ``s``, but if the argument is *NULL*, output a JSON null + value. + + .. versionadded:: 2.8 + +``s*`` (string) [const char \*] + Like ``s``, but if the argument is *NULL*, do not output any value. + This format can only be used inside an object or an array. If used + inside an object, the corresponding key is additionally suppressed + when the value is omitted. See below for an example. + + .. versionadded:: 2.11 + +``s#`` (string) [const char \*, int] + Convert a UTF-8 buffer of a given length to a JSON string. + + .. versionadded:: 2.5 + +``s%`` (string) [const char \*, size_t] + Like ``s#`` but the length argument is of type :type:`size_t`. + + .. versionadded:: 2.6 + +``+`` [const char \*] + Like ``s``, but concatenate to the previous string. Only valid + after ``s``, ``s#``, ``+`` or ``+#``. + + .. versionadded:: 2.5 + +``+#`` [const char \*, int] + Like ``s#``, but concatenate to the previous string. Only valid + after ``s``, ``s#``, ``+`` or ``+#``. + + .. versionadded:: 2.5 + +``+%`` (string) [const char \*, size_t] + Like ``+#`` but the length argument is of type :type:`size_t`. + + .. versionadded:: 2.6 + +``n`` (null) + Output a JSON null value. No argument is consumed. + +``b`` (boolean) [int] + Convert a C ``int`` to JSON boolean value. Zero is converted + to ``false`` and non-zero to ``true``. + +``i`` (integer) [int] + Convert a C ``int`` to JSON integer. + +``I`` (integer) [json_int_t] + Convert a C :type:`json_int_t` to JSON integer. + +``f`` (real) [double] + Convert a C ``double`` to JSON real. + +``o`` (any value) [json_t \*] + Output any given JSON value as-is. If the value is added to an + array or object, the reference to the value passed to ``o`` is + stolen by the container. + +``O`` (any value) [json_t \*] + Like ``o``, but the argument's reference count is incremented. + This is useful if you pack into an array or object and want to + keep the reference for the JSON value consumed by ``O`` to + yourself. + +``o?``, ``O?`` (any value) [json_t \*] + Like ``o`` and ``O``, respectively, but if the argument is + *NULL*, output a JSON null value. + + .. versionadded:: 2.8 + +``o*``, ``O*`` (any value) [json_t \*] + Like ``o`` and ``O``, respectively, but if the argument is + *NULL*, do not output any value. This format can only be used + inside an object or an array. If used inside an object, the + corresponding key is additionally suppressed. See below for an + example. + + .. versionadded:: 2.11 + +``[fmt]`` (array) + Build an array with contents from the inner format string. ``fmt`` + may contain objects and arrays, i.e. recursive value building is + supported. + +``{fmt}`` (object) + Build an object with contents from the inner format string + ``fmt``. The first, third, etc. format specifier represent a key, + and must be a string (see ``s``, ``s#``, ``+`` and ``+#`` above), + as object keys are always strings. The second, fourth, etc. format + specifier represent a value. Any value may be an object or array, + i.e. recursive value building is supported. + +Whitespace, ``:`` and ``,`` are ignored. + +.. function:: json_t *json_pack(const char *fmt, ...) + + .. refcounting:: new + + Build a new JSON value according to the format string *fmt*. For + each format specifier (except for ``{}[]n``), one or more arguments + are consumed and used to build the corresponding value. Returns + *NULL* on error. + +.. function:: json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) + json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) + + .. refcounting:: new + + Like :func:`json_pack()`, but an in the case of an error, an error + message is written to *error*, if it's not *NULL*. The *flags* + parameter is currently unused and should be set to 0. + + As only the errors in format string (and out-of-memory errors) can + be caught by the packer, these two functions are most likely only + useful for debugging format strings. + +More examples:: + + /* Build an empty JSON object */ + json_pack("{}"); + + /* Build the JSON object {"foo": 42, "bar": 7} */ + json_pack("{sisi}", "foo", 42, "bar", 7); + + /* Like above, ':', ',' and whitespace are ignored */ + json_pack("{s:i, s:i}", "foo", 42, "bar", 7); + + /* Build the JSON array [[1, 2], {"cool": true}] */ + json_pack("[[i,i],{s:b}]", 1, 2, "cool", 1); + + /* Build a string from a non-null terminated buffer */ + char buffer[4] = {'t', 'e', 's', 't'}; + json_pack("s#", buffer, 4); + + /* Concatenate strings together to build the JSON string "foobarbaz" */ + json_pack("s++", "foo", "bar", "baz"); + + /* Create an empty object or array when optional members are missing */ + json_pack("{s:s*,s:o*,s:O*}", "foo", NULL, "bar", NULL, "baz", NULL); + json_pack("[s*,o*,O*]", NULL, NULL, NULL); + + +.. _apiref-unpack: + +Parsing and Validating Values +============================= + +This section describes functions that help to validate complex values +and extract, or *unpack*, data from them. Like :ref:`building values +<apiref-pack>`, this is also based on format strings. + +While a JSON value is unpacked, the type specified in the format +string is checked to match that of the JSON value. This is the +validation part of the process. In addition to this, the unpacking +functions can also check that all items of arrays and objects are +unpacked. This check be enabled with the format specifier ``!`` or by +using the flag ``JSON_STRICT``. See below for details. + +Here's the full list of format specifiers. The type in parentheses +denotes the JSON type, and the type in brackets (if any) denotes the C +type whose address should be passed. + +``s`` (string) [const char \*] + Convert a JSON string to a pointer to a null terminated UTF-8 + string. The resulting string is extracted by using + :func:`json_string_value()` internally, so it exists as long as + there are still references to the corresponding JSON string. + +``s%`` (string) [const char \*, size_t \*] + Convert a JSON string to a pointer to a null terminated UTF-8 + string and its length. + + .. versionadded:: 2.6 + +``n`` (null) + Expect a JSON null value. Nothing is extracted. + +``b`` (boolean) [int] + Convert a JSON boolean value to a C ``int``, so that ``true`` + is converted to 1 and ``false`` to 0. + +``i`` (integer) [int] + Convert a JSON integer to C ``int``. + +``I`` (integer) [json_int_t] + Convert a JSON integer to C :type:`json_int_t`. + +``f`` (real) [double] + Convert a JSON real to C ``double``. + +``F`` (integer or real) [double] + Convert a JSON number (integer or real) to C ``double``. + +``o`` (any value) [json_t \*] + Store a JSON value with no conversion to a :type:`json_t` pointer. + +``O`` (any value) [json_t \*] + Like ``o``, but the JSON value's reference count is incremented. + Storage pointers should be initialized NULL before using unpack. + The caller is responsible for releasing all references incremented + by unpack, even when an error occurs. + +``[fmt]`` (array) + Convert each item in the JSON array according to the inner format + string. ``fmt`` may contain objects and arrays, i.e. recursive + value extraction is supported. + +``{fmt}`` (object) + Convert each item in the JSON object according to the inner format + string ``fmt``. The first, third, etc. format specifier represent + a key, and must be ``s``. The corresponding argument to unpack + functions is read as the object key. The second, fourth, etc. + format specifier represent a value and is written to the address + given as the corresponding argument. **Note** that every other + argument is read from and every other is written to. + + ``fmt`` may contain objects and arrays as values, i.e. recursive + value extraction is supported. + + .. versionadded:: 2.3 + Any ``s`` representing a key may be suffixed with a ``?`` to + make the key optional. If the key is not found, nothing is + extracted. See below for an example. + +``!`` + This special format specifier is used to enable the check that + all object and array items are accessed, on a per-value basis. It + must appear inside an array or object as the last format specifier + before the closing bracket or brace. To enable the check globally, + use the ``JSON_STRICT`` unpacking flag. + +``*`` + This special format specifier is the opposite of ``!``. If the + ``JSON_STRICT`` flag is used, ``*`` can be used to disable the + strict check on a per-value basis. It must appear inside an array + or object as the last format specifier before the closing bracket + or brace. + +Whitespace, ``:`` and ``,`` are ignored. + +.. function:: int json_unpack(json_t *root, const char *fmt, ...) + + Validate and unpack the JSON value *root* according to the format + string *fmt*. Returns 0 on success and -1 on failure. + +.. function:: int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...) + int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap) + + Validate and unpack the JSON value *root* according to the format + string *fmt*. If an error occurs and *error* is not *NULL*, write + error information to *error*. *flags* can be used to control the + behaviour of the unpacker, see below for the flags. Returns 0 on + success and -1 on failure. + +.. note:: + + The first argument of all unpack functions is ``json_t *root`` + instead of ``const json_t *root``, because the use of ``O`` format + specifier causes the reference count of ``root``, or some value + reachable from ``root``, to be increased. Furthermore, the ``o`` + format specifier may be used to extract a value as-is, which allows + modifying the structure or contents of a value reachable from + ``root``. + + If the ``O`` and ``o`` format specifiers are not used, it's + perfectly safe to cast a ``const json_t *`` variable to plain + ``json_t *`` when used with these functions. + +The following unpacking flags are available: + +``JSON_STRICT`` + Enable the extra validation step checking that all object and + array items are unpacked. This is equivalent to appending the + format specifier ``!`` to the end of every array and object in the + format string. + +``JSON_VALIDATE_ONLY`` + Don't extract any data, just validate the JSON value against the + given format string. Note that object keys must still be specified + after the format string. + +Examples:: + + /* root is the JSON integer 42 */ + int myint; + json_unpack(root, "i", &myint); + assert(myint == 42); + + /* root is the JSON object {"foo": "bar", "quux": true} */ + const char *str; + int boolean; + json_unpack(root, "{s:s, s:b}", "foo", &str, "quux", &boolean); + assert(strcmp(str, "bar") == 0 && boolean == 1); + + /* root is the JSON array [[1, 2], {"baz": null} */ + json_error_t error; + json_unpack_ex(root, &error, JSON_VALIDATE_ONLY, "[[i,i], {s:n}]", "baz"); + /* returns 0 for validation success, nothing is extracted */ + + /* root is the JSON array [1, 2, 3, 4, 5] */ + int myint1, myint2; + json_unpack(root, "[ii!]", &myint1, &myint2); + /* returns -1 for failed validation */ + + /* root is an empty JSON object */ + int myint = 0, myint2 = 0, myint3 = 0; + json_unpack(root, "{s?i, s?[ii]}", + "foo", &myint1, + "bar", &myint2, &myint3); + /* myint1, myint2 or myint3 is no touched as "foo" and "bar" don't exist */ + + +Equality +======== + +Testing for equality of two JSON values cannot, in general, be +achieved using the ``==`` operator. Equality in the terms of the +``==`` operator states that the two :type:`json_t` pointers point to +exactly the same JSON value. However, two JSON values can be equal not +only if they are exactly the same value, but also if they have equal +"contents": + +* Two integer or real values are equal if their contained numeric + values are equal. An integer value is never equal to a real value, + though. + +* Two strings are equal if their contained UTF-8 strings are equal, + byte by byte. Unicode comparison algorithms are not implemented. + +* Two arrays are equal if they have the same number of elements and + each element in the first array is equal to the corresponding + element in the second array. + +* Two objects are equal if they have exactly the same keys and the + value for each key in the first object is equal to the value of the + corresponding key in the second object. + +* Two true, false or null values have no "contents", so they are equal + if their types are equal. (Because these values are singletons, + their equality can actually be tested with ``==``.) + +.. function:: int json_equal(json_t *value1, json_t *value2) + + Returns 1 if *value1* and *value2* are equal, as defined above. + Returns 0 if they are unequal or one or both of the pointers are + *NULL*. + + +Copying +======= + +Because of reference counting, passing JSON values around doesn't +require copying them. But sometimes a fresh copy of a JSON value is +needed. For example, if you need to modify an array, but still want to +use the original afterwards, you should take a copy of it first. + +Jansson supports two kinds of copying: shallow and deep. There is a +difference between these methods only for arrays and objects. Shallow +copying only copies the first level value (array or object) and uses +the same child values in the copied value. Deep copying makes a fresh +copy of the child values, too. Moreover, all the child values are deep +copied in a recursive fashion. + +Copying objects preserves the insertion order of keys. + +.. function:: json_t *json_copy(json_t *value) + + .. refcounting:: new + + Returns a shallow copy of *value*, or *NULL* on error. + +.. function:: json_t *json_deep_copy(const json_t *value) + + .. refcounting:: new + + Returns a deep copy of *value*, or *NULL* on error. + + +.. _apiref-custom-memory-allocation: + +Custom Memory Allocation +======================== + +By default, Jansson uses :func:`malloc()` and :func:`free()` for +memory allocation. These functions can be overridden if custom +behavior is needed. + +.. type:: json_malloc_t + + A typedef for a function pointer with :func:`malloc()`'s + signature:: + + typedef void *(*json_malloc_t)(size_t); + +.. type:: json_free_t + + A typedef for a function pointer with :func:`free()`'s + signature:: + + typedef void (*json_free_t)(void *); + +.. function:: void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) + + Use *malloc_fn* instead of :func:`malloc()` and *free_fn* instead + of :func:`free()`. This function has to be called before any other + Jansson's API functions to ensure that all memory operations use + the same functions. + +.. function:: void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn) + + Fetch the current malloc_fn and free_fn used. Either parameter + may be NULL. + + .. versionadded:: 2.8 + +**Examples:** + +Circumvent problems with different CRT heaps on Windows by using +application's :func:`malloc()` and :func:`free()`:: + + json_set_alloc_funcs(malloc, free); + +Use the `Boehm's conservative garbage collector`_ for memory +operations:: + + json_set_alloc_funcs(GC_malloc, GC_free); + +.. _Boehm's conservative garbage collector: http://www.hboehm.info/gc/ + +Allow storing sensitive data (e.g. passwords or encryption keys) in +JSON structures by zeroing all memory when freed:: + + static void *secure_malloc(size_t size) + { + /* Store the memory area size in the beginning of the block */ + void *ptr = malloc(size + 8); + *((size_t *)ptr) = size; + return ptr + 8; + } + + static void secure_free(void *ptr) + { + size_t size; + + ptr -= 8; + size = *((size_t *)ptr); + + guaranteed_memset(ptr, 0, size + 8); + free(ptr); + } + + int main() + { + json_set_alloc_funcs(secure_malloc, secure_free); + /* ... */ + } + +For more information about the issues of storing sensitive data in +memory, see +http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html. +The page also explains the :func:`guaranteed_memset()` function used +in the example and gives a sample implementation for it. + +.. _fixed_length_keys: + +Fixed-Length keys +================= + +The Jansson API allows work with fixed-length keys. This can be useful in the following cases: + +* The key is contained inside a buffer and is not null-terminated. In this case creating a new temporary buffer is not needed. +* The key contains U+0000 inside it. + +List of API for fixed-length keys: + +* :c:func:`json_object_getn` +* :c:func:`json_object_setn` +* :c:func:`json_object_setn_nocheck` +* :c:func:`json_object_setn_new` +* :c:func:`json_object_setn_new_nocheck` +* :c:func:`json_object_deln` +* :c:func:`json_object_iter_key_len` +* :c:func:`json_object_keylen_foreach` +* :c:func:`json_object_keylen_foreach_safe` + +**Examples:** + +Try to write a new function to get :c:struct:`json_t` by path separated by ``.`` + +This requires: + +* string iterator (no need to modify the input for better performance) +* API for working with fixed-size keys + +The iterator:: + + struct string { + const char *string; + size_t length; + }; + + size_t string_try_next(struct string *str, const char *delimiter) { + str->string += strspn(str->string, delimiter); + str->length = strcspn(str->string, delimiter); + return str->length; + } + + #define string_foreach(_string, _delimiter) \ + for (; string_try_next(&(_string), _delimiter); (_string).string += (_string).length) + + +The function:: + + json_t *json_object_get_by_path(json_t *object, const char *path) { + struct string str; + json_t *out = object; + + str.string = path; + + string_foreach(str, ".") { + out = json_object_getn(out, str.string, str.length); + if (out == NULL) + return NULL; + } + + return out; + } + +And usage:: + + int main(void) { + json_t *obj = json_pack("{s:{s:{s:b}}}", "a", "b", "c", 1); + + json_t *c = json_object_get_by_path(obj, "a.b.c"); + assert(json_is_true(c)); + + json_decref(obj); + } diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/changes.rst b/src/fluent-bit/lib/jansson-e23f558/doc/changes.rst new file mode 100644 index 000000000..ea5684377 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/changes.rst @@ -0,0 +1,5 @@ +****************** +Changes in Jansson +****************** + +.. include:: ../CHANGES diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/conf.py b/src/fluent-bit/lib/jansson-e23f558/doc/conf.py new file mode 100644 index 000000000..242617170 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/conf.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- +# +# Jansson documentation build configuration file, created by +# sphinx-quickstart on Sun Sep 5 21:47:20 2010. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('ext')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['refcounting'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Jansson' +copyright = u'2009-2020, Petri Lehtinen' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2.14' +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +default_role = 'c:func' +primary_domain = 'c' + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +#html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Janssondoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Jansson.tex', u'Jansson Documentation', + u'Petri Lehtinen', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'jansson', u'Jansson Documentation', + [u'Petri Lehtinen'], 1) +] diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/conformance.rst b/src/fluent-bit/lib/jansson-e23f558/doc/conformance.rst new file mode 100644 index 000000000..5556a6b81 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/conformance.rst @@ -0,0 +1,119 @@ +.. _rfc-conformance: + +*************** +RFC Conformance +*************** + +JSON is specified in :rfc:`4627`, *"The application/json Media Type +for JavaScript Object Notation (JSON)"*. + +Character Encoding +================== + +Jansson only supports UTF-8 encoded JSON texts. It does not support or +auto-detect any of the other encodings mentioned in the RFC, namely +UTF-16LE, UTF-16BE, UTF-32LE or UTF-32BE. Pure ASCII is supported, as +it's a subset of UTF-8. + +Strings +======= + +JSON strings are mapped to C-style null-terminated character arrays, +and UTF-8 encoding is used internally. + +All Unicode codepoints U+0000 through U+10FFFF are allowed in string +values. However, U+0000 is allowed in object keys only for length-aware functions. + +Unicode normalization or any other transformation is never performed +on any strings (string values or object keys). When checking for +equivalence of strings or object keys, the comparison is performed +byte by byte between the original UTF-8 representations of the +strings. + +Numbers +======= + +.. _real-vs-integer: + +Real vs. Integer +---------------- + +JSON makes no distinction between real and integer numbers; Jansson +does. Real numbers are mapped to the ``double`` type and integers to +the ``json_int_t`` type, which is a typedef of ``long long`` or +``long``, depending on whether ``long long`` is supported by your +compiler or not. + +A JSON number is considered to be a real number if its lexical +representation includes one of ``e``, ``E``, or ``.``; regardless if +its actual numeric value is a true integer (e.g., all of ``1E6``, +``3.0``, ``400E-2``, and ``3.14E3`` are mathematical integers, but +will be treated as real values). With the ``JSON_DECODE_INT_AS_REAL`` +decoder flag set all numbers are interpreted as real. + +All other JSON numbers are considered integers. + +When encoding to JSON, real values are always represented +with a fractional part; e.g., the ``double`` value 3.0 will be +represented in JSON as ``3.0``, not ``3``. + +Overflow, Underflow & Precision +------------------------------- + +Real numbers whose absolute values are too small to be represented in +a C ``double`` will be silently estimated with 0.0. Thus, depending on +platform, JSON numbers very close to zero such as 1E-999 may result in +0.0. + +Real numbers whose absolute values are too large to be represented in +a C ``double`` will result in an overflow error (a JSON decoding +error). Thus, depending on platform, JSON numbers like 1E+999 or +-1E+999 may result in a parsing error. + +Likewise, integer numbers whose absolute values are too large to be +represented in the ``json_int_t`` type (see above) will result in an +overflow error (a JSON decoding error). Thus, depending on platform, +JSON numbers like 1000000000000000 may result in parsing error. + +Parsing JSON real numbers may result in a loss of precision. As long +as overflow does not occur (i.e. a total loss of precision), the +rounded approximate value is silently used. Thus the JSON number +1.000000000000000005 may, depending on platform, result in the +``double`` value 1.0. + +Signed zeros +------------ + +JSON makes no statement about what a number means; however Javascript +(ECMAscript) does state that +0.0 and -0.0 must be treated as being +distinct values, i.e. -0.0 |not-equal| 0.0. Jansson relies on the +underlying floating point library in the C environment in which it is +compiled. Therefore it is platform-dependent whether 0.0 and -0.0 will +be distinct values. Most platforms that use the IEEE 754 +floating-point standard will support signed zeros. + +Note that this only applies to floating-point; neither JSON, C, or +IEEE support the concept of signed integer zeros. + +.. |not-equal| unicode:: U+2260 + +Types +----- + +No support is provided in Jansson for any C numeric types other than +``json_int_t`` and ``double``. This excludes things such as unsigned +types, ``long double``, etc. Obviously, shorter types like ``short``, +``int``, ``long`` (if ``json_int_t`` is ``long long``) and ``float`` +are implicitly handled via the ordinary C type coercion rules (subject +to overflow semantics). Also, no support or hooks are provided for any +supplemental "bignum" type add-on packages. + +Depth of nested values +====================== + +To avoid stack exhaustion, Jansson currently limits the nesting depth +for arrays and objects to a certain value (default: 2048), defined as +a macro ``JSON_PARSER_MAX_DEPTH`` within ``jansson_config.h``. + +The limit is allowed to be set by the RFC; there is no recommended value +or required minimum depth to be supported. diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/ext/refcounting.py b/src/fluent-bit/lib/jansson-e23f558/doc/ext/refcounting.py new file mode 100644 index 000000000..e72c481c5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/ext/refcounting.py @@ -0,0 +1,69 @@ +""" + refcounting + ~~~~~~~~~~~ + + Reference count annotations for C API functions. Has the same + result as the sphinx.ext.refcounting extension but works for all + functions regardless of the signature, and the reference counting + information is written inline with the documentation instead of a + separate file. + + Adds a new directive "refcounting". The directive has no content + and one required positional parameter:: "new" or "borrow". + + Example: + + .. cfunction:: json_t *json_object(void) + + .. refcounting:: new + + <description of the json_object function> + + :copyright: Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + :license: MIT, see LICENSE for details. +""" + +from docutils import nodes +from docutils.parsers.rst import Directive + + +def visit(self, node): + self.visit_emphasis(node) + +def depart(self, node): + self.depart_emphasis(node) + +def html_visit(self, node): + self.body.append(self.starttag(node, 'em', '', CLASS='refcount')) + +def html_depart(self, node): + self.body.append('</em>') + + +class refcounting(nodes.emphasis): + pass + +class refcounting_directive(Directive): + has_content = False + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = False + + def run(self): + if self.arguments[0] == 'borrow': + text = 'Return value: Borrowed reference.' + elif self.arguments[0] == 'new': + text = 'Return value: New reference.' + else: + raise Error('Valid arguments: new, borrow') + + return [refcounting(text, text)] + + +def setup(app): + app.add_node(refcounting, + html=(html_visit, html_depart), + latex=(visit, depart), + text=(visit, depart), + man=(visit, depart)) + app.add_directive('refcounting', refcounting_directive) diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/gettingstarted.rst b/src/fluent-bit/lib/jansson-e23f558/doc/gettingstarted.rst new file mode 100644 index 000000000..4cd19773d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/gettingstarted.rst @@ -0,0 +1,264 @@ +*************** +Getting Started +*************** + +.. highlight:: c + +Compiling and Installing Jansson +================================ + +The Jansson source is available at +http://www.digip.org/jansson/releases/. + +Unix-like systems (including MinGW) +----------------------------------- + +Unpack the source tarball and change to the source directory: + +.. parsed-literal:: + + bunzip2 -c jansson-|release|.tar.bz2 | tar xf - + cd jansson-|release| + +The source uses GNU Autotools (autoconf_, automake_, libtool_), so +compiling and installing is extremely simple:: + + ./configure + make + make check + make install + +To change the destination directory (``/usr/local`` by default), use +the ``--prefix=DIR`` argument to ``./configure``. See ``./configure +--help`` for the list of all possible configuration options. + +The command ``make check`` runs the test suite distributed with +Jansson. This step is not strictly necessary, but it may find possible +problems that Jansson has on your platform. If any problems are found, +please report them. + +If you obtained the source from a Git repository (or any other source +control system), there's no ``./configure`` script as it's not kept in +version control. To create the script, the build system needs to be +bootstrapped. There are many ways to do this, but the easiest one is +to use ``autoreconf``:: + + autoreconf -fi + +This command creates the ``./configure`` script, which can then be +used as described above. + +.. _autoconf: http://www.gnu.org/software/autoconf/ +.. _automake: http://www.gnu.org/software/automake/ +.. _libtool: http://www.gnu.org/software/libtool/ + + +.. _build-cmake: + +CMake (various platforms, including Windows) +-------------------------------------------- + +Jansson can be built using CMake_. Create a build directory for an +out-of-tree build, change to that directory, and run ``cmake`` (or ``ccmake``, +``cmake-gui``, or similar) to configure the project. + +See the examples below for more detailed information. + +.. note:: In the below examples ``..`` is used as an argument for ``cmake``. + This is simply the path to the jansson project root directory. + In the example it is assumed you've created a sub-directory ``build`` + and are using that. You could use any path you want. + +.. _build-cmake-unix: + +Unix (Make files) +^^^^^^^^^^^^^^^^^ +Generating make files on unix: + +.. parsed-literal:: + + bunzip2 -c jansson-|release|.tar.bz2 | tar xf - + cd jansson-|release| + + mkdir build + cd build + cmake .. # or ccmake .. for a GUI. + +.. note:: + + If you don't want to build docs or ``Sphinx`` is not installed, you should add ``"-DJANSSON_BUILD_DOCS=OFF"`` in the ``cmake`` command. + + +Then to build:: + + make + make check + make install + +Windows (Visual Studio) +^^^^^^^^^^^^^^^^^^^^^^^ +Creating Visual Studio project files from the command line: + +.. parsed-literal:: + + <unpack> + cd jansson-|release| + + md build + cd build + cmake -G "Visual Studio 15 2017" .. + +.. note:: + + You should replace the name of the generator (``-G`` flag) matching + the Visual Studio version installed on your system. Currently, the + following versions are supported: + + - ``Visual Studio 9 2008`` + - ``Visual Studio 10 2010`` + - ``Visual Studio 11 2012`` + - ``Visual Studio 12 2013`` + - ``Visual Studio 14 2015`` + - ``Visual Studio 15 2017`` + - ``Visual Studio 16 2019`` + + Any later version should also work. + +You will now have a *Visual Studio Solution* in your build directory. +To run the unit tests build the ``RUN_TESTS`` project. + +If you prefer a GUI the ``cmake`` line in the above example can +be replaced with:: + + cmake-gui .. + +For command line help (including a list of available generators) +for CMake_ simply run:: + + cmake + +To list available CMake_ settings (and what they are currently set to) +for the project, run:: + + cmake -LH .. + +Windows (MinGW) +^^^^^^^^^^^^^^^ +If you prefer using MinGW on Windows, make sure MinGW installed and ``{MinGW}/bin`` has been added to ``PATH``, then do the following commands: + +.. parsed-literal:: + + <unpack> + cd jansson-|release| + + md build + cd build + cmake -G "MinGW Makefiles" .. + mingw32-make + + +Mac OSX (Xcode) +^^^^^^^^^^^^^^^ +If you prefer using Xcode instead of make files on OSX, +do the following. (Use the same steps as +for :ref:`Unix <build-cmake-unix>`):: + + ... + cmake -G "Xcode" .. + +Additional CMake settings +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Shared library +"""""""""""""" +By default the CMake_ project will generate build files for building the +static library. To build the shared version use:: + + ... + cmake -DJANSSON_BUILD_SHARED_LIBS=1 .. + +Changing install directory (same as autoconf --prefix) +"""""""""""""""""""""""""""""""""""""""""""""""""""""" +Just as with the autoconf_ project you can change the destination directory +for ``make install``. The equivalent for autoconfs ``./configure --prefix`` +in CMake_ is:: + + ... + cmake -DCMAKE_INSTALL_PREFIX:PATH=/some/other/path .. + make install + +.. _CMake: http://www.cmake.org + + +Android +------- + +Jansson can be built for Android platforms. Android.mk is in the +source root directory. The configuration header file is located in the +``android`` directory in the source distribution. + + +Other Systems +------------- + +On non Unix-like systems, you may be unable to run the ``./configure`` +script. In this case, follow these steps. All the files mentioned can +be found in the ``src/`` directory. + +1. Create ``jansson_config.h`` (which has some platform-specific + parameters that are normally filled in by the ``./configure`` + script). Edit ``jansson_config.h.in``, replacing all ``@variable@`` + placeholders, and rename the file to ``jansson_config.h``. + +2. Make ``jansson.h`` and ``jansson_config.h`` available to the + compiler, so that they can be found when compiling programs that + use Jansson. + +3. Compile all the ``.c`` files (in the ``src/`` directory) into a + library file. Make the library available to the compiler, as in + step 2. + + +Building the Documentation +-------------------------- + +(This subsection describes how to build the HTML documentation you are +currently reading, so it can be safely skipped.) + +Documentation is in the ``doc/`` subdirectory. It's written in +reStructuredText_ with Sphinx_ annotations. To generate the HTML +documentation, invoke:: + + make html + +and point your browser to ``doc/_build/html/index.html``. Sphinx_ 1.0 +or newer is required to generate the documentation. + +.. _reStructuredText: http://docutils.sourceforge.net/rst.html +.. _Sphinx: http://sphinx.pocoo.org/ + + +Compiling Programs that Use Jansson +=================================== + +Jansson involves one C header file, :file:`jansson.h`, so it's enough +to put the line + +:: + + #include <jansson.h> + +in the beginning of every source file that uses Jansson. + +There's also just one library to link with, ``libjansson``. Compile and +link the program as follows:: + + cc -o prog prog.c -ljansson + +Starting from version 1.2, there's also support for pkg-config_: + +.. code-block:: shell + + cc -o prog prog.c `pkg-config --cflags --libs jansson` + +.. _pkg-config: http://pkg-config.freedesktop.org/ diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/github_commits.c b/src/fluent-bit/lib/jansson-e23f558/doc/github_commits.c new file mode 100644 index 000000000..81c806393 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/github_commits.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include <stdlib.h> +#include <string.h> + +#include <curl/curl.h> +#include <jansson.h> + +#define BUFFER_SIZE (256 * 1024) /* 256 KB */ + +#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits" +#define URL_SIZE 256 + +/* Return the offset of the first newline in text or the length of + text if there's no newline */ +static int newline_offset(const char *text) { + const char *newline = strchr(text, '\n'); + if (!newline) + return strlen(text); + else + return (int)(newline - text); +} + +struct write_result { + char *data; + int pos; +}; + +static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream) { + struct write_result *result = (struct write_result *)stream; + + if (result->pos + size * nmemb >= BUFFER_SIZE - 1) { + fprintf(stderr, "error: too small buffer\n"); + return 0; + } + + memcpy(result->data + result->pos, ptr, size * nmemb); + result->pos += size * nmemb; + + return size * nmemb; +} + +static char *request(const char *url) { + CURL *curl = NULL; + CURLcode status; + struct curl_slist *headers = NULL; + char *data = NULL; + long code; + + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if (!curl) + goto error; + + data = malloc(BUFFER_SIZE); + if (!data) + goto error; + + struct write_result write_result = {.data = data, .pos = 0}; + + curl_easy_setopt(curl, CURLOPT_URL, url); + + /* GitHub commits API v3 requires a User-Agent header */ + headers = curl_slist_append(headers, "User-Agent: Jansson-Tutorial"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); + + status = curl_easy_perform(curl); + if (status != 0) { + fprintf(stderr, "error: unable to request data from %s:\n", url); + fprintf(stderr, "%s\n", curl_easy_strerror(status)); + goto error; + } + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); + if (code != 200) { + fprintf(stderr, "error: server responded with code %ld\n", code); + goto error; + } + + curl_easy_cleanup(curl); + curl_slist_free_all(headers); + curl_global_cleanup(); + + /* zero-terminate the result */ + data[write_result.pos] = '\0'; + + return data; + +error: + if (data) + free(data); + if (curl) + curl_easy_cleanup(curl); + if (headers) + curl_slist_free_all(headers); + curl_global_cleanup(); + return NULL; +} + +int main(int argc, char *argv[]) { + size_t i; + char *text; + char url[URL_SIZE]; + + json_t *root; + json_error_t error; + + if (argc != 3) { + fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); + fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); + return 2; + } + + snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); + + text = request(url); + if (!text) + return 1; + + root = json_loads(text, 0, &error); + free(text); + + if (!root) { + fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); + return 1; + } + + if (!json_is_array(root)) { + fprintf(stderr, "error: root is not an array\n"); + json_decref(root); + return 1; + } + + for (i = 0; i < json_array_size(root); i++) { + json_t *data, *sha, *commit, *message; + const char *message_text; + + data = json_array_get(root, i); + if (!json_is_object(data)) { + fprintf(stderr, "error: commit data %d is not an object\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + sha = json_object_get(data, "sha"); + if (!json_is_string(sha)) { + fprintf(stderr, "error: commit %d: sha is not a string\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + commit = json_object_get(data, "commit"); + if (!json_is_object(commit)) { + fprintf(stderr, "error: commit %d: commit is not an object\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + message = json_object_get(commit, "message"); + if (!json_is_string(message)) { + fprintf(stderr, "error: commit %d: message is not a string\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + message_text = json_string_value(message); + printf("%.8s %.*s\n", json_string_value(sha), newline_offset(message_text), + message_text); + } + + json_decref(root); + return 0; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/index.rst b/src/fluent-bit/lib/jansson-e23f558/doc/index.rst new file mode 100644 index 000000000..c679f409b --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/index.rst @@ -0,0 +1,53 @@ +Jansson Documentation +===================== + +This is the documentation for Jansson_ |release|, last updated |today|. + +Introduction +------------ + +Jansson_ is a C library for encoding, decoding and manipulating JSON +data. Its main features and design principles are: + +- Simple and intuitive API and data model + +- Comprehensive documentation + +- No dependencies on other libraries + +- Full Unicode support (UTF-8) + +- Extensive test suite + +Jansson is licensed under the `MIT license`_; see LICENSE in the +source distribution for details. + +Jansson is used in production and its API is stable. It works on +numerous platforms, including numerous Unix like systems and Windows. +It's suitable for use on any system, including desktop, server, and +small embedded systems. + + +.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php +.. _Jansson: http://www.digip.org/jansson/ + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + + gettingstarted + upgrading + tutorial + conformance + threadsafety + apiref + changes + + +Indices and Tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/threadsafety.rst b/src/fluent-bit/lib/jansson-e23f558/doc/threadsafety.rst new file mode 100644 index 000000000..0eebb29a9 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/threadsafety.rst @@ -0,0 +1,82 @@ +.. _thread-safety: + +************* +Thread safety +************* + +Jansson as a library is thread safe and has no mutable global state. +The only exceptions are the hash function seed and memory allocation +functions, see below. + +There's no locking performed inside Jansson's code. **Read-only** +access to JSON values shared by multiple threads is safe, but +**mutating** a JSON value that's shared by multiple threads is not. A +multithreaded program must perform its own locking if JSON values +shared by multiple threads are mutated. + +However, **reference count manipulation** (:func:`json_incref()`, +:func:`json_decref()`) is usually thread-safe, and can be performed on +JSON values that are shared among threads. The thread-safety of +reference counting can be checked with the +``JANSSON_THREAD_SAFE_REFCOUNT`` preprocessor constant. Thread-safe +reference count manipulation is achieved using compiler built-in +atomic functions, which are available in most modern compilers. + +If compiler support is not available (``JANSSON_THREAD_SAFE_REFCOUNT`` +is not defined), it may be very difficult to ensure thread safety of +reference counting. It's possible to have a reference to a value +that's also stored inside an array or object in another thread. +Modifying the container (adding or removing values) may trigger +concurrent access to such values, as containers manage the reference +count of their contained values. + + +Hash function seed +================== + +To prevent an attacker from intentionally causing large JSON objects +with specially crafted keys to perform very slow, the hash function +used by Jansson is randomized using a seed value. The seed is +automatically generated on the first explicit or implicit call to +:func:`json_object()`, if :func:`json_object_seed()` has not been +called beforehand. + +The seed is generated by using operating system's entropy sources if +they are available (``/dev/urandom``, ``CryptGenRandom()``). The +initialization is done in as thread safe manner as possible, by using +architecture specific lockless operations if provided by the platform +or the compiler. + +If you're using threads, it's recommended to autoseed the hashtable +explicitly before spawning any threads by calling +``json_object_seed(0)`` , especially if you're unsure whether the +initialization is thread safe on your platform. + + +Memory allocation functions +=========================== + +Memory allocation functions should be set at most once, and only on +program startup. See :ref:`apiref-custom-memory-allocation`. + + +Locale +====== + +Jansson works fine under any locale. + +However, if the host program is multithreaded and uses ``setlocale()`` +to switch the locale in one thread while Jansson is currently encoding +or decoding JSON data in another thread, the result may be wrong or +the program may even crash. + +Jansson uses locale specific functions for certain string conversions +in the encoder and decoder, and then converts the locale specific +values to/from the JSON representation. This fails if the locale +changes between the string conversion and the locale-to-JSON +conversion. This can only happen in multithreaded programs that use +``setlocale()``, because ``setlocale()`` switches the locale for all +running threads, not only the thread that calls ``setlocale()``. + +If your program uses ``setlocale()`` as described above, consider +using the thread-safe ``uselocale()`` instead. diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/tutorial.rst b/src/fluent-bit/lib/jansson-e23f558/doc/tutorial.rst new file mode 100644 index 000000000..bb7a6c21c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/tutorial.rst @@ -0,0 +1,288 @@ +.. _tutorial: + +******** +Tutorial +******** + +.. highlight:: c + +In this tutorial, we create a program that fetches the latest commits +of a repository in GitHub_ over the web. `GitHub API`_ uses JSON, so +the result can be parsed using Jansson. + +To stick to the scope of this tutorial, we will only cover the +parts of the program related to handling JSON data. For the best user +experience, the full source code is available: +:download:`github_commits.c`. To compile it (on Unix-like systems with +gcc), use the following command:: + + gcc -o github_commits github_commits.c -ljansson -lcurl + +libcurl_ is used to communicate over the web, so it is required to +compile the program. + +The command line syntax is:: + + github_commits USER REPOSITORY + +``USER`` is a GitHub user ID and ``REPOSITORY`` is the repository +name. Please note that the GitHub API is rate limited, so if you run +the program too many times within a short period of time, the sever +starts to respond with an error. + +.. _GitHub: https://github.com/ +.. _GitHub API: http://developer.github.com/ +.. _libcurl: http://curl.haxx.se/ + + +.. _tutorial-github-commits-api: + +The GitHub Repo Commits API +=========================== + +The `GitHub Repo Commits API`_ is used by sending HTTP requests to +URLs like ``https://api.github.com/repos/USER/REPOSITORY/commits``, +where ``USER`` and ``REPOSITORY`` are the GitHub user ID and the name +of the repository whose commits are to be listed, respectively. + +GitHub responds with a JSON array of the following form: + +.. code-block:: none + + [ + { + "sha": "<the commit ID>", + "commit": { + "message": "<the commit message>", + <more fields, not important to this tutorial...> + }, + <more fields...> + }, + { + "sha": "<the commit ID>", + "commit": { + "message": "<the commit message>", + <more fields...> + }, + <more fields...> + }, + <more commits...> + ] + +In our program, the HTTP request is sent using the following +function:: + + static char *request(const char *url); + +It takes the URL as a parameter, performs a HTTP GET request, and +returns a newly allocated string that contains the response body. If +the request fails, an error message is printed to stderr and the +return value is *NULL*. For full details, refer to :download:`the code +<github_commits.c>`, as the actual implementation is not important +here. + +.. _GitHub Repo Commits API: http://developer.github.com/v3/repos/commits/ + +.. _tutorial-the-program: + +The Program +=========== + +First the includes:: + + #include <string.h> + #include <jansson.h> + +Like all the programs using Jansson, we need to include +:file:`jansson.h`. + +The following definitions are used to build the GitHub API request +URL:: + + #define URL_FORMAT "https://api.github.com/repos/%s/%s/commits" + #define URL_SIZE 256 + +The following function is used when formatting the result to find the +first newline in the commit message:: + + /* Return the offset of the first newline in text or the length of + text if there's no newline */ + static int newline_offset(const char *text) + { + const char *newline = strchr(text, '\n'); + if(!newline) + return strlen(text); + else + return (int)(newline - text); + } + +The main function follows. In the beginning, we first declare a bunch +of variables and check the command line parameters:: + + int main(int argc, char *argv[]) + { + size_t i; + char *text; + char url[URL_SIZE]; + + json_t *root; + json_error_t error; + + if(argc != 3) + { + fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); + fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); + return 2; + } + +Then we build the request URL using the user and repository names +given as command line parameters:: + + snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); + +This uses the ``URL_SIZE`` and ``URL_FORMAT`` constants defined above. +Now we're ready to actually request the JSON data over the web:: + + text = request(url); + if(!text) + return 1; + +If an error occurs, our function ``request`` prints the error and +returns *NULL*, so it's enough to just return 1 from the main +function. + +Next we'll call :func:`json_loads()` to decode the JSON text we got +as a response:: + + root = json_loads(text, 0, &error); + free(text); + + if(!root) + { + fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); + return 1; + } + +We don't need the JSON text anymore, so we can free the ``text`` +variable right after decoding it. If :func:`json_loads()` fails, it +returns *NULL* and sets error information to the :type:`json_error_t` +structure given as the second parameter. In this case, our program +prints the error information out and returns 1 from the main function. + +Now we're ready to extract the data out of the decoded JSON response. +The structure of the response JSON was explained in section +:ref:`tutorial-github-commits-api`. + +We check that the returned value really is an array:: + + if(!json_is_array(root)) + { + fprintf(stderr, "error: root is not an array\n"); + json_decref(root); + return 1; + } + +Then we proceed to loop over all the commits in the array:: + + for(i = 0; i < json_array_size(root); i++) + { + json_t *data, *sha, *commit, *message; + const char *message_text; + + data = json_array_get(root, i); + if(!json_is_object(data)) + { + fprintf(stderr, "error: commit data %d is not an object\n", i + 1); + json_decref(root); + return 1; + } + ... + +The function :func:`json_array_size()` returns the size of a JSON +array. First, we again declare some variables and then extract the +i'th element of the ``root`` array using :func:`json_array_get()`. +We also check that the resulting value is a JSON object. + +Next we'll extract the commit ID (a hexadecimal SHA-1 sum), +intermediate commit info object, and the commit message from that +object. We also do proper type checks:: + + sha = json_object_get(data, "sha"); + if(!json_is_string(sha)) + { + fprintf(stderr, "error: commit %d: sha is not a string\n", i + 1); + json_decref(root); + return 1; + } + + commit = json_object_get(data, "commit"); + if(!json_is_object(commit)) + { + fprintf(stderr, "error: commit %d: commit is not an object\n", i + 1); + json_decref(root); + return 1; + } + + message = json_object_get(commit, "message"); + if(!json_is_string(message)) + { + fprintf(stderr, "error: commit %d: message is not a string\n", i + 1); + json_decref(root); + return 1; + } + ... + +And finally, we'll print the first 8 characters of the commit ID and +the first line of the commit message. A C-style string is extracted +from a JSON string using :func:`json_string_value()`:: + + message_text = json_string_value(message); + printf("%.8s %.*s\n", + json_string_value(sha), + newline_offset(message_text), + message_text); + } + +After sending the HTTP request, we decoded the JSON text using +:func:`json_loads()`, remember? It returns a *new reference* to the +JSON value it decodes. When we're finished with the value, we'll need +to decrease the reference count using :func:`json_decref()`. This way +Jansson can release the resources:: + + json_decref(root); + return 0; + +For a detailed explanation of reference counting in Jansson, see +:ref:`apiref-reference-count` in :ref:`apiref`. + +The program's ready, let's test it and view the latest commits in +Jansson's repository: + +.. code-block:: shell + + $ ./github_commits akheron jansson + 1581f26a Merge branch '2.3' + aabfd493 load: Change buffer_pos to be a size_t + bd72efbd load: Avoid unexpected behaviour in macro expansion + e8fd3e30 Document and tweak json_load_callback() + 873eddaf Merge pull request #60 from rogerz/contrib + bd2c0c73 Ignore the binary test_load_callback + 17a51a4b Merge branch '2.3' + 09c39adc Add json_load_callback to the list of exported symbols + cbb80baf Merge pull request #57 from rogerz/contrib + 040bd7b0 Add json_load_callback() + 2637faa4 Make test stripping locale independent + <...> + + +Conclusion +========== + +In this tutorial, we implemented a program that fetches the latest +commits of a GitHub repository using the GitHub Repo Commits API. +Jansson was used to decode the JSON response and to extract the commit +data. + +This tutorial only covered a small part of Jansson. For example, we +did not create or manipulate JSON values at all. Proceed to +:ref:`apiref` to explore all features of Jansson. diff --git a/src/fluent-bit/lib/jansson-e23f558/doc/upgrading.rst b/src/fluent-bit/lib/jansson-e23f558/doc/upgrading.rst new file mode 100644 index 000000000..94ff7de3c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/doc/upgrading.rst @@ -0,0 +1,76 @@ +.. highlight:: c + +****************** +Upgrading from 1.x +****************** + +This chapter lists the backwards incompatible changes introduced in +Jansson 2.0, and the steps that are needed for upgrading your code. + +**The incompatibilities are not dramatic.** The biggest change is that +all decoding functions now require and extra parameter. Most programs +can be modified to work with 2.0 by adding a ``0`` as the second +parameter to all calls of :func:`json_loads()`, :func:`json_loadf()` +and :func:`json_load_file()`. + + +Compatibility +============= + +Jansson 2.0 is backwards incompatible with the Jansson 1.x releases. +It is ABI incompatible, i.e. all programs dynamically linking to the +Jansson library need to be recompiled. It's also API incompatible, +i.e. the source code of programs using Jansson 1.x may need +modifications to make them compile against Jansson 2.0. + +All the 2.x releases are guaranteed to be backwards compatible for +both ABI and API, so no recompilation or source changes are needed +when upgrading from 2.x to 2.y. + + +List of Incompatible Changes +============================ + +**Decoding flags** + For future needs, a ``flags`` parameter was added as the second + parameter to all decoding functions, i.e. :func:`json_loads()`, + :func:`json_loadf()` and :func:`json_load_file()`. All calls to + these functions need to be changed by adding a ``0`` as the second + argument. For example:: + + /* old code */ + json_loads(input, &error); + + /* new code */ + json_loads(input, 0, &error); + + +**Underlying type of JSON integers** + The underlying C type of JSON integers has been changed from + ``int`` to the widest available signed integer type, i.e. + ``long long`` or ``long``, depending on whether + ``long long`` is supported on your system or not. This makes + the whole 64-bit integer range available on most modern systems. + + ``jansson.h`` has a typedef :type:`json_int_t` to the underlying + integer type. ``int`` should still be used in most cases when + dealing with smallish JSON integers, as the compiler handles + implicit type coercion. Only when the full 64-bit range is needed, + :type:`json_int_t` should be explicitly used. + + +**Maximum encoder indentation depth** + The maximum argument of the ``JSON_INDENT()`` macro has been + changed from 255 to 31, to free up bits from the ``flags`` + parameter of :func:`json_dumps()`, :func:`json_dumpf()` and + :func:`json_dump_file()`. If your code uses a bigger indentation + than 31, it needs to be changed. + + +**Unsigned integers in API functions** + Version 2.0 unifies unsigned integer usage in the API. All uses of + ``unsigned int`` and ``unsigned long`` have been replaced + with ``size_t``. This includes flags, container sizes, etc. + This should not require source code changes, as both + ``unsigned int`` and ``unsigned long`` are usually + compatible with ``size_t``. diff --git a/src/fluent-bit/lib/jansson-e23f558/examples/README.rst b/src/fluent-bit/lib/jansson-e23f558/examples/README.rst new file mode 100644 index 000000000..a7c5274db --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/examples/README.rst @@ -0,0 +1,4 @@ +Jansson examples +================ + +This directory contains simple example programs that use Jansson. diff --git a/src/fluent-bit/lib/jansson-e23f558/examples/simple_parse.c b/src/fluent-bit/lib/jansson-e23f558/examples/simple_parse.c new file mode 100644 index 000000000..a96a0f831 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/examples/simple_parse.c @@ -0,0 +1,200 @@ +/* + * Simple example of parsing and printing JSON using jansson. + * + * SYNOPSIS: + * $ examples/simple_parse + * Type some JSON > [true, false, null, 1, 0.0, -0.0, "", {"name": "barney"}] + * JSON Array of 8 elements: + * JSON True + * JSON False + * JSON Null + * JSON Integer: "1" + * JSON Real: 0.000000 + * JSON Real: -0.000000 + * JSON String: "" + * JSON Object of 1 pair: + * JSON Key: "name" + * JSON String: "barney" + * + * Copyright (c) 2014 Robert Poor <rdpoor@gmail.com> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include <jansson.h> +#include <stdio.h> +#include <stdlib.h> + +/* forward refs */ +void print_json(json_t *root); +void print_json_aux(json_t *element, int indent); +void print_json_indent(int indent); +const char *json_plural(size_t count); +void print_json_object(json_t *element, int indent); +void print_json_array(json_t *element, int indent); +void print_json_string(json_t *element, int indent); +void print_json_integer(json_t *element, int indent); +void print_json_real(json_t *element, int indent); +void print_json_true(json_t *element, int indent); +void print_json_false(json_t *element, int indent); +void print_json_null(json_t *element, int indent); + +void print_json(json_t *root) { print_json_aux(root, 0); } + +void print_json_aux(json_t *element, int indent) { + switch (json_typeof(element)) { + case JSON_OBJECT: + print_json_object(element, indent); + break; + case JSON_ARRAY: + print_json_array(element, indent); + break; + case JSON_STRING: + print_json_string(element, indent); + break; + case JSON_INTEGER: + print_json_integer(element, indent); + break; + case JSON_REAL: + print_json_real(element, indent); + break; + case JSON_TRUE: + print_json_true(element, indent); + break; + case JSON_FALSE: + print_json_false(element, indent); + break; + case JSON_NULL: + print_json_null(element, indent); + break; + default: + fprintf(stderr, "unrecognized JSON type %d\n", json_typeof(element)); + } +} + +void print_json_indent(int indent) { + int i; + for (i = 0; i < indent; i++) { + putchar(' '); + } +} + +const char *json_plural(size_t count) { return count == 1 ? "" : "s"; } + +void print_json_object(json_t *element, int indent) { + size_t size; + const char *key; + json_t *value; + + print_json_indent(indent); + size = json_object_size(element); + + printf("JSON Object of %lld pair%s:\n", (long long)size, json_plural(size)); + json_object_foreach(element, key, value) { + print_json_indent(indent + 2); + printf("JSON Key: \"%s\"\n", key); + print_json_aux(value, indent + 2); + } +} + +void print_json_array(json_t *element, int indent) { + size_t i; + size_t size = json_array_size(element); + print_json_indent(indent); + + printf("JSON Array of %lld element%s:\n", (long long)size, json_plural(size)); + for (i = 0; i < size; i++) { + print_json_aux(json_array_get(element, i), indent + 2); + } +} + +void print_json_string(json_t *element, int indent) { + print_json_indent(indent); + printf("JSON String: \"%s\"\n", json_string_value(element)); +} + +void print_json_integer(json_t *element, int indent) { + print_json_indent(indent); + printf("JSON Integer: \"%" JSON_INTEGER_FORMAT "\"\n", json_integer_value(element)); +} + +void print_json_real(json_t *element, int indent) { + print_json_indent(indent); + printf("JSON Real: %f\n", json_real_value(element)); +} + +void print_json_true(json_t *element, int indent) { + (void)element; + print_json_indent(indent); + printf("JSON True\n"); +} + +void print_json_false(json_t *element, int indent) { + (void)element; + print_json_indent(indent); + printf("JSON False\n"); +} + +void print_json_null(json_t *element, int indent) { + (void)element; + print_json_indent(indent); + printf("JSON Null\n"); +} + +/* + * Parse text into a JSON object. If text is valid JSON, returns a + * json_t structure, otherwise prints and error and returns null. + */ +json_t *load_json(const char *text) { + json_t *root; + json_error_t error; + + root = json_loads(text, 0, &error); + + if (root) { + return root; + } else { + fprintf(stderr, "json error on line %d: %s\n", error.line, error.text); + return (json_t *)0; + } +} + +/* + * Print a prompt and return (by reference) a null-terminated line of + * text. Returns NULL on eof or some error. + */ +char *read_line(char *line, int max_chars) { + printf("Type some JSON > "); + fflush(stdout); + return fgets(line, max_chars, stdin); +} + +/* ================================================================ + * main + */ + +#define MAX_CHARS 4096 + +int main(int argc, char *argv[]) { + char line[MAX_CHARS]; + + if (argc != 1) { + fprintf(stderr, "Usage: %s\n", argv[0]); + exit(-1); + } + + while (read_line(line, MAX_CHARS) != (char *)NULL) { + + /* parse text into JSON structure */ + json_t *root = load_json(line); + + if (root) { + /* print and release the JSON structure */ + print_json(root); + json_decref(root); + } + } + + return 0; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/jansson.pc.in b/src/fluent-bit/lib/jansson-e23f558/jansson.pc.in new file mode 100644 index 000000000..69c9a43ae --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/jansson.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Jansson +Description: Library for encoding, decoding and manipulating JSON data +Version: @VERSION@ +Libs: -L${libdir} -ljansson +Cflags: -I${includedir} diff --git a/src/fluent-bit/lib/jansson-e23f558/release.sh b/src/fluent-bit/lib/jansson-e23f558/release.sh new file mode 100755 index 000000000..c2551f828 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/release.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# +# Use this script to easily make releases of Jansson. It configures +# the source tree, and builds and signs all tarballs. + +die() { + echo $1 >&2 + exit 1 +} + +confirm() { + local answer + read -p "$1 [yN]: " answer + [ "$answer" = "Y" -o "$answer" = "y" ] || exit 0 +} + +set -e +[ -f configure.ac ] || die "Must be run at project root directory" + +# Determine version +v=$(grep AC_INIT configure.ac | sed -r 's/.*, \[(.+?)\],.*/\1/') +[ -n "$v" ] || die "Unable to determine version" +confirm "Version is $v, proceed?" + +# Sanity checks +vi=$(grep version-info src/Makefile.am | sed 's/^[ \t]*//g' | cut -d" " -f2) +confirm "Libtool version-info is $vi, proceed?" + +r=$(grep 'Released ' CHANGES | head -n 1) +confirm "Last CHANGES entry says \"$r\", proceed??" + +dv=$(grep ^version doc/conf.py | sed -r "s/.*'(.*)'.*/\1/") +if [ "$dv" != "$v" ]; then + die "Documentation version ($dv) doesn't match library version" +fi + +[ -f Makefile ] && make distclean || true +rm -f jansson-$v.tar.* +rm -rf jansson-$v-doc +rm -f jansson-$v-doc.tar.* + +autoreconf -fi +./configure + +# Run tests and make gz source tarball +: ${VALGRIND:=1} +export VALGRIND +make distcheck + +# Make bzip2 source tarball +make dist-bzip2 + +# Sign source tarballs +for s in gz bz2; do + gpg --detach-sign --armor jansson-$v.tar.$s +done + +# Build documentation +make html +mv doc/_build/html jansson-$v-doc + +# Make and sign documentation tarballs +for s in gz bz2; do + [ $s = gz ] && compress=gzip + [ $s = bz2 ] && compress=bzip2 + tar cf - jansson-$v-doc | $compress -9 -c > jansson-$v-doc.tar.$s + gpg --detach-sign --armor jansson-$v-doc.tar.$s +done + +echo "All done" diff --git a/src/fluent-bit/lib/jansson-e23f558/scripts/clang-format b/src/fluent-bit/lib/jansson-e23f558/scripts/clang-format new file mode 100755 index 000000000..d46056c94 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/scripts/clang-format @@ -0,0 +1,3 @@ +#!/bin/bash + +find . -type f -a '(' -name '*.c' -o -name '*.h' ')' | xargs clang-format -i diff --git a/src/fluent-bit/lib/jansson-e23f558/scripts/clang-format-check b/src/fluent-bit/lib/jansson-e23f558/scripts/clang-format-check new file mode 100755 index 000000000..983e55d97 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/scripts/clang-format-check @@ -0,0 +1,27 @@ +#!/bin/bash + +CLANG_FORMAT=${CLANG_FORMAT:-clang-format} +CLANG_FORMAT_VERSION=${CLANG_FORMAT_VERSION:-} + +if ! type $CLANG_FORMAT >/dev/null || \ + ! $CLANG_FORMAT --version | grep -q "version ${CLANG_FORMAT_VERSION}"; then + # If running tests, mark this test as skipped. + exit 77 +fi + +errors=0 +paths=$(git ls-files | grep '\.[ch]$') +for path in $paths; do + in=$(cat $path) + out=$($CLANG_FORMAT $path) + + if [ "$in" != "$out" ]; then + diff -u -L $path -L "$path.formatted" $path - <<<$out + errors=1 + fi +done + +if [ $errors -ne 0 ]; then + echo "Formatting errors detected, run ./scripts/clang-format to fix!" + exit 1 +fi diff --git a/src/fluent-bit/lib/jansson-e23f558/src/Makefile.am b/src/fluent-bit/lib/jansson-e23f558/src/Makefile.am new file mode 100644 index 000000000..63eda3213 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/Makefile.am @@ -0,0 +1,30 @@ +EXTRA_DIST = jansson.def + +include_HEADERS = jansson.h +nodist_include_HEADERS = jansson_config.h + +lib_LTLIBRARIES = libjansson.la +libjansson_la_SOURCES = \ + dump.c \ + error.c \ + hashtable.c \ + hashtable.h \ + hashtable_seed.c \ + jansson_private.h \ + load.c \ + lookup3.h \ + memory.c \ + pack_unpack.c \ + strbuffer.c \ + strbuffer.h \ + strconv.c \ + utf.c \ + utf.h \ + value.c \ + version.c +libjansson_la_LDFLAGS = \ + -no-undefined \ + -export-symbols-regex '^json_|^jansson_' \ + -version-info 18:0:14 \ + @JSON_SYMVER_LDFLAGS@ \ + @JSON_BSYMBOLIC_LDFLAGS@ diff --git a/src/fluent-bit/lib/jansson-e23f558/src/dump.c b/src/fluent-bit/lib/jansson-e23f558/src/dump.c new file mode 100644 index 000000000..c0fb06e78 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/dump.c @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "jansson_private.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "jansson.h" +#include "strbuffer.h" +#include "utf.h" + +#define MAX_INTEGER_STR_LENGTH 100 +#define MAX_REAL_STR_LENGTH 100 + +#define FLAGS_TO_INDENT(f) ((f)&0x1F) +#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F) + +struct buffer { + const size_t size; + size_t used; + char *data; +}; + +static int dump_to_strbuffer(const char *buffer, size_t size, void *data) { + return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); +} + +static int dump_to_buffer(const char *buffer, size_t size, void *data) { + struct buffer *buf = (struct buffer *)data; + + if (buf->used + size <= buf->size) + memcpy(&buf->data[buf->used], buffer, size); + + buf->used += size; + return 0; +} + +static int dump_to_file(const char *buffer, size_t size, void *data) { + FILE *dest = (FILE *)data; + if (fwrite(buffer, size, 1, dest) != 1) + return -1; + return 0; +} + +static int dump_to_fd(const char *buffer, size_t size, void *data) { +#ifdef HAVE_UNISTD_H + int *dest = (int *)data; + if (write(*dest, buffer, size) == (ssize_t)size) + return 0; +#endif + return -1; +} + +/* 32 spaces (the maximum indentation size) */ +static const char whitespace[] = " "; + +static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, + void *data) { + if (FLAGS_TO_INDENT(flags) > 0) { + unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count; + + if (dump("\n", 1, data)) + return -1; + + while (n_spaces > 0) { + int cur_n = + n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1; + + if (dump(whitespace, cur_n, data)) + return -1; + + n_spaces -= cur_n; + } + } else if (space && !(flags & JSON_COMPACT)) { + return dump(" ", 1, data); + } + return 0; +} + +static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, + size_t flags) { + const char *pos, *end, *lim; + int32_t codepoint = 0; + + if (dump("\"", 1, data)) + return -1; + + end = pos = str; + lim = str + len; + while (1) { + const char *text; + char seq[13]; + int length; + + while (end < lim) { + end = utf8_iterate(pos, lim - pos, &codepoint); + if (!end) + return -1; + + /* mandatory escape or control char */ + if (codepoint == '\\' || codepoint == '"' || codepoint < 0x20) + break; + + /* slash */ + if ((flags & JSON_ESCAPE_SLASH) && codepoint == '/') + break; + + /* non-ASCII */ + if ((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F) + break; + + pos = end; + } + + if (pos != str) { + if (dump(str, pos - str, data)) + return -1; + } + + if (end == pos) + break; + + /* handle \, /, ", and control codes */ + length = 2; + switch (codepoint) { + case '\\': + text = "\\\\"; + break; + case '\"': + text = "\\\""; + break; + case '\b': + text = "\\b"; + break; + case '\f': + text = "\\f"; + break; + case '\n': + text = "\\n"; + break; + case '\r': + text = "\\r"; + break; + case '\t': + text = "\\t"; + break; + case '/': + text = "\\/"; + break; + default: { + /* codepoint is in BMP */ + if (codepoint < 0x10000) { + snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint); + length = 6; + } + + /* not in BMP -> construct a UTF-16 surrogate pair */ + else { + int32_t first, last; + + codepoint -= 0x10000; + first = 0xD800 | ((codepoint & 0xffc00) >> 10); + last = 0xDC00 | (codepoint & 0x003ff); + + snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, + (unsigned int)last); + length = 12; + } + + text = seq; + break; + } + } + + if (dump(text, length, data)) + return -1; + + str = pos = end; + } + + return dump("\"", 1, data); +} + +struct key_len { + const char *key; + int len; +}; + +static int compare_keys(const void *key1, const void *key2) { + const struct key_len *k1 = key1; + const struct key_len *k2 = key2; + const size_t min_size = k1->len < k2->len ? k1->len : k2->len; + int res = memcmp(k1->key, k2->key, min_size); + + if (res) + return res; + + return k1->len - k2->len; +} + +static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *parents, + json_dump_callback_t dump, void *data) { + int embed = flags & JSON_EMBED; + + flags &= ~JSON_EMBED; + + if (!json) + return -1; + + switch (json_typeof(json)) { + case JSON_NULL: + return dump("null", 4, data); + + case JSON_TRUE: + return dump("true", 4, data); + + case JSON_FALSE: + return dump("false", 5, data); + + case JSON_INTEGER: { + char buffer[MAX_INTEGER_STR_LENGTH]; + int size; + + size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, "%" JSON_INTEGER_FORMAT, + json_integer_value(json)); + if (size < 0 || size >= MAX_INTEGER_STR_LENGTH) + return -1; + + return dump(buffer, size, data); + } + + case JSON_REAL: { + char buffer[MAX_REAL_STR_LENGTH]; + int size; + double value = json_real_value(json); + + size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value, + FLAGS_TO_PRECISION(flags)); + if (size < 0) + return -1; + + return dump(buffer, size, data); + } + + case JSON_STRING: + return dump_string(json_string_value(json), json_string_length(json), dump, + data, flags); + + case JSON_ARRAY: { + size_t n; + size_t i; + /* Space for "0x", double the sizeof a pointer for the hex and a + * terminator. */ + char key[2 + (sizeof(json) * 2) + 1]; + size_t key_len; + + /* detect circular references */ + if (jsonp_loop_check(parents, json, key, sizeof(key), &key_len)) + return -1; + + n = json_array_size(json); + + if (!embed && dump("[", 1, data)) + return -1; + if (n == 0) { + hashtable_del(parents, key, key_len); + return embed ? 0 : dump("]", 1, data); + } + if (dump_indent(flags, depth + 1, 0, dump, data)) + return -1; + + for (i = 0; i < n; ++i) { + if (do_dump(json_array_get(json, i), flags, depth + 1, parents, dump, + data)) + return -1; + + if (i < n - 1) { + if (dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + return -1; + } else { + if (dump_indent(flags, depth, 0, dump, data)) + return -1; + } + } + + hashtable_del(parents, key, key_len); + return embed ? 0 : dump("]", 1, data); + } + + case JSON_OBJECT: { + void *iter; + const char *separator; + int separator_length; + char loop_key[LOOP_KEY_LEN]; + size_t loop_key_len; + + if (flags & JSON_COMPACT) { + separator = ":"; + separator_length = 1; + } else { + separator = ": "; + separator_length = 2; + } + + /* detect circular references */ + if (jsonp_loop_check(parents, json, loop_key, sizeof(loop_key), + &loop_key_len)) + return -1; + + iter = json_object_iter((json_t *)json); + + if (!embed && dump("{", 1, data)) + return -1; + if (!iter) { + hashtable_del(parents, loop_key, loop_key_len); + return embed ? 0 : dump("}", 1, data); + } + if (dump_indent(flags, depth + 1, 0, dump, data)) + return -1; + + if (flags & JSON_SORT_KEYS) { + struct key_len *keys; + size_t size, i; + + size = json_object_size(json); + keys = jsonp_malloc(size * sizeof(struct key_len)); + if (!keys) + return -1; + + i = 0; + while (iter) { + struct key_len *keylen = &keys[i]; + + keylen->key = json_object_iter_key(iter); + keylen->len = json_object_iter_key_len(iter); + + iter = json_object_iter_next((json_t *)json, iter); + i++; + } + assert(i == size); + + qsort(keys, size, sizeof(struct key_len), compare_keys); + + for (i = 0; i < size; i++) { + const struct key_len *key; + json_t *value; + + key = &keys[i]; + value = json_object_getn(json, key->key, key->len); + assert(value); + + dump_string(key->key, key->len, dump, data, flags); + if (dump(separator, separator_length, data) || + do_dump(value, flags, depth + 1, parents, dump, data)) { + jsonp_free(keys); + return -1; + } + + if (i < size - 1) { + if (dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) { + jsonp_free(keys); + return -1; + } + } else { + if (dump_indent(flags, depth, 0, dump, data)) { + jsonp_free(keys); + return -1; + } + } + } + + jsonp_free(keys); + } else { + /* Don't sort keys */ + + while (iter) { + void *next = json_object_iter_next((json_t *)json, iter); + const char *key = json_object_iter_key(iter); + const size_t key_len = json_object_iter_key_len(iter); + + dump_string(key, key_len, dump, data, flags); + if (dump(separator, separator_length, data) || + do_dump(json_object_iter_value(iter), flags, depth + 1, parents, + dump, data)) + return -1; + + if (next) { + if (dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + return -1; + } else { + if (dump_indent(flags, depth, 0, dump, data)) + return -1; + } + + iter = next; + } + } + + hashtable_del(parents, loop_key, loop_key_len); + return embed ? 0 : dump("}", 1, data); + } + + default: + /* not reached */ + return -1; + } +} + +char *json_dumps(const json_t *json, size_t flags) { + strbuffer_t strbuff; + char *result; + + if (strbuffer_init(&strbuff)) + return NULL; + + if (json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags)) + result = NULL; + else + result = jsonp_strdup(strbuffer_value(&strbuff)); + + strbuffer_close(&strbuff); + return result; +} + +size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) { + struct buffer buf = {size, 0, buffer}; + + if (json_dump_callback(json, dump_to_buffer, (void *)&buf, flags)) + return 0; + + return buf.used; +} + +int json_dumpf(const json_t *json, FILE *output, size_t flags) { + return json_dump_callback(json, dump_to_file, (void *)output, flags); +} + +int json_dumpfd(const json_t *json, int output, size_t flags) { + return json_dump_callback(json, dump_to_fd, (void *)&output, flags); +} + +int json_dump_file(const json_t *json, const char *path, size_t flags) { + int result; + + FILE *output = fopen(path, "w"); + if (!output) + return -1; + + result = json_dumpf(json, output, flags); + + if (fclose(output) != 0) + return -1; + + return result; +} + +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, + size_t flags) { + int res; + hashtable_t parents_set; + + if (!(flags & JSON_ENCODE_ANY)) { + if (!json_is_array(json) && !json_is_object(json)) + return -1; + } + + if (hashtable_init(&parents_set)) + return -1; + res = do_dump(json, flags, 0, &parents_set, callback, data); + hashtable_close(&parents_set); + + return res; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/error.c b/src/fluent-bit/lib/jansson-e23f558/src/error.c new file mode 100644 index 000000000..14d0047d9 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/error.c @@ -0,0 +1,59 @@ +#include "jansson_private.h" +#include <string.h> + +void jsonp_error_init(json_error_t *error, const char *source) { + if (error) { + error->text[0] = '\0'; + error->line = -1; + error->column = -1; + error->position = 0; + if (source) + jsonp_error_set_source(error, source); + else + error->source[0] = '\0'; + } +} + +void jsonp_error_set_source(json_error_t *error, const char *source) { + size_t length; + + if (!error || !source) + return; + + length = strlen(source); + if (length < JSON_ERROR_SOURCE_LENGTH) + strncpy(error->source, source, length + 1); + else { + size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; + memcpy(error->source, "...", 3); + strncpy(error->source + 3, source + extra, length - extra + 1); + } +} + +void jsonp_error_set(json_error_t *error, int line, int column, size_t position, + enum json_error_code code, const char *msg, ...) { + va_list ap; + + va_start(ap, msg); + jsonp_error_vset(error, line, column, position, code, msg, ap); + va_end(ap); +} + +void jsonp_error_vset(json_error_t *error, int line, int column, size_t position, + enum json_error_code code, const char *msg, va_list ap) { + if (!error) + return; + + if (error->text[0] != '\0') { + /* error already set */ + return; + } + + error->line = line; + error->column = column; + error->position = (int)position; + + vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH - 1, msg, ap); + error->text[JSON_ERROR_TEXT_LENGTH - 2] = '\0'; + error->text[JSON_ERROR_TEXT_LENGTH - 1] = code; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/hashtable.c b/src/fluent-bit/lib/jansson-e23f558/src/hashtable.c new file mode 100644 index 000000000..5e97f8511 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/hashtable.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#include "hashtable.h" +#include "jansson_private.h" /* for container_of() */ +#include <jansson_config.h> /* for JSON_INLINE */ + +#ifndef INITIAL_HASHTABLE_ORDER +#define INITIAL_HASHTABLE_ORDER 3 +#endif + +typedef struct hashtable_list list_t; +typedef struct hashtable_pair pair_t; +typedef struct hashtable_bucket bucket_t; + +extern volatile uint32_t hashtable_seed; + +/* Implementation of the hash function */ +#include "lookup3.h" + +#define list_to_pair(list_) container_of(list_, pair_t, list) +#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list) +#define hash_str(key, len) ((size_t)hashlittle((key), len, hashtable_seed)) + +static JSON_INLINE void list_init(list_t *list) { + list->next = list; + list->prev = list; +} + +static JSON_INLINE void list_insert(list_t *list, list_t *node) { + node->next = list; + node->prev = list->prev; + list->prev->next = node; + list->prev = node; +} + +static JSON_INLINE void list_remove(list_t *list) { + list->prev->next = list->next; + list->next->prev = list->prev; +} + +static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) { + return bucket->first == &hashtable->list && bucket->first == bucket->last; +} + +static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, list_t *list) { + if (bucket_is_empty(hashtable, bucket)) { + list_insert(&hashtable->list, list); + bucket->first = bucket->last = list; + } else { + list_insert(bucket->first, list); + bucket->first = list; + } +} + +static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, + const char *key, size_t key_len, size_t hash) { + list_t *list; + pair_t *pair; + + if (bucket_is_empty(hashtable, bucket)) + return NULL; + + list = bucket->first; + while (1) { + pair = list_to_pair(list); + if (pair->hash == hash && pair->key_len == key_len && + memcmp(pair->key, key, key_len) == 0) + return pair; + + if (list == bucket->last) + break; + + list = list->next; + } + + return NULL; +} + +/* returns 0 on success, -1 if key was not found */ +static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t key_len, + size_t hash) { + pair_t *pair; + bucket_t *bucket; + size_t index; + + index = hash & hashmask(hashtable->order); + bucket = &hashtable->buckets[index]; + + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); + if (!pair) + return -1; + + if (&pair->list == bucket->first && &pair->list == bucket->last) + bucket->first = bucket->last = &hashtable->list; + + else if (&pair->list == bucket->first) + bucket->first = pair->list.next; + + else if (&pair->list == bucket->last) + bucket->last = pair->list.prev; + + list_remove(&pair->list); + list_remove(&pair->ordered_list); + json_decref(pair->value); + + jsonp_free(pair); + hashtable->size--; + + return 0; +} + +static void hashtable_do_clear(hashtable_t *hashtable) { + list_t *list, *next; + pair_t *pair; + + for (list = hashtable->list.next; list != &hashtable->list; list = next) { + next = list->next; + pair = list_to_pair(list); + json_decref(pair->value); + jsonp_free(pair); + } +} + +static int hashtable_do_rehash(hashtable_t *hashtable) { + list_t *list, *next; + pair_t *pair; + size_t i, index, new_size, new_order; + struct hashtable_bucket *new_buckets; + + new_order = hashtable->order + 1; + new_size = hashsize(new_order); + + new_buckets = jsonp_malloc(new_size * sizeof(bucket_t)); + if (!new_buckets) + return -1; + + jsonp_free(hashtable->buckets); + hashtable->buckets = new_buckets; + hashtable->order = new_order; + + for (i = 0; i < hashsize(hashtable->order); i++) { + hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; + } + + list = hashtable->list.next; + list_init(&hashtable->list); + + for (; list != &hashtable->list; list = next) { + next = list->next; + pair = list_to_pair(list); + index = pair->hash % new_size; + insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list); + } + + return 0; +} + +int hashtable_init(hashtable_t *hashtable) { + size_t i; + + hashtable->size = 0; + hashtable->order = INITIAL_HASHTABLE_ORDER; + hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t)); + if (!hashtable->buckets) + return -1; + + list_init(&hashtable->list); + list_init(&hashtable->ordered_list); + + for (i = 0; i < hashsize(hashtable->order); i++) { + hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; + } + + return 0; +} + +void hashtable_close(hashtable_t *hashtable) { + hashtable_do_clear(hashtable); + jsonp_free(hashtable->buckets); +} + +static pair_t *init_pair(json_t *value, const char *key, size_t key_len, size_t hash) { + pair_t *pair; + + /* offsetof(...) returns the size of pair_t without the last, + flexible member. This way, the correct amount is + allocated. */ + + if (key_len >= (size_t)-1 - offsetof(pair_t, key)) { + /* Avoid an overflow if the key is very long */ + return NULL; + } + + pair = jsonp_malloc(offsetof(pair_t, key) + key_len + 1); + + if (!pair) + return NULL; + + pair->hash = hash; + memcpy(pair->key, key, key_len); + pair->key[key_len] = '\0'; + pair->key_len = key_len; + pair->value = value; + + list_init(&pair->list); + list_init(&pair->ordered_list); + + return pair; +} + +int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, + json_t *value) { + pair_t *pair; + bucket_t *bucket; + size_t hash, index; + + /* rehash if the load ratio exceeds 1 */ + if (hashtable->size >= hashsize(hashtable->order)) + if (hashtable_do_rehash(hashtable)) + return -1; + + hash = hash_str(key, key_len); + index = hash & hashmask(hashtable->order); + bucket = &hashtable->buckets[index]; + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); + + if (pair) { + json_decref(pair->value); + pair->value = value; + } else { + pair = init_pair(value, key, key_len, hash); + + if (!pair) + return -1; + + insert_to_bucket(hashtable, bucket, &pair->list); + list_insert(&hashtable->ordered_list, &pair->ordered_list); + + hashtable->size++; + } + return 0; +} + +void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len) { + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key, key_len); + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; + + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); + if (!pair) + return NULL; + + return pair->value; +} + +int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len) { + size_t hash = hash_str(key, key_len); + return hashtable_do_del(hashtable, key, key_len, hash); +} + +void hashtable_clear(hashtable_t *hashtable) { + size_t i; + + hashtable_do_clear(hashtable); + + for (i = 0; i < hashsize(hashtable->order); i++) { + hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; + } + + list_init(&hashtable->list); + list_init(&hashtable->ordered_list); + hashtable->size = 0; +} + +void *hashtable_iter(hashtable_t *hashtable) { + return hashtable_iter_next(hashtable, &hashtable->ordered_list); +} + +void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len) { + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key, key_len); + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; + + pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash); + if (!pair) + return NULL; + + return &pair->ordered_list; +} + +void *hashtable_iter_next(hashtable_t *hashtable, void *iter) { + list_t *list = (list_t *)iter; + if (list->next == &hashtable->ordered_list) + return NULL; + return list->next; +} + +void *hashtable_iter_key(void *iter) { + pair_t *pair = ordered_list_to_pair((list_t *)iter); + return pair->key; +} + +size_t hashtable_iter_key_len(void *iter) { + pair_t *pair = ordered_list_to_pair((list_t *)iter); + return pair->key_len; +} + +void *hashtable_iter_value(void *iter) { + pair_t *pair = ordered_list_to_pair((list_t *)iter); + return pair->value; +} + +void hashtable_iter_set(void *iter, json_t *value) { + pair_t *pair = ordered_list_to_pair((list_t *)iter); + + json_decref(pair->value); + pair->value = value; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/hashtable.h b/src/fluent-bit/lib/jansson-e23f558/src/hashtable.h new file mode 100644 index 000000000..03a1f5a99 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/hashtable.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef HASHTABLE_H +#define HASHTABLE_H + +#include "jansson.h" +#include <stdlib.h> + +struct hashtable_list { + struct hashtable_list *prev; + struct hashtable_list *next; +}; + +/* "pair" may be a bit confusing a name, but think of it as a + key-value pair. In this case, it just encodes some extra data, + too */ +struct hashtable_pair { + struct hashtable_list list; + struct hashtable_list ordered_list; + size_t hash; + json_t *value; + size_t key_len; + char key[1]; +}; + +struct hashtable_bucket { + struct hashtable_list *first; + struct hashtable_list *last; +}; + +typedef struct hashtable { + size_t size; + struct hashtable_bucket *buckets; + size_t order; /* hashtable has pow(2, order) buckets */ + struct hashtable_list list; + struct hashtable_list ordered_list; +} hashtable_t; + +#define hashtable_key_to_iter(key_) \ + (&(container_of(key_, struct hashtable_pair, key)->ordered_list)) + +/** + * hashtable_init - Initialize a hashtable object + * + * @hashtable: The (statically allocated) hashtable object + * + * Initializes a statically allocated hashtable object. The object + * should be cleared with hashtable_close when it's no longer used. + * + * Returns 0 on success, -1 on error (out of memory). + */ +int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS((warn_unused_result)); + +/** + * hashtable_close - Release all resources used by a hashtable object + * + * @hashtable: The hashtable + * + * Destroys a statically allocated hashtable object. + */ +void hashtable_close(hashtable_t *hashtable); + +/** + * hashtable_set - Add/modify value in hashtable + * + * @hashtable: The hashtable object + * @key: The key + * @key: The length of key + * @serial: For addition order of keys + * @value: The value + * + * If a value with the given key already exists, its value is replaced + * with the new value. Value is "stealed" in the sense that hashtable + * doesn't increment its refcount but decreases the refcount when the + * value is no longer needed. + * + * Returns 0 on success, -1 on failure (out of memory). + */ +int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len, json_t *value); + +/** + * hashtable_get - Get a value associated with a key + * + * @hashtable: The hashtable object + * @key: The key + * @key: The length of key + * + * Returns value if it is found, or NULL otherwise. + */ +void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len); + +/** + * hashtable_del - Remove a value from the hashtable + * + * @hashtable: The hashtable object + * @key: The key + * @key: The length of key + * + * Returns 0 on success, or -1 if the key was not found. + */ +int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len); + +/** + * hashtable_clear - Clear hashtable + * + * @hashtable: The hashtable object + * + * Removes all items from the hashtable. + */ +void hashtable_clear(hashtable_t *hashtable); + +/** + * hashtable_iter - Iterate over hashtable + * + * @hashtable: The hashtable object + * + * Returns an opaque iterator to the first element in the hashtable. + * The iterator should be passed to hashtable_iter_* functions. + * The hashtable items are not iterated over in any particular order. + * + * There's no need to free the iterator in any way. The iterator is + * valid as long as the item that is referenced by the iterator is not + * deleted. Other values may be added or deleted. In particular, + * hashtable_iter_next() may be called on an iterator, and after that + * the key/value pair pointed by the old iterator may be deleted. + */ +void *hashtable_iter(hashtable_t *hashtable); + +/** + * hashtable_iter_at - Return an iterator at a specific key + * + * @hashtable: The hashtable object + * @key: The key that the iterator should point to + * @key: The length of key + * + * Like hashtable_iter() but returns an iterator pointing to a + * specific key. + */ +void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len); + +/** + * hashtable_iter_next - Advance an iterator + * + * @hashtable: The hashtable object + * @iter: The iterator + * + * Returns a new iterator pointing to the next element in the + * hashtable or NULL if the whole hastable has been iterated over. + */ +void *hashtable_iter_next(hashtable_t *hashtable, void *iter); + +/** + * hashtable_iter_key - Retrieve the key pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_key(void *iter); + +/** + * hashtable_iter_key_len - Retrieve the key length pointed by an iterator + * + * @iter: The iterator + */ +size_t hashtable_iter_key_len(void *iter); + +/** + * hashtable_iter_value - Retrieve the value pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_value(void *iter); + +/** + * hashtable_iter_set - Set the value pointed by an iterator + * + * @iter: The iterator + * @value: The value to set + */ +void hashtable_iter_set(void *iter, json_t *value); + +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/src/hashtable_seed.c b/src/fluent-bit/lib/jansson-e23f558/src/hashtable_seed.c new file mode 100644 index 000000000..d156b400c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/hashtable_seed.c @@ -0,0 +1,277 @@ +/* Generate sizeof(uint32_t) bytes of as random data as possible to seed + the hash function. +*/ + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#include <stdio.h> +#include <time.h> + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef HAVE_SCHED_H +#include <sched.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#if defined(_WIN32) +/* For GetModuleHandle(), GetProcAddress() and GetCurrentProcessId() */ +#include <windows.h> +#endif + +#include "jansson.h" + +static uint32_t buf_to_uint32(char *data) { + size_t i; + uint32_t result = 0; + + for (i = 0; i < sizeof(uint32_t); i++) + result = (result << 8) | (unsigned char)data[i]; + + return result; +} + +/* /dev/urandom */ +#if !defined(_WIN32) && defined(USE_URANDOM) +static int seed_from_urandom(uint32_t *seed) { + /* Use unbuffered I/O if we have open(), close() and read(). Otherwise + fall back to fopen() */ + + char data[sizeof(uint32_t)]; + int ok; + +#if defined(HAVE_OPEN) && defined(HAVE_CLOSE) && defined(HAVE_READ) + int urandom; + urandom = open("/dev/urandom", O_RDONLY); + if (urandom == -1) + return 1; + + ok = read(urandom, data, sizeof(uint32_t)) == sizeof(uint32_t); + close(urandom); +#else + FILE *urandom; + + urandom = fopen("/dev/urandom", "rb"); + if (!urandom) + return 1; + + ok = fread(data, 1, sizeof(uint32_t), urandom) == sizeof(uint32_t); + fclose(urandom); +#endif + + if (!ok) + return 1; + + *seed = buf_to_uint32(data); + return 0; +} +#endif + +/* Windows Crypto API */ +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) +#include <wincrypt.h> + +typedef BOOL(WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, + LPCSTR pszProvider, DWORD dwProvType, + DWORD dwFlags); +typedef BOOL(WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer); +typedef BOOL(WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags); + +static int seed_from_windows_cryptoapi(uint32_t *seed) { + HINSTANCE hAdvAPI32 = NULL; + CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL; + CRYPTGENRANDOM pCryptGenRandom = NULL; + CRYPTRELEASECONTEXT pCryptReleaseContext = NULL; + HCRYPTPROV hCryptProv = 0; + BYTE data[sizeof(uint32_t)]; + int ok; + + hAdvAPI32 = GetModuleHandle(TEXT("advapi32.dll")); + if (hAdvAPI32 == NULL) + return 1; + + pCryptAcquireContext = + (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA"); + if (!pCryptAcquireContext) + return 1; + + pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, "CryptGenRandom"); + if (!pCryptGenRandom) + return 1; + + pCryptReleaseContext = + (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext"); + if (!pCryptReleaseContext) + return 1; + + if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return 1; + + ok = pCryptGenRandom(hCryptProv, sizeof(uint32_t), data); + pCryptReleaseContext(hCryptProv, 0); + + if (!ok) + return 1; + + *seed = buf_to_uint32((char *)data); + return 0; +} +#endif + +/* gettimeofday() and getpid() */ +static int seed_from_timestamp_and_pid(uint32_t *seed) { +#ifdef HAVE_GETTIMEOFDAY + /* XOR of seconds and microseconds */ + struct timeval tv; + gettimeofday(&tv, NULL); + *seed = (uint32_t)tv.tv_sec ^ (uint32_t)tv.tv_usec; +#else + /* Seconds only */ + *seed = (uint32_t)time(NULL); +#endif + + /* XOR with PID for more randomness */ +#if defined(_WIN32) + *seed ^= (uint32_t)GetCurrentProcessId(); +#elif defined(HAVE_GETPID) + *seed ^= (uint32_t)getpid(); +#endif + + return 0; +} + +static uint32_t generate_seed() { + uint32_t seed = 0; + int done = 0; + +#if !defined(_WIN32) && defined(USE_URANDOM) + if (seed_from_urandom(&seed) == 0) + done = 1; +#endif + +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) + if (seed_from_windows_cryptoapi(&seed) == 0) + done = 1; +#endif + + if (!done) { + /* Fall back to timestamp and PID if no better randomness is + available */ + seed_from_timestamp_and_pid(&seed); + } + + /* Make sure the seed is never zero */ + if (seed == 0) + seed = 1; + + return seed; +} + +volatile uint32_t hashtable_seed = 0; + +#if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +static volatile char seed_initialized = 0; + +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (__atomic_test_and_set(&seed_initialized, __ATOMIC_RELAXED) == 0) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + __atomic_store_n(&hashtable_seed, new_seed, __ATOMIC_RELEASE); + } else { + /* Wait for another thread to do the seeding */ + do { +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } while (__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0); + } + } +} +#elif defined(HAVE_SYNC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) { + /* Explicit synchronization fences are not supported by the + __sync builtins, so every thread getting here has to + generate the seed value. + */ + new_seed = generate_seed(); + } + + do { + if (__sync_bool_compare_and_swap(&hashtable_seed, 0, new_seed)) { + /* We were the first to seed */ + break; + } else { + /* Wait for another thread to do the seeding */ +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } + } while (hashtable_seed == 0); + } +} +#elif defined(_WIN32) +static long seed_initialized = 0; +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (InterlockedIncrement(&seed_initialized) == 1) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } else { + /* Wait for another thread to do the seeding */ + do { + SwitchToThread(); + } while (hashtable_seed == 0); + } + } +} +#else +/* Fall back to a thread-unsafe version */ +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } +} +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/src/jansson.def b/src/fluent-bit/lib/jansson-e23f558/src/jansson.def new file mode 100644 index 000000000..5c76c2f68 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/jansson.def @@ -0,0 +1,83 @@ +EXPORTS + json_delete + json_true + json_false + json_null + json_sprintf + json_vsprintf + json_string + json_stringn + json_string_nocheck + json_stringn_nocheck + json_string_value + json_string_length + json_string_set + json_string_setn + json_string_set_nocheck + json_string_setn_nocheck + json_integer + json_integer_value + json_integer_set + json_real + json_real_value + json_real_set + json_number_value + json_array + json_array_size + json_array_get + json_array_set_new + json_array_append_new + json_array_insert_new + json_array_remove + json_array_clear + json_array_extend + json_object + json_object_size + json_object_get + json_object_getn + json_object_set_new + json_object_setn_new + json_object_set_new_nocheck + json_object_setn_new_nocheck + json_object_del + json_object_deln + json_object_clear + json_object_update + json_object_update_existing + json_object_update_missing + json_object_update_recursive + json_object_iter + json_object_iter_at + json_object_iter_next + json_object_iter_key + json_object_iter_key_len + json_object_iter_value + json_object_iter_set_new + json_object_key_to_iter + json_object_seed + json_dumps + json_dumpb + json_dumpf + json_dumpfd + json_dump_file + json_dump_callback + json_loads + json_loadb + json_loadf + json_loadfd + json_load_file + json_load_callback + json_equal + json_copy + json_deep_copy + json_pack + json_pack_ex + json_vpack_ex + json_unpack + json_unpack_ex + json_vunpack_ex + json_set_alloc_funcs + json_get_alloc_funcs + jansson_version_str + jansson_version_cmp + diff --git a/src/fluent-bit/lib/jansson-e23f558/src/jansson.h b/src/fluent-bit/lib/jansson-e23f558/src/jansson.h new file mode 100644 index 000000000..391c85e9c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/jansson.h @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_H +#define JANSSON_H + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> /* for size_t */ + +#include "jansson_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* version */ + +#define JANSSON_MAJOR_VERSION 2 +#define JANSSON_MINOR_VERSION 14 +#define JANSSON_MICRO_VERSION 0 + +/* Micro version is omitted if it's 0 */ +#define JANSSON_VERSION "2.14" + +/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this + for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ +#define JANSSON_VERSION_HEX \ + ((JANSSON_MAJOR_VERSION << 16) | (JANSSON_MINOR_VERSION << 8) | \ + (JANSSON_MICRO_VERSION << 0)) + +/* If __atomic or __sync builtins are available the library is thread + * safe for all read-only functions plus reference counting. */ +#if JSON_HAVE_ATOMIC_BUILTINS || JSON_HAVE_SYNC_BUILTINS +#define JANSSON_THREAD_SAFE_REFCOUNT 1 +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define JANSSON_ATTRS(x) __attribute__(x) +#else +#define JANSSON_ATTRS(x) +#endif + +/* types */ + +typedef enum { + JSON_OBJECT, + JSON_ARRAY, + JSON_STRING, + JSON_INTEGER, + JSON_REAL, + JSON_TRUE, + JSON_FALSE, + JSON_NULL +} json_type; + +typedef struct json_t { + json_type type; + volatile size_t refcount; +} json_t; + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _WIN32 +#define JSON_INTEGER_FORMAT "I64d" +#else +#define JSON_INTEGER_FORMAT "lld" +#endif +typedef long long json_int_t; +#else +#define JSON_INTEGER_FORMAT "ld" +typedef long json_int_t; +#endif /* JSON_INTEGER_IS_LONG_LONG */ +#endif + +#define json_typeof(json) ((json)->type) +#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT) +#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY) +#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING) +#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER) +#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL) +#define json_is_number(json) (json_is_integer(json) || json_is_real(json)) +#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE) +#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE) +#define json_boolean_value json_is_true +#define json_is_boolean(json) (json_is_true(json) || json_is_false(json)) +#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL) + +/* construction, destruction, reference counting */ + +json_t *json_object(void); +json_t *json_array(void); +json_t *json_string(const char *value); +json_t *json_stringn(const char *value, size_t len); +json_t *json_string_nocheck(const char *value); +json_t *json_stringn_nocheck(const char *value, size_t len); +json_t *json_integer(json_int_t value); +json_t *json_real(double value); +json_t *json_true(void); +json_t *json_false(void); +#define json_boolean(val) ((val) ? json_true() : json_false()) +json_t *json_null(void); + +/* do not call JSON_INTERNAL_INCREF or JSON_INTERNAL_DECREF directly */ +#if JSON_HAVE_ATOMIC_BUILTINS +#define JSON_INTERNAL_INCREF(json) \ + __atomic_add_fetch(&json->refcount, 1, __ATOMIC_ACQUIRE) +#define JSON_INTERNAL_DECREF(json) \ + __atomic_sub_fetch(&json->refcount, 1, __ATOMIC_RELEASE) +#elif JSON_HAVE_SYNC_BUILTINS +#define JSON_INTERNAL_INCREF(json) __sync_add_and_fetch(&json->refcount, 1) +#define JSON_INTERNAL_DECREF(json) __sync_sub_and_fetch(&json->refcount, 1) +#else +#define JSON_INTERNAL_INCREF(json) (++json->refcount) +#define JSON_INTERNAL_DECREF(json) (--json->refcount) +#endif + +static JSON_INLINE json_t *json_incref(json_t *json) { + if (json && json->refcount != (size_t)-1) + JSON_INTERNAL_INCREF(json); + return json; +} + +/* do not call json_delete directly */ +void json_delete(json_t *json); + +static JSON_INLINE void json_decref(json_t *json) { + if (json && json->refcount != (size_t)-1 && JSON_INTERNAL_DECREF(json) == 0) + json_delete(json); +} + +#if defined(__GNUC__) || defined(__clang__) +static JSON_INLINE void json_decrefp(json_t **json) { + if (json) { + json_decref(*json); + *json = NULL; + } +} + +#define json_auto_t json_t __attribute__((cleanup(json_decrefp))) +#endif + +/* error reporting */ + +#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct json_error_t { + int line; + int column; + int position; + char source[JSON_ERROR_SOURCE_LENGTH]; + char text[JSON_ERROR_TEXT_LENGTH]; +} json_error_t; + +enum json_error_code { + json_error_unknown, + json_error_out_of_memory, + json_error_stack_overflow, + json_error_cannot_open_file, + json_error_invalid_argument, + json_error_invalid_utf8, + json_error_premature_end_of_input, + json_error_end_of_input_expected, + json_error_invalid_syntax, + json_error_invalid_format, + json_error_wrong_type, + json_error_null_character, + json_error_null_value, + json_error_null_byte_in_key, + json_error_duplicate_key, + json_error_numeric_overflow, + json_error_item_not_found, + json_error_index_out_of_range +}; + +static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) { + return (enum json_error_code)e->text[JSON_ERROR_TEXT_LENGTH - 1]; +} + +/* getters, setters, manipulation */ + +void json_object_seed(size_t seed); +size_t json_object_size(const json_t *object); +json_t *json_object_get(const json_t *object, const char *key) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_object_getn(const json_t *object, const char *key, size_t key_len) + JANSSON_ATTRS((warn_unused_result)); +int json_object_set_new(json_t *object, const char *key, json_t *value); +int json_object_setn_new(json_t *object, const char *key, size_t key_len, json_t *value); +int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); +int json_object_setn_new_nocheck(json_t *object, const char *key, size_t key_len, + json_t *value); +int json_object_del(json_t *object, const char *key); +int json_object_deln(json_t *object, const char *key, size_t key_len); +int json_object_clear(json_t *object); +int json_object_update(json_t *object, json_t *other); +int json_object_update_existing(json_t *object, json_t *other); +int json_object_update_missing(json_t *object, json_t *other); +int json_object_update_recursive(json_t *object, json_t *other); +void *json_object_iter(json_t *object); +void *json_object_iter_at(json_t *object, const char *key); +void *json_object_key_to_iter(const char *key); +void *json_object_iter_next(json_t *object, void *iter); +const char *json_object_iter_key(void *iter); +size_t json_object_iter_key_len(void *iter); +json_t *json_object_iter_value(void *iter); +int json_object_iter_set_new(json_t *object, void *iter, json_t *value); + +#define json_object_foreach(object, key, value) \ + for (key = json_object_iter_key(json_object_iter(object)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key( \ + json_object_iter_next(object, json_object_key_to_iter(key)))) + +#define json_object_keylen_foreach(object, key, key_len, value) \ + for (key = json_object_iter_key(json_object_iter(object)), \ + key_len = json_object_iter_key_len(json_object_key_to_iter(key)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key( \ + json_object_iter_next(object, json_object_key_to_iter(key))), \ + key_len = json_object_iter_key_len(json_object_key_to_iter(key))) + +#define json_object_foreach_safe(object, n, key, value) \ + for (key = json_object_iter_key(json_object_iter(object)), \ + n = json_object_iter_next(object, json_object_key_to_iter(key)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(n), \ + n = json_object_iter_next(object, json_object_key_to_iter(key))) + +#define json_object_keylen_foreach_safe(object, n, key, key_len, value) \ + for (key = json_object_iter_key(json_object_iter(object)), \ + n = json_object_iter_next(object, json_object_key_to_iter(key)), \ + key_len = json_object_iter_key_len(json_object_key_to_iter(key)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(n), key_len = json_object_iter_key_len(n), \ + n = json_object_iter_next(object, json_object_key_to_iter(key))) + +#define json_array_foreach(array, index, value) \ + for (index = 0; \ + index < json_array_size(array) && (value = json_array_get(array, index)); \ + index++) + +static JSON_INLINE int json_object_set(json_t *object, const char *key, json_t *value) { + return json_object_set_new(object, key, json_incref(value)); +} + +static JSON_INLINE int json_object_setn(json_t *object, const char *key, size_t key_len, + json_t *value) { + return json_object_setn_new(object, key, key_len, json_incref(value)); +} + +static JSON_INLINE int json_object_set_nocheck(json_t *object, const char *key, + json_t *value) { + return json_object_set_new_nocheck(object, key, json_incref(value)); +} + +static JSON_INLINE int json_object_setn_nocheck(json_t *object, const char *key, + size_t key_len, json_t *value) { + return json_object_setn_new_nocheck(object, key, key_len, json_incref(value)); +} + +static JSON_INLINE int json_object_iter_set(json_t *object, void *iter, json_t *value) { + return json_object_iter_set_new(object, iter, json_incref(value)); +} + +static JSON_INLINE int json_object_update_new(json_t *object, json_t *other) { + int ret = json_object_update(object, other); + json_decref(other); + return ret; +} + +static JSON_INLINE int json_object_update_existing_new(json_t *object, json_t *other) { + int ret = json_object_update_existing(object, other); + json_decref(other); + return ret; +} + +static JSON_INLINE int json_object_update_missing_new(json_t *object, json_t *other) { + int ret = json_object_update_missing(object, other); + json_decref(other); + return ret; +} + +size_t json_array_size(const json_t *array); +json_t *json_array_get(const json_t *array, size_t index) + JANSSON_ATTRS((warn_unused_result)); +int json_array_set_new(json_t *array, size_t index, json_t *value); +int json_array_append_new(json_t *array, json_t *value); +int json_array_insert_new(json_t *array, size_t index, json_t *value); +int json_array_remove(json_t *array, size_t index); +int json_array_clear(json_t *array); +int json_array_extend(json_t *array, json_t *other); + +static JSON_INLINE int json_array_set(json_t *array, size_t ind, json_t *value) { + return json_array_set_new(array, ind, json_incref(value)); +} + +static JSON_INLINE int json_array_append(json_t *array, json_t *value) { + return json_array_append_new(array, json_incref(value)); +} + +static JSON_INLINE int json_array_insert(json_t *array, size_t ind, json_t *value) { + return json_array_insert_new(array, ind, json_incref(value)); +} + +const char *json_string_value(const json_t *string); +size_t json_string_length(const json_t *string); +json_int_t json_integer_value(const json_t *integer); +double json_real_value(const json_t *real); +double json_number_value(const json_t *json); + +int json_string_set(json_t *string, const char *value); +int json_string_setn(json_t *string, const char *value, size_t len); +int json_string_set_nocheck(json_t *string, const char *value); +int json_string_setn_nocheck(json_t *string, const char *value, size_t len); +int json_integer_set(json_t *integer, json_int_t value); +int json_real_set(json_t *real, double value); + +/* pack, unpack */ + +json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS((warn_unused_result)); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) + JANSSON_ATTRS((warn_unused_result)); + +#define JSON_VALIDATE_ONLY 0x1 +#define JSON_STRICT 0x2 + +int json_unpack(json_t *root, const char *fmt, ...); +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...); +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, + va_list ap); + +/* sprintf */ + +json_t *json_sprintf(const char *fmt, ...) + JANSSON_ATTRS((warn_unused_result, format(printf, 1, 2))); +json_t *json_vsprintf(const char *fmt, va_list ap) + JANSSON_ATTRS((warn_unused_result, format(printf, 1, 0))); + +/* equality */ + +int json_equal(const json_t *value1, const json_t *value2); + +/* copying */ + +json_t *json_copy(json_t *value) JANSSON_ATTRS((warn_unused_result)); +json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS((warn_unused_result)); + +/* decoding */ + +#define JSON_REJECT_DUPLICATES 0x1 +#define JSON_DISABLE_EOF_CHECK 0x2 +#define JSON_DECODE_ANY 0x4 +#define JSON_DECODE_INT_AS_REAL 0x8 +#define JSON_ALLOW_NUL 0x10 + +typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + +json_t *json_loads(const char *input, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_loadfd(int input, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) + JANSSON_ATTRS((warn_unused_result)); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, + json_error_t *error) JANSSON_ATTRS((warn_unused_result)); + +/* encoding */ + +#define JSON_MAX_INDENT 0x1F +#define JSON_INDENT(n) ((n)&JSON_MAX_INDENT) +#define JSON_COMPACT 0x20 +#define JSON_ENSURE_ASCII 0x40 +#define JSON_SORT_KEYS 0x80 +#define JSON_PRESERVE_ORDER 0x100 +#define JSON_ENCODE_ANY 0x200 +#define JSON_ESCAPE_SLASH 0x400 +#define JSON_REAL_PRECISION(n) (((n)&0x1F) << 11) +#define JSON_EMBED 0x10000 + +typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + +char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS((warn_unused_result)); +size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags); +int json_dumpf(const json_t *json, FILE *output, size_t flags); +int json_dumpfd(const json_t *json, int output, size_t flags); +int json_dump_file(const json_t *json, const char *path, size_t flags); +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, + size_t flags); + +/* custom memory allocation */ + +typedef void *(*json_malloc_t)(size_t); +typedef void (*json_free_t)(void *); + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); +void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn); + +/* runtime version checking */ + +const char *jansson_version_str(void); +int jansson_version_cmp(int major, int minor, int micro); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/src/jansson_config.h.in b/src/fluent-bit/lib/jansson-e23f558/src/jansson_config.h.in new file mode 100644 index 000000000..fe692ab4f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/jansson_config.h.in @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @json_inline@ +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@ + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @json_have_localeconv@ + +/* If __atomic builtins are available they will be used to manage + reference counts of json_t. */ +#define JSON_HAVE_ATOMIC_BUILTINS @json_have_atomic_builtins@ + +/* If __atomic builtins are not available we try using __sync builtins + to manage reference counts of json_t. */ +#define JSON_HAVE_SYNC_BUILTINS @json_have_sync_builtins@ + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/src/jansson_private.h b/src/fluent-bit/lib/jansson-e23f558/src/jansson_private.h new file mode 100644 index 000000000..ea2593cde --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/jansson_private.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_PRIVATE_H +#define JANSSON_PRIVATE_H + +#include "hashtable.h" +#include "jansson.h" +#include "jansson_private_config.h" +#include "strbuffer.h" +#include <stddef.h> + +#define container_of(ptr_, type_, member_) \ + ((type_ *)((char *)ptr_ - offsetof(type_, member_))) + +/* On some platforms, max() may already be defined */ +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* va_copy is a C99 feature. In C89 implementations, it's sometimes + available as __va_copy. If not, memcpy() should do the trick. */ +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list)) +#endif +#endif + +typedef struct { + json_t json; + hashtable_t hashtable; +} json_object_t; + +typedef struct { + json_t json; + size_t size; + size_t entries; + json_t **table; +} json_array_t; + +typedef struct { + json_t json; + char *value; + size_t length; +} json_string_t; + +typedef struct { + json_t json; + double value; +} json_real_t; + +typedef struct { + json_t json; + json_int_t value; +} json_integer_t; + +#define json_to_object(json_) container_of(json_, json_object_t, json) +#define json_to_array(json_) container_of(json_, json_array_t, json) +#define json_to_string(json_) container_of(json_, json_string_t, json) +#define json_to_real(json_) container_of(json_, json_real_t, json) +#define json_to_integer(json_) container_of(json_, json_integer_t, json) + +/* Create a string by taking ownership of an existing buffer */ +json_t *jsonp_stringn_nocheck_own(const char *value, size_t len); + +/* Error message formatting */ +void jsonp_error_init(json_error_t *error, const char *source); +void jsonp_error_set_source(json_error_t *error, const char *source); +void jsonp_error_set(json_error_t *error, int line, int column, size_t position, + enum json_error_code code, const char *msg, ...); +void jsonp_error_vset(json_error_t *error, int line, int column, size_t position, + enum json_error_code code, const char *msg, va_list ap); + +/* Locale independent string<->double conversions */ +int jsonp_strtod(strbuffer_t *strbuffer, double *out); +int jsonp_dtostr(char *buffer, size_t size, double value, int prec); + +/* Wrappers for custom memory functions */ +void *jsonp_malloc(size_t size) JANSSON_ATTRS((warn_unused_result)); +void jsonp_free(void *ptr); +char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS((warn_unused_result)); +char *jsonp_strdup(const char *str) JANSSON_ATTRS((warn_unused_result)); +char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS((warn_unused_result)); + +/* Circular reference check*/ +/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ +#define LOOP_KEY_LEN (2 + (sizeof(json_t *) * 2) + 1) +int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size, + size_t *key_len_out); + +/* Windows compatibility */ +#if defined(_WIN32) || defined(WIN32) +#if defined(_MSC_VER) /* MS compiller */ +#if (_MSC_VER < 1900) && \ + !defined(snprintf) /* snprintf not defined yet & not introduced */ +#define snprintf _snprintf +#endif +#if (_MSC_VER < 1500) && \ + !defined(vsnprintf) /* vsnprintf not defined yet & not introduced */ +#define vsnprintf(b, c, f, a) _vsnprintf(b, c, f, a) +#endif +#else /* Other Windows compiller, old definition */ +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif +#endif + +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/src/load.c b/src/fluent-bit/lib/jansson-e23f558/src/load.c new file mode 100644 index 000000000..8ae7abd12 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/load.c @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "jansson_private.h" + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "jansson.h" +#include "strbuffer.h" +#include "utf.h" + +#define STREAM_STATE_OK 0 +#define STREAM_STATE_EOF -1 +#define STREAM_STATE_ERROR -2 + +#define TOKEN_INVALID -1 +#define TOKEN_EOF 0 +#define TOKEN_STRING 256 +#define TOKEN_INTEGER 257 +#define TOKEN_REAL 258 +#define TOKEN_TRUE 259 +#define TOKEN_FALSE 260 +#define TOKEN_NULL 261 + +/* Locale independent versions of isxxx() functions */ +#define l_isupper(c) ('A' <= (c) && (c) <= 'Z') +#define l_islower(c) ('a' <= (c) && (c) <= 'z') +#define l_isalpha(c) (l_isupper(c) || l_islower(c)) +#define l_isdigit(c) ('0' <= (c) && (c) <= '9') +#define l_isxdigit(c) \ + (l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f')) + +/* Read one byte from stream, convert to unsigned char, then int, and + return. return EOF on end of file. This corresponds to the + behaviour of fgetc(). */ +typedef int (*get_func)(void *data); + +typedef struct { + get_func get; + void *data; + char buffer[5]; + size_t buffer_pos; + int state; + int line; + int column, last_column; + size_t position; +} stream_t; + +typedef struct { + stream_t stream; + strbuffer_t saved_text; + size_t flags; + size_t depth; + int token; + union { + struct { + char *val; + size_t len; + } string; + json_int_t integer; + double real; + } value; +} lex_t; + +#define stream_to_lex(stream) container_of(stream, lex_t, stream) + +/*** error reporting ***/ + +static void error_set(json_error_t *error, const lex_t *lex, enum json_error_code code, + const char *msg, ...) { + va_list ap; + char msg_text[JSON_ERROR_TEXT_LENGTH]; + char msg_with_context[JSON_ERROR_TEXT_LENGTH]; + + int line = -1, col = -1; + size_t pos = 0; + const char *result = msg_text; + + if (!error) + return; + + va_start(ap, msg); + vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap); + msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + va_end(ap); + + if (lex) { + const char *saved_text = strbuffer_value(&lex->saved_text); + + line = lex->stream.line; + col = lex->stream.column; + pos = lex->stream.position; + + if (saved_text && saved_text[0]) { + if (lex->saved_text.length <= 20) { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, "%s near '%s'", + msg_text, saved_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } else { + if (code == json_error_invalid_syntax) { + /* More specific error code for premature end of file. */ + code = json_error_premature_end_of_input; + } + if (lex->stream.state == STREAM_STATE_ERROR) { + /* No context for UTF-8 decoding errors */ + result = msg_text; + } else { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, "%s near end of file", + msg_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } + } + + jsonp_error_set(error, line, col, pos, code, "%s", result); +} + +/*** lexical analyzer ***/ + +static void stream_init(stream_t *stream, get_func get, void *data) { + stream->get = get; + stream->data = data; + stream->buffer[0] = '\0'; + stream->buffer_pos = 0; + + stream->state = STREAM_STATE_OK; + stream->line = 1; + stream->column = 0; + stream->position = 0; +} + +static int stream_get(stream_t *stream, json_error_t *error) { + int c; + + if (stream->state != STREAM_STATE_OK) + return stream->state; + + if (!stream->buffer[stream->buffer_pos]) { + c = stream->get(stream->data); + if (c == EOF) { + stream->state = STREAM_STATE_EOF; + return STREAM_STATE_EOF; + } + + stream->buffer[0] = c; + stream->buffer_pos = 0; + + if (0x80 <= c && c <= 0xFF) { + /* multi-byte UTF-8 sequence */ + size_t i, count; + + count = utf8_check_first(c); + if (!count) + goto out; + + assert(count >= 2); + + for (i = 1; i < count; i++) + stream->buffer[i] = stream->get(stream->data); + + if (!utf8_check_full(stream->buffer, count, NULL)) + goto out; + + stream->buffer[count] = '\0'; + } else + stream->buffer[1] = '\0'; + } + + c = stream->buffer[stream->buffer_pos++]; + + stream->position++; + if (c == '\n') { + stream->line++; + stream->last_column = stream->column; + stream->column = 0; + } else if (utf8_check_first(c)) { + /* track the Unicode character column, so increment only if + this is the first character of a UTF-8 sequence */ + stream->column++; + } + + return c; + +out: + stream->state = STREAM_STATE_ERROR; + error_set(error, stream_to_lex(stream), json_error_invalid_utf8, + "unable to decode byte 0x%x", c); + return STREAM_STATE_ERROR; +} + +static void stream_unget(stream_t *stream, int c) { + if (c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR) + return; + + stream->position--; + if (c == '\n') { + stream->line--; + stream->column = stream->last_column; + } else if (utf8_check_first(c)) + stream->column--; + + assert(stream->buffer_pos > 0); + stream->buffer_pos--; + assert(stream->buffer[stream->buffer_pos] == c); +} + +static int lex_get(lex_t *lex, json_error_t *error) { + return stream_get(&lex->stream, error); +} + +static void lex_save(lex_t *lex, int c) { strbuffer_append_byte(&lex->saved_text, c); } + +static int lex_get_save(lex_t *lex, json_error_t *error) { + int c = stream_get(&lex->stream, error); + if (c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) + lex_save(lex, c); + return c; +} + +static void lex_unget(lex_t *lex, int c) { stream_unget(&lex->stream, c); } + +static void lex_unget_unsave(lex_t *lex, int c) { + if (c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) { +/* Since we treat warnings as errors, when assertions are turned + * off the "d" variable would be set but never used. Which is + * treated as an error by GCC. + */ +#ifndef NDEBUG + char d; +#endif + stream_unget(&lex->stream, c); +#ifndef NDEBUG + d = +#endif + strbuffer_pop(&lex->saved_text); + assert(c == d); + } +} + +static void lex_save_cached(lex_t *lex) { + while (lex->stream.buffer[lex->stream.buffer_pos] != '\0') { + lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]); + lex->stream.buffer_pos++; + lex->stream.position++; + } +} + +static void lex_free_string(lex_t *lex) { + jsonp_free(lex->value.string.val); + lex->value.string.val = NULL; + lex->value.string.len = 0; +} + +/* assumes that str points to 'u' plus at least 4 valid hex digits */ +static int32_t decode_unicode_escape(const char *str) { + int i; + int32_t value = 0; + + assert(str[0] == 'u'); + + for (i = 1; i <= 4; i++) { + char c = str[i]; + value <<= 4; + if (l_isdigit(c)) + value += c - '0'; + else if (l_islower(c)) + value += c - 'a' + 10; + else if (l_isupper(c)) + value += c - 'A' + 10; + else + return -1; + } + + return value; +} + +static void lex_scan_string(lex_t *lex, json_error_t *error) { + int c; + const char *p; + char *t; + int i; + + lex->value.string.val = NULL; + lex->token = TOKEN_INVALID; + + c = lex_get_save(lex, error); + + while (c != '"') { + if (c == STREAM_STATE_ERROR) + goto out; + + else if (c == STREAM_STATE_EOF) { + error_set(error, lex, json_error_premature_end_of_input, + "premature end of input"); + goto out; + } + + else if (0 <= c && c <= 0x1F) { + /* control character */ + lex_unget_unsave(lex, c); + if (c == '\n') + error_set(error, lex, json_error_invalid_syntax, "unexpected newline"); + else + error_set(error, lex, json_error_invalid_syntax, "control character 0x%x", + c); + goto out; + } + + else if (c == '\\') { + c = lex_get_save(lex, error); + if (c == 'u') { + c = lex_get_save(lex, error); + for (i = 0; i < 4; i++) { + if (!l_isxdigit(c)) { + error_set(error, lex, json_error_invalid_syntax, + "invalid escape"); + goto out; + } + c = lex_get_save(lex, error); + } + } else if (c == '"' || c == '\\' || c == '/' || c == 'b' || c == 'f' || + c == 'n' || c == 'r' || c == 't') + c = lex_get_save(lex, error); + else { + error_set(error, lex, json_error_invalid_syntax, "invalid escape"); + goto out; + } + } else + c = lex_get_save(lex, error); + } + + /* the actual value is at most of the same length as the source + string, because: + - shortcut escapes (e.g. "\t") (length 2) are converted to 1 byte + - a single \uXXXX escape (length 6) is converted to at most 3 bytes + - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair + are converted to 4 bytes + */ + t = jsonp_malloc(lex->saved_text.length + 1); + if (!t) { + /* this is not very nice, since TOKEN_INVALID is returned */ + goto out; + } + lex->value.string.val = t; + + /* + 1 to skip the " */ + p = strbuffer_value(&lex->saved_text) + 1; + + while (*p != '"') { + if (*p == '\\') { + p++; + if (*p == 'u') { + size_t length; + int32_t value; + + value = decode_unicode_escape(p); + if (value < 0) { + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode escape '%.6s'", p - 1); + goto out; + } + p += 5; + + if (0xD800 <= value && value <= 0xDBFF) { + /* surrogate pair */ + if (*p == '\\' && *(p + 1) == 'u') { + int32_t value2 = decode_unicode_escape(++p); + if (value2 < 0) { + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode escape '%.6s'", p - 1); + goto out; + } + p += 5; + + if (0xDC00 <= value2 && value2 <= 0xDFFF) { + /* valid second surrogate */ + value = + ((value - 0xD800) << 10) + (value2 - 0xDC00) + 0x10000; + } else { + /* invalid second surrogate */ + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode '\\u%04X\\u%04X'", value, value2); + goto out; + } + } else { + /* no second surrogate */ + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode '\\u%04X'", value); + goto out; + } + } else if (0xDC00 <= value && value <= 0xDFFF) { + error_set(error, lex, json_error_invalid_syntax, + "invalid Unicode '\\u%04X'", value); + goto out; + } + + if (utf8_encode(value, t, &length)) + assert(0); + t += length; + } else { + switch (*p) { + case '"': + case '\\': + case '/': + *t = *p; + break; + case 'b': + *t = '\b'; + break; + case 'f': + *t = '\f'; + break; + case 'n': + *t = '\n'; + break; + case 'r': + *t = '\r'; + break; + case 't': + *t = '\t'; + break; + default: + assert(0); + } + t++; + p++; + } + } else + *(t++) = *(p++); + } + *t = '\0'; + lex->value.string.len = t - lex->value.string.val; + lex->token = TOKEN_STRING; + return; + +out: + lex_free_string(lex); +} + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _MSC_VER /* Microsoft Visual Studio */ +#define json_strtoint _strtoi64 +#else +#define json_strtoint strtoll +#endif +#else +#define json_strtoint strtol +#endif +#endif + +static int lex_scan_number(lex_t *lex, int c, json_error_t *error) { + const char *saved_text; + char *end; + double doubleval; + + lex->token = TOKEN_INVALID; + + if (c == '-') + c = lex_get_save(lex, error); + + if (c == '0') { + c = lex_get_save(lex, error); + if (l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + } else if (l_isdigit(c)) { + do + c = lex_get_save(lex, error); + while (l_isdigit(c)); + } else { + lex_unget_unsave(lex, c); + goto out; + } + + if (!(lex->flags & JSON_DECODE_INT_AS_REAL) && c != '.' && c != 'E' && c != 'e') { + json_int_t intval; + + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + errno = 0; + intval = json_strtoint(saved_text, &end, 10); + if (errno == ERANGE) { + if (intval < 0) + error_set(error, lex, json_error_numeric_overflow, + "too big negative integer"); + else + error_set(error, lex, json_error_numeric_overflow, "too big integer"); + goto out; + } + + assert(end == saved_text + lex->saved_text.length); + + lex->token = TOKEN_INTEGER; + lex->value.integer = intval; + return 0; + } + + if (c == '.') { + c = lex_get(lex, error); + if (!l_isdigit(c)) { + lex_unget(lex, c); + goto out; + } + lex_save(lex, c); + + do + c = lex_get_save(lex, error); + while (l_isdigit(c)); + } + + if (c == 'E' || c == 'e') { + c = lex_get_save(lex, error); + if (c == '+' || c == '-') + c = lex_get_save(lex, error); + + if (!l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + + do + c = lex_get_save(lex, error); + while (l_isdigit(c)); + } + + lex_unget_unsave(lex, c); + + if (jsonp_strtod(&lex->saved_text, &doubleval)) { + error_set(error, lex, json_error_numeric_overflow, "real number overflow"); + goto out; + } + + lex->token = TOKEN_REAL; + lex->value.real = doubleval; + return 0; + +out: + return -1; +} + +static int lex_scan(lex_t *lex, json_error_t *error) { + int c; + + strbuffer_clear(&lex->saved_text); + + if (lex->token == TOKEN_STRING) + lex_free_string(lex); + + do + c = lex_get(lex, error); + while (c == ' ' || c == '\t' || c == '\n' || c == '\r'); + + if (c == STREAM_STATE_EOF) { + lex->token = TOKEN_EOF; + goto out; + } + + if (c == STREAM_STATE_ERROR) { + lex->token = TOKEN_INVALID; + goto out; + } + + lex_save(lex, c); + + if (c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',') + lex->token = c; + + else if (c == '"') + lex_scan_string(lex, error); + + else if (l_isdigit(c) || c == '-') { + if (lex_scan_number(lex, c, error)) + goto out; + } + + else if (l_isalpha(c)) { + /* eat up the whole identifier for clearer error messages */ + const char *saved_text; + + do + c = lex_get_save(lex, error); + while (l_isalpha(c)); + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + if (strcmp(saved_text, "true") == 0) + lex->token = TOKEN_TRUE; + else if (strcmp(saved_text, "false") == 0) + lex->token = TOKEN_FALSE; + else if (strcmp(saved_text, "null") == 0) + lex->token = TOKEN_NULL; + else + lex->token = TOKEN_INVALID; + } + + else { + /* save the rest of the input UTF-8 sequence to get an error + message of valid UTF-8 */ + lex_save_cached(lex); + lex->token = TOKEN_INVALID; + } + +out: + return lex->token; +} + +static char *lex_steal_string(lex_t *lex, size_t *out_len) { + char *result = NULL; + if (lex->token == TOKEN_STRING) { + result = lex->value.string.val; + *out_len = lex->value.string.len; + lex->value.string.val = NULL; + lex->value.string.len = 0; + } + return result; +} + +static int lex_init(lex_t *lex, get_func get, size_t flags, void *data) { + stream_init(&lex->stream, get, data); + if (strbuffer_init(&lex->saved_text)) + return -1; + + lex->flags = flags; + lex->token = TOKEN_INVALID; + return 0; +} + +static void lex_close(lex_t *lex) { + if (lex->token == TOKEN_STRING) + lex_free_string(lex); + strbuffer_close(&lex->saved_text); +} + +/*** parser ***/ + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error); + +static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) { + json_t *object = json_object(); + if (!object) + return NULL; + + lex_scan(lex, error); + if (lex->token == '}') + return object; + + while (1) { + char *key; + size_t len; + json_t *value; + + if (lex->token != TOKEN_STRING) { + error_set(error, lex, json_error_invalid_syntax, "string or '}' expected"); + goto error; + } + + key = lex_steal_string(lex, &len); + if (!key) + return NULL; + if (memchr(key, '\0', len)) { + jsonp_free(key); + error_set(error, lex, json_error_null_byte_in_key, + "NUL byte in object key not supported"); + goto error; + } + + if (flags & JSON_REJECT_DUPLICATES) { + if (json_object_getn(object, key, len)) { + jsonp_free(key); + error_set(error, lex, json_error_duplicate_key, "duplicate object key"); + goto error; + } + } + + lex_scan(lex, error); + if (lex->token != ':') { + jsonp_free(key); + error_set(error, lex, json_error_invalid_syntax, "':' expected"); + goto error; + } + + lex_scan(lex, error); + value = parse_value(lex, flags, error); + if (!value) { + jsonp_free(key); + goto error; + } + + if (json_object_setn_new_nocheck(object, key, len, value)) { + jsonp_free(key); + goto error; + } + + jsonp_free(key); + + lex_scan(lex, error); + if (lex->token != ',') + break; + + lex_scan(lex, error); + } + + if (lex->token != '}') { + error_set(error, lex, json_error_invalid_syntax, "'}' expected"); + goto error; + } + + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) { + json_t *array = json_array(); + if (!array) + return NULL; + + lex_scan(lex, error); + if (lex->token == ']') + return array; + + while (lex->token) { + json_t *elem = parse_value(lex, flags, error); + if (!elem) + goto error; + + if (json_array_append_new(array, elem)) { + goto error; + } + + lex_scan(lex, error); + if (lex->token != ',') + break; + + lex_scan(lex, error); + } + + if (lex->token != ']') { + error_set(error, lex, json_error_invalid_syntax, "']' expected"); + goto error; + } + + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) { + json_t *json; + + lex->depth++; + if (lex->depth > JSON_PARSER_MAX_DEPTH) { + error_set(error, lex, json_error_stack_overflow, "maximum parsing depth reached"); + return NULL; + } + + switch (lex->token) { + case TOKEN_STRING: { + const char *value = lex->value.string.val; + size_t len = lex->value.string.len; + + if (!(flags & JSON_ALLOW_NUL)) { + if (memchr(value, '\0', len)) { + error_set(error, lex, json_error_null_character, + "\\u0000 is not allowed without JSON_ALLOW_NUL"); + return NULL; + } + } + + json = jsonp_stringn_nocheck_own(value, len); + lex->value.string.val = NULL; + lex->value.string.len = 0; + break; + } + + case TOKEN_INTEGER: { + json = json_integer(lex->value.integer); + break; + } + + case TOKEN_REAL: { + json = json_real(lex->value.real); + break; + } + + case TOKEN_TRUE: + json = json_true(); + break; + + case TOKEN_FALSE: + json = json_false(); + break; + + case TOKEN_NULL: + json = json_null(); + break; + + case '{': + json = parse_object(lex, flags, error); + break; + + case '[': + json = parse_array(lex, flags, error); + break; + + case TOKEN_INVALID: + error_set(error, lex, json_error_invalid_syntax, "invalid token"); + return NULL; + + default: + error_set(error, lex, json_error_invalid_syntax, "unexpected token"); + return NULL; + } + + if (!json) + return NULL; + + lex->depth--; + return json; +} + +static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) { + json_t *result; + + lex->depth = 0; + + lex_scan(lex, error); + if (!(flags & JSON_DECODE_ANY)) { + if (lex->token != '[' && lex->token != '{') { + error_set(error, lex, json_error_invalid_syntax, "'[' or '{' expected"); + return NULL; + } + } + + result = parse_value(lex, flags, error); + if (!result) + return NULL; + + if (!(flags & JSON_DISABLE_EOF_CHECK)) { + lex_scan(lex, error); + if (lex->token != TOKEN_EOF) { + error_set(error, lex, json_error_end_of_input_expected, + "end of file expected"); + json_decref(result); + return NULL; + } + } + + if (error) { + /* Save the position even though there was no error */ + error->position = (int)lex->stream.position; + } + + return result; +} + +typedef struct { + const char *data; + size_t pos; +} string_data_t; + +static int string_get(void *data) { + char c; + string_data_t *stream = (string_data_t *)data; + c = stream->data[stream->pos]; + if (c == '\0') + return EOF; + else { + stream->pos++; + return (unsigned char)c; + } +} + +json_t *json_loads(const char *string, size_t flags, json_error_t *error) { + lex_t lex; + json_t *result; + string_data_t stream_data; + + jsonp_error_init(error, "<string>"); + + if (string == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + stream_data.data = string; + stream_data.pos = 0; + + if (lex_init(&lex, string_get, flags, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +typedef struct { + const char *data; + size_t len; + size_t pos; +} buffer_data_t; + +static int buffer_get(void *data) { + char c; + buffer_data_t *stream = data; + if (stream->pos >= stream->len) + return EOF; + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) { + lex_t lex; + json_t *result; + buffer_data_t stream_data; + + jsonp_error_init(error, "<buffer>"); + + if (buffer == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + stream_data.data = buffer; + stream_data.pos = 0; + stream_data.len = buflen; + + if (lex_init(&lex, buffer_get, flags, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) { + lex_t lex; + const char *source; + json_t *result; + + if (input == stdin) + source = "<stdin>"; + else + source = "<stream>"; + + jsonp_error_init(error, source); + + if (input == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if (lex_init(&lex, (get_func)fgetc, flags, input)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +static int fd_get_func(int *fd) { +#ifdef HAVE_UNISTD_H + uint8_t c; + if (read(*fd, &c, 1) == 1) + return c; +#endif + return EOF; +} + +json_t *json_loadfd(int input, size_t flags, json_error_t *error) { + lex_t lex; + const char *source; + json_t *result; + +#ifdef HAVE_UNISTD_H + if (input == STDIN_FILENO) + source = "<stdin>"; + else +#endif + source = "<stream>"; + + jsonp_error_init(error, source); + + if (input < 0) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if (lex_init(&lex, (get_func)fd_get_func, flags, &input)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) { + json_t *result; + FILE *fp; + + jsonp_error_init(error, path); + + if (path == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + fp = fopen(path, "rb"); + if (!fp) { + error_set(error, NULL, json_error_cannot_open_file, "unable to open %s: %s", path, + strerror(errno)); + return NULL; + } + + result = json_loadf(fp, flags, error); + + fclose(fp); + return result; +} + +#define MAX_BUF_LEN 1024 + +typedef struct { + char data[MAX_BUF_LEN]; + size_t len; + size_t pos; + json_load_callback_t callback; + void *arg; +} callback_data_t; + +static int callback_get(void *data) { + char c; + callback_data_t *stream = data; + + if (stream->pos >= stream->len) { + stream->pos = 0; + stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg); + if (stream->len == 0 || stream->len == (size_t)-1) + return EOF; + } + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, + json_error_t *error) { + lex_t lex; + json_t *result; + + callback_data_t stream_data; + + memset(&stream_data, 0, sizeof(stream_data)); + stream_data.callback = callback; + stream_data.arg = arg; + + jsonp_error_init(error, "<callback>"); + + if (callback == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if (lex_init(&lex, (get_func)callback_get, flags, &stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/lookup3.h b/src/fluent-bit/lib/jansson-e23f558/src/lookup3.h new file mode 100644 index 000000000..9b39aa1ce --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/lookup3.h @@ -0,0 +1,382 @@ +// clang-format off +/* +------------------------------------------------------------------------------- +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. +------------------------------------------------------------------------------- +*/ + +#include <stdlib.h> + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#ifdef HAVE_STDINT_H +#include <stdint.h> /* defines uint32_t etc */ +#endif + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> /* attempt to define endianness */ +#endif + +#ifdef HAVE_ENDIAN_H +# include <endian.h> /* attempt to define endianness */ +#endif + +/* + * 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) ((size_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<n; ++i) h = hashlittle( k[i], len[i], h); + +By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial. It's free. + +Use for hash table lookup, or anything where one collision in 2^^32 is +acceptable. Do NOT use for cryptographic purposes. +------------------------------------------------------------------------------- +*/ + +static uint32_t hashlittle(const void *key, size_t length, uint32_t initval) +{ + uint32_t a,b,c; /* internal state */ + union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + +/* Detect Valgrind or AddressSanitizer */ +#ifdef VALGRIND +# define NO_MASKING_TRICK 1 +#else +# if defined(__has_feature) /* Clang */ +# if __has_feature(address_sanitizer) /* is ASAN enabled? */ +# define NO_MASKING_TRICK 1 +# endif +# else +# if defined(__SANITIZE_ADDRESS__) /* GCC 4.8.x, is ASAN enabled? */ +# define NO_MASKING_TRICK 1 +# endif +# endif +#endif + +#ifdef NO_MASKING_TRICK + const uint8_t *k8; +#endif + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 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 + * noticeably faster for short strings (like English words). + */ +#ifndef NO_MASKING_TRICK + + 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 */ + + 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; /* fall through */ + case 11: c+=((uint32_t)k[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k[9])<<8; /* fall through */ + case 9 : c+=k[8]; /* fall through */ + case 8 : b+=((uint32_t)k[7])<<24; /* fall through */ + case 7 : b+=((uint32_t)k[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k[5])<<8; /* fall through */ + case 5 : b+=k[4]; /* fall through */ + case 4 : a+=((uint32_t)k[3])<<24; /* fall through */ + case 3 : a+=((uint32_t)k[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k[1])<<8; /* fall through */ + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/memory.c b/src/fluent-bit/lib/jansson-e23f558/src/memory.c new file mode 100644 index 000000000..2733035af --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/memory.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net> + * + * Jansson is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include <stdlib.h> +#include <string.h> + +#include "jansson.h" +#include "jansson_private.h" + +/* C89 allows these to be macros */ +#undef malloc +#undef free + +/* memory function pointers */ +static json_malloc_t do_malloc = malloc; +static json_free_t do_free = free; + +void *jsonp_malloc(size_t size) { + if (!size) + return NULL; + + return (*do_malloc)(size); +} + +void jsonp_free(void *ptr) { + if (!ptr) + return; + + (*do_free)(ptr); +} + +char *jsonp_strdup(const char *str) { return jsonp_strndup(str, strlen(str)); } + +char *jsonp_strndup(const char *str, size_t len) { + char *new_str; + + new_str = jsonp_malloc(len + 1); + if (!new_str) + return NULL; + + memcpy(new_str, str, len); + new_str[len] = '\0'; + return new_str; +} + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) { + do_malloc = malloc_fn; + do_free = free_fn; +} + +void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn) { + if (malloc_fn) + *malloc_fn = do_malloc; + if (free_fn) + *free_fn = do_free; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/pack_unpack.c b/src/fluent-bit/lib/jansson-e23f558/src/pack_unpack.c new file mode 100644 index 000000000..a796ed4fe --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/pack_unpack.c @@ -0,0 +1,936 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "jansson.h" +#include "jansson_private.h" +#include "utf.h" +#include <string.h> + +typedef struct { + int line; + int column; + size_t pos; + char token; +} token_t; + +typedef struct { + const char *start; + const char *fmt; + token_t prev_token; + token_t token; + token_t next_token; + json_error_t *error; + size_t flags; + int line; + int column; + size_t pos; + int has_error; +} scanner_t; + +#define token(scanner) ((scanner)->token.token) + +static const char *const type_names[] = {"object", "array", "string", "integer", + "real", "true", "false", "null"}; + +#define type_name(x) type_names[json_typeof(x)] + +static const char unpack_value_starters[] = "{[siIbfFOon"; + +static void scanner_init(scanner_t *s, json_error_t *error, size_t flags, + const char *fmt) { + s->error = error; + s->flags = flags; + s->fmt = s->start = fmt; + memset(&s->prev_token, 0, sizeof(token_t)); + memset(&s->token, 0, sizeof(token_t)); + memset(&s->next_token, 0, sizeof(token_t)); + s->line = 1; + s->column = 0; + s->pos = 0; + s->has_error = 0; +} + +static void next_token(scanner_t *s) { + const char *t; + s->prev_token = s->token; + + if (s->next_token.line) { + s->token = s->next_token; + s->next_token.line = 0; + return; + } + + if (!token(s) && !*s->fmt) + return; + + t = s->fmt; + s->column++; + s->pos++; + + /* skip space and ignored chars */ + while (*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') { + if (*t == '\n') { + s->line++; + s->column = 1; + } else + s->column++; + + s->pos++; + t++; + } + + s->token.token = *t; + s->token.line = s->line; + s->token.column = s->column; + s->token.pos = s->pos; + + if (*t) + t++; + s->fmt = t; +} + +static void prev_token(scanner_t *s) { + s->next_token = s->token; + s->token = s->prev_token; +} + +static void set_error(scanner_t *s, const char *source, enum json_error_code code, + const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + + jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, code, fmt, + ap); + + jsonp_error_set_source(s->error, source); + + va_end(ap); +} + +static json_t *pack(scanner_t *s, va_list *ap); + +/* ours will be set to 1 if jsonp_free() must be called for the result + afterwards */ +static char *read_string(scanner_t *s, va_list *ap, const char *purpose, size_t *out_len, + int *ours, int optional) { + char t; + strbuffer_t strbuff; + const char *str; + size_t length; + + next_token(s); + t = token(s); + prev_token(s); + + *ours = 0; + if (t != '#' && t != '%' && t != '+') { + /* Optimize the simple case */ + str = va_arg(*ap, const char *); + + if (!str) { + if (!optional) { + set_error(s, "<args>", json_error_null_value, "NULL %s", purpose); + s->has_error = 1; + } + return NULL; + } + + length = strlen(str); + + if (!utf8_check_string(str, length)) { + set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose); + s->has_error = 1; + return NULL; + } + + *out_len = length; + return (char *)str; + } else if (optional) { + set_error(s, "<format>", json_error_invalid_format, + "Cannot use '%c' on optional strings", t); + s->has_error = 1; + + return NULL; + } + + if (strbuffer_init(&strbuff)) { + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + while (1) { + str = va_arg(*ap, const char *); + if (!str) { + set_error(s, "<args>", json_error_null_value, "NULL %s", purpose); + s->has_error = 1; + } + + next_token(s); + + if (token(s) == '#') { + length = va_arg(*ap, int); + } else if (token(s) == '%') { + length = va_arg(*ap, size_t); + } else { + prev_token(s); + length = s->has_error ? 0 : strlen(str); + } + + if (!s->has_error && strbuffer_append_bytes(&strbuff, str, length) == -1) { + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + next_token(s); + if (token(s) != '+') { + prev_token(s); + break; + } + } + + if (s->has_error) { + strbuffer_close(&strbuff); + return NULL; + } + + if (!utf8_check_string(strbuff.value, strbuff.length)) { + set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose); + strbuffer_close(&strbuff); + s->has_error = 1; + return NULL; + } + + *out_len = strbuff.length; + *ours = 1; + return strbuffer_steal_value(&strbuff); +} + +static json_t *pack_object(scanner_t *s, va_list *ap) { + json_t *object = json_object(); + next_token(s); + + while (token(s) != '}') { + char *key; + size_t len; + int ours; + json_t *value; + char valueOptional; + + if (!token(s)) { + set_error(s, "<format>", json_error_invalid_format, + "Unexpected end of format string"); + goto error; + } + + if (token(s) != 's') { + set_error(s, "<format>", json_error_invalid_format, + "Expected format 's', got '%c'", token(s)); + goto error; + } + + key = read_string(s, ap, "object key", &len, &ours, 0); + + next_token(s); + + next_token(s); + valueOptional = token(s); + prev_token(s); + + value = pack(s, ap); + if (!value) { + if (ours) + jsonp_free(key); + + if (valueOptional != '*') { + set_error(s, "<args>", json_error_null_value, "NULL object value"); + s->has_error = 1; + } + + next_token(s); + continue; + } + + if (s->has_error) + json_decref(value); + + if (!s->has_error && json_object_set_new_nocheck(object, key, value)) { + set_error(s, "<internal>", json_error_out_of_memory, + "Unable to add key \"%s\"", key); + s->has_error = 1; + } + + if (ours) + jsonp_free(key); + + next_token(s); + } + + if (!s->has_error) + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *pack_array(scanner_t *s, va_list *ap) { + json_t *array = json_array(); + next_token(s); + + while (token(s) != ']') { + json_t *value; + char valueOptional; + + if (!token(s)) { + set_error(s, "<format>", json_error_invalid_format, + "Unexpected end of format string"); + /* Format string errors are unrecoverable. */ + goto error; + } + + next_token(s); + valueOptional = token(s); + prev_token(s); + + value = pack(s, ap); + if (!value) { + if (valueOptional != '*') { + s->has_error = 1; + } + + next_token(s); + continue; + } + + if (s->has_error) + json_decref(value); + + if (!s->has_error && json_array_append_new(array, value)) { + set_error(s, "<internal>", json_error_out_of_memory, + "Unable to append to array"); + s->has_error = 1; + } + + next_token(s); + } + + if (!s->has_error) + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *pack_string(scanner_t *s, va_list *ap) { + char *str; + char t; + size_t len; + int ours; + int optional; + + next_token(s); + t = token(s); + optional = t == '?' || t == '*'; + if (!optional) + prev_token(s); + + str = read_string(s, ap, "string", &len, &ours, optional); + + if (!str) + return t == '?' && !s->has_error ? json_null() : NULL; + + if (s->has_error) { + /* It's impossible to reach this point if ours != 0, do not free str. */ + return NULL; + } + + if (ours) + return jsonp_stringn_nocheck_own(str, len); + + return json_stringn_nocheck(str, len); +} + +static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref) { + json_t *json; + char ntoken; + + next_token(s); + ntoken = token(s); + + if (ntoken != '?' && ntoken != '*') + prev_token(s); + + json = va_arg(*ap, json_t *); + + if (json) + return need_incref ? json_incref(json) : json; + + switch (ntoken) { + case '?': + return json_null(); + case '*': + return NULL; + default: + break; + } + + set_error(s, "<args>", json_error_null_value, "NULL object"); + s->has_error = 1; + return NULL; +} + +static json_t *pack_integer(scanner_t *s, json_int_t value) { + json_t *json = json_integer(value); + + if (!json) { + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + return json; +} + +static json_t *pack_real(scanner_t *s, double value) { + /* Allocate without setting value so we can identify OOM error. */ + json_t *json = json_real(0.0); + + if (!json) { + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + + return NULL; + } + + if (json_real_set(json, value)) { + json_decref(json); + + set_error(s, "<args>", json_error_numeric_overflow, + "Invalid floating point value"); + s->has_error = 1; + + return NULL; + } + + return json; +} + +static json_t *pack(scanner_t *s, va_list *ap) { + switch (token(s)) { + case '{': + return pack_object(s, ap); + + case '[': + return pack_array(s, ap); + + case 's': /* string */ + return pack_string(s, ap); + + case 'n': /* null */ + return json_null(); + + case 'b': /* boolean */ + return va_arg(*ap, int) ? json_true() : json_false(); + + case 'i': /* integer from int */ + return pack_integer(s, va_arg(*ap, int)); + + case 'I': /* integer from json_int_t */ + return pack_integer(s, va_arg(*ap, json_int_t)); + + case 'f': /* real */ + return pack_real(s, va_arg(*ap, double)); + + case 'O': /* a json_t object; increments refcount */ + return pack_object_inter(s, ap, 1); + + case 'o': /* a json_t object; doesn't increment refcount */ + return pack_object_inter(s, ap, 0); + + default: + set_error(s, "<format>", json_error_invalid_format, + "Unexpected format character '%c'", token(s)); + s->has_error = 1; + return NULL; + } +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap); + +static int unpack_object(scanner_t *s, json_t *root, va_list *ap) { + int ret = -1; + int strict = 0; + int gotopt = 0; + + /* Use a set (emulated by a hashtable) to check that all object + keys are accessed. Checking that the correct number of keys + were accessed is not enough, as the same key can be unpacked + multiple times. + */ + hashtable_t key_set; + + if (hashtable_init(&key_set)) { + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); + return -1; + } + + if (root && !json_is_object(root)) { + set_error(s, "<validation>", json_error_wrong_type, "Expected object, got %s", + type_name(root)); + goto out; + } + next_token(s); + + while (token(s) != '}') { + const char *key; + json_t *value; + int opt = 0; + + if (strict != 0) { + set_error(s, "<format>", json_error_invalid_format, + "Expected '}' after '%c', got '%c'", (strict == 1 ? '!' : '*'), + token(s)); + goto out; + } + + if (!token(s)) { + set_error(s, "<format>", json_error_invalid_format, + "Unexpected end of format string"); + goto out; + } + + if (token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if (token(s) != 's') { + set_error(s, "<format>", json_error_invalid_format, + "Expected format 's', got '%c'", token(s)); + goto out; + } + + key = va_arg(*ap, const char *); + if (!key) { + set_error(s, "<args>", json_error_null_value, "NULL object key"); + goto out; + } + + next_token(s); + + if (token(s) == '?') { + opt = gotopt = 1; + next_token(s); + } + + if (!root) { + /* skipping */ + value = NULL; + } else { + value = json_object_get(root, key); + if (!value && !opt) { + set_error(s, "<validation>", json_error_item_not_found, + "Object item not found: %s", key); + goto out; + } + } + + if (unpack(s, value, ap)) + goto out; + + hashtable_set(&key_set, key, strlen(key), json_null()); + next_token(s); + } + + if (strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if (root && strict == 1) { + /* We need to check that all non optional items have been parsed */ + const char *key; + size_t key_len; + /* keys_res is 1 for uninitialized, 0 for success, -1 for error. */ + int keys_res = 1; + strbuffer_t unrecognized_keys; + json_t *value; + long unpacked = 0; + + if (gotopt || json_object_size(root) != key_set.size) { + json_object_keylen_foreach(root, key, key_len, value) { + if (!hashtable_get(&key_set, key, key_len)) { + unpacked++; + + /* Save unrecognized keys for the error message */ + if (keys_res == 1) { + keys_res = strbuffer_init(&unrecognized_keys); + } else if (!keys_res) { + keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2); + } + + if (!keys_res) + keys_res = + strbuffer_append_bytes(&unrecognized_keys, key, key_len); + } + } + } + if (unpacked) { + set_error(s, "<validation>", json_error_end_of_input_expected, + "%li object item(s) left unpacked: %s", unpacked, + keys_res ? "<unknown>" : strbuffer_value(&unrecognized_keys)); + strbuffer_close(&unrecognized_keys); + goto out; + } + } + + ret = 0; + +out: + hashtable_close(&key_set); + return ret; +} + +static int unpack_array(scanner_t *s, json_t *root, va_list *ap) { + size_t i = 0; + int strict = 0; + + if (root && !json_is_array(root)) { + set_error(s, "<validation>", json_error_wrong_type, "Expected array, got %s", + type_name(root)); + return -1; + } + next_token(s); + + while (token(s) != ']') { + json_t *value; + + if (strict != 0) { + set_error(s, "<format>", json_error_invalid_format, + "Expected ']' after '%c', got '%c'", (strict == 1 ? '!' : '*'), + token(s)); + return -1; + } + + if (!token(s)) { + set_error(s, "<format>", json_error_invalid_format, + "Unexpected end of format string"); + return -1; + } + + if (token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if (!strchr(unpack_value_starters, token(s))) { + set_error(s, "<format>", json_error_invalid_format, + "Unexpected format character '%c'", token(s)); + return -1; + } + + if (!root) { + /* skipping */ + value = NULL; + } else { + value = json_array_get(root, i); + if (!value) { + set_error(s, "<validation>", json_error_index_out_of_range, + "Array index %lu out of range", (unsigned long)i); + return -1; + } + } + + if (unpack(s, value, ap)) + return -1; + + next_token(s); + i++; + } + + if (strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if (root && strict == 1 && i != json_array_size(root)) { + long diff = (long)json_array_size(root) - (long)i; + set_error(s, "<validation>", json_error_end_of_input_expected, + "%li array item(s) left unpacked", diff); + return -1; + } + + return 0; +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap) { + switch (token(s)) { + case '{': + return unpack_object(s, root, ap); + + case '[': + return unpack_array(s, root, ap); + + case 's': + if (root && !json_is_string(root)) { + set_error(s, "<validation>", json_error_wrong_type, + "Expected string, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + const char **str_target; + size_t *len_target = NULL; + + str_target = va_arg(*ap, const char **); + if (!str_target) { + set_error(s, "<args>", json_error_null_value, "NULL string argument"); + return -1; + } + + next_token(s); + + if (token(s) == '%') { + len_target = va_arg(*ap, size_t *); + if (!len_target) { + set_error(s, "<args>", json_error_null_value, + "NULL string length argument"); + return -1; + } + } else + prev_token(s); + + if (root) { + *str_target = json_string_value(root); + if (len_target) + *len_target = json_string_length(root); + } + } + return 0; + + case 'i': + if (root && !json_is_integer(root)) { + set_error(s, "<validation>", json_error_wrong_type, + "Expected integer, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int *); + if (root) + *target = (int)json_integer_value(root); + } + + return 0; + + case 'I': + if (root && !json_is_integer(root)) { + set_error(s, "<validation>", json_error_wrong_type, + "Expected integer, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + json_int_t *target = va_arg(*ap, json_int_t *); + if (root) + *target = json_integer_value(root); + } + + return 0; + + case 'b': + if (root && !json_is_boolean(root)) { + set_error(s, "<validation>", json_error_wrong_type, + "Expected true or false, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int *); + if (root) + *target = json_is_true(root); + } + + return 0; + + case 'f': + if (root && !json_is_real(root)) { + set_error(s, "<validation>", json_error_wrong_type, + "Expected real, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double *); + if (root) + *target = json_real_value(root); + } + + return 0; + + case 'F': + if (root && !json_is_number(root)) { + set_error(s, "<validation>", json_error_wrong_type, + "Expected real or integer, got %s", type_name(root)); + return -1; + } + + if (!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double *); + if (root) + *target = json_number_value(root); + } + + return 0; + + case 'O': + if (root && !(s->flags & JSON_VALIDATE_ONLY)) + json_incref(root); + /* Fall through */ + + case 'o': + if (!(s->flags & JSON_VALIDATE_ONLY)) { + json_t **target = va_arg(*ap, json_t **); + if (root) + *target = root; + } + + return 0; + + case 'n': + /* Never assign, just validate */ + if (root && !json_is_null(root)) { + set_error(s, "<validation>", json_error_wrong_type, + "Expected null, got %s", type_name(root)); + return -1; + } + return 0; + + default: + set_error(s, "<format>", json_error_invalid_format, + "Unexpected format character '%c'", token(s)); + return -1; + } +} + +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) { + scanner_t s; + va_list ap_copy; + json_t *value; + + if (!fmt || !*fmt) { + jsonp_error_init(error, "<format>"); + jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, + "NULL or empty format string"); + return NULL; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + value = pack(&s, &ap_copy); + va_end(ap_copy); + + /* This will cover all situations where s.has_error is true */ + if (!value) + return NULL; + + next_token(&s); + if (token(&s)) { + json_decref(value); + set_error(&s, "<format>", json_error_invalid_format, + "Garbage after format string"); + return NULL; + } + + return value; +} + +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) { + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(error, flags, fmt, ap); + va_end(ap); + + return value; +} + +json_t *json_pack(const char *fmt, ...) { + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(NULL, 0, fmt, ap); + va_end(ap); + + return value; +} + +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, + va_list ap) { + scanner_t s; + va_list ap_copy; + + if (!root) { + jsonp_error_init(error, "<root>"); + jsonp_error_set(error, -1, -1, 0, json_error_null_value, "NULL root value"); + return -1; + } + + if (!fmt || !*fmt) { + jsonp_error_init(error, "<format>"); + jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, + "NULL or empty format string"); + return -1; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + if (unpack(&s, root, &ap_copy)) { + va_end(ap_copy); + return -1; + } + va_end(ap_copy); + + next_token(&s); + if (token(&s)) { + set_error(&s, "<format>", json_error_invalid_format, + "Garbage after format string"); + return -1; + } + + return 0; +} + +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, + ...) { + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, error, flags, fmt, ap); + va_end(ap); + + return ret; +} + +int json_unpack(json_t *root, const char *fmt, ...) { + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, NULL, 0, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/strbuffer.c b/src/fluent-bit/lib/jansson-e23f558/src/strbuffer.c new file mode 100644 index 000000000..d9bcd439d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/strbuffer.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "strbuffer.h" +#include "jansson_private.h" +#include <stdlib.h> +#include <string.h> + +#define STRBUFFER_MIN_SIZE 16 +#define STRBUFFER_FACTOR 2 +#define STRBUFFER_SIZE_MAX ((size_t)-1) + +int strbuffer_init(strbuffer_t *strbuff) { + strbuff->size = STRBUFFER_MIN_SIZE; + strbuff->length = 0; + + strbuff->value = jsonp_malloc(strbuff->size); + if (!strbuff->value) + return -1; + + /* initialize to empty */ + strbuff->value[0] = '\0'; + return 0; +} + +void strbuffer_close(strbuffer_t *strbuff) { + if (strbuff->value) + jsonp_free(strbuff->value); + + strbuff->size = 0; + strbuff->length = 0; + strbuff->value = NULL; +} + +void strbuffer_clear(strbuffer_t *strbuff) { + strbuff->length = 0; + strbuff->value[0] = '\0'; +} + +const char *strbuffer_value(const strbuffer_t *strbuff) { return strbuff->value; } + +char *strbuffer_steal_value(strbuffer_t *strbuff) { + char *result = strbuff->value; + strbuff->value = NULL; + return result; +} + +int strbuffer_append_byte(strbuffer_t *strbuff, char byte) { + return strbuffer_append_bytes(strbuff, &byte, 1); +} + +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) { + if (size >= strbuff->size - strbuff->length) { + size_t new_size; + char *new_value; + + /* avoid integer overflow */ + if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR || + size > STRBUFFER_SIZE_MAX - 1 || + strbuff->length > STRBUFFER_SIZE_MAX - 1 - size) + return -1; + + new_size = max(strbuff->size * STRBUFFER_FACTOR, strbuff->length + size + 1); + + new_value = jsonp_malloc(new_size); + if (!new_value) + return -1; + + memcpy(new_value, strbuff->value, strbuff->length); + + jsonp_free(strbuff->value); + strbuff->value = new_value; + strbuff->size = new_size; + } + + memcpy(strbuff->value + strbuff->length, data, size); + strbuff->length += size; + strbuff->value[strbuff->length] = '\0'; + + return 0; +} + +char strbuffer_pop(strbuffer_t *strbuff) { + if (strbuff->length > 0) { + char c = strbuff->value[--strbuff->length]; + strbuff->value[strbuff->length] = '\0'; + return c; + } else + return '\0'; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/strbuffer.h b/src/fluent-bit/lib/jansson-e23f558/src/strbuffer.h new file mode 100644 index 000000000..70f2646df --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/strbuffer.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef STRBUFFER_H +#define STRBUFFER_H + +#include "jansson.h" +#include <stdlib.h> + +typedef struct { + char *value; + size_t length; /* bytes used */ + size_t size; /* bytes allocated */ +} strbuffer_t; + +int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS((warn_unused_result)); +void strbuffer_close(strbuffer_t *strbuff); + +void strbuffer_clear(strbuffer_t *strbuff); + +const char *strbuffer_value(const strbuffer_t *strbuff); + +/* Steal the value and close the strbuffer */ +char *strbuffer_steal_value(strbuffer_t *strbuff); + +int strbuffer_append_byte(strbuffer_t *strbuff, char byte); +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size); + +char strbuffer_pop(strbuffer_t *strbuff); + +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/src/strconv.c b/src/fluent-bit/lib/jansson-e23f558/src/strconv.c new file mode 100644 index 000000000..c6f4fd16b --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/strconv.c @@ -0,0 +1,132 @@ +#include "jansson_private.h" +#include "strbuffer.h" +#include <assert.h> +#include <errno.h> +#include <math.h> +#include <stdio.h> +#include <string.h> + +/* need jansson_private_config.h to get the correct snprintf */ +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#if JSON_HAVE_LOCALECONV +#include <locale.h> + +/* + - This code assumes that the decimal separator is exactly one + character. + + - If setlocale() is called by another thread between the call to + localeconv() and the call to sprintf() or strtod(), the result may + be wrong. setlocale() is not thread-safe and should not be used + this way. Multi-threaded programs should use uselocale() instead. +*/ + +static void to_locale(strbuffer_t *strbuffer) { + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if (*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(strbuffer->value, '.'); + if (pos) + *pos = *point; +} + +static void from_locale(char *buffer) { + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if (*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(buffer, *point); + if (pos) + *pos = '.'; +} +#endif + +int jsonp_strtod(strbuffer_t *strbuffer, double *out) { + double value; + char *end; + +#if JSON_HAVE_LOCALECONV + to_locale(strbuffer); +#endif + + errno = 0; + value = strtod(strbuffer->value, &end); + assert(end == strbuffer->value + strbuffer->length); + + if ((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) { + /* Overflow */ + return -1; + } + + *out = value; + return 0; +} + +int jsonp_dtostr(char *buffer, size_t size, double value, int precision) { + int ret; + char *start, *end; + size_t length; + + if (precision == 0) + precision = 17; + + ret = snprintf(buffer, size, "%.*g", precision, value); + if (ret < 0) + return -1; + + length = (size_t)ret; + if (length >= size) + return -1; + +#if JSON_HAVE_LOCALECONV + from_locale(buffer); +#endif + + /* Make sure there's a dot or 'e' in the output. Otherwise + a real is converted to an integer when decoding */ + if (strchr(buffer, '.') == NULL && strchr(buffer, 'e') == NULL) { + if (length + 3 >= size) { + /* No space to append ".0" */ + return -1; + } + buffer[length] = '.'; + buffer[length + 1] = '0'; + buffer[length + 2] = '\0'; + length += 2; + } + + /* Remove leading '+' from positive exponent. Also remove leading + zeros from exponents (added by some printf() implementations) */ + start = strchr(buffer, 'e'); + if (start) { + start++; + end = start + 1; + + if (*start == '-') + start++; + + while (*end == '0') + end++; + + if (end != start) { + memmove(start, end, length - (size_t)(end - buffer)); + length -= (size_t)(end - start); + } + } + + return (int)length; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/utf.c b/src/fluent-bit/lib/jansson-e23f558/src/utf.c new file mode 100644 index 000000000..28b2f7d38 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/utf.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "utf.h" +#include <string.h> + +int utf8_encode(int32_t codepoint, char *buffer, size_t *size) { + if (codepoint < 0) + return -1; + else if (codepoint < 0x80) { + buffer[0] = (char)codepoint; + *size = 1; + } else if (codepoint < 0x800) { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + *size = 2; + } else if (codepoint < 0x10000) { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + *size = 3; + } else if (codepoint <= 0x10FFFF) { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + *size = 4; + } else + return -1; + + return 0; +} + +size_t utf8_check_first(char byte) { + unsigned char u = (unsigned char)byte; + + if (u < 0x80) + return 1; + + if (0x80 <= u && u <= 0xBF) { + /* second, third or fourth byte of a multi-byte + sequence, i.e. a "continuation byte" */ + return 0; + } else if (u == 0xC0 || u == 0xC1) { + /* overlong encoding of an ASCII byte */ + return 0; + } else if (0xC2 <= u && u <= 0xDF) { + /* 2-byte sequence */ + return 2; + } + + else if (0xE0 <= u && u <= 0xEF) { + /* 3-byte sequence */ + return 3; + } else if (0xF0 <= u && u <= 0xF4) { + /* 4-byte sequence */ + return 4; + } else { /* u >= 0xF5 */ + /* Restricted (start of 4-, 5- or 6-byte sequence) or invalid + UTF-8 */ + return 0; + } +} + +size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint) { + size_t i; + int32_t value = 0; + unsigned char u = (unsigned char)buffer[0]; + + if (size == 2) { + value = u & 0x1F; + } else if (size == 3) { + value = u & 0xF; + } else if (size == 4) { + value = u & 0x7; + } else + return 0; + + for (i = 1; i < size; i++) { + u = (unsigned char)buffer[i]; + + if (u < 0x80 || u > 0xBF) { + /* not a continuation byte */ + return 0; + } + + value = (value << 6) + (u & 0x3F); + } + + if (value > 0x10FFFF) { + /* not in Unicode range */ + return 0; + } + + else if (0xD800 <= value && value <= 0xDFFF) { + /* invalid code point (UTF-16 surrogate halves) */ + return 0; + } + + else if ((size == 2 && value < 0x80) || (size == 3 && value < 0x800) || + (size == 4 && value < 0x10000)) { + /* overlong encoding */ + return 0; + } + + if (codepoint) + *codepoint = value; + + return 1; +} + +const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint) { + size_t count; + int32_t value; + + if (!bufsize) + return buffer; + + count = utf8_check_first(buffer[0]); + if (count <= 0) + return NULL; + + if (count == 1) + value = (unsigned char)buffer[0]; + else { + if (count > bufsize || !utf8_check_full(buffer, count, &value)) + return NULL; + } + + if (codepoint) + *codepoint = value; + + return buffer + count; +} + +int utf8_check_string(const char *string, size_t length) { + size_t i; + + for (i = 0; i < length; i++) { + size_t count = utf8_check_first(string[i]); + if (count == 0) + return 0; + else if (count > 1) { + if (count > length - i) + return 0; + + if (!utf8_check_full(&string[i], count, NULL)) + return 0; + + i += count - 1; + } + } + + return 1; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/utf.h b/src/fluent-bit/lib/jansson-e23f558/src/utf.h new file mode 100644 index 000000000..5db99df67 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/utf.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef UTF_H +#define UTF_H + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#include <stddef.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +int utf8_encode(int32_t codepoint, char *buffer, size_t *size); + +size_t utf8_check_first(char byte); +size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint); +const char *utf8_iterate(const char *buffer, size_t size, int32_t *codepoint); + +int utf8_check_string(const char *string, size_t length); + +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/src/value.c b/src/fluent-bit/lib/jansson-e23f558/src/value.c new file mode 100644 index 000000000..d5a11fe51 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/value.c @@ -0,0 +1,1120 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#include <math.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#include "hashtable.h" +#include "jansson.h" +#include "jansson_private.h" +#include "utf.h" + +/* Work around nonstandard isnan() and isinf() implementations */ +#ifndef isnan +#ifndef __sun +static JSON_INLINE int isnan(double x) { return x != x; } +#endif +#endif +#ifndef isinf +static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } +#endif + +json_t *do_deep_copy(const json_t *json, hashtable_t *parents); + +static JSON_INLINE void json_init(json_t *json, json_type type) { + json->type = type; + json->refcount = 1; +} + +int jsonp_loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size, + size_t *key_len_out) { + size_t key_len = snprintf(key, key_size, "%p", json); + + if (key_len_out) + *key_len_out = key_len; + + if (hashtable_get(parents, key, key_len)) + return -1; + + return hashtable_set(parents, key, key_len, json_null()); +} + +/*** object ***/ + +extern volatile uint32_t hashtable_seed; + +json_t *json_object(void) { + json_object_t *object = jsonp_malloc(sizeof(json_object_t)); + if (!object) + return NULL; + + if (!hashtable_seed) { + /* Autoseed */ + json_object_seed(0); + } + + json_init(&object->json, JSON_OBJECT); + + if (hashtable_init(&object->hashtable)) { + jsonp_free(object); + return NULL; + } + + return &object->json; +} + +static void json_delete_object(json_object_t *object) { + hashtable_close(&object->hashtable); + jsonp_free(object); +} + +size_t json_object_size(const json_t *json) { + json_object_t *object; + + if (!json_is_object(json)) + return 0; + + object = json_to_object(json); + return object->hashtable.size; +} + +json_t *json_object_get(const json_t *json, const char *key) { + if (!key) + return NULL; + + return json_object_getn(json, key, strlen(key)); +} + +json_t *json_object_getn(const json_t *json, const char *key, size_t key_len) { + json_object_t *object; + + if (!key || !json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_get(&object->hashtable, key, key_len); +} + +int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) { + if (!key) { + json_decref(value); + return -1; + } + return json_object_setn_new_nocheck(json, key, strlen(key), value); +} + +int json_object_setn_new_nocheck(json_t *json, const char *key, size_t key_len, + json_t *value) { + json_object_t *object; + + if (!value) + return -1; + + if (!key || !json_is_object(json) || json == value) { + json_decref(value); + return -1; + } + object = json_to_object(json); + + if (hashtable_set(&object->hashtable, key, key_len, value)) { + json_decref(value); + return -1; + } + + return 0; +} + +int json_object_set_new(json_t *json, const char *key, json_t *value) { + if (!key) { + json_decref(value); + return -1; + } + + return json_object_setn_new(json, key, strlen(key), value); +} + +int json_object_setn_new(json_t *json, const char *key, size_t key_len, json_t *value) { + if (!key || !utf8_check_string(key, key_len)) { + json_decref(value); + return -1; + } + + return json_object_setn_new_nocheck(json, key, key_len, value); +} + +int json_object_del(json_t *json, const char *key) { + if (!key) + return -1; + + return json_object_deln(json, key, strlen(key)); +} + +int json_object_deln(json_t *json, const char *key, size_t key_len) { + json_object_t *object; + + if (!key || !json_is_object(json)) + return -1; + + object = json_to_object(json); + return hashtable_del(&object->hashtable, key, key_len); +} + +int json_object_clear(json_t *json) { + json_object_t *object; + + if (!json_is_object(json)) + return -1; + + object = json_to_object(json); + hashtable_clear(&object->hashtable); + + return 0; +} + +int json_object_update(json_t *object, json_t *other) { + const char *key; + size_t key_len; + json_t *value; + + if (!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_keylen_foreach(other, key, key_len, value) { + if (json_object_setn_nocheck(object, key, key_len, value)) + return -1; + } + + return 0; +} + +int json_object_update_existing(json_t *object, json_t *other) { + const char *key; + size_t key_len; + json_t *value; + + if (!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_keylen_foreach(other, key, key_len, value) { + if (json_object_getn(object, key, key_len)) + json_object_setn_nocheck(object, key, key_len, value); + } + + return 0; +} + +int json_object_update_missing(json_t *object, json_t *other) { + const char *key; + size_t key_len; + json_t *value; + + if (!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_keylen_foreach(other, key, key_len, value) { + if (!json_object_getn(object, key, key_len)) + json_object_setn_nocheck(object, key, key_len, value); + } + + return 0; +} + +int do_object_update_recursive(json_t *object, json_t *other, hashtable_t *parents) { + const char *key; + size_t key_len; + json_t *value; + char loop_key[LOOP_KEY_LEN]; + int res = 0; + size_t loop_key_len; + + if (!json_is_object(object) || !json_is_object(other)) + return -1; + + if (jsonp_loop_check(parents, other, loop_key, sizeof(loop_key), &loop_key_len)) + return -1; + + json_object_keylen_foreach(other, key, key_len, value) { + json_t *v = json_object_getn(object, key, key_len); + + if (json_is_object(v) && json_is_object(value)) { + if (do_object_update_recursive(v, value, parents)) { + res = -1; + break; + } + } else { + if (json_object_setn_nocheck(object, key, key_len, value)) { + res = -1; + break; + } + } + } + + hashtable_del(parents, loop_key, loop_key_len); + + return res; +} + +int json_object_update_recursive(json_t *object, json_t *other) { + int res; + hashtable_t parents_set; + + if (hashtable_init(&parents_set)) + return -1; + res = do_object_update_recursive(object, other, &parents_set); + hashtable_close(&parents_set); + + return res; +} + +void *json_object_iter(json_t *json) { + json_object_t *object; + + if (!json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter(&object->hashtable); +} + +void *json_object_iter_at(json_t *json, const char *key) { + json_object_t *object; + + if (!key || !json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter_at(&object->hashtable, key, strlen(key)); +} + +void *json_object_iter_next(json_t *json, void *iter) { + json_object_t *object; + + if (!json_is_object(json) || iter == NULL) + return NULL; + + object = json_to_object(json); + return hashtable_iter_next(&object->hashtable, iter); +} + +const char *json_object_iter_key(void *iter) { + if (!iter) + return NULL; + + return hashtable_iter_key(iter); +} + +size_t json_object_iter_key_len(void *iter) { + if (!iter) + return 0; + + return hashtable_iter_key_len(iter); +} + +json_t *json_object_iter_value(void *iter) { + if (!iter) + return NULL; + + return (json_t *)hashtable_iter_value(iter); +} + +int json_object_iter_set_new(json_t *json, void *iter, json_t *value) { + if (!json_is_object(json) || !iter || !value) { + json_decref(value); + return -1; + } + + hashtable_iter_set(iter, value); + return 0; +} + +void *json_object_key_to_iter(const char *key) { + if (!key) + return NULL; + + return hashtable_key_to_iter(key); +} + +static int json_object_equal(const json_t *object1, const json_t *object2) { + const char *key; + size_t key_len; + const json_t *value1, *value2; + + if (json_object_size(object1) != json_object_size(object2)) + return 0; + + json_object_keylen_foreach((json_t *)object1, key, key_len, value1) { + value2 = json_object_getn(object2, key, key_len); + + if (!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_object_copy(json_t *object) { + json_t *result; + + const char *key; + size_t key_len; + json_t *value; + + result = json_object(); + if (!result) + return NULL; + + json_object_keylen_foreach(object, key, key_len, value) + json_object_setn_nocheck(result, key, key_len, value); + + return result; +} + +static json_t *json_object_deep_copy(const json_t *object, hashtable_t *parents) { + json_t *result; + void *iter; + char loop_key[LOOP_KEY_LEN]; + size_t loop_key_len; + + if (jsonp_loop_check(parents, object, loop_key, sizeof(loop_key), &loop_key_len)) + return NULL; + + result = json_object(); + if (!result) + goto out; + + /* Cannot use json_object_foreach because object has to be cast + non-const */ + iter = json_object_iter((json_t *)object); + while (iter) { + const char *key; + size_t key_len; + const json_t *value; + key = json_object_iter_key(iter); + key_len = json_object_iter_key_len(iter); + value = json_object_iter_value(iter); + + if (json_object_setn_new_nocheck(result, key, key_len, + do_deep_copy(value, parents))) { + json_decref(result); + result = NULL; + break; + } + iter = json_object_iter_next((json_t *)object, iter); + } + +out: + hashtable_del(parents, loop_key, loop_key_len); + + return result; +} + +/*** array ***/ + +json_t *json_array(void) { + json_array_t *array = jsonp_malloc(sizeof(json_array_t)); + if (!array) + return NULL; + json_init(&array->json, JSON_ARRAY); + + array->entries = 0; + array->size = 8; + + array->table = jsonp_malloc(array->size * sizeof(json_t *)); + if (!array->table) { + jsonp_free(array); + return NULL; + } + + return &array->json; +} + +static void json_delete_array(json_array_t *array) { + size_t i; + + for (i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + jsonp_free(array->table); + jsonp_free(array); +} + +size_t json_array_size(const json_t *json) { + if (!json_is_array(json)) + return 0; + + return json_to_array(json)->entries; +} + +json_t *json_array_get(const json_t *json, size_t index) { + json_array_t *array; + if (!json_is_array(json)) + return NULL; + array = json_to_array(json); + + if (index >= array->entries) + return NULL; + + return array->table[index]; +} + +int json_array_set_new(json_t *json, size_t index, json_t *value) { + json_array_t *array; + + if (!value) + return -1; + + if (!json_is_array(json) || json == value) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if (index >= array->entries) { + json_decref(value); + return -1; + } + + json_decref(array->table[index]); + array->table[index] = value; + + return 0; +} + +static void array_move(json_array_t *array, size_t dest, size_t src, size_t count) { + memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *)); +} + +static void array_copy(json_t **dest, size_t dpos, json_t **src, size_t spos, + size_t count) { + memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *)); +} + +static json_t **json_array_grow(json_array_t *array, size_t amount, int copy) { + size_t new_size; + json_t **old_table, **new_table; + + if (array->entries + amount <= array->size) + return array->table; + + old_table = array->table; + + new_size = max(array->size + amount, array->size * 2); + new_table = jsonp_malloc(new_size * sizeof(json_t *)); + if (!new_table) + return NULL; + + array->size = new_size; + array->table = new_table; + + if (copy) { + array_copy(array->table, 0, old_table, 0, array->entries); + jsonp_free(old_table); + return array->table; + } + + return old_table; +} + +int json_array_append_new(json_t *json, json_t *value) { + json_array_t *array; + + if (!value) + return -1; + + if (!json_is_array(json) || json == value) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if (!json_array_grow(array, 1, 1)) { + json_decref(value); + return -1; + } + + array->table[array->entries] = value; + array->entries++; + + return 0; +} + +int json_array_insert_new(json_t *json, size_t index, json_t *value) { + json_array_t *array; + json_t **old_table; + + if (!value) + return -1; + + if (!json_is_array(json) || json == value) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if (index > array->entries) { + json_decref(value); + return -1; + } + + old_table = json_array_grow(array, 1, 0); + if (!old_table) { + json_decref(value); + return -1; + } + + if (old_table != array->table) { + array_copy(array->table, 0, old_table, 0, index); + array_copy(array->table, index + 1, old_table, index, array->entries - index); + jsonp_free(old_table); + } else + array_move(array, index + 1, index, array->entries - index); + + array->table[index] = value; + array->entries++; + + return 0; +} + +int json_array_remove(json_t *json, size_t index) { + json_array_t *array; + + if (!json_is_array(json)) + return -1; + array = json_to_array(json); + + if (index >= array->entries) + return -1; + + json_decref(array->table[index]); + + /* If we're removing the last element, nothing has to be moved */ + if (index < array->entries - 1) + array_move(array, index, index + 1, array->entries - index - 1); + + array->entries--; + + return 0; +} + +int json_array_clear(json_t *json) { + json_array_t *array; + size_t i; + + if (!json_is_array(json)) + return -1; + array = json_to_array(json); + + for (i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + array->entries = 0; + return 0; +} + +int json_array_extend(json_t *json, json_t *other_json) { + json_array_t *array, *other; + size_t i; + + if (!json_is_array(json) || !json_is_array(other_json)) + return -1; + array = json_to_array(json); + other = json_to_array(other_json); + + if (!json_array_grow(array, other->entries, 1)) + return -1; + + for (i = 0; i < other->entries; i++) + json_incref(other->table[i]); + + array_copy(array->table, array->entries, other->table, 0, other->entries); + + array->entries += other->entries; + return 0; +} + +static int json_array_equal(const json_t *array1, const json_t *array2) { + size_t i, size; + + size = json_array_size(array1); + if (size != json_array_size(array2)) + return 0; + + for (i = 0; i < size; i++) { + json_t *value1, *value2; + + value1 = json_array_get(array1, i); + value2 = json_array_get(array2, i); + + if (!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_array_copy(json_t *array) { + json_t *result; + size_t i; + + result = json_array(); + if (!result) + return NULL; + + for (i = 0; i < json_array_size(array); i++) + json_array_append(result, json_array_get(array, i)); + + return result; +} + +static json_t *json_array_deep_copy(const json_t *array, hashtable_t *parents) { + json_t *result; + size_t i; + char loop_key[LOOP_KEY_LEN]; + size_t loop_key_len; + + if (jsonp_loop_check(parents, array, loop_key, sizeof(loop_key), &loop_key_len)) + return NULL; + + result = json_array(); + if (!result) + goto out; + + for (i = 0; i < json_array_size(array); i++) { + if (json_array_append_new(result, + do_deep_copy(json_array_get(array, i), parents))) { + json_decref(result); + result = NULL; + break; + } + } + +out: + hashtable_del(parents, loop_key, loop_key_len); + + return result; +} + +/*** string ***/ + +static json_t *string_create(const char *value, size_t len, int own) { + char *v; + json_string_t *string; + + if (!value) + return NULL; + + if (own) + v = (char *)value; + else { + v = jsonp_strndup(value, len); + if (!v) + return NULL; + } + + string = jsonp_malloc(sizeof(json_string_t)); + if (!string) { + jsonp_free(v); + return NULL; + } + json_init(&string->json, JSON_STRING); + string->value = v; + string->length = len; + + return &string->json; +} + +json_t *json_string_nocheck(const char *value) { + if (!value) + return NULL; + + return string_create(value, strlen(value), 0); +} + +json_t *json_stringn_nocheck(const char *value, size_t len) { + return string_create(value, len, 0); +} + +/* this is private; "steal" is not a public API concept */ +json_t *jsonp_stringn_nocheck_own(const char *value, size_t len) { + return string_create(value, len, 1); +} + +json_t *json_string(const char *value) { + if (!value) + return NULL; + + return json_stringn(value, strlen(value)); +} + +json_t *json_stringn(const char *value, size_t len) { + if (!value || !utf8_check_string(value, len)) + return NULL; + + return json_stringn_nocheck(value, len); +} + +const char *json_string_value(const json_t *json) { + if (!json_is_string(json)) + return NULL; + + return json_to_string(json)->value; +} + +size_t json_string_length(const json_t *json) { + if (!json_is_string(json)) + return 0; + + return json_to_string(json)->length; +} + +int json_string_set_nocheck(json_t *json, const char *value) { + if (!value) + return -1; + + return json_string_setn_nocheck(json, value, strlen(value)); +} + +int json_string_setn_nocheck(json_t *json, const char *value, size_t len) { + char *dup; + json_string_t *string; + + if (!json_is_string(json) || !value) + return -1; + + dup = jsonp_strndup(value, len); + if (!dup) + return -1; + + string = json_to_string(json); + jsonp_free(string->value); + string->value = dup; + string->length = len; + + return 0; +} + +int json_string_set(json_t *json, const char *value) { + if (!value) + return -1; + + return json_string_setn(json, value, strlen(value)); +} + +int json_string_setn(json_t *json, const char *value, size_t len) { + if (!value || !utf8_check_string(value, len)) + return -1; + + return json_string_setn_nocheck(json, value, len); +} + +static void json_delete_string(json_string_t *string) { + jsonp_free(string->value); + jsonp_free(string); +} + +static int json_string_equal(const json_t *string1, const json_t *string2) { + json_string_t *s1, *s2; + + s1 = json_to_string(string1); + s2 = json_to_string(string2); + return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length); +} + +static json_t *json_string_copy(const json_t *string) { + json_string_t *s; + + s = json_to_string(string); + return json_stringn_nocheck(s->value, s->length); +} + +json_t *json_vsprintf(const char *fmt, va_list ap) { + json_t *json = NULL; + int length; + char *buf; + va_list aq; + va_copy(aq, ap); + + length = vsnprintf(NULL, 0, fmt, ap); + if (length < 0) + goto out; + if (length == 0) { + json = json_string(""); + goto out; + } + + buf = jsonp_malloc((size_t)length + 1); + if (!buf) + goto out; + + vsnprintf(buf, (size_t)length + 1, fmt, aq); + if (!utf8_check_string(buf, length)) { + jsonp_free(buf); + goto out; + } + + json = jsonp_stringn_nocheck_own(buf, length); + +out: + va_end(aq); + return json; +} + +json_t *json_sprintf(const char *fmt, ...) { + json_t *result; + va_list ap; + + va_start(ap, fmt); + result = json_vsprintf(fmt, ap); + va_end(ap); + + return result; +} + +/*** integer ***/ + +json_t *json_integer(json_int_t value) { + json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t)); + if (!integer) + return NULL; + json_init(&integer->json, JSON_INTEGER); + + integer->value = value; + return &integer->json; +} + +json_int_t json_integer_value(const json_t *json) { + if (!json_is_integer(json)) + return 0; + + return json_to_integer(json)->value; +} + +int json_integer_set(json_t *json, json_int_t value) { + if (!json_is_integer(json)) + return -1; + + json_to_integer(json)->value = value; + + return 0; +} + +static void json_delete_integer(json_integer_t *integer) { jsonp_free(integer); } + +static int json_integer_equal(const json_t *integer1, const json_t *integer2) { + return json_integer_value(integer1) == json_integer_value(integer2); +} + +static json_t *json_integer_copy(const json_t *integer) { + return json_integer(json_integer_value(integer)); +} + +/*** real ***/ + +json_t *json_real(double value) { + json_real_t *real; + + if (isnan(value) || isinf(value)) + return NULL; + + real = jsonp_malloc(sizeof(json_real_t)); + if (!real) + return NULL; + json_init(&real->json, JSON_REAL); + + real->value = value; + return &real->json; +} + +double json_real_value(const json_t *json) { + if (!json_is_real(json)) + return 0; + + return json_to_real(json)->value; +} + +int json_real_set(json_t *json, double value) { + if (!json_is_real(json) || isnan(value) || isinf(value)) + return -1; + + json_to_real(json)->value = value; + + return 0; +} + +static void json_delete_real(json_real_t *real) { jsonp_free(real); } + +static int json_real_equal(const json_t *real1, const json_t *real2) { + return json_real_value(real1) == json_real_value(real2); +} + +static json_t *json_real_copy(const json_t *real) { + return json_real(json_real_value(real)); +} + +/*** number ***/ + +double json_number_value(const json_t *json) { + if (json_is_integer(json)) + return (double)json_integer_value(json); + else if (json_is_real(json)) + return json_real_value(json); + else + return 0.0; +} + +/*** simple values ***/ + +json_t *json_true(void) { + static json_t the_true = {JSON_TRUE, (size_t)-1}; + return &the_true; +} + +json_t *json_false(void) { + static json_t the_false = {JSON_FALSE, (size_t)-1}; + return &the_false; +} + +json_t *json_null(void) { + static json_t the_null = {JSON_NULL, (size_t)-1}; + return &the_null; +} + +/*** deletion ***/ + +void json_delete(json_t *json) { + if (!json) + return; + + switch (json_typeof(json)) { + case JSON_OBJECT: + json_delete_object(json_to_object(json)); + break; + case JSON_ARRAY: + json_delete_array(json_to_array(json)); + break; + case JSON_STRING: + json_delete_string(json_to_string(json)); + break; + case JSON_INTEGER: + json_delete_integer(json_to_integer(json)); + break; + case JSON_REAL: + json_delete_real(json_to_real(json)); + break; + default: + return; + } + + /* json_delete is not called for true, false or null */ +} + +/*** equality ***/ + +int json_equal(const json_t *json1, const json_t *json2) { + if (!json1 || !json2) + return 0; + + if (json_typeof(json1) != json_typeof(json2)) + return 0; + + /* this covers true, false and null as they are singletons */ + if (json1 == json2) + return 1; + + switch (json_typeof(json1)) { + case JSON_OBJECT: + return json_object_equal(json1, json2); + case JSON_ARRAY: + return json_array_equal(json1, json2); + case JSON_STRING: + return json_string_equal(json1, json2); + case JSON_INTEGER: + return json_integer_equal(json1, json2); + case JSON_REAL: + return json_real_equal(json1, json2); + default: + return 0; + } +} + +/*** copying ***/ + +json_t *json_copy(json_t *json) { + if (!json) + return NULL; + + switch (json_typeof(json)) { + case JSON_OBJECT: + return json_object_copy(json); + case JSON_ARRAY: + return json_array_copy(json); + case JSON_STRING: + return json_string_copy(json); + case JSON_INTEGER: + return json_integer_copy(json); + case JSON_REAL: + return json_real_copy(json); + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + return json; + default: + return NULL; + } +} + +json_t *json_deep_copy(const json_t *json) { + json_t *res; + hashtable_t parents_set; + + if (hashtable_init(&parents_set)) + return NULL; + res = do_deep_copy(json, &parents_set); + hashtable_close(&parents_set); + + return res; +} + +json_t *do_deep_copy(const json_t *json, hashtable_t *parents) { + if (!json) + return NULL; + + switch (json_typeof(json)) { + case JSON_OBJECT: + return json_object_deep_copy(json, parents); + case JSON_ARRAY: + return json_array_deep_copy(json, parents); + /* for the rest of the types, deep copying doesn't differ from + shallow copying */ + case JSON_STRING: + return json_string_copy(json); + case JSON_INTEGER: + return json_integer_copy(json); + case JSON_REAL: + return json_real_copy(json); + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + return (json_t *)json; + default: + return NULL; + } +} diff --git a/src/fluent-bit/lib/jansson-e23f558/src/version.c b/src/fluent-bit/lib/jansson-e23f558/src/version.c new file mode 100644 index 000000000..f1026af14 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/src/version.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 Sean Bright <sean.bright@gmail.com> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "jansson.h" + +const char *jansson_version_str(void) { return JANSSON_VERSION; } + +int jansson_version_cmp(int major, int minor, int micro) { + int diff; + + if ((diff = JANSSON_MAJOR_VERSION - major)) { + return diff; + } + + if ((diff = JANSSON_MINOR_VERSION - minor)) { + return diff; + } + + return JANSSON_MICRO_VERSION - micro; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/.gitignore b/src/fluent-bit/lib/jansson-e23f558/test/.gitignore new file mode 100644 index 000000000..6a33dea39 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/.gitignore @@ -0,0 +1,20 @@ +logs +bin/json_process +suites/api/test_array +suites/api/test_chaos +suites/api/test_copy +suites/api/test_cpp +suites/api/test_dump +suites/api/test_dump_callback +suites/api/test_equal +suites/api/test_load +suites/api/test_load_callback +suites/api/test_loadb +suites/api/test_memory_funcs +suites/api/test_number +suites/api/test_object +suites/api/test_pack +suites/api/test_simple +suites/api/test_sprintf +suites/api/test_unpack +suites/api/test_version diff --git a/src/fluent-bit/lib/jansson-e23f558/test/Makefile.am b/src/fluent-bit/lib/jansson-e23f558/test/Makefile.am new file mode 100644 index 000000000..344d18d7e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/Makefile.am @@ -0,0 +1,10 @@ +SUBDIRS = bin suites ossfuzz +EXTRA_DIST = scripts run-suites + +TESTS = run-suites +TESTS_ENVIRONMENT = \ + top_srcdir=$(top_srcdir) \ + top_builddir=$(top_builddir) + +clean-local: + rm -rf logs diff --git a/src/fluent-bit/lib/jansson-e23f558/test/bin/Makefile.am b/src/fluent-bit/lib/jansson-e23f558/test/bin/Makefile.am new file mode 100644 index 000000000..63b6dce7e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/bin/Makefile.am @@ -0,0 +1,5 @@ +check_PROGRAMS = json_process + +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src +LDFLAGS = -static # for speed and Valgrind +LDADD = $(top_builddir)/src/libjansson.la diff --git a/src/fluent-bit/lib/jansson-e23f558/test/bin/json_process.c b/src/fluent-bit/lib/jansson-e23f558/test/bin/json_process.c new file mode 100644 index 000000000..fc98543fc --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/bin/json_process.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#include <ctype.h> +#include <jansson.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_LOCALE_H +#include <locale.h> +#endif + +#if _WIN32 +#include <fcntl.h> /* for _O_BINARY */ +#include <io.h> /* for _setmode() */ + +static const char dir_sep = '\\'; +#else +static const char dir_sep = '/'; +#endif + +struct config { + int indent; + int compact; + int preserve_order; + int ensure_ascii; + int sort_keys; + int strip; + int use_env; + int have_hashseed; + int hashseed; + int precision; +} conf; + +#define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t') + +/* Return a pointer to the first non-whitespace character of str. + Modifies str so that all trailing whitespace characters are + replaced by '\0'. */ +static const char *strip(char *str) { + size_t length; + char *result = str; + while (*result && l_isspace(*result)) + result++; + + length = strlen(result); + if (length == 0) + return result; + + while (l_isspace(result[length - 1])) + result[--length] = '\0'; + + return result; +} + +static char *loadfile(FILE *file) { + size_t fsize, ret; + char *buf; + + fseek(file, 0, SEEK_END); + fsize = ftell(file); + fseek(file, 0, SEEK_SET); + + buf = malloc(fsize + 1); + ret = fread(buf, 1, fsize, file); + if (ret != fsize) + exit(1); + buf[fsize] = '\0'; + + return buf; +} + +static void read_conf(FILE *conffile) { + char *buffer, *line, *val; + + buffer = loadfile(conffile); + for (line = strtok(buffer, "\r\n"); line; line = strtok(NULL, "\r\n")) { + if (!strncmp(line, "export ", 7)) + continue; + val = strchr(line, '='); + if (!val) { + printf("invalid configuration line\n"); + break; + } + *val++ = '\0'; + + if (!strcmp(line, "JSON_INDENT")) + conf.indent = atoi(val); + if (!strcmp(line, "JSON_COMPACT")) + conf.compact = atoi(val); + if (!strcmp(line, "JSON_ENSURE_ASCII")) + conf.ensure_ascii = atoi(val); + if (!strcmp(line, "JSON_PRESERVE_ORDER")) + conf.preserve_order = atoi(val); + if (!strcmp(line, "JSON_SORT_KEYS")) + conf.sort_keys = atoi(val); + if (!strcmp(line, "JSON_REAL_PRECISION")) + conf.precision = atoi(val); + if (!strcmp(line, "STRIP")) + conf.strip = atoi(val); + if (!strcmp(line, "HASHSEED")) { + conf.have_hashseed = 1; + conf.hashseed = atoi(val); + } else { + conf.have_hashseed = 0; + } + } + + free(buffer); +} + +static int cmpfile(const char *str, const char *path, const char *fname) { + char filename[1024], *buffer; + int ret; + FILE *file; + + sprintf(filename, "%s%c%s", path, dir_sep, fname); + file = fopen(filename, "rb"); + if (!file) { + if (conf.strip) + strcat(filename, ".strip"); + else + strcat(filename, ".normal"); + file = fopen(filename, "rb"); + } + if (!file) { + printf("Error: test result file could not be opened.\n"); + exit(1); + } + + buffer = loadfile(file); + if (strcmp(buffer, str) != 0) + ret = 1; + else + ret = 0; + free(buffer); + fclose(file); + + return ret; +} + +int use_conf(char *test_path) { + int ret; + size_t flags = 0; + char filename[1024], errstr[1024]; + char *buffer; + FILE *infile, *conffile; + json_t *json; + json_error_t error; + + sprintf(filename, "%s%cinput", test_path, dir_sep); + if (!(infile = fopen(filename, "rb"))) { + fprintf(stderr, "Could not open \"%s\"\n", filename); + return 2; + } + + sprintf(filename, "%s%cenv", test_path, dir_sep); + conffile = fopen(filename, "rb"); + if (conffile) { + read_conf(conffile); + fclose(conffile); + } + + if (conf.indent < 0 || conf.indent > 31) { + fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent); + fclose(infile); + return 2; + } + if (conf.indent) + flags |= JSON_INDENT(conf.indent); + + if (conf.compact) + flags |= JSON_COMPACT; + + if (conf.ensure_ascii) + flags |= JSON_ENSURE_ASCII; + + if (conf.preserve_order) + flags |= JSON_PRESERVE_ORDER; + + if (conf.sort_keys) + flags |= JSON_SORT_KEYS; + + if (conf.precision < 0 || conf.precision > 31) { + fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", conf.precision); + fclose(infile); + return 2; + } + if (conf.precision) + flags |= JSON_REAL_PRECISION(conf.precision); + + if (conf.have_hashseed) + json_object_seed(conf.hashseed); + + if (conf.strip) { + /* Load to memory, strip leading and trailing whitespace */ + buffer = loadfile(infile); + json = json_loads(strip(buffer), 0, &error); + free(buffer); + } else + json = json_loadf(infile, 0, &error); + + fclose(infile); + + if (!json) { + sprintf(errstr, "%d %d %d\n%s\n", error.line, error.column, error.position, + error.text); + + ret = cmpfile(errstr, test_path, "error"); + return ret; + } + + buffer = json_dumps(json, flags); + ret = cmpfile(buffer, test_path, "output"); + free(buffer); + json_decref(json); + + return ret; +} + +static int getenv_int(const char *name) { + char *value, *end; + long result; + + value = getenv(name); + if (!value) + return 0; + + result = strtol(value, &end, 10); + if (*end != '\0') + return 0; + + return (int)result; +} + +int use_env() { + int indent, precision; + size_t flags = 0; + json_t *json; + json_error_t error; + +#ifdef _WIN32 + /* On Windows, set stdout and stderr to binary mode to avoid + outputting DOS line terminators */ + _setmode(_fileno(stdout), _O_BINARY); + _setmode(_fileno(stderr), _O_BINARY); +#endif + + indent = getenv_int("JSON_INDENT"); + if (indent < 0 || indent > 31) { + fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent); + return 2; + } + if (indent > 0) + flags |= JSON_INDENT(indent); + + if (getenv_int("JSON_COMPACT") > 0) + flags |= JSON_COMPACT; + + if (getenv_int("JSON_ENSURE_ASCII")) + flags |= JSON_ENSURE_ASCII; + + if (getenv_int("JSON_PRESERVE_ORDER")) + flags |= JSON_PRESERVE_ORDER; + + if (getenv_int("JSON_SORT_KEYS")) + flags |= JSON_SORT_KEYS; + + precision = getenv_int("JSON_REAL_PRECISION"); + if (precision < 0 || precision > 31) { + fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", precision); + return 2; + } + + if (getenv("HASHSEED")) + json_object_seed(getenv_int("HASHSEED")); + + if (precision > 0) + flags |= JSON_REAL_PRECISION(precision); + + if (getenv_int("STRIP")) { + /* Load to memory, strip leading and trailing whitespace */ + size_t size = 0, used = 0; + char *buffer = NULL, *buf_ck = NULL; + + while (1) { + size_t count; + + size = (size == 0 ? 128 : size * 2); + buf_ck = realloc(buffer, size); + if (!buf_ck) { + fprintf(stderr, "Unable to allocate %d bytes\n", (int)size); + free(buffer); + return 1; + } + buffer = buf_ck; + + count = fread(buffer + used, 1, size - used, stdin); + if (count < size - used) { + buffer[used + count] = '\0'; + break; + } + used += count; + } + + json = json_loads(strip(buffer), 0, &error); + free(buffer); + } else + json = json_loadf(stdin, 0, &error); + + if (!json) { + fprintf(stderr, "%d %d %d\n%s\n", error.line, error.column, error.position, + error.text); + return 1; + } + + json_dumpf(json, stdout, flags); + json_decref(json); + + return 0; +} + +int main(int argc, char *argv[]) { + int i; + char *test_path = NULL; + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + + if (argc < 2) { + goto usage; + } + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--strip")) + conf.strip = 1; + else if (!strcmp(argv[i], "--env")) + conf.use_env = 1; + else + test_path = argv[i]; + } + + if (conf.use_env) + return use_env(); + else { + if (!test_path) + goto usage; + + return use_conf(test_path); + } + +usage: + fprintf(stderr, "argc =%d\n", argc); + fprintf(stderr, "usage: %s [--strip] [--env] test_dir\n", argv[0]); + return 2; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/.gitignore b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/.gitignore new file mode 100644 index 000000000..7fbb8677b --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/.gitignore @@ -0,0 +1 @@ +json_load_dump_fuzzer diff --git a/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/Makefile.am b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/Makefile.am new file mode 100644 index 000000000..a2e802e86 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/Makefile.am @@ -0,0 +1,32 @@ +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src +LDADD = $(top_builddir)/src/libjansson.la + +if USE_OSSFUZZ_FLAG +FUZZ_FLAG = $(LIB_FUZZING_ENGINE) +else +if USE_OSSFUZZ_STATIC +LDADD += $(LIB_FUZZING_ENGINE) +FUZZ_FLAG = +else +LDADD += libstandaloneengine.a +FUZZ_FLAG = +endif +endif + +noinst_PROGRAMS = +noinst_LIBRARIES = + +if USE_OSSFUZZERS +noinst_PROGRAMS += \ + json_load_dump_fuzzer + +noinst_LIBRARIES += \ + libstandaloneengine.a +endif + +json_load_dump_fuzzer_SOURCES = json_load_dump_fuzzer.cc testinput.h +json_load_dump_fuzzer_CXXFLAGS = $(AM_CXXFLAGS) $(FUZZ_FLAG) +json_load_dump_fuzzer_LDFLAGS = $(AM_LDFLAGS) -static + +libstandaloneengine_a_SOURCES = standaloneengine.cc +libstandaloneengine_a_CXXFLAGS = $(AM_CXXFLAGS) diff --git a/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/json_load_dump_fuzzer.cc b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/json_load_dump_fuzzer.cc new file mode 100644 index 000000000..bc3844e75 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/json_load_dump_fuzzer.cc @@ -0,0 +1,132 @@ +#include <stdint.h> +#include <stdlib.h> +#include <sys/types.h> +#include <inttypes.h> + +#include "jansson.h" + +static int enable_diags; + +#define FUZZ_DEBUG(FMT, ...) \ + if (enable_diags) \ + { \ + fprintf(stderr, FMT, ##__VA_ARGS__); \ + fprintf(stderr, "\n"); \ + } + + +static int json_dump_counter(const char *buffer, size_t size, void *data) +{ + uint64_t *counter = reinterpret_cast<uint64_t *>(data); + *counter += size; + return 0; +} + + +#define NUM_COMMAND_BYTES (sizeof(size_t) + sizeof(size_t) + 1) + +#define FUZZ_DUMP_CALLBACK 0x00 +#define FUZZ_DUMP_STRING 0x01 + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + json_error_t error; + unsigned char dump_mode; + + // Enable or disable diagnostics based on the FUZZ_VERBOSE environment flag. + enable_diags = (getenv("FUZZ_VERBOSE") != NULL); + + FUZZ_DEBUG("Input data length: %zd", size); + + if (size < NUM_COMMAND_BYTES) + { + return 0; + } + + // Use the first sizeof(size_t) bytes as load flags. + size_t load_flags = *(const size_t*)data; + data += sizeof(size_t); + + FUZZ_DEBUG("load_flags: 0x%zx\n" + "& JSON_REJECT_DUPLICATES = 0x%zx\n" + "& JSON_DECODE_ANY = 0x%zx\n" + "& JSON_DISABLE_EOF_CHECK = 0x%zx\n" + "& JSON_DECODE_INT_AS_REAL = 0x%zx\n" + "& JSON_ALLOW_NUL = 0x%zx\n", + load_flags, + load_flags & JSON_REJECT_DUPLICATES, + load_flags & JSON_DECODE_ANY, + load_flags & JSON_DISABLE_EOF_CHECK, + load_flags & JSON_DECODE_INT_AS_REAL, + load_flags & JSON_ALLOW_NUL); + + // Use the next sizeof(size_t) bytes as dump flags. + size_t dump_flags = *(const size_t*)data; + data += sizeof(size_t); + + FUZZ_DEBUG("dump_flags: 0x%zx\n" + "& JSON_MAX_INDENT = 0x%zx\n" + "& JSON_COMPACT = 0x%zx\n" + "& JSON_ENSURE_ASCII = 0x%zx\n" + "& JSON_SORT_KEYS = 0x%zx\n" + "& JSON_PRESERVE_ORDER = 0x%zx\n" + "& JSON_ENCODE_ANY = 0x%zx\n" + "& JSON_ESCAPE_SLASH = 0x%zx\n" + "& JSON_REAL_PRECISION = 0x%zx\n" + "& JSON_EMBED = 0x%zx\n", + dump_flags, + dump_flags & JSON_MAX_INDENT, + dump_flags & JSON_COMPACT, + dump_flags & JSON_ENSURE_ASCII, + dump_flags & JSON_SORT_KEYS, + dump_flags & JSON_PRESERVE_ORDER, + dump_flags & JSON_ENCODE_ANY, + dump_flags & JSON_ESCAPE_SLASH, + ((dump_flags >> 11) & 0x1F) << 11, + dump_flags & JSON_EMBED); + + // Use the next byte as the dump mode. + dump_mode = data[0]; + data++; + + FUZZ_DEBUG("dump_mode: 0x%x", (unsigned int)dump_mode); + + // Remove the command bytes from the size total. + size -= NUM_COMMAND_BYTES; + + // Attempt to load the remainder of the data with the given load flags. + const char* text = reinterpret_cast<const char *>(data); + json_t* jobj = json_loadb(text, size, load_flags, &error); + + if (jobj == NULL) + { + return 0; + } + + if (dump_mode & FUZZ_DUMP_STRING) + { + // Dump as a string. Remove indents so that we don't run out of memory. + char *out = json_dumps(jobj, dump_flags & ~JSON_MAX_INDENT); + if (out != NULL) + { + free(out); + } + } + else + { + // Default is callback mode. + // + // Attempt to dump the loaded json object with the given dump flags. + uint64_t counter = 0; + + json_dump_callback(jobj, json_dump_counter, &counter, dump_flags); + FUZZ_DEBUG("Counter function counted %" PRIu64 " bytes.", counter); + } + + if (jobj) + { + json_decref(jobj); + } + + return 0; +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/ossfuzz.sh b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/ossfuzz.sh new file mode 100755 index 000000000..59740c253 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/ossfuzz.sh @@ -0,0 +1,30 @@ +#!/bin/bash -eu + +# This script is called by the oss-fuzz main project when compiling the fuzz +# targets. This script is regression tested by travisoss.sh. + +# Save off the current folder as the build root. +export BUILD_ROOT=$PWD + +echo "CC: $CC" +echo "CXX: $CXX" +echo "LIB_FUZZING_ENGINE: $LIB_FUZZING_ENGINE" +echo "CFLAGS: $CFLAGS" +echo "CXXFLAGS: $CXXFLAGS" +echo "OUT: $OUT" + +export MAKEFLAGS+="-j$(nproc)" + +# Install dependencies +apt-get -y install automake libtool + +# Compile the fuzzer. +autoreconf -i +./configure --enable-ossfuzzers +make + +# Copy the fuzzer to the output directory. +cp -v test/ossfuzz/json_load_dump_fuzzer $OUT/ + +# Zip up all input files to use as a test corpus +find test/suites -name "input" -print | zip $OUT/json_load_dump_fuzzer_seed_corpus.zip -@ diff --git a/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/standaloneengine.cc b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/standaloneengine.cc new file mode 100644 index 000000000..175360e4a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/standaloneengine.cc @@ -0,0 +1,74 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include "testinput.h" + +/** + * Main procedure for standalone fuzzing engine. + * + * Reads filenames from the argument array. For each filename, read the file + * into memory and then call the fuzzing interface with the data. + */ +int main(int argc, char **argv) +{ + int ii; + for(ii = 1; ii < argc; ii++) + { + FILE *infile; + printf("[%s] ", argv[ii]); + + /* Try and open the file. */ + infile = fopen(argv[ii], "rb"); + if(infile) + { + uint8_t *buffer = NULL; + size_t buffer_len; + + printf("Opened.. "); + + /* Get the length of the file. */ + fseek(infile, 0L, SEEK_END); + buffer_len = ftell(infile); + + /* Reset the file indicator to the beginning of the file. */ + fseek(infile, 0L, SEEK_SET); + + /* Allocate a buffer for the file contents. */ + buffer = (uint8_t *)calloc(buffer_len, sizeof(uint8_t)); + if(buffer) + { + /* Read all the text from the file into the buffer. */ + fread(buffer, sizeof(uint8_t), buffer_len, infile); + printf("Read %zu bytes, fuzzing.. ", buffer_len); + + /* Call the fuzzer with the data. */ + LLVMFuzzerTestOneInput(buffer, buffer_len); + + printf("complete !!"); + + /* Free the buffer as it's no longer needed. */ + free(buffer); + buffer = NULL; + } + else + { + fprintf(stderr, + "[%s] Failed to allocate %zu bytes \n", + argv[ii], + buffer_len); + } + + /* Close the file as it's no longer needed. */ + fclose(infile); + infile = NULL; + } + else + { + /* Failed to open the file. Maybe wrong name or wrong permissions? */ + fprintf(stderr, "[%s] Open failed. \n", argv[ii]); + } + + printf("\n"); + } +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/testinput.h b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/testinput.h new file mode 100644 index 000000000..6ab9b515e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/testinput.h @@ -0,0 +1,3 @@ +#include <inttypes.h> + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); diff --git a/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/travisoss.sh b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/travisoss.sh new file mode 100755 index 000000000..ddcfa075a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/ossfuzz/travisoss.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +set -ex + +PROJECT_NAME=jansson + +# Clone the oss-fuzz repository +git clone https://github.com/google/oss-fuzz.git /tmp/ossfuzz + +if [[ ! -d /tmp/ossfuzz/projects/${PROJECT_NAME} ]] +then + echo "Could not find the ${PROJECT_NAME} project in ossfuzz" + + # Exit with a success code while the jansson project is not expected to exist + # on oss-fuzz. + exit 0 +fi + +# Work out which repo to clone from, inside Docker +if [[ ${TRAVIS_PULL_REQUEST} != "false" ]] +then + # Pull-request branch + REPO=${TRAVIS_PULL_REQUEST_SLUG} + BRANCH=${TRAVIS_PULL_REQUEST_BRANCH} +else + # Push build. + REPO=${TRAVIS_REPO_SLUG} + BRANCH=${TRAVIS_BRANCH} +fi + +# Modify the oss-fuzz Dockerfile so that we're checking out the current branch on travis. +sed -i "s@https://github.com/akheron/jansson.git@-b ${BRANCH} https://github.com/${REPO}.git@" /tmp/ossfuzz/projects/${PROJECT_NAME}/Dockerfile + +# Try and build the fuzzers +pushd /tmp/ossfuzz +python infra/helper.py build_image --pull ${PROJECT_NAME} +python infra/helper.py build_fuzzers ${PROJECT_NAME} +popd diff --git a/src/fluent-bit/lib/jansson-e23f558/test/run-suites b/src/fluent-bit/lib/jansson-e23f558/test/run-suites new file mode 100755 index 000000000..fd1b89b5a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/run-suites @@ -0,0 +1,50 @@ +#!/bin/sh + +while [ -n "$1" ]; do + suite=$1 + if [ -x $top_srcdir/test/suites/$suite/run ]; then + SUITES="$SUITES $suite" + else + echo "No such suite: $suite" + exit 1 + fi + shift +done + +if [ -z "$SUITES" ]; then + suitedirs=$top_srcdir/test/suites/* + for suitedir in $suitedirs; do + if [ -d $suitedir ]; then + SUITES="$SUITES `basename $suitedir`" + fi + done +fi + +[ -z "$STOP" ] && STOP=0 + +suites_srcdir=$top_srcdir/test/suites +suites_builddir=suites +scriptdir=$top_srcdir/test/scripts +logdir=logs +bindir=bin +export suites_srcdir suites_builddir scriptdir logdir bindir + +passed=0 +failed=0 +for suite in $SUITES; do + echo "Suite: $suite" + if $suites_srcdir/$suite/run $suite; then + passed=`expr $passed + 1` + else + failed=`expr $failed + 1` + [ $STOP -eq 1 ] && break + fi +done + +if [ $failed -gt 0 ]; then + echo "$failed of `expr $passed + $failed` test suites failed" + exit 1 +else + echo "$passed test suites passed" + rm -rf $logdir +fi diff --git a/src/fluent-bit/lib/jansson-e23f558/test/scripts/run-tests.sh b/src/fluent-bit/lib/jansson-e23f558/test/scripts/run-tests.sh new file mode 100644 index 000000000..f980a7657 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/scripts/run-tests.sh @@ -0,0 +1,100 @@ +# Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +die() { + echo "$1" >&2 + exit 1 +} + +[ -n "$1" ] || die "Usage: $0 suite-name" +[ -n "$bindir" ] || die "Set bindir" +[ -n "$logdir" ] || die "Set logdir" +[ -n "$scriptdir" ] || die "Set scriptdir" +[ -n "$suites_srcdir" ] || die "Set suites_srcdir" +[ -n "$suites_builddir" ] || die "Set suites_builddir" + +json_process=$bindir/json_process + +suite_name=$1 +suite_srcdir=$suites_srcdir/$suite_name +suite_builddir=$suites_builddir/$suite_name +suite_log=$logdir/$suite_name + +[ -z "$VERBOSE" ] && VERBOSE=0 +[ -z "$STOP" ] && STOP=0 + +. $scriptdir/valgrind.sh + +rm -rf $suite_log +mkdir -p $suite_log + +for test_path in $suite_srcdir/*; do + test_name=$(basename $test_path) + test_builddir=$suite_builddir/$test_name + test_log=$suite_log/$test_name + + [ "$test_name" = "run" ] && continue + is_test || continue + + rm -rf $test_log + mkdir -p $test_log + if [ $VERBOSE -eq 1 ]; then + printf '%s... ' "$test_name" + fi + + run_test + case $? in + 0) + # Success + if [ $VERBOSE -eq 1 ]; then + printf 'ok\n' + else + printf '.' + fi + rm -rf $test_log + ;; + + 77) + # Skip + if [ $VERBOSE -eq 1 ]; then + printf 'skipped\n' + else + printf 'S' + fi + rm -rf $test_log + ;; + + *) + # Failure + if [ $VERBOSE -eq 1 ]; then + printf 'FAILED\n' + else + printf 'F' + fi + + [ $STOP -eq 1 ] && break + ;; + esac +done + +if [ $VERBOSE -eq 0 ]; then + printf '\n' +fi + +if [ -n "$(ls -A $suite_log)" ]; then + for test_log in $suite_log/*; do + test_name=$(basename $test_log) + test_path=$suite_srcdir/$test_name + echo "=================================================================" + echo "$suite_name/$test_name" + echo "=================================================================" + show_error + echo + done + echo "=================================================================" + exit 1 +else + rm -rf $suite_log +fi diff --git a/src/fluent-bit/lib/jansson-e23f558/test/scripts/valgrind.sh b/src/fluent-bit/lib/jansson-e23f558/test/scripts/valgrind.sh new file mode 100644 index 000000000..afbdcee15 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/scripts/valgrind.sh @@ -0,0 +1,35 @@ +# Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +[ -z "$VALGRIND" ] && VALGRIND=0 + +VALGRIND_CMDLINE="valgrind --leak-check=full --show-reachable=yes --track-origins=yes -q" + +if [ $VALGRIND -eq 1 ]; then + test_runner="$VALGRIND_CMDLINE" + json_process="$VALGRIND_CMDLINE $json_process" +else + test_runner="" +fi + +valgrind_check() { + if [ $VALGRIND -eq 1 ]; then + # Check for Valgrind error output. The valgrind option + # --error-exitcode is not enough because Valgrind doesn't + # think unfreed allocs are errors. + if grep -E -q '^==[0-9]+== ' $1; then + touch $test_log/valgrind_error + return 1 + fi + fi +} + +valgrind_show_error() { + if [ $VALGRIND -eq 1 -a -f $test_log/valgrind_error ]; then + echo "valgrind detected an error" + return 0 + fi + return 1 +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/.gitattributes b/src/fluent-bit/lib/jansson-e23f558/test/suites/.gitattributes new file mode 100644 index 000000000..68d88612c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/.gitattributes @@ -0,0 +1,2 @@ +api/ text=auto +* text eol=lf
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/Makefile.am b/src/fluent-bit/lib/jansson-e23f558/test/suites/Makefile.am new file mode 100644 index 000000000..a53eb07f1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = api +EXTRA_DIST = invalid invalid-unicode valid diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/Makefile.am b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/Makefile.am new file mode 100644 index 000000000..2bc638b82 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/Makefile.am @@ -0,0 +1,42 @@ +EXTRA_DIST = run check-exports + +check_PROGRAMS = \ + test_array \ + test_chaos \ + test_copy \ + test_dump \ + test_dump_callback \ + test_equal \ + test_fixed_size \ + test_load \ + test_load_callback \ + test_loadb \ + test_memory_funcs \ + test_number \ + test_object \ + test_pack \ + test_simple \ + test_sprintf \ + test_unpack \ + test_version + +test_array_SOURCES = test_array.c util.h +test_chaos_SOURCES = test_chaos.c util.h +test_copy_SOURCES = test_copy.c util.h +test_dump_SOURCES = test_dump.c util.h +test_dump_callback_SOURCES = test_dump_callback.c util.h +test_fixed_size_SOURCES = test_fixed_size.c util.h +test_load_SOURCES = test_load.c util.h +test_loadb_SOURCES = test_loadb.c util.h +test_memory_funcs_SOURCES = test_memory_funcs.c util.h +test_number_SOURCES = test_number.c util.h +test_object_SOURCES = test_object.c util.h +test_pack_SOURCES = test_pack.c util.h +test_simple_SOURCES = test_simple.c util.h +test_sprintf_SOURCES = test_sprintf.c util.h +test_unpack_SOURCES = test_unpack.c util.h +test_version_SOURCES = test_version.c util.h + +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src +LDFLAGS = -static # for speed and Valgrind +LDADD = $(top_builddir)/src/libjansson.la diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/check-exports b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/check-exports new file mode 100755 index 000000000..5c82064c1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/check-exports @@ -0,0 +1,23 @@ +#!/bin/sh +# +# This test checks that libjansson.so exports the correct symbols. +# + +SOFILE="../src/.libs/libjansson.so" + +# The list of symbols, which the shared object should export, is read +# from the def file, which is used in Windows builds +grep 'json_\|jansson_' $top_srcdir/src/jansson.def \ + | sed -e 's/ //g' \ + | sort \ + >$test_log/exports + +nm -D $SOFILE >/dev/null >$test_log/symbols 2>/dev/null \ + || exit 77 # Skip if "nm -D" doesn't seem to work + +grep ' [DT] ' $test_log/symbols | cut -d' ' -f3 | grep -v '^_' | sed 's/@@libjansson.*//' | sort >$test_log/output + +if ! cmp -s $test_log/exports $test_log/output; then + diff -u $test_log/exports $test_log/output >&2 + exit 1 +fi diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/run b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/run new file mode 100755 index 000000000..0c017bca6 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/run @@ -0,0 +1,36 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +is_test() { + case "$test_name" in + *.c|check-exports) + return 0 + ;; + *) + return 1 + ;; + esac +} + +run_test() { + if [ "$test_name" = "check-exports" ]; then + test_log=$test_log $test_path >$test_log/stdout 2>$test_log/stderr + else + $test_runner $suite_builddir/${test_name%.c} \ + >$test_log/stdout \ + 2>$test_log/stderr \ + || return 1 + valgrind_check $test_log/stderr || return 1 + fi +} + +show_error() { + valgrind_show_error && return + cat $test_log/stderr +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_array.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_array.c new file mode 100644 index 000000000..e5d9d1a19 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_array.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> + +static void test_misc(void) { + json_t *array, *five, *seven, *value; + size_t i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if (!array) + fail("unable to create array"); + if (!five || !seven) + fail("unable to create integer"); + + if (json_array_size(array) != 0) + fail("empty array has nonzero size"); + + if (!json_array_append(array, NULL)) + fail("able to append NULL"); + + if (json_array_append(array, five)) + fail("unable to append"); + + if (json_array_size(array) != 1) + fail("wrong array size"); + + value = json_array_get(array, 0); + if (!value) + fail("unable to get item"); + if (value != five) + fail("got wrong value"); + + if (json_array_append(array, seven)) + fail("unable to append value"); + + if (json_array_size(array) != 2) + fail("wrong array size"); + + value = json_array_get(array, 1); + if (!value) + fail("unable to get item"); + if (value != seven) + fail("got wrong value"); + + if (json_array_set(array, 0, seven)) + fail("unable to set value"); + + if (!json_array_set(array, 0, NULL)) + fail("able to set NULL"); + + if (json_array_size(array) != 2) + fail("wrong array size"); + + value = json_array_get(array, 0); + if (!value) + fail("unable to get item"); + if (value != seven) + fail("got wrong value"); + + if (json_array_get(array, 2) != NULL) + fail("able to get value out of bounds"); + + if (!json_array_set(array, 2, seven)) + fail("able to set value out of bounds"); + + for (i = 2; i < 30; i++) { + if (json_array_append(array, seven)) + fail("unable to append value"); + + if (json_array_size(array) != i + 1) + fail("wrong array size"); + } + + for (i = 0; i < 30; i++) { + value = json_array_get(array, i); + if (!value) + fail("unable to get item"); + if (value != seven) + fail("got wrong value"); + } + + if (json_array_set_new(array, 15, json_integer(123))) + fail("unable to set new value"); + + value = json_array_get(array, 15); + if (!json_is_integer(value) || json_integer_value(value) != 123) + fail("json_array_set_new works incorrectly"); + + if (!json_array_set_new(array, 15, NULL)) + fail("able to set_new NULL value"); + + if (json_array_append_new(array, json_integer(321))) + fail("unable to append new value"); + + value = json_array_get(array, json_array_size(array) - 1); + if (!json_is_integer(value) || json_integer_value(value) != 321) + fail("json_array_append_new works incorrectly"); + + if (!json_array_append_new(array, NULL)) + fail("able to append_new NULL value"); + + json_decref(five); + json_decref(seven); + json_decref(array); +} + +static void test_insert(void) { + json_t *array, *five, *seven, *eleven, *value; + int i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + eleven = json_integer(11); + + if (!array) + fail("unable to create array"); + if (!five || !seven || !eleven) + fail("unable to create integer"); + + if (!json_array_insert(array, 1, five)) + fail("able to insert value out of bounds"); + + if (json_array_insert(array, 0, five)) + fail("unable to insert value in an empty array"); + + if (json_array_get(array, 0) != five) + fail("json_array_insert works incorrectly"); + + if (json_array_size(array) != 1) + fail("array size is invalid after insertion"); + + if (json_array_insert(array, 1, seven)) + fail("unable to insert value at the end of an array"); + + if (json_array_get(array, 0) != five) + fail("json_array_insert works incorrectly"); + + if (json_array_get(array, 1) != seven) + fail("json_array_insert works incorrectly"); + + if (json_array_size(array) != 2) + fail("array size is invalid after insertion"); + + if (json_array_insert(array, 1, eleven)) + fail("unable to insert value in the middle of an array"); + + if (json_array_get(array, 0) != five) + fail("json_array_insert works incorrectly"); + + if (json_array_get(array, 1) != eleven) + fail("json_array_insert works incorrectly"); + + if (json_array_get(array, 2) != seven) + fail("json_array_insert works incorrectly"); + + if (json_array_size(array) != 3) + fail("array size is invalid after insertion"); + + if (json_array_insert_new(array, 2, json_integer(123))) + fail("unable to insert value in the middle of an array"); + + value = json_array_get(array, 2); + if (!json_is_integer(value) || json_integer_value(value) != 123) + fail("json_array_insert_new works incorrectly"); + + if (json_array_size(array) != 4) + fail("array size is invalid after insertion"); + + for (i = 0; i < 20; i++) { + if (json_array_insert(array, 0, seven)) + fail("unable to insert value at the beginning of an array"); + } + + for (i = 0; i < 20; i++) { + if (json_array_get(array, i) != seven) + fail("json_aray_insert works incorrectly"); + } + + if (json_array_size(array) != 24) + fail("array size is invalid after loop insertion"); + + json_decref(five); + json_decref(seven); + json_decref(eleven); + json_decref(array); +} + +static void test_remove(void) { + json_t *array, *five, *seven; + int i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if (!array) + fail("unable to create array"); + if (!five) + fail("unable to create integer"); + if (!seven) + fail("unable to create integer"); + + if (!json_array_remove(array, 0)) + fail("able to remove an unexisting index"); + + if (json_array_append(array, five)) + fail("unable to append"); + + if (!json_array_remove(array, 1)) + fail("able to remove an unexisting index"); + + if (json_array_remove(array, 0)) + fail("unable to remove"); + + if (json_array_size(array) != 0) + fail("array size is invalid after removing"); + + if (json_array_append(array, five) || json_array_append(array, seven) || + json_array_append(array, five) || json_array_append(array, seven)) + fail("unable to append"); + + if (json_array_remove(array, 2)) + fail("unable to remove"); + + if (json_array_size(array) != 3) + fail("array size is invalid after removing"); + + if (json_array_get(array, 0) != five || json_array_get(array, 1) != seven || + json_array_get(array, 2) != seven) + fail("remove works incorrectly"); + + json_decref(array); + + array = json_array(); + for (i = 0; i < 4; i++) { + json_array_append(array, five); + json_array_append(array, seven); + } + if (json_array_size(array) != 8) + fail("unable to append 8 items to array"); + + /* Remove an element from a "full" array. */ + json_array_remove(array, 5); + + json_decref(five); + json_decref(seven); + json_decref(array); +} + +static void test_clear(void) { + json_t *array, *five, *seven; + int i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if (!array) + fail("unable to create array"); + if (!five || !seven) + fail("unable to create integer"); + + for (i = 0; i < 10; i++) { + if (json_array_append(array, five)) + fail("unable to append"); + } + for (i = 0; i < 10; i++) { + if (json_array_append(array, seven)) + fail("unable to append"); + } + + if (json_array_size(array) != 20) + fail("array size is invalid after appending"); + + if (json_array_clear(array)) + fail("unable to clear"); + + if (json_array_size(array) != 0) + fail("array size is invalid after clearing"); + + json_decref(five); + json_decref(seven); + json_decref(array); +} + +static void test_extend(void) { + json_t *array1, *array2, *five, *seven; + int i; + + array1 = json_array(); + array2 = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if (!array1 || !array2) + fail("unable to create array"); + if (!five || !seven) + fail("unable to create integer"); + + for (i = 0; i < 10; i++) { + if (json_array_append(array1, five)) + fail("unable to append"); + } + for (i = 0; i < 10; i++) { + if (json_array_append(array2, seven)) + fail("unable to append"); + } + + if (json_array_size(array1) != 10 || json_array_size(array2) != 10) + fail("array size is invalid after appending"); + + if (json_array_extend(array1, array2)) + fail("unable to extend"); + + for (i = 0; i < 10; i++) { + if (json_array_get(array1, i) != five) + fail("invalid array contents after extending"); + } + for (i = 10; i < 20; i++) { + if (json_array_get(array1, i) != seven) + fail("invalid array contents after extending"); + } + + json_decref(five); + json_decref(seven); + json_decref(array1); + json_decref(array2); +} + +static void test_circular() { + json_t *array1, *array2; + + /* the simple cases are checked */ + + array1 = json_array(); + if (!array1) + fail("unable to create array"); + + if (json_array_append(array1, array1) == 0) + fail("able to append self"); + + if (json_array_insert(array1, 0, array1) == 0) + fail("able to insert self"); + + if (json_array_append_new(array1, json_true())) + fail("failed to append true"); + + if (json_array_set(array1, 0, array1) == 0) + fail("able to set self"); + + json_decref(array1); + + /* create circular references */ + + array1 = json_array(); + array2 = json_array(); + if (!array1 || !array2) + fail("unable to create array"); + + if (json_array_append(array1, array2) || json_array_append(array2, array1)) + fail("unable to append"); + + /* circularity is detected when dumping */ + if (json_dumps(array1, 0) != NULL) + fail("able to dump circulars"); + + /* decref twice to deal with the circular references */ + json_decref(array1); + json_decref(array2); + json_decref(array1); +} + +static void test_array_foreach() { + size_t index; + json_t *array1, *array2, *value; + + array1 = json_pack("[sisisi]", "foo", 1, "bar", 2, "baz", 3); + array2 = json_array(); + + json_array_foreach(array1, index, value) { json_array_append(array2, value); } + + if (!json_equal(array1, array2)) + fail("json_array_foreach failed to iterate all elements"); + + json_decref(array1); + json_decref(array2); +} + +static void test_bad_args(void) { + json_t *arr = json_array(); + json_t *num = json_integer(1); + + if (!arr || !num) + fail("failed to create required objects"); + + if (json_array_size(NULL) != 0) + fail("NULL array has nonzero size"); + if (json_array_size(num) != 0) + fail("non-array has nonzero array size"); + + if (json_array_get(NULL, 0)) + fail("json_array_get did not return NULL for non-array"); + if (json_array_get(num, 0)) + fail("json_array_get did not return NULL for non-array"); + + if (!json_array_set_new(NULL, 0, json_incref(num))) + fail("json_array_set_new did not return error for non-array"); + if (!json_array_set_new(num, 0, json_incref(num))) + fail("json_array_set_new did not return error for non-array"); + if (!json_array_set_new(arr, 0, NULL)) + fail("json_array_set_new did not return error for NULL value"); + if (!json_array_set_new(arr, 0, json_incref(arr))) + fail("json_array_set_new did not return error for value == array"); + + if (!json_array_remove(NULL, 0)) + fail("json_array_remove did not return error for non-array"); + if (!json_array_remove(num, 0)) + fail("json_array_remove did not return error for non-array"); + + if (!json_array_clear(NULL)) + fail("json_array_clear did not return error for non-array"); + if (!json_array_clear(num)) + fail("json_array_clear did not return error for non-array"); + + if (!json_array_append_new(NULL, json_incref(num))) + fail("json_array_append_new did not return error for non-array"); + if (!json_array_append_new(num, json_incref(num))) + fail("json_array_append_new did not return error for non-array"); + if (!json_array_append_new(arr, NULL)) + fail("json_array_append_new did not return error for NULL value"); + if (!json_array_append_new(arr, json_incref(arr))) + fail("json_array_append_new did not return error for value == array"); + + if (!json_array_insert_new(NULL, 0, json_incref(num))) + fail("json_array_insert_new did not return error for non-array"); + if (!json_array_insert_new(num, 0, json_incref(num))) + fail("json_array_insert_new did not return error for non-array"); + if (!json_array_insert_new(arr, 0, NULL)) + fail("json_array_insert_new did not return error for NULL value"); + if (!json_array_insert_new(arr, 0, json_incref(arr))) + fail("json_array_insert_new did not return error for value == array"); + + if (!json_array_extend(NULL, arr)) + fail("json_array_extend did not return error for first argument " + "non-array"); + if (!json_array_extend(num, arr)) + fail("json_array_extend did not return error for first argument " + "non-array"); + if (!json_array_extend(arr, NULL)) + fail("json_array_extend did not return error for second argument " + "non-array"); + if (!json_array_extend(arr, num)) + fail("json_array_extend did not return error for second argument " + "non-array"); + + if (num->refcount != 1) + fail("unexpected reference count on num"); + if (arr->refcount != 1) + fail("unexpected reference count on arr"); + + json_decref(num); + json_decref(arr); +} + +static void run_tests() { + test_misc(); + test_insert(); + test_remove(); + test_clear(); + test_extend(); + test_circular(); + test_array_foreach(); + test_bad_args(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_chaos.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_chaos.c new file mode 100644 index 000000000..8687243ed --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_chaos.c @@ -0,0 +1,168 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "util.h" +#include <jansson.h> +#include <stdio.h> +#include <string.h> + +static int chaos_pos = 0; +static int chaos_fail = 0; +#define CHAOS_MAX_FAILURE 100 + +void *chaos_malloc(size_t size) { + if (chaos_pos == chaos_fail) + return NULL; + + chaos_pos++; + + return malloc(size); +} + +void chaos_free(void *obj) { free(obj); } + +/* Test all potential allocation failures. */ +#define chaos_loop(condition, code, cleanup) \ + { \ + chaos_pos = chaos_fail = 0; \ + while (condition) { \ + if (chaos_fail > CHAOS_MAX_FAILURE) \ + fail("too many chaos failures"); \ + code chaos_pos = 0; \ + chaos_fail++; \ + } \ + cleanup \ + } + +#define chaos_loop_new_value(json, initcall) \ + chaos_loop(!json, json = initcall;, json_decref(json); json = NULL;) + +int test_unpack() { + int ret = -1; + int v1; + int v2; + json_error_t error; + json_t *root = json_pack("{s:i, s:i, s:i, s:i}", "n1", 1, "n2", 2, "n3", 3, "n4", 4); + + if (!root) + return -1; + + if (!json_unpack_ex(root, &error, JSON_STRICT, "{s:i, s:i}", "n1", &v1, "n2", &v2)) + fail("Unexpected success"); + + if (json_error_code(&error) != json_error_end_of_input_expected) { + if (json_error_code(&error) != json_error_out_of_memory) + fail("Unexpected error code"); + + goto out; + } + + if (strcmp(error.text, "2 object item(s) left unpacked: n3, n4")) + goto out; + + ret = 0; + +out: + json_decref(root); + return ret; +} + +int dump_chaos_callback(const char *buffer, size_t size, void *data) { + json_t *obj = json_object(); + + (void)buffer; + (void)size; + (void)data; + + if (!obj) + return -1; + + json_decref(obj); + + return 0; +} + +static void test_chaos() { + json_malloc_t orig_malloc; + json_free_t orig_free; + json_t *json = NULL; + json_t *obj = json_object(); + json_t *arr1 = json_array(); + json_t *arr2 = json_array(); + json_t *txt = json_string("test"); + json_t *intnum = json_integer(1); + json_t *dblnum = json_real(0.5); + char *dumptxt = NULL; + json_t *dumpobj = json_pack("{s:[iiis], s:s}", "key1", 1, 2, 3, "txt", "key2", "v2"); + int keyno; + + if (!obj || !arr1 || !arr2 || !txt || !intnum || !dblnum || !dumpobj) + fail("failed to allocate basic objects"); + + json_get_alloc_funcs(&orig_malloc, &orig_free); + json_set_alloc_funcs(chaos_malloc, chaos_free); + + chaos_loop_new_value(json, json_pack("{s:s}", "key", "value")); + chaos_loop_new_value(json, json_pack("{s:[]}", "key")); + chaos_loop_new_value(json, json_pack("[biIf]", 1, 1, (json_int_t)1, 1.0)); + chaos_loop_new_value(json, json_pack("[s*,s*]", "v1", "v2")); + chaos_loop_new_value(json, json_pack("o", json_incref(txt))); + chaos_loop_new_value(json, json_pack("O", txt)); + chaos_loop_new_value(json, json_pack("s++", "a", "long string to force realloc", + "another long string to force yet another " + "reallocation of the string because " + "that's what we are testing.")); + + chaos_loop(test_unpack(), , ); + + chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1)), + , ); + chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, + JSON_INDENT(1) | JSON_SORT_KEYS), + , ); + chaos_loop(!dumptxt, dumptxt = json_dumps(dumpobj, JSON_COMPACT);, free(dumptxt); + dumptxt = NULL;); + + chaos_loop_new_value(json, json_copy(obj)); + chaos_loop_new_value(json, json_deep_copy(obj)); + + chaos_loop_new_value(json, json_copy(arr1)); + chaos_loop_new_value(json, json_deep_copy(arr1)); + + chaos_loop_new_value(json, json_copy(txt)); + chaos_loop_new_value(json, json_copy(intnum)); + chaos_loop_new_value(json, json_copy(dblnum)); + +#define JSON_LOAD_TXT "{\"n\":[1,2,3,4,5,6,7,8,9,10]}" + chaos_loop_new_value(json, json_loads(JSON_LOAD_TXT, 0, NULL)); + chaos_loop_new_value(json, json_loadb(JSON_LOAD_TXT, strlen(JSON_LOAD_TXT), 0, NULL)); + + chaos_loop_new_value(json, json_sprintf("%s", "string")); + + for (keyno = 0; keyno < 100; ++keyno) { +#if !defined(_MSC_VER) || _MSC_VER >= 1900 + /* Skip this test on old Windows compilers. */ + char testkey[10]; + + snprintf(testkey, sizeof(testkey), "test%d", keyno); + chaos_loop(json_object_set_new_nocheck(obj, testkey, json_object()), , ); +#endif + chaos_loop(json_array_append_new(arr1, json_null()), , ); + chaos_loop(json_array_insert_new(arr2, 0, json_null()), , ); + } + + chaos_loop(json_array_extend(arr1, arr2), , ); + chaos_loop(json_string_set_nocheck(txt, "test"), , ); + + json_set_alloc_funcs(orig_malloc, orig_free); + json_decref(obj); + json_decref(arr1); + json_decref(arr2); + json_decref(txt); + json_decref(intnum); + json_decref(dblnum); + json_decref(dumpobj); +} + +static void run_tests() { test_chaos(); } diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_copy.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_copy.c new file mode 100644 index 000000000..656d98dd7 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_copy.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <string.h> + +static void test_copy_simple(void) { + json_t *value, *copy; + + if (json_copy(NULL)) + fail("copying NULL doesn't return NULL"); + + /* true */ + value = json_true(); + copy = json_copy(value); + if (value != copy) + fail("copying true failed"); + json_decref(value); + json_decref(copy); + + /* false */ + value = json_false(); + copy = json_copy(value); + if (value != copy) + fail("copying false failed"); + json_decref(value); + json_decref(copy); + + /* null */ + value = json_null(); + copy = json_copy(value); + if (value != copy) + fail("copying null failed"); + json_decref(value); + json_decref(copy); + + /* string */ + value = json_string("foo"); + if (!value) + fail("unable to create a string"); + copy = json_copy(value); + if (!copy) + fail("unable to copy a string"); + if (copy == value) + fail("copying a string doesn't copy"); + if (!json_equal(copy, value)) + fail("copying a string produces an inequal copy"); + if (value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); + + /* integer */ + value = json_integer(543); + if (!value) + fail("unable to create an integer"); + copy = json_copy(value); + if (!copy) + fail("unable to copy an integer"); + if (copy == value) + fail("copying an integer doesn't copy"); + if (!json_equal(copy, value)) + fail("copying an integer produces an inequal copy"); + if (value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); + + /* real */ + value = json_real(123e9); + if (!value) + fail("unable to create a real"); + copy = json_copy(value); + if (!copy) + fail("unable to copy a real"); + if (copy == value) + fail("copying a real doesn't copy"); + if (!json_equal(copy, value)) + fail("copying a real produces an inequal copy"); + if (value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); +} + +static void test_deep_copy_simple(void) { + json_t *value, *copy; + + if (json_deep_copy(NULL)) + fail("deep copying NULL doesn't return NULL"); + + /* true */ + value = json_true(); + copy = json_deep_copy(value); + if (value != copy) + fail("deep copying true failed"); + json_decref(value); + json_decref(copy); + + /* false */ + value = json_false(); + copy = json_deep_copy(value); + if (value != copy) + fail("deep copying false failed"); + json_decref(value); + json_decref(copy); + + /* null */ + value = json_null(); + copy = json_deep_copy(value); + if (value != copy) + fail("deep copying null failed"); + json_decref(value); + json_decref(copy); + + /* string */ + value = json_string("foo"); + if (!value) + fail("unable to create a string"); + copy = json_deep_copy(value); + if (!copy) + fail("unable to deep copy a string"); + if (copy == value) + fail("deep copying a string doesn't copy"); + if (!json_equal(copy, value)) + fail("deep copying a string produces an inequal copy"); + if (value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); + + /* integer */ + value = json_integer(543); + if (!value) + fail("unable to create an integer"); + copy = json_deep_copy(value); + if (!copy) + fail("unable to deep copy an integer"); + if (copy == value) + fail("deep copying an integer doesn't copy"); + if (!json_equal(copy, value)) + fail("deep copying an integer produces an inequal copy"); + if (value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); + + /* real */ + value = json_real(123e9); + if (!value) + fail("unable to create a real"); + copy = json_deep_copy(value); + if (!copy) + fail("unable to deep copy a real"); + if (copy == value) + fail("deep copying a real doesn't copy"); + if (!json_equal(copy, value)) + fail("deep copying a real produces an inequal copy"); + if (value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); +} + +static void test_copy_array(void) { + const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]"; + + json_t *array, *copy; + size_t i; + + array = json_loads(json_array_text, 0, NULL); + if (!array) + fail("unable to parse an array"); + + copy = json_copy(array); + if (!copy) + fail("unable to copy an array"); + if (copy == array) + fail("copying an array doesn't copy"); + if (!json_equal(copy, array)) + fail("copying an array produces an inequal copy"); + + for (i = 0; i < json_array_size(copy); i++) { + if (json_array_get(array, i) != json_array_get(copy, i)) + fail("copying an array modifies its elements"); + } + + json_decref(array); + json_decref(copy); +} + +static void test_deep_copy_array(void) { + const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]"; + + json_t *array, *copy; + size_t i; + + array = json_loads(json_array_text, 0, NULL); + if (!array) + fail("unable to parse an array"); + + copy = json_deep_copy(array); + if (!copy) + fail("unable to deep copy an array"); + if (copy == array) + fail("deep copying an array doesn't copy"); + if (!json_equal(copy, array)) + fail("deep copying an array produces an inequal copy"); + + for (i = 0; i < json_array_size(copy); i++) { + if (json_array_get(array, i) == json_array_get(copy, i)) + fail("deep copying an array doesn't copy its elements"); + } + + json_decref(array); + json_decref(copy); +} + +static void test_copy_object(void) { + const char *json_object_text = + "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}"; + + const char *keys[] = {"foo", "a", "b", "c"}; + int i; + + json_t *object, *copy; + void *iter; + + object = json_loads(json_object_text, 0, NULL); + if (!object) + fail("unable to parse an object"); + + copy = json_copy(object); + if (!copy) + fail("unable to copy an object"); + if (copy == object) + fail("copying an object doesn't copy"); + if (!json_equal(copy, object)) + fail("copying an object produces an inequal copy"); + + i = 0; + iter = json_object_iter(object); + while (iter) { + const char *key; + json_t *value1, *value2; + + key = json_object_iter_key(iter); + value1 = json_object_iter_value(iter); + value2 = json_object_get(copy, key); + + if (value1 != value2) + fail("copying an object modifies its items"); + + if (strcmp(key, keys[i]) != 0) + fail("copying an object doesn't preserve key order"); + + iter = json_object_iter_next(object, iter); + i++; + } + + json_decref(object); + json_decref(copy); +} + +static void test_deep_copy_object(void) { + const char *json_object_text = + "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}"; + + const char *keys[] = {"foo", "a", "b", "c"}; + int i; + + json_t *object, *copy; + void *iter; + + object = json_loads(json_object_text, 0, NULL); + if (!object) + fail("unable to parse an object"); + + copy = json_deep_copy(object); + if (!copy) + fail("unable to deep copy an object"); + if (copy == object) + fail("deep copying an object doesn't copy"); + if (!json_equal(copy, object)) + fail("deep copying an object produces an inequal copy"); + + i = 0; + iter = json_object_iter(object); + while (iter) { + const char *key; + json_t *value1, *value2; + + key = json_object_iter_key(iter); + value1 = json_object_iter_value(iter); + value2 = json_object_get(copy, key); + + if (value1 == value2) + fail("deep copying an object doesn't copy its items"); + + if (strcmp(key, keys[i]) != 0) + fail("deep copying an object doesn't preserve key order"); + + iter = json_object_iter_next(object, iter); + i++; + } + + json_decref(object); + json_decref(copy); +} + +static void test_deep_copy_circular_references(void) { + /* Construct a JSON object/array with a circular reference: + + object: {"a": {"b": {"c": <circular reference to $.a>}}} + array: [[[<circular reference to the $[0] array>]]] + + Deep copy it, remove the circular reference and deep copy again. + */ + + json_t *json; + json_t *copy; + + json = json_object(); + json_object_set_new(json, "a", json_object()); + json_object_set_new(json_object_get(json, "a"), "b", json_object()); + json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c", + json_object_get(json, "a")); + + copy = json_deep_copy(json); + if (copy) + fail("json_deep_copy copied a circular reference!"); + + json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c"); + + copy = json_deep_copy(json); + if (!copy) + fail("json_deep_copy failed!"); + + json_decref(copy); + json_decref(json); + + json = json_array(); + json_array_append_new(json, json_array()); + json_array_append_new(json_array_get(json, 0), json_array()); + json_array_append(json_array_get(json_array_get(json, 0), 0), + json_array_get(json, 0)); + + copy = json_deep_copy(json); + if (copy) + fail("json_deep_copy copied a circular reference!"); + + json_array_remove(json_array_get(json_array_get(json, 0), 0), 0); + + copy = json_deep_copy(json); + if (!copy) + fail("json_deep_copy failed!"); + + json_decref(copy); + json_decref(json); +} + +static void run_tests() { + test_copy_simple(); + test_deep_copy_simple(); + test_copy_array(); + test_deep_copy_array(); + test_copy_object(); + test_deep_copy_object(); + test_deep_copy_circular_references(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_dump.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_dump.c new file mode 100644 index 000000000..e8cb51962 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_dump.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "jansson_private_config.h" + +#include <jansson.h> +#include <string.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include "util.h" +#ifdef __MINGW32__ +#include <fcntl.h> +#define pipe(fds) _pipe(fds, 1024, _O_BINARY) +#endif + +static int encode_null_callback(const char *buffer, size_t size, void *data) { + (void)buffer; + (void)size; + (void)data; + return 0; +} + +static void encode_null() { + if (json_dumps(NULL, JSON_ENCODE_ANY) != NULL) + fail("json_dumps didn't fail for NULL"); + + if (json_dumpb(NULL, NULL, 0, JSON_ENCODE_ANY) != 0) + fail("json_dumpb didn't fail for NULL"); + + if (json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1) + fail("json_dumpf didn't fail for NULL"); + +#ifdef HAVE_UNISTD_H + if (json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1) + fail("json_dumpfd didn't fail for NULL"); +#endif + + /* Don't test json_dump_file to avoid creating a file */ + + if (json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1) + fail("json_dump_callback didn't fail for NULL"); +} + +static void encode_twice() { + /* Encode an empty object/array, add an item, encode again */ + + json_t *json; + char *result; + + json = json_object(); + result = json_dumps(json, 0); + if (!result || strcmp(result, "{}")) + fail("json_dumps failed"); + free(result); + + json_object_set_new(json, "foo", json_integer(5)); + result = json_dumps(json, 0); + if (!result || strcmp(result, "{\"foo\": 5}")) + fail("json_dumps failed"); + free(result); + + json_decref(json); + + json = json_array(); + result = json_dumps(json, 0); + if (!result || strcmp(result, "[]")) + fail("json_dumps failed"); + free(result); + + json_array_append_new(json, json_integer(5)); + result = json_dumps(json, 0); + if (!result || strcmp(result, "[5]")) + fail("json_dumps failed"); + free(result); + + json_decref(json); +} + +static void circular_references() { + /* Construct a JSON object/array with a circular reference: + + object: {"a": {"b": {"c": <circular reference to $.a>}}} + array: [[[<circular reference to the $[0] array>]]] + + Encode it, remove the circular reference and encode again. + */ + + json_t *json; + char *result; + + json = json_object(); + json_object_set_new(json, "a", json_object()); + json_object_set_new(json_object_get(json, "a"), "b", json_object()); + json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c", + json_object_get(json, "a")); + + if (json_dumps(json, 0)) + fail("json_dumps encoded a circular reference!"); + + json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c"); + + result = json_dumps(json, 0); + if (!result || strcmp(result, "{\"a\": {\"b\": {}}}")) + fail("json_dumps failed!"); + free(result); + + json_decref(json); + + json = json_array(); + json_array_append_new(json, json_array()); + json_array_append_new(json_array_get(json, 0), json_array()); + json_array_append(json_array_get(json_array_get(json, 0), 0), + json_array_get(json, 0)); + + if (json_dumps(json, 0)) + fail("json_dumps encoded a circular reference!"); + + json_array_remove(json_array_get(json_array_get(json, 0), 0), 0); + + result = json_dumps(json, 0); + if (!result || strcmp(result, "[[[]]]")) + fail("json_dumps failed!"); + free(result); + + json_decref(json); +} + +static void encode_other_than_array_or_object() { + /* Encoding anything other than array or object should only + * succeed if the JSON_ENCODE_ANY flag is used */ + + json_t *json; + char *result; + + json = json_string("foo"); + if (json_dumps(json, 0) != NULL) + fail("json_dumps encoded a string!"); + if (json_dumpf(json, NULL, 0) == 0) + fail("json_dumpf encoded a string!"); + if (json_dumpfd(json, -1, 0) == 0) + fail("json_dumpfd encoded a string!"); + + result = json_dumps(json, JSON_ENCODE_ANY); + if (!result || strcmp(result, "\"foo\"") != 0) + fail("json_dumps failed to encode a string with JSON_ENCODE_ANY"); + + free(result); + json_decref(json); + + json = json_integer(42); + if (json_dumps(json, 0) != NULL) + fail("json_dumps encoded an integer!"); + if (json_dumpf(json, NULL, 0) == 0) + fail("json_dumpf encoded an integer!"); + if (json_dumpfd(json, -1, 0) == 0) + fail("json_dumpfd encoded an integer!"); + + result = json_dumps(json, JSON_ENCODE_ANY); + if (!result || strcmp(result, "42") != 0) + fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY"); + + free(result); + json_decref(json); +} + +static void escape_slashes() { + /* Test dump escaping slashes */ + + json_t *json; + char *result; + + json = json_object(); + json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson")); + + result = json_dumps(json, 0); + if (!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}")) + fail("json_dumps failed to not escape slashes"); + + free(result); + + result = json_dumps(json, JSON_ESCAPE_SLASH); + if (!result || + strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}")) + fail("json_dumps failed to escape slashes"); + + free(result); + json_decref(json); +} + +static void encode_nul_byte() { + json_t *json; + char *result; + + json = json_stringn("nul byte \0 in string", 20); + result = json_dumps(json, JSON_ENCODE_ANY); + if (!result || memcmp(result, "\"nul byte \\u0000 in string\"", 27)) + fail("json_dumps failed to dump an embedded NUL byte"); + + free(result); + json_decref(json); +} + +static void dump_file() { + json_t *json; + int result; + + result = json_dump_file(NULL, "", 0); + if (result != -1) + fail("json_dump_file succeeded with invalid args"); + + json = json_object(); + result = json_dump_file(json, "json_dump_file.json", 0); + if (result != 0) + fail("json_dump_file failed"); + + json_decref(json); + remove("json_dump_file.json"); +} + +static void dumpb() { + char buf[2]; + json_t *obj; + size_t size; + + obj = json_object(); + + size = json_dumpb(obj, buf, sizeof(buf), 0); + if (size != 2 || strncmp(buf, "{}", 2)) + fail("json_dumpb failed"); + + json_decref(obj); + obj = json_pack("{s:s}", "foo", "bar"); + + size = json_dumpb(obj, buf, sizeof(buf), JSON_COMPACT); + if (size != 13) + fail("json_dumpb size check failed"); + + json_decref(obj); +} + +static void dumpfd() { +#ifdef HAVE_UNISTD_H + int fds[2] = {-1, -1}; + json_t *a, *b; + + if (pipe(fds)) + fail("pipe() failed"); + + a = json_pack("{s:s}", "foo", "bar"); + + if (json_dumpfd(a, fds[1], 0)) + fail("json_dumpfd() failed"); + close(fds[1]); + + b = json_loadfd(fds[0], 0, NULL); + if (!b) + fail("json_loadfd() failed"); + close(fds[0]); + + if (!json_equal(a, b)) + fail("json_equal() failed for fd test"); + + json_decref(a); + json_decref(b); +#endif +} + +static void embed() { + static const char *plains[] = {"{\"bar\":[],\"foo\":{}}", "[[],{}]", "{}", "[]", + NULL}; + + size_t i; + + for (i = 0; plains[i]; i++) { + const char *plain = plains[i]; + json_t *parse = NULL; + char *embed = NULL; + size_t psize = 0; + size_t esize = 0; + + psize = strlen(plain) - 2; + embed = calloc(1, psize); + parse = json_loads(plain, 0, NULL); + esize = + json_dumpb(parse, embed, psize, JSON_COMPACT | JSON_SORT_KEYS | JSON_EMBED); + json_decref(parse); + if (esize != psize) + fail("json_dumpb(JSON_EMBED) returned an invalid size"); + if (strncmp(plain + 1, embed, esize) != 0) + fail("json_dumps(JSON_EMBED) returned an invalid value"); + free(embed); + } +} + +static void run_tests() { + encode_null(); + encode_twice(); + circular_references(); + encode_other_than_array_or_object(); + escape_slashes(); + encode_nul_byte(); + dump_file(); + dumpb(); + dumpfd(); + embed(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_dump_callback.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_dump_callback.c new file mode 100644 index 000000000..80ea00845 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_dump_callback.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <stdlib.h> +#include <string.h> + +struct my_sink { + char *buf; + size_t off; + size_t cap; +}; + +static int my_writer(const char *buffer, size_t len, void *data) { + struct my_sink *s = data; + if (len > s->cap - s->off) { + return -1; + } + memcpy(s->buf + s->off, buffer, len); + s->off += len; + return 0; +} + +static void run_tests() { + struct my_sink s; + json_t *json; + const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]"; + char *dumped_to_string; + + json = json_loads(str, 0, NULL); + if (!json) { + fail("json_loads failed"); + } + + dumped_to_string = json_dumps(json, 0); + if (!dumped_to_string) { + json_decref(json); + fail("json_dumps failed"); + } + + s.off = 0; + s.cap = strlen(dumped_to_string); + s.buf = malloc(s.cap); + if (!s.buf) { + json_decref(json); + free(dumped_to_string); + fail("malloc failed"); + } + + if (json_dump_callback(json, my_writer, &s, 0) == -1) { + json_decref(json); + free(dumped_to_string); + free(s.buf); + fail("json_dump_callback failed on an exact-length sink buffer"); + } + + if (strncmp(dumped_to_string, s.buf, s.off) != 0) { + json_decref(json); + free(dumped_to_string); + free(s.buf); + fail("json_dump_callback and json_dumps did not produce identical " + "output"); + } + + s.off = 1; + if (json_dump_callback(json, my_writer, &s, 0) != -1) { + json_decref(json); + free(dumped_to_string); + free(s.buf); + fail("json_dump_callback succeeded on a short buffer when it should " + "have failed"); + } + + json_decref(json); + free(dumped_to_string); + free(s.buf); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_equal.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_equal.c new file mode 100644 index 000000000..d068b7bf8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_equal.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> + +static void test_equal_simple() { + json_t *value1, *value2; + + if (json_equal(NULL, NULL)) + fail("json_equal fails for two NULLs"); + + value1 = json_true(); + if (json_equal(value1, NULL) || json_equal(NULL, value1)) + fail("json_equal fails for NULL"); + + /* this covers true, false and null as they are singletons */ + if (!json_equal(value1, value1)) + fail("identical objects are not equal"); + json_decref(value1); + + /* integer */ + value1 = json_integer(1); + value2 = json_integer(1); + if (!value1 || !value2) + fail("unable to create integers"); + if (!json_equal(value1, value2)) + fail("json_equal fails for two equal integers"); + json_decref(value2); + + value2 = json_integer(2); + if (!value2) + fail("unable to create an integer"); + if (json_equal(value1, value2)) + fail("json_equal fails for two inequal integers"); + + json_decref(value1); + json_decref(value2); + + /* real */ + value1 = json_real(1.2); + value2 = json_real(1.2); + if (!value1 || !value2) + fail("unable to create reals"); + if (!json_equal(value1, value2)) + fail("json_equal fails for two equal reals"); + json_decref(value2); + + value2 = json_real(3.141592); + if (!value2) + fail("unable to create an real"); + if (json_equal(value1, value2)) + fail("json_equal fails for two inequal reals"); + + json_decref(value1); + json_decref(value2); + + /* string */ + value1 = json_string("foo"); + value2 = json_string("foo"); + if (!value1 || !value2) + fail("unable to create strings"); + if (!json_equal(value1, value2)) + fail("json_equal fails for two equal strings"); + json_decref(value2); + + value2 = json_string("bar"); + if (!value2) + fail("unable to create an string"); + if (json_equal(value1, value2)) + fail("json_equal fails for two inequal strings"); + json_decref(value2); + + value2 = json_string("bar2"); + if (!value2) + fail("unable to create an string"); + if (json_equal(value1, value2)) + fail("json_equal fails for two inequal length strings"); + + json_decref(value1); + json_decref(value2); +} + +static void test_equal_array() { + json_t *array1, *array2; + + array1 = json_array(); + array2 = json_array(); + if (!array1 || !array2) + fail("unable to create arrays"); + + if (!json_equal(array1, array2)) + fail("json_equal fails for two empty arrays"); + + json_array_append_new(array1, json_integer(1)); + json_array_append_new(array2, json_integer(1)); + json_array_append_new(array1, json_string("foo")); + json_array_append_new(array2, json_string("foo")); + json_array_append_new(array1, json_integer(2)); + json_array_append_new(array2, json_integer(2)); + if (!json_equal(array1, array2)) + fail("json_equal fails for two equal arrays"); + + json_array_remove(array2, 2); + if (json_equal(array1, array2)) + fail("json_equal fails for two inequal arrays"); + + json_array_append_new(array2, json_integer(3)); + if (json_equal(array1, array2)) + fail("json_equal fails for two inequal arrays"); + + json_decref(array1); + json_decref(array2); +} + +static void test_equal_object() { + json_t *object1, *object2; + + object1 = json_object(); + object2 = json_object(); + if (!object1 || !object2) + fail("unable to create objects"); + + if (!json_equal(object1, object2)) + fail("json_equal fails for two empty objects"); + + json_object_set_new(object1, "a", json_integer(1)); + json_object_set_new(object2, "a", json_integer(1)); + json_object_set_new(object1, "b", json_string("foo")); + json_object_set_new(object2, "b", json_string("foo")); + json_object_set_new(object1, "c", json_integer(2)); + json_object_set_new(object2, "c", json_integer(2)); + if (!json_equal(object1, object2)) + fail("json_equal fails for two equal objects"); + + json_object_del(object2, "c"); + if (json_equal(object1, object2)) + fail("json_equal fails for two inequal objects"); + + json_object_set_new(object2, "c", json_integer(3)); + if (json_equal(object1, object2)) + fail("json_equal fails for two inequal objects"); + + json_object_del(object2, "c"); + json_object_set_new(object2, "d", json_integer(2)); + if (json_equal(object1, object2)) + fail("json_equal fails for two inequal objects"); + + json_decref(object1); + json_decref(object2); +} + +static void test_equal_complex() { + json_t *value1, *value2, *value3; + + const char *complex_json = "{" + " \"integer\": 1, " + " \"real\": 3.141592, " + " \"string\": \"foobar\", " + " \"true\": true, " + " \"object\": {" + " \"array-in-object\": [1,true,\"foo\",{}]," + " \"object-in-object\": {\"foo\": \"bar\"}" + " }," + " \"array\": [\"foo\", false, null, 1.234]" + "}"; + + value1 = json_loads(complex_json, 0, NULL); + value2 = json_loads(complex_json, 0, NULL); + value3 = json_loads(complex_json, 0, NULL); + if (!value1 || !value2) + fail("unable to parse JSON"); + if (!json_equal(value1, value2)) + fail("json_equal fails for two equal objects"); + + json_array_set_new( + json_object_get(json_object_get(value2, "object"), "array-in-object"), 1, + json_false()); + if (json_equal(value1, value2)) + fail("json_equal fails for two inequal objects"); + + json_object_set_new( + json_object_get(json_object_get(value3, "object"), "object-in-object"), "foo", + json_string("baz")); + if (json_equal(value1, value3)) + fail("json_equal fails for two inequal objects"); + + json_decref(value1); + json_decref(value2); + json_decref(value3); +} + +static void run_tests() { + test_equal_simple(); + test_equal_array(); + test_equal_object(); + test_equal_complex(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_fixed_size.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_fixed_size.c new file mode 100644 index 000000000..4ae9e079c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_fixed_size.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2020 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <string.h> + +static void test_keylen_iterator(json_t *object) { + const char key1[] = {'t', 'e', 's', 't', '1'}; + const char key2[] = {'t', 'e', 's', 't'}; + const char key3[] = {'t', 'e', 's', '\0', 't'}; + const char key4[] = {'t', 'e', 's', 't', '\0'}; + const char *reference_keys[] = {key1, key2, key3, key4}; + const size_t reference_keys_len[] = {sizeof(key1), sizeof(key2), sizeof(key3), + sizeof(key4)}; + size_t index = 0; + json_t *value; + const char *key; + size_t keylen; + + json_object_keylen_foreach(object, key, keylen, value) { + if (keylen != reference_keys_len[index]) + fail("invalid key len in iterator"); + if (memcmp(key, reference_keys[index], reference_keys_len[index]) != 0) + fail("invalid key in iterator"); + + index++; + } +} + +static void test_keylen(void) { + json_t *obj = json_object(); + const char key[] = {'t', 'e', 's', 't', '1'}; + const char key2[] = {'t', 'e', 's', 't'}; + const char key3[] = {'t', 'e', 's', '\0', 't'}; + const char key4[] = {'t', 'e', 's', 't', '\0'}; + + if (json_object_size(obj) != 0) + fail("incorrect json"); + + json_object_set_new_nocheck(obj, "test1", json_true()); + + if (json_object_size(obj) != 1) + fail("incorrect json"); + + if (json_object_getn(obj, key, sizeof(key)) != json_true()) + fail("json_object_getn failed"); + + if (json_object_getn(obj, key2, sizeof(key2)) != NULL) + fail("false positive json_object_getn by key2"); + + if (json_object_setn_nocheck(obj, key2, sizeof(key2), json_false())) + fail("json_object_setn_nocheck for key2 failed"); + + if (json_object_size(obj) != 2) + fail("incorrect json"); + + if (json_object_get(obj, "test") != json_false()) + fail("json_object_setn_nocheck for key2 failed"); + + if (json_object_getn(obj, key2, sizeof(key2)) != json_false()) + fail("json_object_getn by key 2 failed"); + + if (json_object_getn(obj, key3, sizeof(key3)) != NULL) + fail("false positive json_object_getn by key3"); + + if (json_object_setn_nocheck(obj, key3, sizeof(key3), json_false())) + fail("json_object_setn_nocheck for key3 failed"); + + if (json_object_size(obj) != 3) + fail("incorrect json"); + + if (json_object_getn(obj, key3, sizeof(key3)) != json_false()) + fail("json_object_getn by key 3 failed"); + + if (json_object_getn(obj, key4, sizeof(key4)) != NULL) + fail("false positive json_object_getn by key3"); + + if (json_object_setn_nocheck(obj, key4, sizeof(key4), json_false())) + fail("json_object_setn_nocheck for key3 failed"); + + if (json_object_size(obj) != 4) + fail("incorrect json"); + + test_keylen_iterator(obj); + + if (json_object_getn(obj, key4, sizeof(key4)) != json_false()) + fail("json_object_getn by key 3 failed"); + + if (json_object_size(obj) != 4) + fail("incorrect json"); + + if (json_object_deln(obj, key4, sizeof(key4))) + fail("json_object_deln failed"); + if (json_object_getn(obj, key4, sizeof(key4)) != NULL) + fail("json_object_deln failed"); + if (json_object_size(obj) != 3) + fail("incorrect json"); + + if (json_object_deln(obj, key3, sizeof(key3))) + fail("json_object_deln failed"); + if (json_object_getn(obj, key3, sizeof(key3)) != NULL) + fail("json_object_deln failed"); + if (json_object_size(obj) != 2) + fail("incorrect json"); + + if (json_object_deln(obj, key2, sizeof(key2))) + fail("json_object_deln failed"); + if (json_object_getn(obj, key2, sizeof(key2)) != NULL) + fail("json_object_deln failed"); + if (json_object_size(obj) != 1) + fail("incorrect json"); + + if (json_object_deln(obj, key, sizeof(key))) + fail("json_object_deln failed"); + if (json_object_getn(obj, key, sizeof(key)) != NULL) + fail("json_object_deln failed"); + if (json_object_size(obj) != 0) + fail("incorrect json"); + + json_decref(obj); +} + +static void test_invalid_keylen(void) { + json_t *obj = json_object(); + json_t *empty_obj = json_object(); + const char key[] = {'t', 'e', 's', 't', '1'}; + + json_object_set_new_nocheck(obj, "test1", json_true()); + + if (json_object_getn(NULL, key, sizeof(key)) != NULL) + fail("json_object_getn on NULL failed"); + + if (json_object_getn(obj, NULL, sizeof(key)) != NULL) + fail("json_object_getn on NULL failed"); + + if (json_object_getn(obj, key, 0) != NULL) + fail("json_object_getn on NULL failed"); + + if (!json_object_setn_new(obj, NULL, sizeof(key), json_true())) + fail("json_object_setn_new with NULL key failed"); + + if (!json_object_setn_new_nocheck(obj, NULL, sizeof(key), json_true())) + fail("json_object_setn_new_nocheck with NULL key failed"); + + if (!json_object_del(obj, NULL)) + fail("json_object_del with NULL failed"); + + if (!json_object_deln(empty_obj, key, sizeof(key))) + fail("json_object_deln with empty object failed"); + + if (!json_object_deln(obj, key, sizeof(key) - 1)) + fail("json_object_deln with incomplete key failed"); + + json_decref(obj); + json_decref(empty_obj); +} + +static void test_binary_keys(void) { + json_t *obj = json_object(); + int key1 = 0; + int key2 = 1; + + json_object_setn_nocheck(obj, (const char *)&key1, sizeof(key1), json_true()); + json_object_setn_nocheck(obj, (const char *)&key2, sizeof(key2), json_true()); + + if (!json_is_true(json_object_getn(obj, (const char *)&key1, sizeof(key1)))) + fail("cannot get integer key1"); + + if (!json_is_true(json_object_getn(obj, (const char *)&key1, sizeof(key2)))) + fail("cannot get integer key2"); + + if (json_object_size(obj) != 2) + fail("binary object size missmatch"); + + if (json_object_deln(obj, (const char *)&key1, sizeof(key1))) + fail("cannot del integer key1"); + + if (json_object_size(obj) != 1) + fail("binary object size missmatch"); + + if (json_object_deln(obj, (const char *)&key2, sizeof(key2))) + fail("cannot del integer key2"); + + if (json_object_size(obj) != 0) + fail("binary object size missmatch"); + + json_decref(obj); +} + +static void test_dump_order(void) { + json_t *obj = json_object(); + char key1[] = {'k', '\0', '-', '2'}; + char key2[] = {'k', '\0', '-', '1'}; + const char expected_sorted_str[] = + "{\"k\\u0000-1\": \"first\", \"k\\u0000-2\": \"second\"}"; + const char expected_nonsorted_str[] = + "{\"k\\u0000-2\": \"second\", \"k\\u0000-1\": \"first\"}"; + char *out; + + json_object_setn_new_nocheck(obj, key1, sizeof(key1), json_string("second")); + json_object_setn_new_nocheck(obj, key2, sizeof(key2), json_string("first")); + + out = malloc(512); + + json_dumpb(obj, out, 512, 0); + + if (memcmp(expected_nonsorted_str, out, sizeof(expected_nonsorted_str) - 1) != 0) + fail("preserve order failed"); + + json_dumpb(obj, out, 512, JSON_SORT_KEYS); + if (memcmp(expected_sorted_str, out, sizeof(expected_sorted_str) - 1) != 0) + fail("utf-8 sort failed"); + + free(out); + json_decref(obj); +} + +static void run_tests() { + test_keylen(); + test_invalid_keylen(); + test_binary_keys(); + test_dump_order(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_load.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_load.c new file mode 100644 index 000000000..1c64b0c8d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_load.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <string.h> + +static void file_not_found() { + json_t *json; + json_error_t error; + char *pos; + + json = json_load_file("/path/to/nonexistent/file.json", 0, &error); + if (json) + fail("json_load_file returned non-NULL for a nonexistent file"); + if (error.line != -1) + fail("json_load_file returned an invalid line number"); + + /* The error message is locale specific, only check the beginning + of the error message. */ + + pos = strchr(error.text, ':'); + if (!pos) + fail("json_load_file returne an invalid error message"); + + *pos = '\0'; + + if (strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0) + fail("json_load_file returned an invalid error message"); + if (json_error_code(&error) != json_error_cannot_open_file) + fail("json_load_file returned an invalid error code"); +} + +static void very_long_file_name() { + json_t *json; + json_error_t error; + + json = json_load_file("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + 0, &error); + if (json) + fail("json_load_file returned non-NULL for a nonexistent file"); + if (error.line != -1) + fail("json_load_file returned an invalid line number"); + + if (strncmp(error.source, "...aaa", 6) != 0) + fail("error source was set incorrectly"); + if (json_error_code(&error) != json_error_cannot_open_file) + fail("error code was set incorrectly"); +} + +static void reject_duplicates() { + json_error_t error; + + if (json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error)) + fail("json_loads did not detect a duplicate key"); + check_error(json_error_duplicate_key, "duplicate object key near '\"foo\"'", + "<string>", 1, 16, 16); +} + +static void disable_eof_check() { + json_error_t error; + json_t *json; + + const char *text = "{\"foo\": 1} garbage"; + + if (json_loads(text, 0, &error)) + fail("json_loads did not detect garbage after JSON text"); + check_error(json_error_end_of_input_expected, "end of file expected near 'garbage'", + "<string>", 1, 18, 18); + + json = json_loads(text, JSON_DISABLE_EOF_CHECK, &error); + if (!json) + fail("json_loads failed with JSON_DISABLE_EOF_CHECK"); + + json_decref(json); +} + +static void decode_any() { + json_t *json; + json_error_t error; + + json = json_loads("\"foo\"", JSON_DECODE_ANY, &error); + if (!json || !json_is_string(json)) + fail("json_load decoded any failed - string"); + json_decref(json); + + json = json_loads("42", JSON_DECODE_ANY, &error); + if (!json || !json_is_integer(json)) + fail("json_load decoded any failed - integer"); + json_decref(json); + + json = json_loads("true", JSON_DECODE_ANY, &error); + if (!json || !json_is_true(json)) + fail("json_load decoded any failed - boolean"); + json_decref(json); + + json = json_loads("null", JSON_DECODE_ANY, &error); + if (!json || !json_is_null(json)) + fail("json_load decoded any failed - null"); + json_decref(json); +} + +static void decode_int_as_real() { + json_t *json; + json_error_t error; + +#if JSON_INTEGER_IS_LONG_LONG + const char *imprecise; + json_int_t expected; +#endif + + char big[311]; + + json = json_loads("42", JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error); + if (!json || !json_is_real(json) || json_real_value(json) != 42.0) + fail("json_load decode int as real failed - int"); + json_decref(json); + +#if JSON_INTEGER_IS_LONG_LONG + /* This number cannot be represented exactly by a double */ + imprecise = "9007199254740993"; + expected = 9007199254740992ll; + + json = json_loads(imprecise, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error); + if (!json || !json_is_real(json) || expected != (json_int_t)json_real_value(json)) + fail("json_load decode int as real failed - expected imprecision"); + json_decref(json); +#endif + + /* 1E309 overflows. Here we create 1E309 as a decimal number, i.e. + 1000...(309 zeroes)...0. */ + big[0] = '1'; + memset(big + 1, '0', 309); + big[310] = '\0'; + + json = json_loads(big, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error); + if (json || strcmp(error.text, "real number overflow") != 0 || + json_error_code(&error) != json_error_numeric_overflow) + fail("json_load decode int as real failed - expected overflow"); + json_decref(json); +} + +static void allow_nul() { + const char *text = "\"nul byte \\u0000 in string\""; + const char *expected = "nul byte \0 in string"; + size_t len = 20; + json_t *json; + + json = json_loads(text, JSON_ALLOW_NUL | JSON_DECODE_ANY, NULL); + if (!json || !json_is_string(json)) + fail("unable to decode embedded NUL byte"); + + if (json_string_length(json) != len) + fail("decoder returned wrong string length"); + + if (memcmp(json_string_value(json), expected, len + 1)) + fail("decoder returned wrong string content"); + + json_decref(json); +} + +static void load_wrong_args() { + json_t *json; + json_error_t error; + + json = json_loads(NULL, 0, &error); + if (json) + fail("json_loads should return NULL if the first argument is NULL"); + + json = json_loadb(NULL, 0, 0, &error); + if (json) + fail("json_loadb should return NULL if the first argument is NULL"); + + json = json_loadf(NULL, 0, &error); + if (json) + fail("json_loadf should return NULL if the first argument is NULL"); + + json = json_loadfd(-1, 0, &error); + if (json) + fail("json_loadfd should return NULL if the first argument is < 0"); + + json = json_load_file(NULL, 0, &error); + if (json) + fail("json_load_file should return NULL if the first argument is NULL"); +} + +static void position() { + json_t *json; + size_t flags = JSON_DISABLE_EOF_CHECK; + json_error_t error; + + json = json_loads("{\"foo\": \"bar\"}", 0, &error); + if (error.position != 14) + fail("json_loads returned a wrong position"); + json_decref(json); + + json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error); + if (error.position != 14) + fail("json_loads returned a wrong position"); + json_decref(json); +} + +static void error_code() { + json_error_t error; + json_t *json = json_loads("[123] garbage", 0, &error); + if (json != NULL) + fail("json_loads returned not NULL"); + if (strlen(error.text) >= JSON_ERROR_TEXT_LENGTH) + fail("error.text longer than expected"); + if (json_error_code(&error) != json_error_end_of_input_expected) + fail("json_loads returned incorrect error code"); + + json = json_loads("{\"foo\": ", 0, &error); + if (json != NULL) + fail("json_loads returned not NULL"); + if (strlen(error.text) >= JSON_ERROR_TEXT_LENGTH) + fail("error.text longer than expected"); + if (json_error_code(&error) != json_error_premature_end_of_input) + fail("json_loads returned incorrect error code"); +} + +static void run_tests() { + file_not_found(); + very_long_file_name(); + reject_duplicates(); + disable_eof_check(); + decode_any(); + decode_int_as_real(); + allow_nul(); + load_wrong_args(); + position(); + error_code(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_load_callback.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_load_callback.c new file mode 100644 index 000000000..b292fcf42 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_load_callback.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009-2011 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <stdlib.h> +#include <string.h> + +struct my_source { + const char *buf; + size_t off; + size_t cap; +}; + +static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]"; + +static size_t greedy_reader(void *buf, size_t buflen, void *arg) { + struct my_source *s = arg; + if (buflen > s->cap - s->off) + buflen = s->cap - s->off; + if (buflen > 0) { + memcpy(buf, s->buf + s->off, buflen); + s->off += buflen; + return buflen; + } else { + return 0; + } +} + +static void run_tests() { + struct my_source s; + json_t *json; + json_error_t error; + + s.off = 0; + s.cap = strlen(my_str); + s.buf = my_str; + + json = json_load_callback(greedy_reader, &s, 0, &error); + + if (!json) + fail("json_load_callback failed on a valid callback"); + json_decref(json); + + s.off = 0; + s.cap = strlen(my_str) - 1; + s.buf = my_str; + + json = json_load_callback(greedy_reader, &s, 0, &error); + if (json) { + json_decref(json); + fail("json_load_callback should have failed on an incomplete stream, " + "but it didn't"); + } + if (strcmp(error.source, "<callback>") != 0) { + fail("json_load_callback returned an invalid error source"); + } + if (strcmp(error.text, "']' expected near end of file") != 0) { + fail("json_load_callback returned an invalid error message for an " + "unclosed top-level array"); + } + + json = json_load_callback(NULL, NULL, 0, &error); + if (json) { + json_decref(json); + fail("json_load_callback should have failed on NULL load callback, but " + "it didn't"); + } + if (strcmp(error.text, "wrong arguments") != 0) { + fail("json_load_callback returned an invalid error message for a NULL " + "load callback"); + } +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_loadb.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_loadb.c new file mode 100644 index 000000000..2cd88fef3 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_loadb.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <string.h> + +static void run_tests() { + json_t *json; + json_error_t error; + const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage"; + size_t len = strlen(str) - strlen("garbage"); + + json = json_loadb(str, len, 0, &error); + if (!json) { + fail("json_loadb failed on a valid JSON buffer"); + } + json_decref(json); + + json = json_loadb(str, len - 1, 0, &error); + if (json) { + json_decref(json); + fail("json_loadb should have failed on an incomplete buffer, but it " + "didn't"); + } + if (error.line != 1) { + fail("json_loadb returned an invalid line number on fail"); + } + if (strcmp(error.text, "']' expected near end of file") != 0) { + fail("json_loadb returned an invalid error message for an unclosed " + "top-level array"); + } +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_memory_funcs.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_memory_funcs.c new file mode 100644 index 000000000..4fd616654 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_memory_funcs.c @@ -0,0 +1,115 @@ +#include <jansson.h> +#include <string.h> + +#include "util.h" + +static int malloc_called = 0; +static int free_called = 0; +static size_t malloc_used = 0; + +/* helpers */ +static void create_and_free_complex_object() { + json_t *obj; + + obj = json_pack("{s:i,s:n,s:b,s:b,s:{s:s},s:[i,i,i]}", "foo", 42, "bar", "baz", 1, + "qux", 0, "alice", "bar", "baz", "bob", 9, 8, 7); + + json_decref(obj); +} + +static void create_and_free_object_with_oom() { + int i; + char key[4]; + json_t *obj = json_object(); + + for (i = 0; i < 10; i++) { + snprintf(key, sizeof key, "%d", i); + json_object_set_new(obj, key, json_integer(i)); + } + + json_decref(obj); +} + +static void *my_malloc(size_t size) { + malloc_called = 1; + return malloc(size); +} + +static void my_free(void *ptr) { + free_called = 1; + free(ptr); +} + +static void test_simple() { + json_malloc_t mfunc = NULL; + json_free_t ffunc = NULL; + + json_set_alloc_funcs(my_malloc, my_free); + json_get_alloc_funcs(&mfunc, &ffunc); + create_and_free_complex_object(); + + if (malloc_called != 1 || free_called != 1 || mfunc != my_malloc || ffunc != my_free) + fail("Custom allocation failed"); +} + +static void *oom_malloc(size_t size) { + if (malloc_used + size > 800) + return NULL; + + malloc_used += size; + return malloc(size); +} + +static void oom_free(void *ptr) { + free_called++; + free(ptr); +} + +static void test_oom() { + free_called = 0; + json_set_alloc_funcs(oom_malloc, oom_free); + create_and_free_object_with_oom(); + + if (free_called == 0) + fail("Allocation with OOM failed"); +} + +/* + Test the secure memory functions code given in the API reference + documentation, but by using plain memset instead of + guaranteed_memset(). +*/ + +static void *secure_malloc(size_t size) { + /* Store the memory area size in the beginning of the block */ + void *ptr = malloc(size + 8); + *((size_t *)ptr) = size; + return (char *)ptr + 8; +} + +static void secure_free(void *ptr) { + size_t size; + + ptr = (char *)ptr - 8; + size = *((size_t *)ptr); + + /*guaranteed_*/ memset(ptr, 0, size + 8); + free(ptr); +} + +static void test_secure_funcs(void) { + json_set_alloc_funcs(secure_malloc, secure_free); + create_and_free_complex_object(); +} + +static void test_bad_args(void) { + /* The result of this test is not crashing. */ + json_get_alloc_funcs(NULL, NULL); +} + +static void run_tests() { + test_simple(); + test_secure_funcs(); + test_oom(); + test_bad_args(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_number.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_number.c new file mode 100644 index 000000000..2a22a67d3 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_number.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <math.h> + +#ifdef INFINITY +// This test triggers "warning C4756: overflow in constant arithmetic" +// in Visual Studio. This warning is triggered here by design, so disable it. +// (This can only be done on function level so we keep these tests separate) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4756) +#endif +static void test_inifity() { + json_t *real = json_real(INFINITY); + if (real != NULL) + fail("could construct a real from Inf"); + + real = json_real(1.0); + if (json_real_set(real, INFINITY) != -1) + fail("could set a real to Inf"); + + if (json_real_value(real) != 1.0) + fail("real value changed unexpectedly"); + + json_decref(real); +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} +#endif // INFINITY + +static void test_bad_args(void) { + json_t *txt = json_string("test"); + + if (json_integer_value(NULL) != 0) + fail("json_integer_value did not return 0 for non-integer"); + if (json_integer_value(txt) != 0) + fail("json_integer_value did not return 0 for non-integer"); + + if (!json_integer_set(NULL, 0)) + fail("json_integer_set did not return error for non-integer"); + if (!json_integer_set(txt, 0)) + fail("json_integer_set did not return error for non-integer"); + + if (json_real_value(NULL) != 0.0) + fail("json_real_value did not return 0.0 for non-real"); + if (json_real_value(txt) != 0.0) + fail("json_real_value did not return 0.0 for non-real"); + + if (!json_real_set(NULL, 0.0)) + fail("json_real_set did not return error for non-real"); + if (!json_real_set(txt, 0.0)) + fail("json_real_set did not return error for non-real"); + + if (json_number_value(NULL) != 0.0) + fail("json_number_value did not return 0.0 for non-numeric"); + if (json_number_value(txt) != 0.0) + fail("json_number_value did not return 0.0 for non-numeric"); + + if (txt->refcount != 1) + fail("unexpected reference count for txt"); + + json_decref(txt); +} + +static void run_tests() { + json_t *integer, *real; + json_int_t i; + double d; + + integer = json_integer(5); + real = json_real(100.1); + + if (!integer) + fail("unable to create integer"); + if (!real) + fail("unable to create real"); + + i = json_integer_value(integer); + if (i != 5) + fail("wrong integer value"); + + d = json_real_value(real); + if (d != 100.1) + fail("wrong real value"); + + d = json_number_value(integer); + if (d != 5.0) + fail("wrong number value"); + d = json_number_value(real); + if (d != 100.1) + fail("wrong number value"); + + json_decref(integer); + json_decref(real); + +#ifdef NAN + real = json_real(NAN); + if (real != NULL) + fail("could construct a real from NaN"); + + real = json_real(1.0); + if (json_real_set(real, NAN) != -1) + fail("could set a real to NaN"); + + if (json_real_value(real) != 1.0) + fail("real value changed unexpectedly"); + + json_decref(real); +#endif + +#ifdef INFINITY + test_inifity(); +#endif + test_bad_args(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_object.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_object.c new file mode 100644 index 000000000..331edf229 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_object.c @@ -0,0 +1,797 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <string.h> + +static void test_clear() { + json_t *object, *ten; + + object = json_object(); + ten = json_integer(10); + + if (!object) + fail("unable to create object"); + if (!ten) + fail("unable to create integer"); + + if (json_object_set(object, "a", ten) || json_object_set(object, "b", ten) || + json_object_set(object, "c", ten) || json_object_set(object, "d", ten) || + json_object_set(object, "e", ten)) + fail("unable to set value"); + + if (json_object_size(object) != 5) + fail("invalid size"); + + json_object_clear(object); + + if (json_object_size(object) != 0) + fail("invalid size after clear"); + + json_decref(ten); + json_decref(object); +} + +static void test_update() { + json_t *object, *other, *nine, *ten; + + object = json_object(); + other = json_object(); + + nine = json_integer(9); + ten = json_integer(10); + + if (!object || !other) + fail("unable to create object"); + if (!nine || !ten) + fail("unable to create integer"); + + /* update an empty object with an empty object */ + + if (json_object_update(object, other)) + fail("unable to update an empty object with an empty object"); + + if (json_object_size(object) != 0) + fail("invalid size after update"); + + if (json_object_size(other) != 0) + fail("invalid size for updater after update"); + + /* update an empty object with a nonempty object */ + + if (json_object_set(other, "a", ten) || json_object_set(other, "b", ten) || + json_object_set(other, "c", ten) || json_object_set(other, "d", ten) || + json_object_set(other, "e", ten)) + fail("unable to set value"); + + if (json_object_update(object, other)) + fail("unable to update an empty object"); + + if (json_object_size(object) != 5) + fail("invalid size after update"); + + if (json_object_get(object, "a") != ten || json_object_get(object, "b") != ten || + json_object_get(object, "c") != ten || json_object_get(object, "d") != ten || + json_object_get(object, "e") != ten) + fail("update works incorrectly"); + + /* perform the same update again */ + + if (json_object_update(object, other)) + fail("unable to update a non-empty object"); + + if (json_object_size(object) != 5) + fail("invalid size after update"); + + if (json_object_get(object, "a") != ten || json_object_get(object, "b") != ten || + json_object_get(object, "c") != ten || json_object_get(object, "d") != ten || + json_object_get(object, "e") != ten) + fail("update works incorrectly"); + + /* update a nonempty object with a nonempty object with both old + and new keys */ + + if (json_object_clear(other)) + fail("clear failed"); + + if (json_object_set(other, "a", nine) || json_object_set(other, "b", nine) || + json_object_set(other, "f", nine) || json_object_set(other, "g", nine) || + json_object_set(other, "h", nine)) + fail("unable to set value"); + + if (json_object_update(object, other)) + fail("unable to update a nonempty object"); + + if (json_object_size(object) != 8) + fail("invalid size after update"); + + if (json_object_get(object, "a") != nine || json_object_get(object, "b") != nine || + json_object_get(object, "f") != nine || json_object_get(object, "g") != nine || + json_object_get(object, "h") != nine) + fail("update works incorrectly"); + + /* update_new check */ + if (json_object_clear(object)) + fail("clear failed"); + + if (json_object_set(object, "a", ten) || json_object_set(object, "b", ten) || + json_object_set(object, "c", ten) || json_object_set(object, "d", ten) || + json_object_set(object, "e", ten)) + fail("unable to set value"); + + if (json_object_update_new( + object, json_pack("{s:O, s:O, s:O}", "b", nine, "f", nine, "g", nine))) + fail("unable to update_new a nonempty object"); + + if (json_object_size(object) != 7) + fail("invalid size after update_new"); + + if (json_object_get(object, "a") != ten || json_object_get(object, "b") != nine || + json_object_get(object, "c") != ten || json_object_get(object, "d") != ten || + json_object_get(object, "e") != ten || json_object_get(object, "f") != nine || + json_object_get(object, "g") != nine) + fail("update_new works incorrectly"); + + json_decref(nine); + json_decref(ten); + json_decref(other); + json_decref(object); +} + +static void test_set_many_keys() { + json_t *object, *value; + const char *keys = "abcdefghijklmnopqrstuvwxyz"; + char buf[2]; + size_t i; + + object = json_object(); + if (!object) + fail("unable to create object"); + + value = json_string("a"); + if (!value) + fail("unable to create string"); + + buf[1] = '\0'; + for (i = 0; i < strlen(keys); i++) { + buf[0] = keys[i]; + if (json_object_set(object, buf, value)) + fail("unable to set object key"); + } + + json_decref(object); + json_decref(value); +} + +static void test_conditional_updates() { + json_t *object, *other; + + object = json_pack("{sisi}", "foo", 1, "bar", 2); + other = json_pack("{sisi}", "foo", 3, "baz", 4); + + if (json_object_update_existing(object, other)) + fail("json_object_update_existing failed"); + + if (json_object_size(object) != 2) + fail("json_object_update_existing added new items"); + + if (json_integer_value(json_object_get(object, "foo")) != 3) + fail("json_object_update_existing failed to update existing key"); + + if (json_integer_value(json_object_get(object, "bar")) != 2) + fail("json_object_update_existing updated wrong key"); + + json_decref(object); + + /* json_object_update_existing_new check */ + object = json_pack("{sisi}", "foo", 1, "bar", 2); + + if (json_object_update_existing_new(object, json_pack("{sisi}", "foo", 3, "baz", 4))) + fail("json_object_update_existing_new failed"); + + if (json_object_size(object) != 2) + fail("json_object_update_existing_new added new items"); + + if (json_integer_value(json_object_get(object, "foo")) != 3) + fail("json_object_update_existing_new failed to update existing key"); + + if (json_integer_value(json_object_get(object, "bar")) != 2) + fail("json_object_update_existing_new updated wrong key"); + + json_decref(object); + + object = json_pack("{sisi}", "foo", 1, "bar", 2); + + if (json_object_update_missing(object, other)) + fail("json_object_update_missing failed"); + + if (json_object_size(object) != 3) + fail("json_object_update_missing didn't add new items"); + + if (json_integer_value(json_object_get(object, "foo")) != 1) + fail("json_object_update_missing updated existing key"); + + if (json_integer_value(json_object_get(object, "bar")) != 2) + fail("json_object_update_missing updated wrong key"); + + if (json_integer_value(json_object_get(object, "baz")) != 4) + fail("json_object_update_missing didn't add new items"); + + json_decref(object); + + /* json_object_update_missing_new check */ + object = json_pack("{sisi}", "foo", 1, "bar", 2); + + if (json_object_update_missing_new(object, json_pack("{sisi}", "foo", 3, "baz", 4))) + fail("json_object_update_missing_new failed"); + + if (json_object_size(object) != 3) + fail("json_object_update_missing_new didn't add new items"); + + if (json_integer_value(json_object_get(object, "foo")) != 1) + fail("json_object_update_missing_new updated existing key"); + + if (json_integer_value(json_object_get(object, "bar")) != 2) + fail("json_object_update_missing_new updated wrong key"); + + if (json_integer_value(json_object_get(object, "baz")) != 4) + fail("json_object_update_missing_new didn't add new items"); + + json_decref(object); + json_decref(other); +} + +static void test_recursive_updates() { + json_t *invalid, *object, *other, *barBefore, *barAfter; + + invalid = json_integer(42); + + object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2); + other = json_pack("{sisisi}", "foo", 3, "bar", 4, "baz", 5); + + if (!json_object_update_recursive(invalid, other)) + fail("json_object_update_recursive accepted non-object argument"); + + json_decref(invalid); + + if (json_object_update_recursive(object, other)) + fail("json_object_update_recursive failed"); + + if (json_object_size(object) != 3) + fail("invalid size after update"); + + if (json_integer_value(json_object_get(object, "foo")) != 3) + fail("json_object_update_recursive failed to update existing key"); + + if (json_integer_value(json_object_get(object, "bar")) != 4) + fail("json_object_update_recursive failed to overwrite object"); + + if (json_integer_value(json_object_get(object, "baz")) != 5) + fail("json_object_update_recursive didn't add new item"); + + json_decref(object); + json_decref(other); + + object = json_pack("{sis{si}}", "foo", 1, "bar", "baz", 2); + other = json_pack("{s{si}}", "bar", "baz", 3); + barBefore = json_object_get(object, "bar"); + + if (!barBefore) + fail("can't get bar object before json_object_update_recursive"); + + if (json_object_update_recursive(object, other)) + fail("json_object_update_recursive failed"); + + if (json_object_size(object) != 2) + fail("invalid size after update"); + + if (!json_object_get(object, "foo")) + fail("json_object_update_recursive removed existing key"); + + if (json_integer_value(json_object_get(json_object_get(object, "bar"), "baz")) != 3) + fail("json_object_update_recursive failed to update nested value"); + + barAfter = json_object_get(object, "bar"); + if (!barAfter) + fail("can't get bar object after json_object_update_recursive"); + + if (barBefore != barAfter) + fail("bar object reference changed after json_object_update_recursive"); + + json_decref(object); + json_decref(other); + + /* check circular reference */ + object = json_pack("{s{s{s{si}}}}", "foo", "bar", "baz", "xxx", 2); + other = json_pack("{s{s{si}}}", "foo", "bar", "baz", 2); + json_object_set(json_object_get(json_object_get(other, "foo"), "bar"), "baz", + json_object_get(other, "foo")); + + if (!json_object_update_recursive(object, other)) + fail("json_object_update_recursive update a circular reference!"); + + json_object_set_new(json_object_get(json_object_get(other, "foo"), "bar"), "baz", + json_integer(1)); + + if (json_object_update_recursive(object, other)) + fail("json_object_update_recursive failed!"); + + json_decref(object); + json_decref(other); +} + +static void test_circular() { + json_t *object1, *object2; + + object1 = json_object(); + object2 = json_object(); + if (!object1 || !object2) + fail("unable to create object"); + + /* the simple case is checked */ + if (json_object_set(object1, "a", object1) == 0) + fail("able to set self"); + + /* create circular references */ + if (json_object_set(object1, "a", object2) || json_object_set(object2, "a", object1)) + fail("unable to set value"); + + /* circularity is detected when dumping */ + if (json_dumps(object1, 0) != NULL) + fail("able to dump circulars"); + + /* decref twice to deal with the circular references */ + json_decref(object1); + json_decref(object2); + json_decref(object1); +} + +static void test_set_nocheck() { + json_t *object, *string; + + object = json_object(); + string = json_string("bar"); + + if (!object) + fail("unable to create object"); + if (!string) + fail("unable to create string"); + + if (json_object_set_nocheck(object, "foo", string)) + fail("json_object_set_nocheck failed"); + if (json_object_get(object, "foo") != string) + fail("json_object_get after json_object_set_nocheck failed"); + + /* invalid UTF-8 in key */ + if (json_object_set_nocheck(object, "a\xefz", string)) + fail("json_object_set_nocheck failed for invalid UTF-8"); + if (json_object_get(object, "a\xefz") != string) + fail("json_object_get after json_object_set_nocheck failed"); + + if (json_object_set_new_nocheck(object, "bax", json_integer(123))) + fail("json_object_set_new_nocheck failed"); + if (json_integer_value(json_object_get(object, "bax")) != 123) + fail("json_object_get after json_object_set_new_nocheck failed"); + + /* invalid UTF-8 in key */ + if (json_object_set_new_nocheck(object, "asdf\xfe", json_integer(321))) + fail("json_object_set_new_nocheck failed for invalid UTF-8"); + if (json_integer_value(json_object_get(object, "asdf\xfe")) != 321) + fail("json_object_get after json_object_set_new_nocheck failed"); + + json_decref(string); + json_decref(object); +} + +static void test_iterators() { + json_t *object, *foo, *bar, *baz; + void *iter; + + if (json_object_iter(NULL)) + fail("able to iterate over NULL"); + + if (json_object_iter_next(NULL, NULL)) + fail("able to increment an iterator on a NULL object"); + + object = json_object(); + foo = json_string("foo"); + bar = json_string("bar"); + baz = json_string("baz"); + if (!object || !foo || !bar || !baz) + fail("unable to create values"); + + if (json_object_iter_next(object, NULL)) + fail("able to increment a NULL iterator"); + + if (json_object_set(object, "a", foo) || json_object_set(object, "b", bar) || + json_object_set(object, "c", baz)) + fail("unable to populate object"); + + iter = json_object_iter(object); + if (!iter) + fail("unable to get iterator"); + if (strcmp(json_object_iter_key(iter), "a") != 0) + fail("iterating doesn't yield keys in order"); + if (json_object_iter_value(iter) != foo) + fail("iterating doesn't yield values in order"); + + iter = json_object_iter_next(object, iter); + if (!iter) + fail("unable to increment iterator"); + if (strcmp(json_object_iter_key(iter), "b") != 0) + fail("iterating doesn't yield keys in order"); + if (json_object_iter_value(iter) != bar) + fail("iterating doesn't yield values in order"); + + iter = json_object_iter_next(object, iter); + if (!iter) + fail("unable to increment iterator"); + if (strcmp(json_object_iter_key(iter), "c") != 0) + fail("iterating doesn't yield keys in order"); + if (json_object_iter_value(iter) != baz) + fail("iterating doesn't yield values in order"); + + if (json_object_iter_next(object, iter) != NULL) + fail("able to iterate over the end"); + + if (json_object_iter_at(object, "foo")) + fail("json_object_iter_at() succeeds for non-existent key"); + + iter = json_object_iter_at(object, "b"); + if (!iter) + fail("json_object_iter_at() fails for an existing key"); + + if (strcmp(json_object_iter_key(iter), "b")) + fail("iterating failed: wrong key"); + if (json_object_iter_value(iter) != bar) + fail("iterating failed: wrong value"); + + if (json_object_iter_set(object, iter, baz)) + fail("unable to set value at iterator"); + + if (strcmp(json_object_iter_key(iter), "b")) + fail("json_object_iter_key() fails after json_object_iter_set()"); + if (json_object_iter_value(iter) != baz) + fail("json_object_iter_value() fails after json_object_iter_set()"); + if (json_object_get(object, "b") != baz) + fail("json_object_get() fails after json_object_iter_set()"); + + json_decref(object); + json_decref(foo); + json_decref(bar); + json_decref(baz); +} + +static void test_misc() { + json_t *object, *string, *other_string, *value; + + object = json_object(); + string = json_string("test"); + other_string = json_string("other"); + + if (!object) + fail("unable to create object"); + if (!string || !other_string) + fail("unable to create string"); + + if (json_object_get(object, "a")) + fail("value for nonexisting key"); + + if (json_object_set(object, "a", string)) + fail("unable to set value"); + + if (!json_object_set(object, NULL, string)) + fail("able to set NULL key"); + + if (json_object_del(object, "a")) + fail("unable to del the only key"); + + if (json_object_set(object, "a", string)) + fail("unable to set value"); + + if (!json_object_set(object, "a", NULL)) + fail("able to set NULL value"); + + /* invalid UTF-8 in key */ + if (!json_object_set(object, "a\xefz", string)) + fail("able to set invalid unicode key"); + + value = json_object_get(object, "a"); + if (!value) + fail("no value for existing key"); + if (value != string) + fail("got different value than what was added"); + + /* "a", "lp" and "px" collide in a five-bucket hashtable */ + if (json_object_set(object, "b", string) || json_object_set(object, "lp", string) || + json_object_set(object, "px", string)) + fail("unable to set value"); + + value = json_object_get(object, "a"); + if (!value) + fail("no value for existing key"); + if (value != string) + fail("got different value than what was added"); + + if (json_object_set(object, "a", other_string)) + fail("unable to replace an existing key"); + + value = json_object_get(object, "a"); + if (!value) + fail("no value for existing key"); + if (value != other_string) + fail("got different value than what was set"); + + if (!json_object_del(object, "nonexisting")) + fail("able to delete a nonexisting key"); + + if (json_object_del(object, "px")) + fail("unable to delete an existing key"); + + if (json_object_del(object, "a")) + fail("unable to delete an existing key"); + + if (json_object_del(object, "lp")) + fail("unable to delete an existing key"); + + /* add many keys to initiate rehashing */ + + if (json_object_set(object, "a", string)) + fail("unable to set value"); + + if (json_object_set(object, "lp", string)) + fail("unable to set value"); + + if (json_object_set(object, "px", string)) + fail("unable to set value"); + + if (json_object_set(object, "c", string)) + fail("unable to set value"); + + if (json_object_set(object, "d", string)) + fail("unable to set value"); + + if (json_object_set(object, "e", string)) + fail("unable to set value"); + + if (json_object_set_new(object, "foo", json_integer(123))) + fail("unable to set new value"); + + value = json_object_get(object, "foo"); + if (!json_is_integer(value) || json_integer_value(value) != 123) + fail("json_object_set_new works incorrectly"); + + if (!json_object_set_new(object, NULL, json_integer(432))) + fail("able to set_new NULL key"); + + if (!json_object_set_new(object, "foo", NULL)) + fail("able to set_new NULL value"); + + json_decref(string); + json_decref(other_string); + json_decref(object); +} + +static void test_preserve_order() { + json_t *object; + char *result; + + const char *expected = "{\"foobar\": 1, \"bazquux\": 6, \"lorem ipsum\": " + "3, \"sit amet\": 5, \"helicopter\": 7}"; + + object = json_object(); + + json_object_set_new(object, "foobar", json_integer(1)); + json_object_set_new(object, "bazquux", json_integer(2)); + json_object_set_new(object, "lorem ipsum", json_integer(3)); + json_object_set_new(object, "dolor", json_integer(4)); + json_object_set_new(object, "sit amet", json_integer(5)); + + /* changing a value should preserve the order */ + json_object_set_new(object, "bazquux", json_integer(6)); + + /* deletion shouldn't change the order of others */ + json_object_del(object, "dolor"); + + /* add a new item just to make sure */ + json_object_set_new(object, "helicopter", json_integer(7)); + + result = json_dumps(object, JSON_PRESERVE_ORDER); + + if (strcmp(expected, result) != 0) { + fprintf(stderr, "%s != %s", expected, result); + fail("JSON_PRESERVE_ORDER doesn't work"); + } + + free(result); + json_decref(object); +} + +static void test_object_foreach() { + const char *key; + json_t *object1, *object2, *value; + + object1 = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3); + object2 = json_object(); + + json_object_foreach(object1, key, value) json_object_set(object2, key, value); + + if (!json_equal(object1, object2)) + fail("json_object_foreach failed to iterate all key-value pairs"); + + json_decref(object1); + json_decref(object2); +} + +static void test_object_foreach_safe() { + const char *key; + void *tmp; + json_t *object, *value; + + object = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3); + + json_object_foreach_safe(object, tmp, key, value) { json_object_del(object, key); } + + if (json_object_size(object) != 0) + fail("json_object_foreach_safe failed to iterate all key-value pairs"); + + json_decref(object); +} + +static void test_bad_args(void) { + json_t *obj = json_object(); + json_t *num = json_integer(1); + void *iter; + + if (!obj || !num) + fail("failed to allocate test objects"); + + if (json_object_set(obj, "testkey", json_null())) + fail("failed to set testkey on object"); + + iter = json_object_iter(obj); + if (!iter) + fail("failed to retrieve test iterator"); + + if (json_object_size(NULL) != 0) + fail("json_object_size with non-object argument returned non-zero"); + if (json_object_size(num) != 0) + fail("json_object_size with non-object argument returned non-zero"); + + if (json_object_get(NULL, "test") != NULL) + fail("json_object_get with non-object argument returned non-NULL"); + if (json_object_get(num, "test") != NULL) + fail("json_object_get with non-object argument returned non-NULL"); + if (json_object_get(obj, NULL) != NULL) + fail("json_object_get with NULL key returned non-NULL"); + + if (!json_object_set_new_nocheck(NULL, "test", json_null())) + fail("json_object_set_new_nocheck with non-object argument did not " + "return error"); + if (!json_object_set_new_nocheck(num, "test", json_null())) + fail("json_object_set_new_nocheck with non-object argument did not " + "return error"); + if (!json_object_set_new_nocheck(obj, "test", json_incref(obj))) + fail("json_object_set_new_nocheck with object == value did not return " + "error"); + if (!json_object_set_new_nocheck(obj, NULL, json_object())) + fail("json_object_set_new_nocheck with NULL key did not return error"); + + if (!json_object_del(NULL, "test")) + fail("json_object_del with non-object argument did not return error"); + if (!json_object_del(num, "test")) + fail("json_object_del with non-object argument did not return error"); + if (!json_object_del(obj, NULL)) + fail("json_object_del with NULL key did not return error"); + + if (!json_object_clear(NULL)) + fail("json_object_clear with non-object argument did not return error"); + if (!json_object_clear(num)) + fail("json_object_clear with non-object argument did not return error"); + + if (!json_object_update(NULL, obj)) + fail("json_object_update with non-object first argument did not return " + "error"); + if (!json_object_update(num, obj)) + fail("json_object_update with non-object first argument did not return " + "error"); + if (!json_object_update(obj, NULL)) + fail("json_object_update with non-object second argument did not " + "return error"); + if (!json_object_update(obj, num)) + fail("json_object_update with non-object second argument did not " + "return error"); + + if (!json_object_update_existing(NULL, obj)) + fail("json_object_update_existing with non-object first argument did " + "not return error"); + if (!json_object_update_existing(num, obj)) + fail("json_object_update_existing with non-object first argument did " + "not return error"); + if (!json_object_update_existing(obj, NULL)) + fail("json_object_update_existing with non-object second argument did " + "not return error"); + if (!json_object_update_existing(obj, num)) + fail("json_object_update_existing with non-object second argument did " + "not return error"); + + if (!json_object_update_missing(NULL, obj)) + fail("json_object_update_missing with non-object first argument did " + "not return error"); + if (!json_object_update_missing(num, obj)) + fail("json_object_update_missing with non-object first argument did " + "not return error"); + if (!json_object_update_missing(obj, NULL)) + fail("json_object_update_missing with non-object second argument did " + "not return error"); + if (!json_object_update_missing(obj, num)) + fail("json_object_update_missing with non-object second argument did " + "not return error"); + + if (json_object_iter(NULL) != NULL) + fail("json_object_iter with non-object argument returned non-NULL"); + if (json_object_iter(num) != NULL) + fail("json_object_iter with non-object argument returned non-NULL"); + + if (json_object_iter_at(NULL, "test") != NULL) + fail("json_object_iter_at with non-object argument returned non-NULL"); + if (json_object_iter_at(num, "test") != NULL) + fail("json_object_iter_at with non-object argument returned non-NULL"); + if (json_object_iter_at(obj, NULL) != NULL) + fail("json_object_iter_at with NULL iter returned non-NULL"); + + if (json_object_iter_next(obj, NULL) != NULL) + fail("json_object_iter_next with NULL iter returned non-NULL"); + if (json_object_iter_next(num, iter) != NULL) + fail("json_object_iter_next with non-object argument returned non-NULL"); + + if (json_object_iter_key(NULL) != NULL) + fail("json_object_iter_key with NULL iter returned non-NULL"); + + if (json_object_key_to_iter(NULL) != NULL) + fail("json_object_key_to_iter with NULL iter returned non-NULL"); + + if (json_object_iter_value(NULL) != NULL) + fail("json_object_iter_value with NULL iter returned non-NULL"); + + if (!json_object_iter_set_new(NULL, iter, json_incref(num))) + fail("json_object_iter_set_new with non-object argument did not return " + "error"); + if (!json_object_iter_set_new(num, iter, json_incref(num))) + fail("json_object_iter_set_new with non-object argument did not return " + "error"); + if (!json_object_iter_set_new(obj, NULL, json_incref(num))) + fail("json_object_iter_set_new with NULL iter did not return error"); + if (!json_object_iter_set_new(obj, iter, NULL)) + fail("json_object_iter_set_new with NULL value did not return error"); + + if (obj->refcount != 1) + fail("unexpected reference count for obj"); + + if (num->refcount != 1) + fail("unexpected reference count for num"); + + json_decref(obj); + json_decref(num); +} + +static void run_tests() { + test_misc(); + test_clear(); + test_update(); + test_set_many_keys(); + test_conditional_updates(); + test_recursive_updates(); + test_circular(); + test_set_nocheck(); + test_iterators(); + test_preserve_order(); + test_object_foreach(); + test_object_foreach_safe(); + test_bad_args(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_pack.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_pack.c new file mode 100644 index 000000000..865f60b68 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_pack.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#include <jansson_config.h> + +#include "util.h" +#include <jansson.h> +#include <math.h> +#include <stdio.h> +#include <string.h> + +#ifdef INFINITY +// This test triggers "warning C4756: overflow in constant arithmetic" +// in Visual Studio. This warning is triggered here by design, so disable it. +// (This can only be done on function level so we keep these tests separate) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4756) +#endif +static void test_inifity() { + json_error_t error; + + if (json_pack_ex(&error, 0, "f", INFINITY)) + fail("json_pack infinity incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, + 1, 1); + + if (json_pack_ex(&error, 0, "[f]", INFINITY)) + fail("json_pack infinity array element incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, + 2, 2); + + if (json_pack_ex(&error, 0, "{s:f}", "key", INFINITY)) + fail("json_pack infinity object value incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, + 4, 4); + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} +#endif // INFINITY + +static void run_tests() { + json_t *value; + int i; + char buffer[4] = {'t', 'e', 's', 't'}; + json_error_t error; + + /* + * Simple, valid json_pack cases + */ + /* true */ + value = json_pack("b", 1); + if (!json_is_true(value)) + fail("json_pack boolean failed"); + if (value->refcount != (size_t)-1) + fail("json_pack boolean refcount failed"); + json_decref(value); + + /* false */ + value = json_pack("b", 0); + if (!json_is_false(value)) + fail("json_pack boolean failed"); + if (value->refcount != (size_t)-1) + fail("json_pack boolean refcount failed"); + json_decref(value); + + /* null */ + value = json_pack("n"); + if (!json_is_null(value)) + fail("json_pack null failed"); + if (value->refcount != (size_t)-1) + fail("json_pack null refcount failed"); + json_decref(value); + + /* integer */ + value = json_pack("i", 1); + if (!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack integer failed"); + if (value->refcount != (size_t)1) + fail("json_pack integer refcount failed"); + json_decref(value); + + /* integer from json_int_t */ + value = json_pack("I", (json_int_t)555555); + if (!json_is_integer(value) || json_integer_value(value) != 555555) + fail("json_pack json_int_t failed"); + if (value->refcount != (size_t)1) + fail("json_pack integer refcount failed"); + json_decref(value); + + /* real */ + value = json_pack("f", 1.0); + if (!json_is_real(value) || json_real_value(value) != 1.0) + fail("json_pack real failed"); + if (value->refcount != (size_t)1) + fail("json_pack real refcount failed"); + json_decref(value); + + /* string */ + value = json_pack("s", "test"); + if (!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string failed"); + if (value->refcount != (size_t)1) + fail("json_pack string refcount failed"); + json_decref(value); + + /* nullable string (defined case) */ + value = json_pack("s?", "test"); + if (!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack nullable string (defined case) failed"); + if (value->refcount != (size_t)1) + fail("json_pack nullable string (defined case) refcount failed"); + json_decref(value); + + /* nullable string (NULL case) */ + value = json_pack("s?", NULL); + if (!json_is_null(value)) + fail("json_pack nullable string (NULL case) failed"); + if (value->refcount != (size_t)-1) + fail("json_pack nullable string (NULL case) refcount failed"); + json_decref(value); + + /* nullable string concatenation */ + if (json_pack_ex(&error, 0, "s?+", "test", "ing")) + fail("json_pack failed to catch invalid format 's?+'"); + check_error(json_error_invalid_format, "Cannot use '+' on optional strings", + "<format>", 1, 2, 2); + + /* nullable string with integer length */ + if (json_pack_ex(&error, 0, "s?#", "test", 4)) + fail("json_pack failed to catch invalid format 's?#'"); + check_error(json_error_invalid_format, "Cannot use '#' on optional strings", + "<format>", 1, 2, 2); + + /* string and length (int) */ + value = json_pack("s#", "test asdf", 4); + if (!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string and length failed"); + if (value->refcount != (size_t)1) + fail("json_pack string and length refcount failed"); + json_decref(value); + + /* string and length (size_t) */ + value = json_pack("s%", "test asdf", (size_t)4); + if (!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string and length failed"); + if (value->refcount != (size_t)1) + fail("json_pack string and length refcount failed"); + json_decref(value); + + /* string and length (int), non-NUL terminated string */ + value = json_pack("s#", buffer, 4); + if (!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string and length (int) failed"); + if (value->refcount != (size_t)1) + fail("json_pack string and length (int) refcount failed"); + json_decref(value); + + /* string and length (size_t), non-NUL terminated string */ + value = json_pack("s%", buffer, (size_t)4); + if (!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string and length (size_t) failed"); + if (value->refcount != (size_t)1) + fail("json_pack string and length (size_t) refcount failed"); + json_decref(value); + + /* string concatenation */ + if (json_pack("s+", "test", NULL)) + fail("json_pack string concatenation succeeded with NULL string"); + + value = json_pack("s++", "te", "st", "ing"); + if (!json_is_string(value) || strcmp("testing", json_string_value(value))) + fail("json_pack string concatenation failed"); + if (value->refcount != (size_t)1) + fail("json_pack string concatenation refcount failed"); + json_decref(value); + + /* string concatenation and length (int) */ + value = json_pack("s#+#+", "test", 1, "test", 2, "test"); + if (!json_is_string(value) || strcmp("ttetest", json_string_value(value))) + fail("json_pack string concatenation and length (int) failed"); + if (value->refcount != (size_t)1) + fail("json_pack string concatenation and length (int) refcount failed"); + json_decref(value); + + /* string concatenation and length (size_t) */ + value = json_pack("s%+%+", "test", (size_t)1, "test", (size_t)2, "test"); + if (!json_is_string(value) || strcmp("ttetest", json_string_value(value))) + fail("json_pack string concatenation and length (size_t) failed"); + if (value->refcount != (size_t)1) + fail("json_pack string concatenation and length (size_t) refcount " + "failed"); + json_decref(value); + + /* empty object */ + value = json_pack("{}", 1.0); + if (!json_is_object(value) || json_object_size(value) != 0) + fail("json_pack empty object failed"); + if (value->refcount != (size_t)1) + fail("json_pack empty object refcount failed"); + json_decref(value); + + /* empty list */ + value = json_pack("[]", 1.0); + if (!json_is_array(value) || json_array_size(value) != 0) + fail("json_pack empty list failed"); + if (value->refcount != (size_t)1) + fail("json_pack empty list failed"); + json_decref(value); + + /* non-incref'd object */ + value = json_pack("o", json_integer(1)); + if (!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack object failed"); + if (value->refcount != (size_t)1) + fail("json_pack integer refcount failed"); + json_decref(value); + + /* non-incref'd nullable object (defined case) */ + value = json_pack("o?", json_integer(1)); + if (!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack nullable object (defined case) failed"); + if (value->refcount != (size_t)1) + fail("json_pack nullable object (defined case) refcount failed"); + json_decref(value); + + /* non-incref'd nullable object (NULL case) */ + value = json_pack("o?", NULL); + if (!json_is_null(value)) + fail("json_pack nullable object (NULL case) failed"); + if (value->refcount != (size_t)-1) + fail("json_pack nullable object (NULL case) refcount failed"); + json_decref(value); + + /* incref'd object */ + value = json_pack("O", json_integer(1)); + if (!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack object failed"); + if (value->refcount != (size_t)2) + fail("json_pack integer refcount failed"); + json_decref(value); + json_decref(value); + + /* incref'd nullable object (defined case) */ + value = json_pack("O?", json_integer(1)); + if (!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack incref'd nullable object (defined case) failed"); + if (value->refcount != (size_t)2) + fail("json_pack incref'd nullable object (defined case) refcount " + "failed"); + json_decref(value); + json_decref(value); + + /* incref'd nullable object (NULL case) */ + value = json_pack("O?", NULL); + if (!json_is_null(value)) + fail("json_pack incref'd nullable object (NULL case) failed"); + if (value->refcount != (size_t)-1) + fail("json_pack incref'd nullable object (NULL case) refcount failed"); + + /* simple object */ + value = json_pack("{s:[]}", "foo"); + if (!json_is_object(value) || json_object_size(value) != 1) + fail("json_pack array failed"); + if (!json_is_array(json_object_get(value, "foo"))) + fail("json_pack array failed"); + if (json_object_get(value, "foo")->refcount != (size_t)1) + fail("json_pack object refcount failed"); + json_decref(value); + + /* object with complex key */ + value = json_pack("{s+#+: []}", "foo", "barbar", 3, "baz"); + if (!json_is_object(value) || json_object_size(value) != 1) + fail("json_pack array failed"); + if (!json_is_array(json_object_get(value, "foobarbaz"))) + fail("json_pack array failed"); + if (json_object_get(value, "foobarbaz")->refcount != (size_t)1) + fail("json_pack object refcount failed"); + json_decref(value); + + /* object with optional members */ + value = json_pack("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL); + if (value) + fail("json_pack object optional incorrectly succeeded"); + + value = json_pack("{s:**}", "a", NULL); + if (value) + fail("json_pack object optional invalid incorrectly succeeded"); + + if (json_pack_ex(&error, 0, "{s:i*}", "a", 1)) + fail("json_pack object optional invalid incorrectly succeeded"); + check_error(json_error_invalid_format, "Expected format 's', got '*'", "<format>", 1, + 5, 5); + + value = json_pack("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL); + if (!json_is_object(value) || json_object_size(value) != 0) + fail("json_pack object optional failed"); + json_decref(value); + + value = json_pack("{s:s*}", "key", "\xff\xff"); + if (value) + fail("json_pack object optional with invalid UTF-8 incorrectly " + "succeeded"); + + if (json_pack_ex(&error, 0, "{s: s*#}", "key", "test", 1)) + fail("json_pack failed to catch invalid format 's*#'"); + check_error(json_error_invalid_format, "Cannot use '#' on optional strings", + "<format>", 1, 6, 6); + + if (json_pack_ex(&error, 0, "{s: s*+}", "key", "test", "ing")) + fail("json_pack failed to catch invalid format 's*+'"); + check_error(json_error_invalid_format, "Cannot use '+' on optional strings", + "<format>", 1, 6, 6); + + /* simple array */ + value = json_pack("[i,i,i]", 0, 1, 2); + if (!json_is_array(value) || json_array_size(value) != 3) + fail("json_pack object failed"); + for (i = 0; i < 3; i++) { + if (!json_is_integer(json_array_get(value, i)) || + json_integer_value(json_array_get(value, i)) != i) + + fail("json_pack integer array failed"); + } + json_decref(value); + + /* simple array with optional members */ + value = json_pack("[s,o,O]", NULL, NULL, NULL); + if (value) + fail("json_pack array optional incorrectly succeeded"); + + if (json_pack_ex(&error, 0, "[i*]", 1)) + fail("json_pack array optional invalid incorrectly succeeded"); + check_error(json_error_invalid_format, "Unexpected format character '*'", "<format>", + 1, 3, 3); + + value = json_pack("[**]", NULL); + if (value) + fail("json_pack array optional invalid incorrectly succeeded"); + value = json_pack("[s*,o*,O*]", NULL, NULL, NULL); + if (!json_is_array(value) || json_array_size(value) != 0) + fail("json_pack array optional failed"); + json_decref(value); + +#ifdef NAN + /* Invalid float values */ + if (json_pack_ex(&error, 0, "f", NAN)) + fail("json_pack NAN incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, + 1, 1); + + if (json_pack_ex(&error, 0, "[f]", NAN)) + fail("json_pack NAN array element incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, + 2, 2); + + if (json_pack_ex(&error, 0, "{s:f}", "key", NAN)) + fail("json_pack NAN object value incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "<args>", 1, + 4, 4); +#endif + +#ifdef INFINITY + test_inifity(); +#endif + + /* Whitespace; regular string */ + value = json_pack(" s\t ", "test"); + if (!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string (with whitespace) failed"); + json_decref(value); + + /* Whitespace; empty array */ + value = json_pack("[ ]"); + if (!json_is_array(value) || json_array_size(value) != 0) + fail("json_pack empty array (with whitespace) failed"); + json_decref(value); + + /* Whitespace; array */ + value = json_pack("[ i , i, i ] ", 1, 2, 3); + if (!json_is_array(value) || json_array_size(value) != 3) + fail("json_pack array (with whitespace) failed"); + json_decref(value); + + /* + * Invalid cases + */ + + /* newline in format string */ + if (json_pack_ex(&error, 0, "{\n\n1")) + fail("json_pack failed to catch invalid format '1'"); + check_error(json_error_invalid_format, "Expected format 's', got '1'", "<format>", 3, + 1, 4); + + /* mismatched open/close array/object */ + if (json_pack_ex(&error, 0, "[}")) + fail("json_pack failed to catch mismatched '}'"); + check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>", + 1, 2, 2); + + if (json_pack_ex(&error, 0, "{]")) + fail("json_pack failed to catch mismatched ']'"); + check_error(json_error_invalid_format, "Expected format 's', got ']'", "<format>", 1, + 2, 2); + + /* missing close array */ + if (json_pack_ex(&error, 0, "[")) + fail("json_pack failed to catch missing ']'"); + check_error(json_error_invalid_format, "Unexpected end of format string", "<format>", + 1, 2, 2); + + /* missing close object */ + if (json_pack_ex(&error, 0, "{")) + fail("json_pack failed to catch missing '}'"); + check_error(json_error_invalid_format, "Unexpected end of format string", "<format>", + 1, 2, 2); + + /* garbage after format string */ + if (json_pack_ex(&error, 0, "[i]a", 42)) + fail("json_pack failed to catch garbage after format string"); + check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1, + 4, 4); + + if (json_pack_ex(&error, 0, "ia", 42)) + fail("json_pack failed to catch garbage after format string"); + check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1, + 2, 2); + + /* NULL string */ + if (json_pack_ex(&error, 0, "s", NULL)) + fail("json_pack failed to catch null argument string"); + check_error(json_error_null_value, "NULL string", "<args>", 1, 1, 1); + + /* + on its own */ + if (json_pack_ex(&error, 0, "+", NULL)) + fail("json_pack failed to a lone +"); + check_error(json_error_invalid_format, "Unexpected format character '+'", "<format>", + 1, 1, 1); + + /* Empty format */ + if (json_pack_ex(&error, 0, "")) + fail("json_pack failed to catch empty format string"); + check_error(json_error_invalid_argument, "NULL or empty format string", "<format>", + -1, -1, 0); + + /* NULL format */ + if (json_pack_ex(&error, 0, NULL)) + fail("json_pack failed to catch NULL format string"); + check_error(json_error_invalid_argument, "NULL or empty format string", "<format>", + -1, -1, 0); + + /* NULL key */ + if (json_pack_ex(&error, 0, "{s:i}", NULL, 1)) + fail("json_pack failed to catch NULL key"); + check_error(json_error_null_value, "NULL object key", "<args>", 1, 2, 2); + + /* NULL value followed by object still steals the object's ref */ + value = json_incref(json_object()); + if (json_pack_ex(&error, 0, "{s:s,s:o}", "badnull", NULL, "dontleak", value)) + fail("json_pack failed to catch NULL value"); + check_error(json_error_null_value, "NULL string", "<args>", 1, 4, 4); + if (value->refcount != (size_t)1) + fail("json_pack failed to steal reference after error."); + json_decref(value); + + /* More complicated checks for row/columns */ + if (json_pack_ex(&error, 0, "{ {}: s }", "foo")) + fail("json_pack failed to catch object as key"); + check_error(json_error_invalid_format, "Expected format 's', got '{'", "<format>", 1, + 3, 3); + + /* Complex object */ + if (json_pack_ex(&error, 0, "{ s: {}, s:[ii{} }", "foo", "bar", 12, 13)) + fail("json_pack failed to catch missing ]"); + check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>", + 1, 19, 19); + + /* Complex array */ + if (json_pack_ex(&error, 0, "[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]")) + fail("json_pack failed to catch extra }"); + check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>", + 1, 21, 21); + + /* Invalid UTF-8 in object key */ + if (json_pack_ex(&error, 0, "{s:i}", "\xff\xff", 42)) + fail("json_pack failed to catch invalid UTF-8 in an object key"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 object key", "<args>", 1, 2, 2); + + /* Invalid UTF-8 in a string */ + if (json_pack_ex(&error, 0, "{s:s}", "foo", "\xff\xff")) + fail("json_pack failed to catch invalid UTF-8 in a string"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 4, 4); + + /* Invalid UTF-8 in an optional '?' string */ + if (json_pack_ex(&error, 0, "{s:s?}", "foo", "\xff\xff")) + fail("json_pack failed to catch invalid UTF-8 in an optional '?' " + "string"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 5, 5); + + /* Invalid UTF-8 in an optional '*' string */ + if (json_pack_ex(&error, 0, "{s:s*}", "foo", "\xff\xff")) + fail("json_pack failed to catch invalid UTF-8 in an optional '*' " + "string"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "<args>", 1, 5, 5); + + /* Invalid UTF-8 in a concatenated key */ + if (json_pack_ex(&error, 0, "{s+:i}", "\xff\xff", "concat", 42)) + fail("json_pack failed to catch invalid UTF-8 in an object key"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 object key", "<args>", 1, 3, 3); + + if (json_pack_ex(&error, 0, "{s:o}", "foo", NULL)) + fail("json_pack failed to catch nullable object"); + check_error(json_error_null_value, "NULL object", "<args>", 1, 4, 4); + + if (json_pack_ex(&error, 0, "{s:O}", "foo", NULL)) + fail("json_pack failed to catch nullable incref object"); + check_error(json_error_null_value, "NULL object", "<args>", 1, 4, 4); + + if (json_pack_ex(&error, 0, "{s+:o}", "foo", "bar", NULL)) + fail("json_pack failed to catch non-nullable object value"); + check_error(json_error_null_value, "NULL object", "<args>", 1, 5, 5); + + if (json_pack_ex(&error, 0, "[1s", "Hi")) + fail("json_pack failed to catch invalid format"); + check_error(json_error_invalid_format, "Unexpected format character '1'", "<format>", + 1, 2, 2); + + if (json_pack_ex(&error, 0, "[1s+", "Hi", "ya")) + fail("json_pack failed to catch invalid format"); + check_error(json_error_invalid_format, "Unexpected format character '1'", "<format>", + 1, 2, 2); + + if (json_pack_ex(&error, 0, "[so]", NULL, json_object())) + fail("json_pack failed to catch NULL value"); + check_error(json_error_null_value, "NULL string", "<args>", 1, 2, 2); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_simple.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_simple.c new file mode 100644 index 000000000..7a3f6b7bf --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_simple.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <string.h> + +static void test_bad_args(void) { + json_t *num = json_integer(1); + json_t *txt = json_string("test"); + + if (!num || !txt) + fail("failed to allocate test objects"); + + if (json_string_nocheck(NULL) != NULL) + fail("json_string_nocheck with NULL argument did not return NULL"); + if (json_stringn_nocheck(NULL, 0) != NULL) + fail("json_stringn_nocheck with NULL argument did not return NULL"); + if (json_string(NULL) != NULL) + fail("json_string with NULL argument did not return NULL"); + if (json_stringn(NULL, 0) != NULL) + fail("json_stringn with NULL argument did not return NULL"); + + if (json_string_length(NULL) != 0) + fail("json_string_length with non-string argument did not return 0"); + if (json_string_length(num) != 0) + fail("json_string_length with non-string argument did not return 0"); + + if (json_string_value(NULL) != NULL) + fail("json_string_value with non-string argument did not return NULL"); + if (json_string_value(num) != NULL) + fail("json_string_value with non-string argument did not return NULL"); + + if (!json_string_setn_nocheck(NULL, "", 0)) + fail("json_string_setn with non-string argument did not return error"); + if (!json_string_setn_nocheck(num, "", 0)) + fail("json_string_setn with non-string argument did not return error"); + if (!json_string_setn_nocheck(txt, NULL, 0)) + fail("json_string_setn_nocheck with NULL value did not return error"); + + if (!json_string_set_nocheck(txt, NULL)) + fail("json_string_set_nocheck with NULL value did not return error"); + if (!json_string_set(txt, NULL)) + fail("json_string_set with NULL value did not return error"); + if (!json_string_setn(txt, NULL, 0)) + fail("json_string_setn with NULL value did not return error"); + + if (num->refcount != 1) + fail("unexpected reference count for num"); + if (txt->refcount != 1) + fail("unexpected reference count for txt"); + + json_decref(num); + json_decref(txt); +} + +/* Call the simple functions not covered by other tests of the public API */ +static void run_tests() { + json_t *value; + + value = json_boolean(1); + if (!json_is_true(value)) + fail("json_boolean(1) failed"); + json_decref(value); + + value = json_boolean(-123); + if (!json_is_true(value)) + fail("json_boolean(-123) failed"); + json_decref(value); + + value = json_boolean(0); + if (!json_is_false(value)) + fail("json_boolean(0) failed"); + if (json_boolean_value(value) != 0) + fail("json_boolean_value failed"); + json_decref(value); + + value = json_integer(1); + if (json_typeof(value) != JSON_INTEGER) + fail("json_typeof failed"); + + if (json_is_object(value)) + fail("json_is_object failed"); + + if (json_is_array(value)) + fail("json_is_array failed"); + + if (json_is_string(value)) + fail("json_is_string failed"); + + if (!json_is_integer(value)) + fail("json_is_integer failed"); + + if (json_is_real(value)) + fail("json_is_real failed"); + + if (!json_is_number(value)) + fail("json_is_number failed"); + + if (json_is_true(value)) + fail("json_is_true failed"); + + if (json_is_false(value)) + fail("json_is_false failed"); + + if (json_is_boolean(value)) + fail("json_is_boolean failed"); + + if (json_is_null(value)) + fail("json_is_null failed"); + + json_decref(value); + + value = json_string("foo"); + if (!value) + fail("json_string failed"); + if (strcmp(json_string_value(value), "foo")) + fail("invalid string value"); + if (json_string_length(value) != 3) + fail("invalid string length"); + + if (json_string_set(value, "barr")) + fail("json_string_set failed"); + if (strcmp(json_string_value(value), "barr")) + fail("invalid string value"); + if (json_string_length(value) != 4) + fail("invalid string length"); + + if (json_string_setn(value, "hi\0ho", 5)) + fail("json_string_set failed"); + if (memcmp(json_string_value(value), "hi\0ho\0", 6)) + fail("invalid string value"); + if (json_string_length(value) != 5) + fail("invalid string length"); + + json_decref(value); + + value = json_string(NULL); + if (value) + fail("json_string(NULL) failed"); + + /* invalid UTF-8 */ + value = json_string("a\xefz"); + if (value) + fail("json_string(<invalid utf-8>) failed"); + + value = json_string_nocheck("foo"); + if (!value) + fail("json_string_nocheck failed"); + if (strcmp(json_string_value(value), "foo")) + fail("invalid string value"); + if (json_string_length(value) != 3) + fail("invalid string length"); + + if (json_string_set_nocheck(value, "barr")) + fail("json_string_set_nocheck failed"); + if (strcmp(json_string_value(value), "barr")) + fail("invalid string value"); + if (json_string_length(value) != 4) + fail("invalid string length"); + + if (json_string_setn_nocheck(value, "hi\0ho", 5)) + fail("json_string_set failed"); + if (memcmp(json_string_value(value), "hi\0ho\0", 6)) + fail("invalid string value"); + if (json_string_length(value) != 5) + fail("invalid string length"); + + json_decref(value); + + /* invalid UTF-8 */ + value = json_string_nocheck("qu\xff"); + if (!value) + fail("json_string_nocheck failed"); + if (strcmp(json_string_value(value), "qu\xff")) + fail("invalid string value"); + if (json_string_length(value) != 3) + fail("invalid string length"); + + if (json_string_set_nocheck(value, "\xfd\xfe\xff")) + fail("json_string_set_nocheck failed"); + if (strcmp(json_string_value(value), "\xfd\xfe\xff")) + fail("invalid string value"); + if (json_string_length(value) != 3) + fail("invalid string length"); + + json_decref(value); + + value = json_integer(123); + if (!value) + fail("json_integer failed"); + if (json_integer_value(value) != 123) + fail("invalid integer value"); + if (json_number_value(value) != 123.0) + fail("invalid number value"); + + if (json_integer_set(value, 321)) + fail("json_integer_set failed"); + if (json_integer_value(value) != 321) + fail("invalid integer value"); + if (json_number_value(value) != 321.0) + fail("invalid number value"); + + json_decref(value); + + value = json_real(123.123); + if (!value) + fail("json_real failed"); + if (json_real_value(value) != 123.123) + fail("invalid integer value"); + if (json_number_value(value) != 123.123) + fail("invalid number value"); + + if (json_real_set(value, 321.321)) + fail("json_real_set failed"); + if (json_real_value(value) != 321.321) + fail("invalid real value"); + if (json_number_value(value) != 321.321) + fail("invalid number value"); + + json_decref(value); + + value = json_true(); + if (!value) + fail("json_true failed"); + json_decref(value); + + value = json_false(); + if (!value) + fail("json_false failed"); + json_decref(value); + + value = json_null(); + if (!value) + fail("json_null failed"); + json_decref(value); + + /* Test reference counting on singletons (true, false, null) */ + value = json_true(); + if (value->refcount != (size_t)-1) + fail("refcounting true works incorrectly"); + json_decref(value); + if (value->refcount != (size_t)-1) + fail("refcounting true works incorrectly"); + json_incref(value); + if (value->refcount != (size_t)-1) + fail("refcounting true works incorrectly"); + + value = json_false(); + if (value->refcount != (size_t)-1) + fail("refcounting false works incorrectly"); + json_decref(value); + if (value->refcount != (size_t)-1) + fail("refcounting false works incorrectly"); + json_incref(value); + if (value->refcount != (size_t)-1) + fail("refcounting false works incorrectly"); + + value = json_null(); + if (value->refcount != (size_t)-1) + fail("refcounting null works incorrectly"); + json_decref(value); + if (value->refcount != (size_t)-1) + fail("refcounting null works incorrectly"); + json_incref(value); + if (value->refcount != (size_t)-1) + fail("refcounting null works incorrectly"); + +#ifdef json_auto_t + value = json_string("foo"); + { + json_auto_t *test = json_incref(value); + /* Use test so GCC doesn't complain it is unused. */ + if (!json_is_string(test)) + fail("value type check failed"); + } + if (value->refcount != 1) + fail("automatic decrement failed"); + json_decref(value); +#endif + + test_bad_args(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_sprintf.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_sprintf.c new file mode 100644 index 000000000..60a0b601d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_sprintf.c @@ -0,0 +1,29 @@ +#include "util.h" +#include <jansson.h> +#include <string.h> + +static void test_sprintf() { + json_t *s = json_sprintf("foo bar %d", 42); + if (!s) + fail("json_sprintf returned NULL"); + if (!json_is_string(s)) + fail("json_sprintf didn't return a JSON string"); + if (strcmp(json_string_value(s), "foo bar 42")) + fail("json_sprintf generated an unexpected string"); + + json_decref(s); + + s = json_sprintf("%s", ""); + if (!s) + fail("json_sprintf returned NULL"); + if (!json_is_string(s)) + fail("json_sprintf didn't return a JSON string"); + if (json_string_length(s) != 0) + fail("string is not empty"); + json_decref(s); + + if (json_sprintf("%s", "\xff\xff")) + fail("json_sprintf unexpected success with invalid UTF"); +} + +static void run_tests() { test_sprintf(); } diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_unpack.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_unpack.c new file mode 100644 index 000000000..139ec6f7b --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_unpack.c @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2010-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <stdio.h> +#include <string.h> + +static void run_tests() { + json_t *j, *j2; + int i1, i2, i3; + json_int_t I1; + int rv; + size_t z; + double f; + char *s; + + json_error_t error; + + /* + * Simple, valid json_pack cases + */ + + /* true */ + rv = json_unpack(json_true(), "b", &i1); + if (rv || !i1) + fail("json_unpack boolean failed"); + + /* false */ + rv = json_unpack(json_false(), "b", &i1); + if (rv || i1) + fail("json_unpack boolean failed"); + + /* null */ + if (json_unpack(json_null(), "n")) + fail("json_unpack null failed"); + + /* integer */ + j = json_integer(42); + rv = json_unpack(j, "i", &i1); + if (rv || i1 != 42) + fail("json_unpack integer failed"); + json_decref(j); + + /* json_int_t */ + j = json_integer(5555555); + rv = json_unpack(j, "I", &I1); + if (rv || I1 != 5555555) + fail("json_unpack json_int_t failed"); + json_decref(j); + + /* real */ + j = json_real(1.7); + rv = json_unpack(j, "f", &f); + if (rv || f != 1.7) + fail("json_unpack real failed"); + json_decref(j); + + /* number */ + j = json_integer(12345); + rv = json_unpack(j, "F", &f); + if (rv || f != 12345.0) + fail("json_unpack (real or) integer failed"); + json_decref(j); + + j = json_real(1.7); + rv = json_unpack(j, "F", &f); + if (rv || f != 1.7) + fail("json_unpack real (or integer) failed"); + json_decref(j); + + /* string */ + j = json_string("foo"); + rv = json_unpack(j, "s", &s); + if (rv || strcmp(s, "foo")) + fail("json_unpack string failed"); + json_decref(j); + + /* string with length (size_t) */ + j = json_string("foo"); + rv = json_unpack(j, "s%", &s, &z); + if (rv || strcmp(s, "foo") || z != 3) + fail("json_unpack string with length (size_t) failed"); + json_decref(j); + + /* empty object */ + j = json_object(); + if (json_unpack(j, "{}")) + fail("json_unpack empty object failed"); + json_decref(j); + + /* empty list */ + j = json_array(); + if (json_unpack(j, "[]")) + fail("json_unpack empty list failed"); + json_decref(j); + + /* non-incref'd object */ + j = json_object(); + rv = json_unpack(j, "o", &j2); + if (rv || j2 != j || j->refcount != 1) + fail("json_unpack object failed"); + json_decref(j); + + /* incref'd object */ + j = json_object(); + rv = json_unpack(j, "O", &j2); + if (rv || j2 != j || j->refcount != 2) + fail("json_unpack object failed"); + json_decref(j); + json_decref(j); + + /* simple object */ + j = json_pack("{s:i}", "foo", 42); + rv = json_unpack(j, "{s:i}", "foo", &i1); + if (rv || i1 != 42) + fail("json_unpack simple object failed"); + json_decref(j); + + /* simple array */ + j = json_pack("[iii]", 1, 2, 3); + rv = json_unpack(j, "[i,i,i]", &i1, &i2, &i3); + if (rv || i1 != 1 || i2 != 2 || i3 != 3) + fail("json_unpack simple array failed"); + json_decref(j); + + /* object with many items & strict checking */ + j = json_pack("{s:i, s:i, s:i}", "a", 1, "b", 2, "c", 3); + rv = json_unpack(j, "{s:i, s:i, s:i}", "a", &i1, "b", &i2, "c", &i3); + if (rv || i1 != 1 || i2 != 2 || i3 != 3) + fail("json_unpack object with many items failed"); + json_decref(j); + + /* + * Invalid cases + */ + + j = json_integer(42); + if (!json_unpack_ex(j, &error, 0, "z")) + fail("json_unpack succeeded with invalid format character"); + check_error(json_error_invalid_format, "Unexpected format character 'z'", "<format>", + 1, 1, 1); + + if (!json_unpack_ex(NULL, &error, 0, "[i]")) + fail("json_unpack succeeded with NULL root"); + check_error(json_error_null_value, "NULL root value", "<root>", -1, -1, 0); + json_decref(j); + + /* mismatched open/close array/object */ + j = json_pack("[]"); + if (!json_unpack_ex(j, &error, 0, "[}")) + fail("json_unpack failed to catch mismatched ']'"); + check_error(json_error_invalid_format, "Unexpected format character '}'", "<format>", + 1, 2, 2); + json_decref(j); + + j = json_pack("{}"); + if (!json_unpack_ex(j, &error, 0, "{]")) + fail("json_unpack failed to catch mismatched '}'"); + check_error(json_error_invalid_format, "Expected format 's', got ']'", "<format>", 1, + 2, 2); + json_decref(j); + + /* missing close array */ + j = json_pack("[]"); + if (!json_unpack_ex(j, &error, 0, "[")) + fail("json_unpack failed to catch missing ']'"); + check_error(json_error_invalid_format, "Unexpected end of format string", "<format>", + 1, 2, 2); + json_decref(j); + + /* missing close object */ + j = json_pack("{}"); + if (!json_unpack_ex(j, &error, 0, "{")) + fail("json_unpack failed to catch missing '}'"); + check_error(json_error_invalid_format, "Unexpected end of format string", "<format>", + 1, 2, 2); + json_decref(j); + + /* garbage after format string */ + j = json_pack("[i]", 42); + if (!json_unpack_ex(j, &error, 0, "[i]a", &i1)) + fail("json_unpack failed to catch garbage after format string"); + check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1, + 4, 4); + json_decref(j); + + j = json_integer(12345); + if (!json_unpack_ex(j, &error, 0, "ia", &i1)) + fail("json_unpack failed to catch garbage after format string"); + check_error(json_error_invalid_format, "Garbage after format string", "<format>", 1, + 2, 2); + json_decref(j); + + /* NULL format string */ + j = json_pack("[]"); + if (!json_unpack_ex(j, &error, 0, NULL)) + fail("json_unpack failed to catch null format string"); + check_error(json_error_invalid_argument, "NULL or empty format string", "<format>", + -1, -1, 0); + json_decref(j); + + /* NULL string pointer */ + j = json_string("foobie"); + if (!json_unpack_ex(j, &error, 0, "s", NULL)) + fail("json_unpack failed to catch null string pointer"); + check_error(json_error_null_value, "NULL string argument", "<args>", 1, 1, 1); + json_decref(j); + + /* invalid types */ + j = json_integer(42); + j2 = json_string("foo"); + if (!json_unpack_ex(j, &error, 0, "s")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected string, got integer", "<validation>", 1, + 1, 1); + + if (!json_unpack_ex(j, &error, 0, "n")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected null, got integer", "<validation>", 1, 1, + 1); + + if (!json_unpack_ex(j, &error, 0, "b")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected true or false, got integer", + "<validation>", 1, 1, 1); + + if (!json_unpack_ex(j2, &error, 0, "i")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected integer, got string", "<validation>", 1, + 1, 1); + + if (!json_unpack_ex(j2, &error, 0, "I")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected integer, got string", "<validation>", 1, + 1, 1); + + if (!json_unpack_ex(j, &error, 0, "f")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected real, got integer", "<validation>", 1, 1, + 1); + + if (!json_unpack_ex(j2, &error, 0, "F")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected real or integer, got string", + "<validation>", 1, 1, 1); + + if (!json_unpack_ex(j, &error, 0, "[i]")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected array, got integer", "<validation>", 1, + 1, 1); + + if (!json_unpack_ex(j, &error, 0, "{si}", "foo")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected object, got integer", "<validation>", 1, + 1, 1); + + json_decref(j); + json_decref(j2); + + /* Array index out of range */ + j = json_pack("[i]", 1); + if (!json_unpack_ex(j, &error, 0, "[ii]", &i1, &i2)) + fail("json_unpack failed to catch index out of array bounds"); + check_error(json_error_index_out_of_range, "Array index 1 out of range", + "<validation>", 1, 3, 3); + json_decref(j); + + /* NULL object key */ + j = json_pack("{si}", "foo", 42); + if (!json_unpack_ex(j, &error, 0, "{si}", NULL, &i1)) + fail("json_unpack failed to catch null string pointer"); + check_error(json_error_null_value, "NULL object key", "<args>", 1, 2, 2); + json_decref(j); + + /* Object key not found */ + j = json_pack("{si}", "foo", 42); + if (!json_unpack_ex(j, &error, 0, "{si}", "baz", &i1)) + fail("json_unpack failed to catch null string pointer"); + check_error(json_error_item_not_found, "Object item not found: baz", "<validation>", + 1, 3, 3); + json_decref(j); + + /* + * Strict validation + */ + + j = json_pack("[iii]", 1, 2, 3); + rv = json_unpack(j, "[iii!]", &i1, &i2, &i3); + if (rv || i1 != 1 || i2 != 2 || i3 != 3) + fail("json_unpack array with strict validation failed"); + json_decref(j); + + j = json_pack("[iii]", 1, 2, 3); + if (!json_unpack_ex(j, &error, 0, "[ii!]", &i1, &i2)) + fail("json_unpack array with strict validation failed"); + check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked", + "<validation>", 1, 5, 5); + json_decref(j); + + /* Like above, but with JSON_STRICT instead of '!' format */ + j = json_pack("[iii]", 1, 2, 3); + if (!json_unpack_ex(j, &error, JSON_STRICT, "[ii]", &i1, &i2)) + fail("json_unpack array with strict validation failed"); + check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked", + "<validation>", 1, 4, 4); + json_decref(j); + + j = json_pack("{s:s, s:i}", "foo", "bar", "baz", 42); + rv = json_unpack(j, "{sssi!}", "foo", &s, "baz", &i1); + if (rv || strcmp(s, "bar") != 0 || i1 != 42) + fail("json_unpack object with strict validation failed"); + json_decref(j); + + /* Unpack the same item twice */ + j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1); + if (!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s)) + fail("json_unpack object with strict validation failed"); + { + const char *possible_errors[] = {"2 object item(s) left unpacked: baz, quux", + "2 object item(s) left unpacked: quux, baz"}; + check_errors(json_error_end_of_input_expected, possible_errors, 2, "<validation>", + 1, 10, 10); + } + json_decref(j); + + j = json_pack("[i,{s:i,s:n},[i,i]]", 1, "foo", 2, "bar", 3, 4); + if (json_unpack_ex(j, NULL, JSON_STRICT | JSON_VALIDATE_ONLY, "[i{sisn}[ii]]", "foo", + "bar")) + fail("json_unpack complex value with strict validation failed"); + json_decref(j); + + /* ! and * must be last */ + j = json_pack("[ii]", 1, 2); + if (!json_unpack_ex(j, &error, 0, "[i!i]", &i1, &i2)) + fail("json_unpack failed to catch ! in the middle of an array"); + check_error(json_error_invalid_format, "Expected ']' after '!', got 'i'", "<format>", + 1, 4, 4); + + if (!json_unpack_ex(j, &error, 0, "[i*i]", &i1, &i2)) + fail("json_unpack failed to catch * in the middle of an array"); + check_error(json_error_invalid_format, "Expected ']' after '*', got 'i'", "<format>", + 1, 4, 4); + json_decref(j); + + j = json_pack("{sssi}", "foo", "bar", "baz", 42); + if (!json_unpack_ex(j, &error, 0, "{ss!si}", "foo", &s, "baz", &i1)) + fail("json_unpack failed to catch ! in the middle of an object"); + check_error(json_error_invalid_format, "Expected '}' after '!', got 's'", "<format>", + 1, 5, 5); + + if (!json_unpack_ex(j, &error, 0, "{ss*si}", "foo", &s, "baz", &i1)) + fail("json_unpack failed to catch ! in the middle of an object"); + check_error(json_error_invalid_format, "Expected '}' after '*', got 's'", "<format>", + 1, 5, 5); + json_decref(j); + + /* Error in nested object */ + j = json_pack("{s{snsn}}", "foo", "bar", "baz"); + if (!json_unpack_ex(j, &error, 0, "{s{sn!}}", "foo", "bar")) + fail("json_unpack nested object with strict validation failed"); + check_error(json_error_end_of_input_expected, "1 object item(s) left unpacked: baz", + "<validation>", 1, 7, 7); + json_decref(j); + + /* Error in nested array */ + j = json_pack("[[ii]]", 1, 2); + if (!json_unpack_ex(j, &error, 0, "[[i!]]", &i1)) + fail("json_unpack nested array with strict validation failed"); + check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked", + "<validation>", 1, 5, 5); + json_decref(j); + + /* Optional values */ + j = json_object(); + i1 = 0; + if (json_unpack(j, "{s?i}", "foo", &i1)) + fail("json_unpack failed for optional key"); + if (i1 != 0) + fail("json_unpack unpacked an optional key"); + json_decref(j); + + i1 = 0; + j = json_pack("{si}", "foo", 42); + if (json_unpack(j, "{s?i}", "foo", &i1)) + fail("json_unpack failed for an optional value"); + if (i1 != 42) + fail("json_unpack failed to unpack an optional value"); + json_decref(j); + + j = json_object(); + i1 = i2 = i3 = 0; + if (json_unpack(j, "{s?[ii]s?{s{si}}}", "foo", &i1, &i2, "bar", "baz", "quux", &i3)) + fail("json_unpack failed for complex optional values"); + if (i1 != 0 || i2 != 0 || i3 != 0) + fail("json_unpack unexpectedly unpacked something"); + json_decref(j); + + j = json_pack("{s{si}}", "foo", "bar", 42); + if (json_unpack(j, "{s?{s?i}}", "foo", "bar", &i1)) + fail("json_unpack failed for complex optional values"); + if (i1 != 42) + fail("json_unpack failed to unpack"); + json_decref(j); + + /* Combine ? and ! */ + j = json_pack("{si}", "foo", 42); + i1 = i2 = 0; + if (json_unpack(j, "{sis?i!}", "foo", &i1, "bar", &i2)) + fail("json_unpack failed for optional values with strict mode"); + if (i1 != 42) + fail("json_unpack failed to unpack"); + if (i2 != 0) + fail("json_unpack failed to unpack"); + json_decref(j); + + /* But don't compensate a missing key with an optional one. */ + j = json_pack("{sisi}", "foo", 42, "baz", 43); + i1 = i2 = i3 = 0; + if (!json_unpack_ex(j, &error, 0, "{sis?i!}", "foo", &i1, "bar", &i2)) + fail("json_unpack failed for optional values with strict mode and " + "compensation"); + check_error(json_error_end_of_input_expected, "1 object item(s) left unpacked: baz", + "<validation>", 1, 8, 8); + json_decref(j); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_version.c b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_version.c new file mode 100644 index 000000000..05e0e9614 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/test_version.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019 Sean Bright <sean.bright@gmail.com> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "util.h" +#include <jansson.h> +#include <string.h> + +static void test_version_str(void) { + if (strcmp(jansson_version_str(), JANSSON_VERSION)) { + fail("jansson_version_str returned invalid version string"); + } +} + +static void test_version_cmp() { + if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION, + JANSSON_MICRO_VERSION)) { + fail("jansson_version_cmp equality check failed"); + } + + if (jansson_version_cmp(JANSSON_MAJOR_VERSION - 1, 0, 0) <= 0) { + fail("jansson_version_cmp less than check failed"); + } + + if (JANSSON_MINOR_VERSION) { + if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION - 1, + JANSSON_MICRO_VERSION) <= 0) { + fail("jansson_version_cmp less than check failed"); + } + } + + if (JANSSON_MICRO_VERSION) { + if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION, + JANSSON_MICRO_VERSION - 1) <= 0) { + fail("jansson_version_cmp less than check failed"); + } + } + + if (jansson_version_cmp(JANSSON_MAJOR_VERSION + 1, JANSSON_MINOR_VERSION, + JANSSON_MICRO_VERSION) >= 0) { + fail("jansson_version_cmp greater than check failed"); + } + + if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION + 1, + JANSSON_MICRO_VERSION) >= 0) { + fail("jansson_version_cmp greater than check failed"); + } + + if (jansson_version_cmp(JANSSON_MAJOR_VERSION, JANSSON_MINOR_VERSION, + JANSSON_MICRO_VERSION + 1) >= 0) { + fail("jansson_version_cmp greater than check failed"); + } +} + +static void run_tests() { + test_version_str(); + test_version_cmp(); +} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/api/util.h b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/util.h new file mode 100644 index 000000000..d964c4930 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/api/util.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef UTIL_H +#define UTIL_H + +#ifdef HAVE_CONFIG_H +#include <jansson_private_config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#if HAVE_LOCALE_H +#include <locale.h> +#endif + +#include <jansson.h> + +#define failhdr fprintf(stderr, "%s:%d: ", __FILE__, __LINE__) + +#define fail(msg) \ + do { \ + failhdr; \ + fprintf(stderr, "%s\n", msg); \ + exit(1); \ + } while (0) + +/* Assumes json_error_t error */ +#define check_errors(code_, texts_, num_, source_, line_, column_, position_) \ + do { \ + int i_, found_ = 0; \ + if (json_error_code(&error) != code_) { \ + failhdr; \ + fprintf(stderr, "code: %d != %d\n", json_error_code(&error), code_); \ + exit(1); \ + } \ + for (i_ = 0; i_ < num_; i_++) { \ + if (strcmp(error.text, texts_[i_]) == 0) { \ + found_ = 1; \ + break; \ + } \ + } \ + if (!found_) { \ + failhdr; \ + if (num_ == 1) { \ + fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, texts_[0]); \ + } else { \ + fprintf(stderr, "text: \"%s\" does not match\n", error.text); \ + } \ + exit(1); \ + } \ + if (strcmp(error.source, source_) != 0) { \ + failhdr; \ + \ + fprintf(stderr, "source: \"%s\" != \"%s\"\n", error.source, source_); \ + exit(1); \ + } \ + if (error.line != line_) { \ + failhdr; \ + fprintf(stderr, "line: %d != %d\n", error.line, line_); \ + exit(1); \ + } \ + if (error.column != column_) { \ + failhdr; \ + fprintf(stderr, "column: %d != %d\n", error.column, column_); \ + exit(1); \ + } \ + if (error.position != position_) { \ + failhdr; \ + fprintf(stderr, "position: %d != %d\n", error.position, position_); \ + exit(1); \ + } \ + } while (0) + +/* Assumes json_error_t error */ +#define check_error(code_, text_, source_, line_, column_, position_) \ + check_errors(code_, &text_, 1, source_, line_, column_, position_) + +static void run_tests(); + +int main() { +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + run_tests(); + return 0; +} + +#endif diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/array/input new file mode 100644 index 000000000..44e2ace7e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/array/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/array/output new file mode 100644 index 000000000..fd8ef0957 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/array/output @@ -0,0 +1 @@ +[1, 2]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-array/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-array/env new file mode 100644 index 000000000..4474aaf14 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-array/env @@ -0,0 +1,2 @@ +JSON_COMPACT=1 +export JSON_COMPACT diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-array/input new file mode 100644 index 000000000..44e2ace7e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-array/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-array/output new file mode 100644 index 000000000..3169929f6 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-array/output @@ -0,0 +1 @@ +[1,2]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-object/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-object/env new file mode 100644 index 000000000..93cb33dda --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-object/env @@ -0,0 +1,3 @@ +JSON_COMPACT=1 +HASHSEED=1 +export JSON_COMPACT HASHSEED diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-object/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-object/input new file mode 100644 index 000000000..062e54fb4 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-object/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-object/output new file mode 100644 index 000000000..73a5d70e3 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/compact-object/output @@ -0,0 +1 @@ +{"a":1,"b":2}
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/ensure-ascii/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/ensure-ascii/env new file mode 100644 index 000000000..1b7b3e3f9 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/ensure-ascii/env @@ -0,0 +1,2 @@ +JSON_ENSURE_ASCII=1 +export JSON_ENSURE_ASCII diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/ensure-ascii/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/ensure-ascii/input new file mode 100644 index 000000000..69469cef5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/ensure-ascii/input @@ -0,0 +1,8 @@ +[ + "foo", + "å ä ö", + "foo åä", + "åä foo", + "å foo ä", + "clef g: 𝄞" +] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/ensure-ascii/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/ensure-ascii/output new file mode 100644 index 000000000..94fa79d2d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/ensure-ascii/output @@ -0,0 +1 @@ +["foo", "\u00E5 \u00E4 \u00F6", "foo \u00E5\u00E4", "\u00E5\u00E4 foo", "\u00E5 foo \u00E4", "clef g: \uD834\uDD1E"]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-array/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-array/env new file mode 100644 index 000000000..d220f837c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-array/env @@ -0,0 +1,2 @@ +JSON_INDENT=4 +export JSON_INDENT diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-array/input new file mode 100644 index 000000000..44e2ace7e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-array/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-array/output new file mode 100644 index 000000000..c57d705ba --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-array/output @@ -0,0 +1,4 @@ +[ + 1, + 2 +]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-array/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-array/env new file mode 100644 index 000000000..78fbfcc2e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-array/env @@ -0,0 +1,3 @@ +JSON_INDENT=4 +JSON_COMPACT=1 +export JSON_INDENT JSON_COMPACT diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-array/input new file mode 100644 index 000000000..44e2ace7e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-array/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-array/output new file mode 100644 index 000000000..c57d705ba --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-array/output @@ -0,0 +1,4 @@ +[ + 1, + 2 +]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-object/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-object/env new file mode 100644 index 000000000..c73acc179 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-object/env @@ -0,0 +1,4 @@ +JSON_INDENT=4 +JSON_COMPACT=1 +HASHSEED=1 +export JSON_INDENT JSON_COMPACT HASHSEED diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-object/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-object/input new file mode 100644 index 000000000..062e54fb4 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-object/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-object/output new file mode 100644 index 000000000..9cc42948d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-compact-object/output @@ -0,0 +1,4 @@ +{ + "a":1, + "b":2 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-object/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-object/env new file mode 100644 index 000000000..961558ca2 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-object/env @@ -0,0 +1,3 @@ +JSON_INDENT=4 +HASHSEED=1 +export JSON_INDENT HASHSEED diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-object/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-object/input new file mode 100644 index 000000000..062e54fb4 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-object/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-object/output new file mode 100644 index 000000000..0fbddba44 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/indent-object/output @@ -0,0 +1,4 @@ +{ + "a": 1, + "b": 2 +}
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/object/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/object/env new file mode 100644 index 000000000..9120b0351 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/object/env @@ -0,0 +1,2 @@ +HASHSEED=1 +export HASHSEED diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/object/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/object/input new file mode 100644 index 000000000..062e54fb4 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/object/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/object/output new file mode 100644 index 000000000..ecd219f72 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/object/output @@ -0,0 +1 @@ +{"a": 1, "b": 2}
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/preserve-order/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/preserve-order/env new file mode 100644 index 000000000..4d9d20659 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/preserve-order/env @@ -0,0 +1,2 @@ +JSON_PRESERVE_ORDER=1 +export JSON_PRESERVE_ORDER diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/preserve-order/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/preserve-order/input new file mode 100644 index 000000000..27bcf18a0 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/preserve-order/input @@ -0,0 +1 @@ +{"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/preserve-order/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/preserve-order/output new file mode 100644 index 000000000..7a443f684 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/preserve-order/output @@ -0,0 +1 @@ +{"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6}
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/real-precision/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/real-precision/env new file mode 100644 index 000000000..9c52cbcd6 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/real-precision/env @@ -0,0 +1,2 @@ +JSON_REAL_PRECISION=4 +export JSON_REAL_PRECISION diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/real-precision/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/real-precision/input new file mode 100644 index 000000000..e291165c1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/real-precision/input @@ -0,0 +1 @@ +[1.23456789, 1.0, 1.0000000000000002] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/real-precision/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/real-precision/output new file mode 100644 index 000000000..f273c73e5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/real-precision/output @@ -0,0 +1 @@ +[1.235, 1.0, 1.0]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/run b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/run new file mode 100755 index 000000000..5db7d5e5c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/run @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +is_test() { + test -d $test_path +} + +run_test() { + ( + if [ -f $test_path/env ]; then + . $test_path/env + fi + $json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr + ) + valgrind_check $test_log/stderr || return 1 + cmp -s $test_path/output $test_log/stdout +} + +show_error() { + valgrind_show_error && return + + echo "EXPECTED OUTPUT:" + nl -bn $test_path/output + echo "ACTUAL OUTPUT:" + nl -bn $test_log/stdout +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/sort-keys/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/sort-keys/env new file mode 100644 index 000000000..3ef24cb7b --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/sort-keys/env @@ -0,0 +1,2 @@ +JSON_SORT_KEYS=1 +export JSON_SORT_KEYS diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/sort-keys/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/sort-keys/input new file mode 100644 index 000000000..66951d6b0 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/sort-keys/input @@ -0,0 +1 @@ +{"foo": 1, "bar": 2, "baz": 3, "quux": 4} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/sort-keys/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/sort-keys/output new file mode 100644 index 000000000..132d9df31 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/encoding-flags/sort-keys/output @@ -0,0 +1 @@ +{"bar": 2, "baz": 3, "foo": 1, "quux": 4}
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/encoded-surrogate-half/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/encoded-surrogate-half/error new file mode 100644 index 000000000..762d2c4b1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/encoded-surrogate-half/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xed near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/encoded-surrogate-half/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/encoded-surrogate-half/input new file mode 100644 index 000000000..515dd933c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/encoded-surrogate-half/input @@ -0,0 +1 @@ +[" <-- encoded surrogate half"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-after-backslash/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-after-backslash/error new file mode 100644 index 000000000..b16dc171e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-after-backslash/error @@ -0,0 +1,2 @@ +1 3 3 +unable to decode byte 0xe5 near '"\' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input new file mode 100644 index 000000000..57c8beef6 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input @@ -0,0 +1 @@ +["\"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-array/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-array/error new file mode 100644 index 000000000..be15386df --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-array/error @@ -0,0 +1,2 @@ +1 1 1 +unable to decode byte 0xe5 diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-array/input new file mode 100644 index 000000000..ebefcd6f8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-array/input @@ -0,0 +1 @@ +[] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error new file mode 100644 index 000000000..01b447639 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error @@ -0,0 +1,2 @@ +1 4 4 +unable to decode byte 0xe5 near '123' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input new file mode 100644 index 000000000..e512f9ae0 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input @@ -0,0 +1 @@ +[123] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-escape/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-escape/error new file mode 100644 index 000000000..c13583dd8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-escape/error @@ -0,0 +1,2 @@ +1 4 4 +unable to decode byte 0xe5 near '"\u' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-escape/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-escape/input new file mode 100644 index 000000000..2b271b82f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-escape/input @@ -0,0 +1 @@ +["\u"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-exponent/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-exponent/error new file mode 100644 index 000000000..c7b20b7a2 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-exponent/error @@ -0,0 +1,2 @@ +1 4 4 +unable to decode byte 0xe5 near '1e1' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input new file mode 100644 index 000000000..d8e83c595 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input @@ -0,0 +1 @@ +[1e1] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-identifier/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-identifier/error new file mode 100644 index 000000000..33dfc2324 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-identifier/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe5 near 'a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input new file mode 100644 index 000000000..ef038514a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input @@ -0,0 +1 @@ +[a] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-int/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-int/error new file mode 100644 index 000000000..8f08970c1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-int/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe5 near '0' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-int/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-int/input new file mode 100644 index 000000000..371226e4c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-int/input @@ -0,0 +1 @@ +[0] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error new file mode 100644 index 000000000..b7660e327 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error @@ -0,0 +1,2 @@ +1 3 3 +unable to decode byte 0xe5 near '1e' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input new file mode 100644 index 000000000..17fc29c90 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input @@ -0,0 +1 @@ +[1e] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-string/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-string/error new file mode 100644 index 000000000..0b7039a52 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-string/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe5 near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-string/input new file mode 100644 index 000000000..00b79c0af --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/invalid-utf-8-in-string/input @@ -0,0 +1 @@ +[" <-- invalid UTF-8"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-invalid-utf-8/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-invalid-utf-8/error new file mode 100644 index 000000000..8e9a51119 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-invalid-utf-8/error @@ -0,0 +1,2 @@ +1 0 0 +unable to decode byte 0xe5 diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-invalid-utf-8/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-invalid-utf-8/input new file mode 100644 index 000000000..eb8079699 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-invalid-utf-8/input @@ -0,0 +1 @@ + diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-utf-8-continuation-byte/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-utf-8-continuation-byte/error new file mode 100644 index 000000000..86bbad3c8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-utf-8-continuation-byte/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0x81 near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input new file mode 100644 index 000000000..62a26b6fb --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input @@ -0,0 +1 @@ +[""] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/not-in-unicode-range/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/not-in-unicode-range/error new file mode 100644 index 000000000..d07ccb3e5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/not-in-unicode-range/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xf4 near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/not-in-unicode-range/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/not-in-unicode-range/input new file mode 100644 index 000000000..1216186a7 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/not-in-unicode-range/input @@ -0,0 +1 @@ +[""] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-3-byte-encoding/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-3-byte-encoding/error new file mode 100644 index 000000000..8a05abaed --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-3-byte-encoding/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe0 near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-3-byte-encoding/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-3-byte-encoding/input new file mode 100644 index 000000000..0bf909f7b --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-3-byte-encoding/input @@ -0,0 +1 @@ +[" <-- overlong encoding"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-4-byte-encoding/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-4-byte-encoding/error new file mode 100644 index 000000000..7e19c5fe4 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-4-byte-encoding/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xf0 near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-4-byte-encoding/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-4-byte-encoding/input new file mode 100644 index 000000000..c6b631350 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-4-byte-encoding/input @@ -0,0 +1 @@ +[" <-- overlong encoding"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-ascii-encoding/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-ascii-encoding/error new file mode 100644 index 000000000..1d382edd7 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-ascii-encoding/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xc1 near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-ascii-encoding/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-ascii-encoding/input new file mode 100644 index 000000000..ef6e10a34 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/overlong-ascii-encoding/input @@ -0,0 +1 @@ +[""] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/restricted-utf-8/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/restricted-utf-8/error new file mode 100644 index 000000000..d018f5ff3 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/restricted-utf-8/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xfd near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/restricted-utf-8/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/restricted-utf-8/input new file mode 100644 index 000000000..ba6017002 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/restricted-utf-8/input @@ -0,0 +1 @@ +[""] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/run b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/run new file mode 100755 index 000000000..369c43da5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/run @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +is_test() { + test -d $test_path +} + +run_test() { + $json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr + valgrind_check $test_log/stderr || return 1 + cmp -s $test_path/error $test_log/stderr +} + +show_error() { + valgrind_show_error && return + + echo "EXPECTED ERROR:" + nl -bn $test_path/error + echo "ACTUAL ERROR:" + nl -bn $test_log/stderr +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/truncated-utf-8/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/truncated-utf-8/error new file mode 100644 index 000000000..8a05abaed --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/truncated-utf-8/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe0 near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/truncated-utf-8/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/truncated-utf-8/input new file mode 100644 index 000000000..bce9e18bf --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid-unicode/truncated-utf-8/input @@ -0,0 +1 @@ +[" <-- truncated UTF-8"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/apostrophe/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/apostrophe/error new file mode 100644 index 000000000..79bb2a0eb --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/apostrophe/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near ''' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/apostrophe/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/apostrophe/input new file mode 100644 index 000000000..f2dd4d224 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/apostrophe/input @@ -0,0 +1 @@ +[' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/ascii-unicode-identifier/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/ascii-unicode-identifier/error new file mode 100644 index 000000000..a4d814280 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/ascii-unicode-identifier/error @@ -0,0 +1,2 @@ +1 1 1 +'[' or '{' expected near 'a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/ascii-unicode-identifier/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/ascii-unicode-identifier/input new file mode 100644 index 000000000..c2c0208ed --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/ascii-unicode-identifier/input @@ -0,0 +1 @@ +aå diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/brace-comma/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/brace-comma/error new file mode 100644 index 000000000..ce046213c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/brace-comma/error @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near ',' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/brace-comma/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/brace-comma/input new file mode 100644 index 000000000..74a6628d4 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/brace-comma/input @@ -0,0 +1 @@ +{, diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-comma/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-comma/error new file mode 100644 index 000000000..ce0a912bf --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-comma/error @@ -0,0 +1,2 @@ +1 2 2 +unexpected token near ',' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-comma/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-comma/input new file mode 100644 index 000000000..5b911f11d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-comma/input @@ -0,0 +1 @@ +[, diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-one-comma/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-one-comma/error.normal new file mode 100644 index 000000000..0248b114a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-one-comma/error.normal @@ -0,0 +1,2 @@ +2 0 4 +']' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-one-comma/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-one-comma/error.strip new file mode 100644 index 000000000..f89b38fcb --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-one-comma/error.strip @@ -0,0 +1,2 @@ +1 3 3 +']' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-one-comma/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-one-comma/input new file mode 100644 index 000000000..874691b1d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/bracket-one-comma/input @@ -0,0 +1 @@ +[1, diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/empty/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/empty/error new file mode 100644 index 000000000..f45da6f82 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/empty/error @@ -0,0 +1,2 @@ +1 0 0 +'[' or '{' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/empty/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/empty/input new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/empty/input diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-array/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-array/error new file mode 100644 index 000000000..cae86c246 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-array/error @@ -0,0 +1,2 @@ +1 4 4 +unexpected token near ']' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-array/input new file mode 100644 index 000000000..e8b1a170f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-array/input @@ -0,0 +1 @@ +[1,] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-multiline-array/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-multiline-array/error new file mode 100644 index 000000000..5baeea447 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-multiline-array/error @@ -0,0 +1,2 @@ +6 1 17 +unexpected token near ']' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-multiline-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-multiline-array/input new file mode 100644 index 000000000..bcb2a7526 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/extra-comma-in-multiline-array/input @@ -0,0 +1,6 @@ +[1, +2, +3, +4, +5, +] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-after-newline/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-after-newline/error new file mode 100644 index 000000000..5d2dec374 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-after-newline/error @@ -0,0 +1,2 @@ +2 3 11 +end of file expected near 'foo' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-after-newline/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-after-newline/input new file mode 100644 index 000000000..3614ac78f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-after-newline/input @@ -0,0 +1,2 @@ +[1,2,3] +foo diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-at-the-end/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-at-the-end/error new file mode 100644 index 000000000..cdd817572 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-at-the-end/error @@ -0,0 +1,2 @@ +1 10 10 +end of file expected near 'foo' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-at-the-end/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-at-the-end/input new file mode 100644 index 000000000..55aee53d2 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/garbage-at-the-end/input @@ -0,0 +1 @@ +[1,2,3]foo diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/integer-starting-with-zero/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/integer-starting-with-zero/error new file mode 100644 index 000000000..64e0536aa --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/integer-starting-with-zero/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near '0' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/integer-starting-with-zero/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/integer-starting-with-zero/input new file mode 100644 index 000000000..12f67e2c2 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/integer-starting-with-zero/input @@ -0,0 +1 @@ +[012] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-escape/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-escape/error new file mode 100644 index 000000000..d9863f73b --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-escape/error @@ -0,0 +1,2 @@ +1 4 4 +invalid escape near '"\a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-escape/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-escape/input new file mode 100644 index 000000000..64c7b70d9 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-escape/input @@ -0,0 +1 @@ +["\a <-- invalid escape"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-identifier/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-identifier/error new file mode 100644 index 000000000..496c6aba2 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-identifier/error @@ -0,0 +1,2 @@ +1 5 5 +invalid token near 'troo' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-identifier/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-identifier/input new file mode 100644 index 000000000..3d2860da1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-identifier/input @@ -0,0 +1 @@ +[troo diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-integer/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-integer/error new file mode 100644 index 000000000..f2526c51e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-integer/error @@ -0,0 +1,2 @@ +1 8 8 +']' expected near 'foo' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-integer/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-integer/input new file mode 100644 index 000000000..6196980ec --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-integer/input @@ -0,0 +1 @@ +[-123foo] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-real/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-real/error new file mode 100644 index 000000000..933158ae5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-real/error @@ -0,0 +1,2 @@ +1 12 12 +']' expected near 'foo' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-real/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-real/input new file mode 100644 index 000000000..3c763d334 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-negative-real/input @@ -0,0 +1 @@ +[-123.123foo] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-second-surrogate/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-second-surrogate/error new file mode 100644 index 000000000..e5a2359e6 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-second-surrogate/error @@ -0,0 +1,2 @@ +1 62 62 +invalid Unicode '\uD888\u3210' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-second-surrogate/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-second-surrogate/input new file mode 100644 index 000000000..b21453f6f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-second-surrogate/input @@ -0,0 +1 @@ +["\uD888\u3210 (first surrogate and invalid second surrogate)"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-unicode-escape/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-unicode-escape/error new file mode 100644 index 000000000..221c762eb --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-unicode-escape/error @@ -0,0 +1,2 @@ +1 5 5 +invalid escape near '"\uq' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-unicode-escape/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-unicode-escape/input new file mode 100644 index 000000000..f381e85b8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/invalid-unicode-escape/input @@ -0,0 +1 @@ +["\uqqqq <-- invalid unicode escape"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-brace/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-brace/error.normal new file mode 100644 index 000000000..00dc765b9 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-brace/error.normal @@ -0,0 +1,2 @@ +2 0 2 +string or '}' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-brace/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-brace/error.strip new file mode 100644 index 000000000..bb1c04745 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-brace/error.strip @@ -0,0 +1,2 @@ +1 1 1 +string or '}' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-brace/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-brace/input new file mode 100644 index 000000000..98232c64f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-brace/input @@ -0,0 +1 @@ +{ diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-bracket/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-bracket/error.normal new file mode 100644 index 000000000..f463928f8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-bracket/error.normal @@ -0,0 +1,2 @@ +2 0 2 +']' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-bracket/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-bracket/error.strip new file mode 100644 index 000000000..2bc07ea0c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-bracket/error.strip @@ -0,0 +1,2 @@ +1 1 1 +']' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-bracket/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-bracket/input new file mode 100644 index 000000000..558ed37d9 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-open-bracket/input @@ -0,0 +1 @@ +[ diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-second-surrogate/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-second-surrogate/error new file mode 100644 index 000000000..bc5f34e11 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-second-surrogate/error @@ -0,0 +1,2 @@ +1 40 40 +invalid Unicode '\uDFAA' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-second-surrogate/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-second-surrogate/input new file mode 100644 index 000000000..328e35c82 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/lone-second-surrogate/input @@ -0,0 +1 @@ +["\uDFAA (second surrogate on it's own)"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/minus-sign-without-number/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/minus-sign-without-number/error new file mode 100644 index 000000000..b3a78b978 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/minus-sign-without-number/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near '-' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/minus-sign-without-number/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/minus-sign-without-number/input new file mode 100644 index 000000000..033788355 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/minus-sign-without-number/input @@ -0,0 +1 @@ +[-foo] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/negative-integer-starting-with-zero/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/negative-integer-starting-with-zero/error new file mode 100644 index 000000000..36adc34b4 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/negative-integer-starting-with-zero/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '-0' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/negative-integer-starting-with-zero/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/negative-integer-starting-with-zero/input new file mode 100644 index 000000000..6fbb7a2f8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/negative-integer-starting-with-zero/input @@ -0,0 +1 @@ +[-012] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-object-key/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-object-key/error new file mode 100644 index 000000000..3ec685b5d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-object-key/error @@ -0,0 +1,2 @@ +1 15 15 +NUL byte in object key not supported near '"foo\u0000bar"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-object-key/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-object-key/input new file mode 100644 index 000000000..593f0f67f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-object-key/input @@ -0,0 +1 @@ +{"foo\u0000bar": 42}
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-string/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-string/error new file mode 100644 index 000000000..45f9bd817 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-string/error @@ -0,0 +1,2 @@ +1 12 12 +control character 0x0 near '"null byte ' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-string/input Binary files differnew file mode 100644 index 000000000..268d1f194 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-string/input diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-string/nostrip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-string/nostrip new file mode 100644 index 000000000..80f4bf761 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-in-string/nostrip @@ -0,0 +1,2 @@ +The embedded NULL byte breaks json_loads(), which is used instead of +json_loadf() in the stripped tests. diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-outside-string/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-outside-string/error new file mode 100644 index 000000000..44d4def92 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-outside-string/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-outside-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-outside-string/input Binary files differnew file mode 100644 index 000000000..aa550eb0c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-outside-string/input diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-outside-string/nostrip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-outside-string/nostrip new file mode 100644 index 000000000..80f4bf761 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-byte-outside-string/nostrip @@ -0,0 +1,2 @@ +The embedded NULL byte breaks json_loads(), which is used instead of +json_loadf() in the stripped tests. diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-escape-in-string/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-escape-in-string/error new file mode 100644 index 000000000..3f5c8c6ca --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-escape-in-string/error @@ -0,0 +1,2 @@ +1 33 33 +\u0000 is not allowed without JSON_ALLOW_NUL diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-escape-in-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-escape-in-string/input new file mode 100644 index 000000000..dbc9c9a99 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null-escape-in-string/input @@ -0,0 +1 @@ +["null escape \u0000 not allowed"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null/error new file mode 100644 index 000000000..1f5d46490 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null/error @@ -0,0 +1,2 @@ +1 4 4 +'[' or '{' expected near 'null' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null/input new file mode 100644 index 000000000..19765bd50 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/null/input @@ -0,0 +1 @@ +null diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-apostrophes/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-apostrophes/error new file mode 100644 index 000000000..23fab01f6 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-apostrophes/error @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near ''' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-apostrophes/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-apostrophes/input new file mode 100644 index 000000000..52b290574 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-apostrophes/input @@ -0,0 +1 @@ +{'a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-garbage-at-end/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-garbage-at-end/error new file mode 100644 index 000000000..06c4ec1c2 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-garbage-at-end/error @@ -0,0 +1,2 @@ +1 12 12 +'}' expected near '123' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-garbage-at-end/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-garbage-at-end/input new file mode 100644 index 000000000..62c19d742 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-garbage-at-end/input @@ -0,0 +1 @@ +{"a":"a" 123} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-in-unterminated-array/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-in-unterminated-array/error.normal new file mode 100644 index 000000000..0248b114a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-in-unterminated-array/error.normal @@ -0,0 +1,2 @@ +2 0 4 +']' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-in-unterminated-array/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-in-unterminated-array/error.strip new file mode 100644 index 000000000..f89b38fcb --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-in-unterminated-array/error.strip @@ -0,0 +1,2 @@ +1 3 3 +']' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-in-unterminated-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-in-unterminated-array/input new file mode 100644 index 000000000..ca9ec378e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-in-unterminated-array/input @@ -0,0 +1 @@ +[{} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-colon/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-colon/error.normal new file mode 100644 index 000000000..78d84f7b7 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-colon/error.normal @@ -0,0 +1,2 @@ +2 0 5 +':' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-colon/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-colon/error.strip new file mode 100644 index 000000000..528e266d2 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-colon/error.strip @@ -0,0 +1,2 @@ +1 4 4 +':' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-colon/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-colon/input new file mode 100644 index 000000000..107e6265c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-colon/input @@ -0,0 +1 @@ +{"a" diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-value/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-value/error.normal new file mode 100644 index 000000000..47ad902dd --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-value/error.normal @@ -0,0 +1,2 @@ +2 0 6 +unexpected token near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-value/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-value/error.strip new file mode 100644 index 000000000..b36c5e2bc --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-value/error.strip @@ -0,0 +1,2 @@ +1 5 5 +unexpected token near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-value/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-value/input new file mode 100644 index 000000000..f68f26269 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-no-value/input @@ -0,0 +1 @@ +{"a": diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-unterminated-value/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-unterminated-value/error.normal new file mode 100644 index 000000000..2ad76d473 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-unterminated-value/error.normal @@ -0,0 +1,2 @@ +1 7 7 +unexpected newline near '"a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-unterminated-value/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-unterminated-value/error.strip new file mode 100644 index 000000000..385afb534 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-unterminated-value/error.strip @@ -0,0 +1,2 @@ +1 7 7 +premature end of input near '"a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-unterminated-value/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-unterminated-value/input new file mode 100644 index 000000000..b854d7e18 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/object-unterminated-value/input @@ -0,0 +1 @@ +{"a":"a diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-garbage-after-e/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-garbage-after-e/error new file mode 100644 index 000000000..b40ffa9b5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-garbage-after-e/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '1e' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-garbage-after-e/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-garbage-after-e/input new file mode 100644 index 000000000..6a945ac0f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-garbage-after-e/input @@ -0,0 +1 @@ +[1ea] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-negative-overflow/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-negative-overflow/error new file mode 100644 index 000000000..d7f8e412d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-negative-overflow/error @@ -0,0 +1,2 @@ +1 15 15 +real number overflow near '-123123e100000' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-negative-overflow/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-negative-overflow/input new file mode 100644 index 000000000..b5bd21c46 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-negative-overflow/input @@ -0,0 +1 @@ +[-123123e100000] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-positive-overflow/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-positive-overflow/error new file mode 100644 index 000000000..55883c981 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-positive-overflow/error @@ -0,0 +1,2 @@ +1 14 14 +real number overflow near '123123e100000' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-positive-overflow/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-positive-overflow/input new file mode 100644 index 000000000..524e53b31 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-positive-overflow/input @@ -0,0 +1 @@ +[123123e100000] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-e/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-e/error new file mode 100644 index 000000000..b40ffa9b5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-e/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '1e' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-e/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-e/input new file mode 100644 index 000000000..1d67b7b82 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-e/input @@ -0,0 +1 @@ +[1e] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-point/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-point/error new file mode 100644 index 000000000..db972e8e1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-point/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '1.' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-point/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-point/input new file mode 100644 index 000000000..b652b3fe0 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/real-truncated-at-point/input @@ -0,0 +1 @@ +[1.] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/recursion-depth/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/recursion-depth/error new file mode 100644 index 000000000..11e0537ff --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/recursion-depth/error @@ -0,0 +1,2 @@ +1 2049 2049 +maximum parsing depth reached near '[' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/recursion-depth/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/recursion-depth/input new file mode 100644 index 000000000..bfa47d9d1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/recursion-depth/input @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/run b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/run new file mode 100755 index 000000000..d1d490c63 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/run @@ -0,0 +1,57 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +is_test() { + test -d $test_path +} + +do_run() { + variant=$1 + s=".$1" + + strip=0 + if [ "$variant" = "strip" ]; then + # This test should not be stripped + [ -f $test_path/nostrip ] && return + strip=1 + fi + + STRIP=$strip $json_process --env \ + <$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s + valgrind_check $test_log/stderr$s || return 1 + + ref=error + [ -f $test_path/error$s ] && ref=error$s + + if ! cmp -s $test_path/$ref $test_log/stderr$s; then + echo $variant > $test_log/variant + return 1 + fi +} + +run_test() { + do_run normal && do_run strip +} + +show_error() { + valgrind_show_error && return + + read variant < $test_log/variant + s=".$variant" + + echo "VARIANT: $variant" + + echo "EXPECTED ERROR:" + ref=error + [ -f $test_path/error$s ] && ref=error$s + nl -bn $test_path/$ref + + echo "ACTUAL ERROR:" + nl -bn $test_log/stderr$s +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/tab-character-in-string/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/tab-character-in-string/error new file mode 100644 index 000000000..9e2f76ed2 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/tab-character-in-string/error @@ -0,0 +1,2 @@ +1 2 2 +control character 0x9 near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/tab-character-in-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/tab-character-in-string/input new file mode 100644 index 000000000..3ebae0953 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/tab-character-in-string/input @@ -0,0 +1 @@ +[" <-- tab character"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-negative-integer/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-negative-integer/error new file mode 100644 index 000000000..a0640b9a9 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-negative-integer/error @@ -0,0 +1,2 @@ +1 32 32 +too big negative integer diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-negative-integer/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-negative-integer/input new file mode 100644 index 000000000..d6c26f1cf --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-negative-integer/input @@ -0,0 +1 @@ +[-123123123123123123123123123123] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-positive-integer/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-positive-integer/error new file mode 100644 index 000000000..3bdbefd53 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-positive-integer/error @@ -0,0 +1,2 @@ +1 31 31 +too big integer diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-positive-integer/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-positive-integer/input new file mode 100644 index 000000000..27c855399 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/too-big-positive-integer/input @@ -0,0 +1 @@ +[123123123123123123123123123123] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/truncated-unicode-surrogate/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/truncated-unicode-surrogate/error new file mode 100644 index 000000000..1b99f061a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/truncated-unicode-surrogate/error @@ -0,0 +1,2 @@ +1 46 46 +invalid Unicode '\uDADA' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/truncated-unicode-surrogate/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/truncated-unicode-surrogate/input new file mode 100644 index 000000000..2b340f4ad --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/truncated-unicode-surrogate/input @@ -0,0 +1 @@ +["\uDADA (first surrogate without the second)"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unicode-identifier/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unicode-identifier/error new file mode 100644 index 000000000..178b0dd4d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unicode-identifier/error @@ -0,0 +1,2 @@ +1 1 2 +'[' or '{' expected near 'å' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unicode-identifier/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unicode-identifier/input new file mode 100644 index 000000000..aad321caf --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unicode-identifier/input @@ -0,0 +1 @@ +å diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array-and-object/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array-and-object/error.normal new file mode 100644 index 000000000..5b19804bc --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array-and-object/error.normal @@ -0,0 +1,2 @@ +2 0 3 +string or '}' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array-and-object/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array-and-object/error.strip new file mode 100644 index 000000000..da2bb22f1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array-and-object/error.strip @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array-and-object/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array-and-object/input new file mode 100644 index 000000000..cd9dc6482 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array-and-object/input @@ -0,0 +1 @@ +[{ diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array/error.normal new file mode 100644 index 000000000..8025ed1b0 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array/error.normal @@ -0,0 +1,2 @@ +2 0 5 +']' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array/error.strip new file mode 100644 index 000000000..495d0f7c4 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array/error.strip @@ -0,0 +1,2 @@ +1 4 4 +']' expected near end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array/input new file mode 100644 index 000000000..727ee8106 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-array/input @@ -0,0 +1 @@ +["a" diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-empty-key/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-empty-key/error.normal new file mode 100644 index 000000000..3d646abda --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-empty-key/error.normal @@ -0,0 +1,2 @@ +1 2 2 +unexpected newline near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-empty-key/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-empty-key/error.strip new file mode 100644 index 000000000..94f194715 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-empty-key/error.strip @@ -0,0 +1,2 @@ +1 2 2 +premature end of input near '"' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-empty-key/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-empty-key/input new file mode 100644 index 000000000..4117452de --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-empty-key/input @@ -0,0 +1 @@ +{" diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-key/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-key/error.normal new file mode 100644 index 000000000..5f09b77da --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-key/error.normal @@ -0,0 +1,2 @@ +1 3 3 +unexpected newline near '"a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-key/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-key/error.strip new file mode 100644 index 000000000..8b6bec430 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-key/error.strip @@ -0,0 +1,2 @@ +1 3 3 +premature end of input near '"a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-key/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-key/input new file mode 100644 index 000000000..705948c64 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-key/input @@ -0,0 +1 @@ +{"a diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-object-and-array/error b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-object-and-array/error new file mode 100644 index 000000000..ed97be73e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-object-and-array/error @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near '[' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-object-and-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-object-and-array/input new file mode 100644 index 000000000..da35a8620 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-object-and-array/input @@ -0,0 +1 @@ +{[ diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-string/error.normal b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-string/error.normal new file mode 100644 index 000000000..5f09b77da --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-string/error.normal @@ -0,0 +1,2 @@ +1 3 3 +unexpected newline near '"a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-string/error.strip b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-string/error.strip new file mode 100644 index 000000000..8b6bec430 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-string/error.strip @@ -0,0 +1,2 @@ +1 3 3 +premature end of input near '"a' diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-string/input new file mode 100644 index 000000000..38ab6b04c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/invalid/unterminated-string/input @@ -0,0 +1 @@ +["a diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/complex-array/env b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/complex-array/env new file mode 100644 index 000000000..bd89eff9d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/complex-array/env @@ -0,0 +1 @@ +JSON_SORT_KEYS=1
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/complex-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/complex-array/input new file mode 100644 index 000000000..1b9bbb949 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/complex-array/input @@ -0,0 +1,5 @@ +[1,2,3,4, +"a", "b", "c", +{"foo": "bar", "core": "dump"}, +true, false, true, true, null, false +] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/complex-array/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/complex-array/output new file mode 100644 index 000000000..7aefe5642 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/complex-array/output @@ -0,0 +1 @@ +[1, 2, 3, 4, "a", "b", "c", {"core": "dump", "foo": "bar"}, true, false, true, true, null, false]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-array/input new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-array/input @@ -0,0 +1 @@ +[] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-array/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-array/output new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-array/output @@ -0,0 +1 @@ +[]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object-in-array/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object-in-array/input new file mode 100644 index 000000000..93d51406d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object-in-array/input @@ -0,0 +1 @@ +[{}] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object-in-array/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object-in-array/output new file mode 100644 index 000000000..ee1aac42b --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object-in-array/output @@ -0,0 +1 @@ +[{}]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object/input new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object/input @@ -0,0 +1 @@ +{} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object/output new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-object/output @@ -0,0 +1 @@ +{}
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-string/input new file mode 100644 index 000000000..66a1e1856 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-string/input @@ -0,0 +1 @@ +[""] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-string/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-string/output new file mode 100644 index 000000000..93b6be2bc --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/empty-string/output @@ -0,0 +1 @@ +[""]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/escaped-utf-control-char/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/escaped-utf-control-char/input new file mode 100644 index 000000000..9a98545c0 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/escaped-utf-control-char/input @@ -0,0 +1 @@ +["\u0012 escaped control character"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/escaped-utf-control-char/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/escaped-utf-control-char/output new file mode 100644 index 000000000..07221b78d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/escaped-utf-control-char/output @@ -0,0 +1 @@ +["\u0012 escaped control character"]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/false/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/false/input new file mode 100644 index 000000000..434365202 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/false/input @@ -0,0 +1 @@ +[false] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/false/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/false/output new file mode 100644 index 000000000..67b2f0760 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/false/output @@ -0,0 +1 @@ +[false]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-int/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-int/input new file mode 100644 index 000000000..a96d5cdb3 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-int/input @@ -0,0 +1 @@ +[-123] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-int/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-int/output new file mode 100644 index 000000000..8e30f8bd9 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-int/output @@ -0,0 +1 @@ +[-123]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-one/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-one/input new file mode 100644 index 000000000..2363a1ac0 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-one/input @@ -0,0 +1 @@ +[-1] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-one/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-one/output new file mode 100644 index 000000000..99d21a2a0 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-one/output @@ -0,0 +1 @@ +[-1]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-zero/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-zero/input new file mode 100644 index 000000000..40fc49c71 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-zero/input @@ -0,0 +1 @@ +[-0] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-zero/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-zero/output new file mode 100644 index 000000000..6e7ea636e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/negative-zero/output @@ -0,0 +1 @@ +[0]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/null/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/null/input new file mode 100644 index 000000000..62864b313 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/null/input @@ -0,0 +1 @@ +[null] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/null/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/null/output new file mode 100644 index 000000000..500db4a86 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/null/output @@ -0,0 +1 @@ +[null]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/one-byte-utf-8/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/one-byte-utf-8/input new file mode 100644 index 000000000..8bda4685d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/one-byte-utf-8/input @@ -0,0 +1 @@ +["\u002c one-byte UTF-8"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/one-byte-utf-8/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/one-byte-utf-8/output new file mode 100644 index 000000000..c33d250ff --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/one-byte-utf-8/output @@ -0,0 +1 @@ +[", one-byte UTF-8"]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-negative-exponent/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-negative-exponent/input new file mode 100644 index 000000000..1e9fa5153 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-negative-exponent/input @@ -0,0 +1 @@ +[1E-2] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-negative-exponent/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-negative-exponent/output new file mode 100644 index 000000000..75b9ef92c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-negative-exponent/output @@ -0,0 +1 @@ +[0.01]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-positive-exponent/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-positive-exponent/input new file mode 100644 index 000000000..6a6ab9337 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-positive-exponent/input @@ -0,0 +1 @@ +[1E+2] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-positive-exponent/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-positive-exponent/output new file mode 100644 index 000000000..d8ff702a1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e-positive-exponent/output @@ -0,0 +1 @@ +[100.0]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e/input new file mode 100644 index 000000000..e70322356 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e/input @@ -0,0 +1 @@ +[1E22] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e/output new file mode 100644 index 000000000..9a739f21f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-capital-e/output @@ -0,0 +1 @@ +[1e22]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-exponent/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-exponent/input new file mode 100644 index 000000000..b2a69b9a3 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-exponent/input @@ -0,0 +1 @@ +[123e45] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-exponent/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-exponent/output new file mode 100644 index 000000000..5ffc7196d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-exponent/output @@ -0,0 +1 @@ +[1.2299999999999999e47]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-fraction-exponent/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-fraction-exponent/input new file mode 100644 index 000000000..0c1660d1e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-fraction-exponent/input @@ -0,0 +1 @@ +[123.456e78] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-fraction-exponent/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-fraction-exponent/output new file mode 100644 index 000000000..66a3c8186 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-fraction-exponent/output @@ -0,0 +1 @@ +[1.23456e80]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-negative-exponent/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-negative-exponent/input new file mode 100644 index 000000000..daa4af932 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-negative-exponent/input @@ -0,0 +1 @@ +[1e-2] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-negative-exponent/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-negative-exponent/output new file mode 100644 index 000000000..75b9ef92c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-negative-exponent/output @@ -0,0 +1 @@ +[0.01]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-positive-exponent/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-positive-exponent/input new file mode 100644 index 000000000..f3780773a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-positive-exponent/input @@ -0,0 +1 @@ +[1e+2] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-positive-exponent/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-positive-exponent/output new file mode 100644 index 000000000..d8ff702a1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-positive-exponent/output @@ -0,0 +1 @@ +[100.0]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-subnormal-number/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-subnormal-number/input new file mode 100644 index 000000000..df6065345 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-subnormal-number/input @@ -0,0 +1 @@ +[1.8011670033376514e-308] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-subnormal-number/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-subnormal-number/output new file mode 100644 index 000000000..e6b0a58e8 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-subnormal-number/output @@ -0,0 +1 @@ +[1.8011670033376514e-308]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-underflow/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-underflow/input new file mode 100644 index 000000000..dc709960a --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-underflow/input @@ -0,0 +1 @@ +[123e-10000000] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-underflow/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-underflow/output new file mode 100644 index 000000000..92df1df1d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/real-underflow/output @@ -0,0 +1 @@ +[0.0]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/run b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/run new file mode 100755 index 000000000..d99548960 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/run @@ -0,0 +1,56 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +JSON_SORT_KEYS=1 +export JSON_SORT_KEYS + +is_test() { + test -d $test_path +} + +do_run() { + variant=$1 + s=".$1" + + strip=0 + [ "$variant" = "strip" ] && strip=1 + + STRIP=$strip $json_process --env \ + <$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s + valgrind_check $test_log/stderr$s || return 1 + + ref=output + [ -f $test_path/output$s ] && ref=output$s + + if ! cmp -s $test_path/$ref $test_log/stdout$s; then + echo $variant > $test_log/variant + return 1 + fi +} + +run_test() { + do_run normal && do_run strip +} + +show_error() { + valgrind_show_error && return + + read variant < $test_log/variant + s=".$variant" + + echo "VARIANT: $variant" + + echo "EXPECTED OUTPUT:" + ref=output + [ -f $test_path/output$s ] && ref=output$s + nl -bn $test_path/$ref + + echo "ACTUAL OUTPUT:" + nl -bn $test_log/stdout$s +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/short-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/short-string/input new file mode 100644 index 000000000..0c3426d4c --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/short-string/input @@ -0,0 +1 @@ +["a"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/short-string/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/short-string/output new file mode 100644 index 000000000..eac5f7b46 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/short-string/output @@ -0,0 +1 @@ +["a"]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-ascii-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-ascii-string/input new file mode 100644 index 000000000..929b215c1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-ascii-string/input @@ -0,0 +1 @@ +["abcdefghijklmnopqrstuvwxyz1234567890 "] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-ascii-string/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-ascii-string/output new file mode 100644 index 000000000..90358ab70 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-ascii-string/output @@ -0,0 +1 @@ +["abcdefghijklmnopqrstuvwxyz1234567890 "]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-0/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-0/input new file mode 100644 index 000000000..111bb8686 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-0/input @@ -0,0 +1 @@ +[0] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-0/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-0/output new file mode 100644 index 000000000..6e7ea636e --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-0/output @@ -0,0 +1 @@ +[0]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-1/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-1/input new file mode 100644 index 000000000..7660873d1 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-1/input @@ -0,0 +1 @@ +[1] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-1/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-1/output new file mode 100644 index 000000000..bace2a0be --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-1/output @@ -0,0 +1 @@ +[1]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-123/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-123/input new file mode 100644 index 000000000..3214bfe58 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-123/input @@ -0,0 +1 @@ +[123] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-123/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-123/output new file mode 100644 index 000000000..e47f69afc --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-int-123/output @@ -0,0 +1 @@ +[123]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-object/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-object/input new file mode 100644 index 000000000..a34fb4907 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-object/input @@ -0,0 +1 @@ +{"a":[]} diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-object/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-object/output new file mode 100644 index 000000000..982abe826 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-object/output @@ -0,0 +1 @@ +{"a": []}
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-real/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-real/input new file mode 100644 index 000000000..0fed7df36 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-real/input @@ -0,0 +1 @@ +[123.456789] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-real/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-real/output new file mode 100644 index 000000000..b02878e5f --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/simple-real/output @@ -0,0 +1 @@ +[123.456789]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/string-escapes/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/string-escapes/input new file mode 100644 index 000000000..d994564d3 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/string-escapes/input @@ -0,0 +1 @@ +["\"\\\/\b\f\n\r\t"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/string-escapes/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/string-escapes/output new file mode 100644 index 000000000..ca5c1c658 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/string-escapes/output @@ -0,0 +1 @@ +["\"\\/\b\f\n\r\t"]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/three-byte-utf-8/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/three-byte-utf-8/input new file mode 100644 index 000000000..ccc0bfa57 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/three-byte-utf-8/input @@ -0,0 +1 @@ +["\u0821 three-byte UTF-8"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/three-byte-utf-8/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/three-byte-utf-8/output new file mode 100644 index 000000000..c44d124e7 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/three-byte-utf-8/output @@ -0,0 +1 @@ +["ࠡ three-byte UTF-8"]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/true/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/true/input new file mode 100644 index 000000000..29513c491 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/true/input @@ -0,0 +1 @@ +[true] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/true/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/true/output new file mode 100644 index 000000000..de601e305 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/true/output @@ -0,0 +1 @@ +[true]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/two-byte-utf-8/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/two-byte-utf-8/input new file mode 100644 index 000000000..05ae854b5 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/two-byte-utf-8/input @@ -0,0 +1 @@ +["\u0123 two-byte UTF-8"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/two-byte-utf-8/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/two-byte-utf-8/output new file mode 100644 index 000000000..1f0988d94 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/two-byte-utf-8/output @@ -0,0 +1 @@ +["ģ two-byte UTF-8"]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-8-string/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-8-string/input new file mode 100644 index 000000000..20dc64a45 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-8-string/input @@ -0,0 +1 @@ +["€þıœəßð some utf-8 ĸʒ×ŋµåäö𝄞"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-8-string/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-8-string/output new file mode 100644 index 000000000..53728650d --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-8-string/output @@ -0,0 +1 @@ +["€þıœəßð some utf-8 ĸʒ×ŋµåäö𝄞"]
\ No newline at end of file diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-surrogate-four-byte-encoding/input b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-surrogate-four-byte-encoding/input new file mode 100644 index 000000000..c598b4172 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-surrogate-four-byte-encoding/input @@ -0,0 +1 @@ +["\uD834\uDD1E surrogate, four-byte UTF-8"] diff --git a/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-surrogate-four-byte-encoding/output b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-surrogate-four-byte-encoding/output new file mode 100644 index 000000000..fa806d254 --- /dev/null +++ b/src/fluent-bit/lib/jansson-e23f558/test/suites/valid/utf-surrogate-four-byte-encoding/output @@ -0,0 +1 @@ +["𝄞 surrogate, four-byte UTF-8"]
\ No newline at end of file |