mirror of https://github.com/akheron/jansson
Rebase Deron Meranda's original bignum patch
This commit is contained in:
parent
30fdf6067e
commit
f8716ac336
717
doc/apiref.rst
717
doc/apiref.rst
|
@ -97,29 +97,39 @@ functions:
|
|||
|
||||
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`` |
|
||||
+--------------------+
|
||||
+---------------------+
|
||||
| ``JSON_OBJECT`` |
|
||||
+---------------------+
|
||||
| ``JSON_ARRAY`` |
|
||||
+---------------------+
|
||||
| ``JSON_STRING`` |
|
||||
+---------------------+
|
||||
| ``JSON_INTEGER`` |
|
||||
+---------------------+
|
||||
| ``JSON_BIGINTEGER`` |
|
||||
+---------------------+
|
||||
| ``JSON_REAL`` |
|
||||
+---------------------+
|
||||
| ``JSON_BIGREAL`` |
|
||||
+---------------------+
|
||||
| ``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``.
|
||||
null. A number is represented by one of the values of type
|
||||
``JSON_INTEGER``, ``JSON_BIGINTEGER``, ``JSON_REAL``, or ``JSON_BIGREAL``.
|
||||
A true boolean value is represented by a value of the type ``JSON_TRUE``
|
||||
and false by a value of the type ``JSON_FALSE``.
|
||||
|
||||
The two big-number types, ``JSON_BIGINTEGER`` and ``JSON_BIGREAL``,
|
||||
are used with add-on extensions to allow arbitrarily large or
|
||||
high-precision numbers to be represented. Unless an extension is
|
||||
provided and enabled using the big number extension API, these
|
||||
types will not be used.
|
||||
|
||||
.. function:: int json_typeof(const json_t *json)
|
||||
|
||||
|
@ -131,7 +141,9 @@ functions:
|
|||
json_is_array(const json_t *json)
|
||||
json_is_string(const json_t *json)
|
||||
json_is_integer(const json_t *json)
|
||||
json_is_biginteger(const json_t *json)
|
||||
json_is_real(const json_t *json)
|
||||
json_is_bigreal(const json_t *json)
|
||||
json_is_true(const json_t *json)
|
||||
json_is_false(const json_t *json)
|
||||
json_is_null(const json_t *json)
|
||||
|
@ -143,7 +155,28 @@ functions:
|
|||
.. function:: 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*.
|
||||
``JSON_REAL``; and false for other types and for *NULL*.
|
||||
|
||||
.. function:: json_is_bignumber(const json_t *json)
|
||||
|
||||
Returns true for values of types ``JSON_BIGINTEGER`` and
|
||||
``JSON_BIGREAL``, and false for other types and for *NULL*.
|
||||
|
||||
.. function:: json_is_anynumber(const json_t *json)
|
||||
|
||||
Returns true for values of types ``JSON_INTEGER``,
|
||||
``JSON_BIGINTEGER``, ``JSON_REAL`` and ``JSON_BIGREAL``, and false
|
||||
for other types and for *NULL*.
|
||||
|
||||
.. function:: json_is_anyinteger(const json_t *json)
|
||||
|
||||
Returns true for values of types ``JSON_INTEGER`` and
|
||||
``JSON_BIGINTEGER``, and false for other types and for *NULL*.
|
||||
|
||||
.. function:: json_is_anyreal(const json_t *json)
|
||||
|
||||
Returns true for values of types ``JSON_REAL`` and
|
||||
``JSON_BIGREAL``, and false for other types and for *NULL*.
|
||||
|
||||
.. function:: json_is_boolean(const json_t *json)
|
||||
|
||||
|
@ -376,21 +409,55 @@ 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`.
|
||||
the two. They are called "integer" and "real", respectively.
|
||||
|
||||
Additionally, Jansson provides an extension API to allow external
|
||||
packages to be used to represent arbitrarily large integers or
|
||||
arbitrarily high-precision real numbers. So a JSON number may be
|
||||
represented by any of four different C types.
|
||||
|
||||
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``.
|
||||
This is the C type that is used to store JSON integer values in the
|
||||
absence of a big number extension. 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.
|
||||
|
||||
.. type:: double
|
||||
|
||||
The C type ``double`` is used to store JSON real values in the
|
||||
absence of a big number extension.
|
||||
|
||||
Note that the C type ``long double`` is only supported by using the
|
||||
big number extension API.
|
||||
|
||||
.. type:: json_bigz_t
|
||||
.. type:: json_bigz_const_t
|
||||
|
||||
This is an unspecified C pointer type used to reference JSON
|
||||
integer values that are stored using an external big number
|
||||
package. The ``_const_t`` type is the same only it is used to
|
||||
point to a constant value.
|
||||
|
||||
.. type:: json_bigr_t
|
||||
.. type:: json_bigr_const_t
|
||||
|
||||
This is an unspecified C pointer type used to reference JSON real
|
||||
values that are stored using an external big number package. The
|
||||
``_const_t`` type is the same only it is used to point to a
|
||||
constant value.
|
||||
|
||||
All of the functions and macros for dealing with the big number types
|
||||
:type:`json_bigz_t` and :type:`json_bigr_t` are documented separately
|
||||
in the section :ref:`apiref-big-number-extension`.
|
||||
|
||||
``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
|
||||
|
@ -407,7 +474,7 @@ information, see :ref:`rfc-conformance`.
|
|||
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()` reuiqres
|
||||
either ``long`` or ``long long``, and :func:`printf()` requires
|
||||
different length modifiers for the two.
|
||||
|
||||
Example::
|
||||
|
@ -1009,6 +1076,40 @@ macros can be ORed together to obtain *flags*.
|
|||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
``JSON_USE_BIGINT``
|
||||
This will enable the use of a big number package to be used to
|
||||
store large integer values, assuming a suitable big number package
|
||||
has been registered. Only those JSON integers whose values can not
|
||||
be stored in a :type:`json_int_t` will use the big number
|
||||
extension.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
``JSON_USE_BIGINT_ALWAYS``
|
||||
This flag implies ``JSON_USE_BIGINT`` and differs by using the big
|
||||
number extension to store all JSON integers, even those that could
|
||||
have otherwise been stored in a :type:`json_int_t`.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
``JSON_USE_BIGREAL``
|
||||
This will enable the use of a big number package to be used to
|
||||
store large real values, assuming a suitable big number package has
|
||||
been registered. Only those JSON reals whose values can not be
|
||||
accurately stored in a :type:`json_real_t`, either because their
|
||||
values or exponents are out of range or there would be a loss of
|
||||
precision (dropped significant digits), will use the big number
|
||||
extension.
|
||||
|
||||
.. versionadded:: 2.6
|
||||
|
||||
``JSON_USE_BIGREAL_ALWAYS``
|
||||
This flag implies ``JSON_USE_BIGREAL`` and differs by using the big
|
||||
number extension to store all JSON reals, even those that could
|
||||
have otherwise been accurately stored in a :type:`json_real_t`.
|
||||
|
||||
.. 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
|
||||
|
@ -1170,9 +1271,21 @@ arguments.
|
|||
``I`` (integer) [json_int_t]
|
||||
Convert a C :type:`json_int_t` to JSON integer.
|
||||
|
||||
``z`` (big integer) [json_bigz_t]
|
||||
Convert a C :type:`json_bigz_const_t` (a constant-pointer version
|
||||
of a :type:`json_bigz_t`) to a JSON integer. The provided value
|
||||
will be copied, no reference to it will be maintained. You must
|
||||
have already registered a suitable big number package extension.
|
||||
|
||||
``f`` (real) [double]
|
||||
Convert a C :type:`double` to JSON real.
|
||||
|
||||
``r`` (big real) [json_bigr_t]
|
||||
Convert a C :type:`json_bigr_const_t` (a constant-pointer version
|
||||
of a :type:`json_bigr_t`) to a JSON real. The provided value will
|
||||
be copied, no reference to it will be maintained. You must have
|
||||
already registered a suitable big number package extension.
|
||||
|
||||
``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
|
||||
|
@ -1290,18 +1403,47 @@ type whose address should be passed.
|
|||
``I`` (integer) [json_int_t]
|
||||
Convert a JSON integer to C :type:`json_int_t`.
|
||||
|
||||
``z`` (big integer) [json_bigz_t]
|
||||
Convert a JSON big integer to a C :type:`json_bigz_t`. The
|
||||
returned pointer will reference a newly allocated big number; you
|
||||
are responsible for eventually freeing it. You must have already
|
||||
registered a suitable big number package extension.
|
||||
|
||||
``Z`` (any integer) [json_bigz_t]
|
||||
Like ``z``, except that both plain integers and big integers will
|
||||
be accepted. When extracting values, a big integer will always be
|
||||
returned.
|
||||
|
||||
``f`` (real) [double]
|
||||
Convert a JSON real to C :type:`double`.
|
||||
|
||||
``F`` (integer or real) [double]
|
||||
Convert a JSON number (integer or real) to C :type:`double`.
|
||||
|
||||
``r`` (big real) [json_bigr_t]
|
||||
Convert a JSON big real to a C :type:`json_bigr_t`. The returned
|
||||
pointer will reference newly allocated big number; you are
|
||||
responsible for eventually freeing it. You must have already
|
||||
registered a suitable big number package extension.
|
||||
|
||||
``R`` (any integer) [json_bigr_t]
|
||||
Like``r``, except that both plain reals and big reals will be
|
||||
accepted. When extracting values, a big real will always be
|
||||
returned.
|
||||
|
||||
``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.
|
||||
|
||||
``v`` (any scalar) [json_t \*]
|
||||
Store any JSON scalar value (any type except lists or objects)
|
||||
with no conversion to a :type:`json_t` pointer.
|
||||
|
||||
``V`` (any scalar) [json_t \*]
|
||||
Like ``v``, but the JSON value's reference count is incremented.
|
||||
|
||||
``[fmt]`` (array)
|
||||
Convert each item in the JSON array according to the inner format
|
||||
string. ``fmt`` may contain objects and arrays, i.e. recursive
|
||||
|
@ -1356,6 +1498,17 @@ The following functions compose the parsing and validation API:
|
|||
behaviour of the unpacker, see below for the flags. Returns 0 on
|
||||
success and -1 on failure.
|
||||
|
||||
.. note::
|
||||
|
||||
The unpacking will halt at the first error, which may leave some of
|
||||
the variables that you designated to hold unpacked values in an
|
||||
uninitialized state. In partciular, as the big number formats
|
||||
(``z``, ``Z``, ``r``, and ``R``) return pointers to newly allocated
|
||||
memory, it is good practice to always initialize those
|
||||
corresponding variables to *NULL* prior to unpacking, and to
|
||||
remember to free the memory for those (if not null) afterwards,
|
||||
regardless if the unpacking succeeded or resulted in an error.
|
||||
|
||||
.. note::
|
||||
|
||||
The first argument of all unpack functions is ``json_t *root``
|
||||
|
@ -1424,9 +1577,11 @@ 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 integer or two real values are equal if their contained numeric
|
||||
values are equal. Comparisons between big number and corresponding
|
||||
regular number types are allowable, and are likewise determined based
|
||||
upon their equivalent numeric values. However, an integer value is
|
||||
never equal to a real value.
|
||||
|
||||
* Two strings are equal if their contained UTF-8 strings are equal,
|
||||
byte by byte. Unicode comparison algorithms are not implemented.
|
||||
|
@ -1487,8 +1642,8 @@ 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.
|
||||
memory allocation. These and other memory-related functions can be
|
||||
overridden if custom behavior is needed.
|
||||
|
||||
.. type:: json_malloc_t
|
||||
|
||||
|
@ -1504,6 +1659,23 @@ behavior is needed.
|
|||
|
||||
typedef void (*json_free_t)(void *);
|
||||
|
||||
.. type:: json_realloc_t
|
||||
|
||||
A typedef for a function pointer with :func:`realloc()`'s
|
||||
signature::
|
||||
|
||||
typedef void (*json_realloc_t)(void *, size_t);
|
||||
|
||||
Jansson does not itself use a realloc function, though it will pass
|
||||
it on to big number extensions that may require a realloc.
|
||||
|
||||
.. type:: json_overwrite_t
|
||||
|
||||
A typedef for a function pointer that will securely overwrite
|
||||
a region of memory that has a signature::
|
||||
|
||||
typedef void (*json_overwrite_t)(void *, size_t);
|
||||
|
||||
.. 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
|
||||
|
@ -1511,6 +1683,12 @@ behavior is needed.
|
|||
Jansson's API functions to ensure that all memory operations use
|
||||
the same functions.
|
||||
|
||||
Supplying *NULL* as either function pointer will restore the default
|
||||
of using :func:`malloc()` or :func:`free()`.
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
Restore the default by supplying NULL.
|
||||
|
||||
**Examples:**
|
||||
|
||||
Circumvent problems with different CRT heaps on Windows by using
|
||||
|
@ -1522,11 +1700,19 @@ Use the `Boehm's conservative garbage collector`_ for memory
|
|||
operations::
|
||||
|
||||
json_set_alloc_funcs(GC_malloc, GC_free);
|
||||
json_set_realloc_func(GC_realloc)
|
||||
|
||||
.. _Boehm's conservative garbage collector: http://www.hpl.hp.com/personal/Hans_Boehm/gc/
|
||||
|
||||
Allow storing sensitive data (e.g. passwords or encryption keys) in
|
||||
JSON structures by zeroing all memory when freed::
|
||||
JSON structures by zeroing all memory when freed. You do not need to
|
||||
provide the secure_realloc function unless you use a big number
|
||||
extension which uses realloc::
|
||||
|
||||
static void secure_overwrite(void *ptr, size_t size)
|
||||
{
|
||||
guaranteed_memset(ptr, 0, size);
|
||||
}
|
||||
|
||||
static void *secure_malloc(size_t size)
|
||||
{
|
||||
|
@ -1543,13 +1729,40 @@ JSON structures by zeroing all memory when freed::
|
|||
ptr -= 8;
|
||||
size = *((size_t *)ptr);
|
||||
|
||||
guaranteed_memset(ptr, 0, size + 8);
|
||||
secure_overwrite(ptr, size + 8);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void *secure_realloc(void *ptr, size_t size)
|
||||
{
|
||||
size_t oldsize;
|
||||
|
||||
if(ptr == NULL)
|
||||
return secure_malloc(size);
|
||||
if(size == 0) {
|
||||
secure_free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
oldsize = *((size_t *)(ptr - 8));
|
||||
|
||||
if( oldsize > size ) {
|
||||
secure_overwrite(ptr+size, oldsize-size);
|
||||
}
|
||||
else if( oldsize < size ) {
|
||||
void *newptr = secure_malloc(size);
|
||||
memcpy(newptr, ptr, size);
|
||||
secure_free(ptr);
|
||||
ptr = newptr;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
json_set_alloc_funcs(secure_malloc, secure_free);
|
||||
json_set_realloc_func(secure_realloc);
|
||||
json_set_overwrite_func(secure_overwrite);
|
||||
/* ... */
|
||||
}
|
||||
|
||||
|
@ -1558,3 +1771,435 @@ 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.
|
||||
|
||||
.. function:: void json_set_realloc_func(json_realloc_t realloc_fn)
|
||||
|
||||
Uses *realloc_fn* instead of :func:`realloc()`. This function will
|
||||
get passed to any big number extension for its possible use. Note
|
||||
that Jansson does not itself use realloc. This function should be
|
||||
called before any other of Jansson's APIs are called which may deal
|
||||
with big number types.
|
||||
|
||||
Supplying *NULL* as the function pointer will restore the default of
|
||||
using :func:`realloc`.
|
||||
|
||||
.. function:: void json_set_overwrite_func(json_overwrite_t overwrite_fn)
|
||||
|
||||
Uses *overwrite_fn* to overwrite a region of memory. The default is
|
||||
to use an internal function that wraps :func:`memset()` to write
|
||||
zero-bytes. However as some systems may optimize away the memset
|
||||
technique, a caller may wish to provide a more secure memory
|
||||
overwriting function.
|
||||
|
||||
Supplying *NULL* as the function pointer will restore the default
|
||||
of using an internal :func:`memset()` based wrapper.
|
||||
|
||||
|
||||
.. _apiref-big-number-extension:
|
||||
|
||||
Big Number Extensions
|
||||
=====================
|
||||
|
||||
It is possible to extend Jansson so that it may support numeric values
|
||||
that are larger or more precise than may be represented by the native
|
||||
C types. Big number extensions may be independently provided for
|
||||
integer values and real values.
|
||||
|
||||
The extension API is designed to be generic so that many different big
|
||||
number packages may be used. Each extension is enabled by registering
|
||||
a set of user-supplied callback functions that perform basic
|
||||
operations on a big number. These callbacks will often be thin
|
||||
wrapper functions around the routines provided by the big number
|
||||
package being used.
|
||||
|
||||
For more information on big numbers and a list of some software
|
||||
packages which support them see
|
||||
http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic
|
||||
|
||||
|
||||
Big number types and functions
|
||||
------------------------------
|
||||
|
||||
Within Jansson, a big number type is represented as an opaque pointer
|
||||
type of ``json_bigz_t`` and ``json_bigr_t`` for big integers and big
|
||||
reals respectively. There are corresponding constant-pointer types
|
||||
as well, ``json_bigz_const_t`` and ``json_bigr_const_t``.
|
||||
|
||||
By default these pointer types are declared as ``void *`` or ``void
|
||||
const *``. To allow for better type safety, the user may provide a
|
||||
more specific type name for these pointers by defining a macro prior
|
||||
to including the Jansson header file; for example if using GMP::
|
||||
|
||||
#define JSON_BIGZ_TYPE mpz_t
|
||||
#define JSON_BIGR_TYPE mpf_t
|
||||
#include <jansson.h>
|
||||
|
||||
Then the ``json_bigz_t`` type will be equivalent to ``mpz_t *``,
|
||||
and similar for the real types.
|
||||
|
||||
.. note:: Jansson adopts the convention of using the letter *Z* to mean
|
||||
integer and *R* to mean a real number. Do not let this cause you
|
||||
confusion, as some big number packages may use *F* for reals
|
||||
instead.
|
||||
|
||||
.. function:: json_t *json_biginteger(json_bigz_const_t value);
|
||||
|
||||
.. refcounting:: new
|
||||
|
||||
Returns a new JSON big integer, or *NULL* on error. The passed-in
|
||||
value is copied.
|
||||
|
||||
.. function:: json_bigz_const_t json_biginteger_value(const json_t *biginteger)
|
||||
|
||||
Returns the pointer to the value of *biginteger*, or *NULL* if it
|
||||
is not a JSON big integer. Note that the returned pointer is a
|
||||
reference to the existing value and not a copy; use caution if
|
||||
retaining this reference.
|
||||
|
||||
.. function:: int json_biginteger_set(json_t *integer, json_bigz_const_t value)
|
||||
|
||||
Sets the associated value of *biginteger* to *value*. Returns 0 on
|
||||
success and -1 if *biginteger* is not a JSON big integer. A copy is
|
||||
made of *value*.
|
||||
|
||||
.. function:: json_t *json_bigreal(json_bigr_const_t value);
|
||||
|
||||
.. refcounting:: new
|
||||
|
||||
Returns a new JSON big real, or *NULL* on error. The passed-in
|
||||
value is copied.
|
||||
|
||||
.. function:: json_bigr_const_t json_bigreal_value(const json_t *bigreal)
|
||||
|
||||
Returns the pointer to the value of *bigreal*, or *NULL* if it is
|
||||
not a JSON big real. Note that the returned pointer is a reference
|
||||
to the existing value and not a copy; use caution if retaining this
|
||||
reference.
|
||||
|
||||
.. function:: int json_bigreal_set(json_t *bigreal, json_bigr_const_t value)
|
||||
|
||||
Sets the associated value of *bigreal* to *value*. Returns 0 on
|
||||
success and -1 if *bigreal* is not a JSON big real. A copy is
|
||||
made of *value*.
|
||||
|
||||
Sample bignum packages
|
||||
----------------------
|
||||
|
||||
Included with the Jansson distribution are a sampling of extensions
|
||||
for supporting several popular big number formats. These samples are C
|
||||
code files which may be included and compiled into your own
|
||||
application.
|
||||
|
||||
*C long double:* The C standard provides a native type ``long double``
|
||||
which may have greater range and precision than a plain ``double``
|
||||
for real numbers. To use it add the sample file ``json_bignum_ldbl.c``
|
||||
into your project sources. Then arrange your own source similar to::
|
||||
|
||||
#define JSON_BIGR_TYPE long double
|
||||
#include <jansson.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
json_use_ldbl_for_bigreals();
|
||||
...
|
||||
}
|
||||
|
||||
*GNU Quadmath:* The GNU libquadmath library provides support for
|
||||
quad-precision floating-point numbers, which may have even greater
|
||||
range and precision than a ``long double``. Quadmath is built into
|
||||
newer versions of the GCC compiler on some platforms, so that it acts
|
||||
like a native type. To use it add the sample file
|
||||
``json_bignum_quad.c`` into your project sources. Then arrange your
|
||||
own source similar to::
|
||||
|
||||
#include <quadmath.h>
|
||||
#define JSON_BIGR_TYPE __float128
|
||||
#include <jansson.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
json_use_quad_for_bigreals();
|
||||
...
|
||||
}
|
||||
|
||||
Note that you may need to link your project with an additional system
|
||||
library typically named *libquadmath* (use the ``-lquadmath`` linker option
|
||||
in Unix-like environments). For more information see
|
||||
http://gcc.gnu.org/onlinedocs/libquadmath/
|
||||
|
||||
|
||||
*GNU Multiprecision Library (GMP):* The GMP package supports arbitrary
|
||||
sized integers and arbitrary precision real numbers. To use it add
|
||||
the sample file ``json_bignum_gmp.c`` into your project sources. Then
|
||||
arrange your own source similar to::
|
||||
|
||||
#include <gmp.h>
|
||||
#define JSON_BIGZ_TYPE mpz_t
|
||||
#define JSON_BIGR_TYPE mpf_t
|
||||
#include <jansson.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
json_use_gmp_for_bigintegers();
|
||||
json_use_gmp_for_bigreals();
|
||||
mpf_set_default_prec( 1024 ); /* precision in bits */
|
||||
...
|
||||
}
|
||||
|
||||
Notice that you may wish to call the GMP function
|
||||
`mpf_set_default_prec` to set up the default number of bits
|
||||
of precision that are kept. Jansson will always attempt to preserve
|
||||
all of the digits, but this GMP default if not set appropriately may
|
||||
still result in loss of significant digits.
|
||||
|
||||
You will need to link your project with the GMP library (use the
|
||||
``-lgmp`` linker option in Unix-like environments). For more
|
||||
information see http://gmplib.org/
|
||||
|
||||
*OpenSSL Big Numbers (BN):* The OpenSSL cryptographic library provides
|
||||
generic support for arbitrary sized integers. To use it add the
|
||||
sample file ``json_bignum_openssl.c`` into your project sources. Then
|
||||
arrange your own source similar to::
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#define JSON_BIGZ_TYPE BIGNUM
|
||||
#include <jansson.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
json_use_openssl_for_bigintegers();
|
||||
...
|
||||
}
|
||||
|
||||
You will need to link your project with the OpenSSL *crypto* library
|
||||
(use the ``-lcrypto`` linker option in Unix-like environments). For
|
||||
more information see http://www.openssl.org/docs/crypto/bn.html
|
||||
|
||||
|
||||
The callback functions
|
||||
----------------------
|
||||
|
||||
To use a big number package you must provide a set of callback
|
||||
functions that manipulate big number values. There are six callbacks
|
||||
needed: copy, delete, compare, convert to string, convert from string,
|
||||
and up-convert from a native number type. The callbacks are generally
|
||||
the same for both big integers and big reals except for the specific
|
||||
type signatures.
|
||||
|
||||
|
||||
When invoked by Jansson, all of the callback function will be provided
|
||||
with a ``json_memory_funcs_t`` argument that contains the set of
|
||||
function pointers for common memory-related routines. The callback
|
||||
functions should make use of these functions when possible so that
|
||||
both Jansson and the big number package use compatible memory
|
||||
management routines. The members of the ``json_memory_funcs_t``
|
||||
include::
|
||||
|
||||
malloc_fn(size_t size)
|
||||
free_fn(void *ptr)
|
||||
realloc_fn(void *ptr, size_t size)
|
||||
overwrite_fn(void *ptr, size_t size)
|
||||
strdup_fn(const char *str)
|
||||
|
||||
Each big number package must provide the following callback functions,
|
||||
shown here for big integers:
|
||||
|
||||
.. type:: json_bigint_copy_t
|
||||
|
||||
A typedef for a function pointer that will make a copy of a big integer value. It has a signature::
|
||||
|
||||
typedef json_bigz_t (*json_bigint_copy_t)(json_bigz_const_t bignum, const json_memory_funcs_t *memfuncs)
|
||||
|
||||
.. type:: json_bigint_del_t
|
||||
|
||||
A typedef for a function pointer that will delete a big integer value. It has a signature::
|
||||
|
||||
typedef void (*json_bigint_del_t)(json_bigz_t bignum, const json_memory_funcs_t *memfuncs)
|
||||
|
||||
.. type:: json_bigint_cmp_t
|
||||
|
||||
A typedef for a function pointer that will numerically compare two big integer values, returning -1 (less-than), 0 (equal), or +1 (greater-than). It has a signature::
|
||||
|
||||
typedef int (*json_bigint_cmp_t)(json_bigz_const_t bignum1, json_bigz_const_t bignum2, const json_memory_funcs_t *memfuncs)
|
||||
|
||||
.. type:: json_bigint_to_str_t
|
||||
|
||||
A typedef for a function pointer that will convert a big number
|
||||
value into a decimal string format. The resulting format must
|
||||
adhere strictly to the JSON standard syntax, e.g., "+0" or ".3"
|
||||
are invalid. It has a signature::
|
||||
|
||||
typedef int (*json_bigint_to_str_t)(json_bigz_const_t bignum, char *buffer, size_t size, const json_memory_funcs_t *memfuncs)
|
||||
|
||||
The function will be provided a buffer, identified with ``buffer``
|
||||
and ``size``, into which it should write the string. The string
|
||||
must be null terminated. The length of the string excluding the
|
||||
null byte must be returned.
|
||||
|
||||
If the resulting string is too large to fit into the provided
|
||||
buffer, then the function should return the number of bytes needed
|
||||
(excluding the null terminator), after which the function will be
|
||||
called again with a larger buffer. In this case it is not
|
||||
necessary to write into the buffer or insure it is null
|
||||
terminated.
|
||||
|
||||
.. type:: json_bigint_from_str_t
|
||||
|
||||
A typedef for a function pointer that will convert a decimal
|
||||
string repreentation of a number (in standard JSON syntax) into a
|
||||
big number value. It has the signature::
|
||||
|
||||
typedef json_bigz_t (*json_bigint_from_str_t)(const char *value, const json_memory_funcs_t *memfuncs)
|
||||
|
||||
The returned value should be a newly-allocated big number type. If
|
||||
the string value can not be converted then *NULL* should be
|
||||
returned.
|
||||
|
||||
.. type:: json_bigint_from_int_t
|
||||
|
||||
A typedef for a function pointer that will convert a standard
|
||||
native type of :type:`json_int_t` into a big number value. It has the signture::
|
||||
|
||||
typedef json_bigz_t (*json_bigint_from_int_t)(json_int_t value, const json_memory_funcs_t *memfuncs)
|
||||
|
||||
The returned value should be a newly-allocated big number type.
|
||||
|
||||
To register the callback functions, they must first be assembled into a structure of type :type:`json_bigint_funcs_t` or :type:`json_bigreal_funcs_t`, for example::
|
||||
|
||||
json_bigint_funcs_t callbacks;
|
||||
callbacks.copy_fn = my_copy_function;
|
||||
callbacks.delete_fn = my_delete_function;
|
||||
callbacks.compare_fn = my_compare_function;
|
||||
callbacks.to_string_fn = my_to_string_function;
|
||||
callbacks.from_string_fn = my_from_string_function;
|
||||
callbacks.from_int_fn = my_from_int_function;
|
||||
|
||||
Callbacks for big reals are similar except the last member is named ``from_real_fn`` instead of ``from_int_fn``.
|
||||
|
||||
Then the whole set of callbacks are registered with a single API call.
|
||||
|
||||
.. function:: void json_set_biginteger_funcs(const json_bigint_funcs_t* functions)
|
||||
|
||||
Registers the set of callback functions to use for manipulating
|
||||
big integer values. Passing *NULL* will unregister any callback
|
||||
functions and disable the use of big integers. This function
|
||||
should be called before any other functions that may involve big
|
||||
integers, such as loading JSON.
|
||||
|
||||
.. function:: void json_set_bigreal_funcs(const json_bigreal_funcs_t* functions)
|
||||
|
||||
Registers the set of callback functions to use for manipulating
|
||||
big real values. Passing *NULL* will unregister any callback
|
||||
functions and disable the use of big reals. This function should
|
||||
be called before any other functions that may involve big
|
||||
integers, such as loading JSON.
|
||||
|
||||
Example using long double
|
||||
-------------------------
|
||||
|
||||
The following example code shows how to use the big number extensions
|
||||
to support the native C type of ``long double`` for big real numbers.
|
||||
This is essentially the same as what is in the supplied
|
||||
``json_bignum_ldbl.c`` sample::
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <float.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define JSON_BIGR_TYPE long double
|
||||
#include <jansson.h>
|
||||
|
||||
/* These typedefs are now in effect:
|
||||
json_bigr_t => long double *
|
||||
json_bigr_const_t => long double const *
|
||||
*/
|
||||
|
||||
static int json_bigreal_ldbl_compare(json_bigr_const_t r1, json_bigr_const_t r2,
|
||||
const json_memory_funcs_t *memfuncs)
|
||||
{
|
||||
const long double * f1 = r1;
|
||||
const long double * f2 = r2;
|
||||
|
||||
if( *f1 == *f2 ) return 0;
|
||||
if( *f1 < *f2 ) return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static json_bigr_t json_bigreal_ldbl_copy(json_bigr_const_t r,
|
||||
const json_memory_funcs_t *memfuncs)
|
||||
{
|
||||
const long double * f1 = r;
|
||||
long double * f2;
|
||||
|
||||
f2 = memfuncs->malloc_fn( sizeof(long double) );
|
||||
if(!f2)
|
||||
return NULL;
|
||||
*f2 = *f1;
|
||||
return f2;
|
||||
}
|
||||
|
||||
static void json_bigreal_ldbl_delete(json_bigr_t r,
|
||||
const json_memory_funcs_t *memfuncs)
|
||||
{
|
||||
long double * f = r;
|
||||
|
||||
memfuncs->free_fn( f );
|
||||
return;
|
||||
}
|
||||
|
||||
static json_bigr_t json_bigreal_ldbl_from_real(double value,
|
||||
const json_memory_funcs_t *memfuncs)
|
||||
{
|
||||
long double * f;
|
||||
|
||||
f = memfuncs->malloc_fn( sizeof(long double) );
|
||||
if(!f)
|
||||
return NULL;
|
||||
*f = value;
|
||||
return f;
|
||||
}
|
||||
|
||||
static json_bigr_t json_bigreal_ldbl_from_str(const char *value,
|
||||
const json_memory_funcs_t *memfuncs)
|
||||
{
|
||||
long double f0;
|
||||
long double *f1;
|
||||
|
||||
errno = 0;
|
||||
f0 = strtold( value, NULL );
|
||||
|
||||
f1 = json_bigreal_ldbl_copy( &f0, memfuncs );
|
||||
memfuncs->overwrite_fn( &f0, sizeof(long double) );
|
||||
return f1;
|
||||
}
|
||||
|
||||
static int json_bigreal_ldbl_to_str(json_bigr_const_t r, char *buffer, size_t size,
|
||||
const json_memory_funcs_t *memfuncs)
|
||||
{
|
||||
const long double *f = r;
|
||||
int outsize;
|
||||
|
||||
outsize = snprintf( buffer, size, "%.*Lg", LDBL_DIG, *f );
|
||||
return outsize;
|
||||
}
|
||||
|
||||
int json_use_ldbl_for_bigreals()
|
||||
{
|
||||
static json_bigreal_funcs_t funcs;
|
||||
funcs.copy_fn = json_bigreal_ldbl_copy;
|
||||
funcs.delete_fn = json_bigreal_ldbl_delete;
|
||||
funcs.compare_fn = json_bigreal_ldbl_compare;
|
||||
funcs.to_string_fn = json_bigreal_ldbl_to_str;
|
||||
funcs.from_string_fn = json_bigreal_ldbl_from_str;
|
||||
funcs.from_real_fn = json_bigreal_ldbl_from_real;
|
||||
|
||||
json_set_bigreal_funcs( &funcs );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
json_use_ldbl_for_bigreals();
|
||||
...
|
||||
}
|
||||
|
|
|
@ -43,7 +43,9 @@ 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.
|
||||
compiler or not. Jansson also has an extension mechanism that allows
|
||||
an externally provided big number package to be used to represent
|
||||
arbitrary-sized integers and real numbers.
|
||||
|
||||
A JSON number is considered to be a real number if its lexical
|
||||
representation includes one of ``e``, ``E``, or ``.``; regardless if
|
||||
|
@ -61,6 +63,13 @@ represented in JSON as ``3.0``, not ``3``.
|
|||
Overflow, Underflow & Precision
|
||||
-------------------------------
|
||||
|
||||
If a big number extension is used for either integer or real values,
|
||||
then the behavior of all overflows, underflows, or loss of precision
|
||||
is left to the extension. It is possible that no errors or loss of
|
||||
information need ever occur.
|
||||
|
||||
However lacking a big number extension there are limitations.
|
||||
|
||||
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
|
||||
|
@ -101,10 +110,12 @@ IEEE support the concept of signed integer zeros.
|
|||
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``,
|
||||
The only numeric types with direct built-in support in Jansson are the
|
||||
``json_int_t`` and ``double`` types. 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.
|
||||
to overflow semantics).
|
||||
|
||||
Larger or more precise numeric types may be supported by using the big
|
||||
number extension API; though such support depends upon an external big
|
||||
number package.
|
||||
|
|
89
src/dump.c
89
src/dump.c
|
@ -192,29 +192,102 @@ static int do_dump(const json_t *json, size_t flags, int depth,
|
|||
{
|
||||
char buffer[MAX_INTEGER_STR_LENGTH];
|
||||
int size;
|
||||
int rc;
|
||||
|
||||
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);
|
||||
if(size < 0 || size >= MAX_INTEGER_STR_LENGTH) {
|
||||
rc = -1;
|
||||
}
|
||||
else {
|
||||
rc = dump(buffer, size, data);
|
||||
}
|
||||
jsonp_overwrite(buffer, sizeof(buffer));
|
||||
return rc;
|
||||
}
|
||||
|
||||
case JSON_BIGINTEGER:
|
||||
{
|
||||
json_context_t *ctx;
|
||||
json_bigz_const_t z;
|
||||
int size;
|
||||
int rc;
|
||||
char buffer[MAX_INTEGER_STR_LENGTH * 5];
|
||||
|
||||
ctx = jsonp_context();
|
||||
if(!ctx->have_bigint)
|
||||
return -1;
|
||||
z = json_biginteger_value(json);
|
||||
size = ctx->bigint.to_string_fn(z, buffer, sizeof(buffer), &ctx->memfuncs);
|
||||
|
||||
if(size >= (int)sizeof(buffer)) {
|
||||
/* Buffer was too small, allocate a bigger one */
|
||||
char* bigbuffer;
|
||||
bigbuffer = ctx->memfuncs.malloc_fn(size + 4 /*extra for safety*/);
|
||||
if(!bigbuffer)
|
||||
return -1;
|
||||
size = ctx->bigint.to_string_fn(z, bigbuffer, size, &ctx->memfuncs);
|
||||
rc = dump(bigbuffer, size, data);
|
||||
ctx->memfuncs.free_fn(bigbuffer);
|
||||
}
|
||||
else {
|
||||
rc = dump(buffer, size, data);
|
||||
}
|
||||
ctx->memfuncs.overwrite_fn(buffer, sizeof(buffer));
|
||||
return rc;
|
||||
}
|
||||
|
||||
case JSON_REAL:
|
||||
{
|
||||
char buffer[MAX_REAL_STR_LENGTH];
|
||||
int rc;
|
||||
int size;
|
||||
double value = json_real_value(json);
|
||||
|
||||
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value);
|
||||
if(size < 0)
|
||||
return -1;
|
||||
|
||||
return dump(buffer, size, data);
|
||||
if(size < 0) {
|
||||
rc = -1;
|
||||
}
|
||||
else {
|
||||
rc = dump(buffer, size, data);
|
||||
}
|
||||
jsonp_overwrite(buffer, sizeof(buffer));
|
||||
value = 0.0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
case JSON_BIGREAL:
|
||||
{
|
||||
json_context_t *ctx;
|
||||
json_bigr_const_t r;
|
||||
int size;
|
||||
int rc;
|
||||
char buffer[MAX_REAL_STR_LENGTH * 5];
|
||||
|
||||
ctx = jsonp_context();
|
||||
if(!ctx->have_bigreal)
|
||||
return -1;
|
||||
r = json_bigreal_value(json);
|
||||
size = ctx->bigreal.to_string_fn(r, buffer, sizeof(buffer), &ctx->memfuncs);
|
||||
|
||||
if(size >= (int)sizeof(buffer)) {
|
||||
/* Buffer was too small, allocate a bigger one */
|
||||
char* bigbuffer;
|
||||
bigbuffer = ctx->memfuncs.malloc_fn(size + 4 /*extra for safety*/);
|
||||
if(!bigbuffer)
|
||||
return -1;
|
||||
size = ctx->bigreal.to_string_fn(r, bigbuffer, size, &ctx->memfuncs);
|
||||
rc = dump(bigbuffer, size, data);
|
||||
ctx->memfuncs.free_fn(bigbuffer);
|
||||
}
|
||||
else {
|
||||
rc = dump(buffer, size, data);
|
||||
}
|
||||
ctx->memfuncs.overwrite_fn(buffer, sizeof(buffer));
|
||||
return rc;
|
||||
}
|
||||
|
||||
case JSON_STRING:
|
||||
return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);
|
||||
|
||||
|
|
134
src/jansson.h
134
src/jansson.h
|
@ -14,6 +14,10 @@
|
|||
|
||||
#include <jansson_config.h>
|
||||
|
||||
#if USE_GNU_MP
|
||||
#include <gmp.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -36,6 +40,9 @@ extern "C" {
|
|||
|
||||
/* types */
|
||||
|
||||
|
||||
struct json_context; /* forward reference */
|
||||
|
||||
typedef enum {
|
||||
JSON_OBJECT,
|
||||
JSON_ARRAY,
|
||||
|
@ -44,7 +51,9 @@ typedef enum {
|
|||
JSON_REAL,
|
||||
JSON_TRUE,
|
||||
JSON_FALSE,
|
||||
JSON_NULL
|
||||
JSON_NULL,
|
||||
JSON_BIGINTEGER,
|
||||
JSON_BIGREAL
|
||||
} json_type;
|
||||
|
||||
typedef struct json_t {
|
||||
|
@ -66,13 +75,32 @@ typedef long json_int_t;
|
|||
#endif /* JSON_INTEGER_IS_LONG_LONG */
|
||||
#endif
|
||||
|
||||
#ifndef JSON_BIGZ_TYPE
|
||||
#define JSON_BIGZ_TYPE void
|
||||
#endif
|
||||
#ifndef JSON_BIGR_TYPE
|
||||
#define JSON_BIGR_TYPE void
|
||||
#endif
|
||||
|
||||
typedef JSON_BIGZ_TYPE * json_bigz_t;
|
||||
typedef JSON_BIGR_TYPE * json_bigr_t;
|
||||
typedef JSON_BIGZ_TYPE const * json_bigz_const_t;
|
||||
typedef JSON_BIGR_TYPE const * json_bigr_const_t;
|
||||
|
||||
|
||||
#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_biginteger(json) (json && json_typeof(json) == JSON_BIGINTEGER)
|
||||
#define json_is_anyinteger(json) (json_is_integer(json) || json_is_biginteger(json))
|
||||
#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL)
|
||||
#define json_is_bigreal(json) (json && json_typeof(json) == JSON_BIGREAL)
|
||||
#define json_is_anyreal(json) (json_is_real(json) || json_is_bigreal(json))
|
||||
#define json_is_number(json) (json_is_integer(json) || json_is_real(json))
|
||||
#define json_is_bignumber(json) (json_is_biginteger(json) || json_is_bigreal(json))
|
||||
#define json_is_anynumber(json) (json_is_number(json) || json_is_bignumber(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
|
||||
|
@ -93,6 +121,8 @@ json_t *json_true(void);
|
|||
json_t *json_false(void);
|
||||
#define json_boolean(val) ((val) ? json_true() : json_false())
|
||||
json_t *json_null(void);
|
||||
json_t *json_biginteger(json_bigz_const_t value);
|
||||
json_t *json_bigreal(json_bigr_const_t value);
|
||||
|
||||
static JSON_INLINE
|
||||
json_t *json_incref(json_t *json)
|
||||
|
@ -214,6 +244,12 @@ 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);
|
||||
|
||||
json_bigz_const_t json_biginteger_value(const json_t *biginteger);
|
||||
int json_biginteger_set(json_t *biginteger, json_bigz_const_t mpz);
|
||||
|
||||
json_bigr_const_t json_bigreal_value(const json_t *bigreal);
|
||||
int json_bigreal_set(json_t *bigreal, json_bigr_const_t mpf);
|
||||
|
||||
/* pack, unpack */
|
||||
|
||||
json_t *json_pack(const char *fmt, ...);
|
||||
|
@ -258,13 +294,17 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla
|
|||
|
||||
/* encoding */
|
||||
|
||||
#define JSON_INDENT(n) (n & 0x1F)
|
||||
#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_INDENT(n) (n & 0x1F)
|
||||
#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_USE_BIGINT 0x800
|
||||
#define JSON_USE_BIGINT_ALWAYS 0x1000
|
||||
#define JSON_USE_BIGREAL 0x2000
|
||||
#define JSON_USE_BIGREAL_ALWAYS 0x4000
|
||||
|
||||
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
|
||||
|
||||
|
@ -273,12 +313,84 @@ int json_dumpf(const json_t *json, FILE *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 */
|
||||
/* custom memory functions */
|
||||
|
||||
typedef void *(*json_malloc_t)(size_t);
|
||||
typedef void (*json_free_t)(void *);
|
||||
typedef void *(*json_malloc_t)(size_t); /* allocate memory */
|
||||
typedef void (*json_free_t)(void *); /* free memory */
|
||||
typedef void *(*json_realloc_t)(void *, size_t); /* change allocation size */
|
||||
typedef void (*json_overwrite_t)(void *, size_t); /* overwrite memory */
|
||||
typedef char *(*json_strdup_t)(const char *); /* duplicate string */
|
||||
|
||||
typedef struct {
|
||||
json_malloc_t malloc_fn;
|
||||
json_free_t free_fn;
|
||||
json_realloc_t realloc_fn;
|
||||
json_overwrite_t overwrite_fn;
|
||||
json_strdup_t strdup_fn;
|
||||
} json_memory_funcs_t;
|
||||
|
||||
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn);
|
||||
void json_set_realloc_func(json_realloc_t realloc_fn);
|
||||
void json_set_overwrite_func( json_overwrite_t overwrite_fn );
|
||||
|
||||
|
||||
/* big integers */
|
||||
|
||||
typedef json_bigz_t (*json_bigint_copy_t)(json_bigz_const_t bignum,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef void (*json_bigint_del_t)(json_bigz_t bignum,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef int (*json_bigint_cmp_t)(json_bigz_const_t bignum1,
|
||||
json_bigz_const_t bignum2,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef int (*json_bigint_to_str_t)(json_bigz_const_t bignum,
|
||||
char *buffer, size_t size,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef json_bigz_t (*json_bigint_from_str_t)(const char *value,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef json_bigz_t (*json_bigint_from_int_t)(json_int_t value,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
|
||||
typedef struct {
|
||||
json_bigint_copy_t copy_fn;
|
||||
json_bigint_del_t delete_fn;
|
||||
json_bigint_cmp_t compare_fn;
|
||||
json_bigint_to_str_t to_string_fn;
|
||||
json_bigint_from_str_t from_string_fn;
|
||||
json_bigint_from_int_t from_int_fn;
|
||||
} json_bigint_funcs_t;
|
||||
|
||||
void json_set_biginteger_funcs(const json_bigint_funcs_t* functions);
|
||||
|
||||
|
||||
/* Big reals */
|
||||
|
||||
typedef json_bigr_t (*json_bigreal_copy_t)(json_bigr_const_t bigreal,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef void (*json_bigreal_del_t)(json_bigr_t bigreal,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef int (*json_bigreal_cmp_t)(json_bigr_const_t bigreal1,
|
||||
json_bigr_const_t bigreal2,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef int (*json_bigreal_to_str_t)(json_bigr_const_t bigreal,
|
||||
char *buffer, size_t size,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef json_bigr_t (*json_bigreal_from_str_t)(const char *value,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
typedef json_bigr_t (*json_bigreal_from_real_t)(double value,
|
||||
const json_memory_funcs_t *memfuncs);
|
||||
|
||||
typedef struct {
|
||||
json_bigreal_copy_t copy_fn;
|
||||
json_bigreal_del_t delete_fn;
|
||||
json_bigreal_cmp_t compare_fn;
|
||||
json_bigreal_to_str_t to_string_fn;
|
||||
json_bigreal_from_str_t from_string_fn;
|
||||
json_bigreal_from_real_t from_real_fn;
|
||||
} json_bigreal_funcs_t;
|
||||
|
||||
void json_set_bigreal_funcs(const json_bigreal_funcs_t* functions);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -57,16 +57,28 @@ typedef struct {
|
|||
double value;
|
||||
} json_real_t;
|
||||
|
||||
typedef struct {
|
||||
json_t json;
|
||||
json_bigr_t value;
|
||||
} json_bigreal_t;
|
||||
|
||||
typedef struct {
|
||||
json_t json;
|
||||
json_int_t value;
|
||||
} json_integer_t;
|
||||
|
||||
typedef struct {
|
||||
json_t json;
|
||||
json_bigz_t value;
|
||||
} json_biginteger_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)
|
||||
#define json_to_biginteger(json_) container_of(json_, json_biginteger_t, json)
|
||||
#define json_to_bigreal(json_) container_of(json_, json_bigreal_t, json)
|
||||
|
||||
/* Create a string by taking ownership of an existing buffer */
|
||||
json_t *jsonp_stringn_nocheck_own(const char *value, size_t len);
|
||||
|
@ -83,12 +95,27 @@ void jsonp_error_vset(json_error_t *error, int line, int column,
|
|||
int jsonp_strtod(strbuffer_t *strbuffer, double *out);
|
||||
int jsonp_dtostr(char *buffer, size_t size, double value);
|
||||
|
||||
/* For estimating precision needed to store a real number */
|
||||
int jsonp_count_significand_digits(strbuffer_t *strbuffer);
|
||||
|
||||
/* Global context */
|
||||
|
||||
typedef struct json_context {
|
||||
json_memory_funcs_t memfuncs;
|
||||
int have_bigint;
|
||||
int have_bigreal;
|
||||
json_bigint_funcs_t bigint;
|
||||
json_bigreal_funcs_t bigreal;
|
||||
} json_context_t;
|
||||
|
||||
json_context_t *jsonp_context(void);
|
||||
|
||||
/* Wrappers for custom memory functions */
|
||||
void* jsonp_malloc(size_t size);
|
||||
void *jsonp_malloc(size_t size);
|
||||
void jsonp_free(void *ptr);
|
||||
char *jsonp_strndup(const char *str, size_t length);
|
||||
char *jsonp_strdup(const char *str);
|
||||
char *jsonp_strndup(const char *str, size_t len);
|
||||
void jsonp_overwrite(void *ptr, size_t size);
|
||||
|
||||
/* Windows compatibility */
|
||||
#ifdef _WIN32
|
||||
|
|
186
src/load.c
186
src/load.c
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -33,6 +34,12 @@
|
|||
#define TOKEN_TRUE 259
|
||||
#define TOKEN_FALSE 260
|
||||
#define TOKEN_NULL 261
|
||||
#define TOKEN_BIGINTEGER 262
|
||||
#define TOKEN_BIGREAL 263
|
||||
|
||||
/* Big number functions */
|
||||
json_bigint_funcs_t* jsonp_biginteger_funcs = NULL;
|
||||
json_bigreal_funcs_t* jsonp_bigreal_funcs = NULL;
|
||||
|
||||
/* Locale independent versions of isxxx() functions */
|
||||
#define l_isupper(c) ('A' <= (c) && (c) <= 'Z')
|
||||
|
@ -69,11 +76,18 @@ typedef struct {
|
|||
} string;
|
||||
json_int_t integer;
|
||||
double real;
|
||||
json_bigz_t bigz;
|
||||
json_bigr_t bigr;
|
||||
} value;
|
||||
} lex_t;
|
||||
|
||||
#define stream_to_lex(stream) container_of(stream, lex_t, stream)
|
||||
|
||||
/* forward references */
|
||||
static int lex_init(lex_t *, get_func, void *);
|
||||
static void lex_clear(lex_t *);
|
||||
static void lex_close(lex_t *);
|
||||
|
||||
|
||||
/*** error reporting ***/
|
||||
|
||||
|
@ -479,12 +493,14 @@ out:
|
|||
#endif
|
||||
#endif
|
||||
|
||||
static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
|
||||
static int lex_scan_number(lex_t *lex, int c, size_t flags, json_error_t *error)
|
||||
{
|
||||
json_context_t *ctx;
|
||||
const char *saved_text;
|
||||
char *end;
|
||||
double value;
|
||||
int significand_digits;
|
||||
|
||||
ctx = jsonp_context();
|
||||
lex->token = TOKEN_INVALID;
|
||||
|
||||
if(c == '-')
|
||||
|
@ -494,6 +510,8 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
|
|||
c = lex_get_save(lex, error);
|
||||
if(l_isdigit(c)) {
|
||||
lex_unget_unsave(lex, c);
|
||||
error_set(error, lex,
|
||||
"numbers may not have unnecessary leading zeros");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -508,26 +526,44 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
|
|||
}
|
||||
|
||||
if(c != '.' && c != 'E' && c != 'e') {
|
||||
json_int_t value;
|
||||
|
||||
lex_unget_unsave(lex, c);
|
||||
|
||||
saved_text = strbuffer_value(&lex->saved_text);
|
||||
|
||||
errno = 0;
|
||||
value = json_strtoint(saved_text, &end, 10);
|
||||
if(errno == ERANGE) {
|
||||
if(value < 0)
|
||||
error_set(error, lex, "too big negative integer");
|
||||
else
|
||||
error_set(error, lex, "too big integer");
|
||||
goto out;
|
||||
}
|
||||
|
||||
assert(end == saved_text + lex->saved_text.length);
|
||||
if(flags & JSON_USE_BIGINT_ALWAYS) {
|
||||
json_bigz_t bigvalue;
|
||||
bigvalue = ctx->bigint.from_string_fn(saved_text, &ctx->memfuncs);
|
||||
lex->token = TOKEN_BIGINTEGER;
|
||||
lex->value.bigz = bigvalue;
|
||||
}
|
||||
else {
|
||||
json_int_t value;
|
||||
|
||||
value = json_strtoint(saved_text, &end, 10);
|
||||
if(errno == ERANGE) {
|
||||
if(flags & JSON_USE_BIGINT) {
|
||||
json_bigz_t bigvalue;
|
||||
bigvalue = ctx->bigint.from_string_fn(saved_text, &ctx->memfuncs);
|
||||
lex->token = TOKEN_BIGINTEGER;
|
||||
lex->value.bigz = bigvalue;
|
||||
}
|
||||
else {
|
||||
if(value < 0)
|
||||
error_set(error, lex, "too big negative integer");
|
||||
else
|
||||
error_set(error, lex, "too big integer");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(end == saved_text + lex->saved_text.length);
|
||||
lex->token = TOKEN_INTEGER;
|
||||
lex->value.integer = value;
|
||||
}
|
||||
}
|
||||
|
||||
lex->token = TOKEN_INTEGER;
|
||||
lex->value.integer = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -544,6 +580,13 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
|
|||
c = lex_get_save(lex, error);
|
||||
}
|
||||
|
||||
if((flags & JSON_USE_BIGREAL) && ! (flags & JSON_USE_BIGREAL_ALWAYS)) {
|
||||
/* Determine digits of precision needed to store number before
|
||||
* a partial loss of precision occurs.
|
||||
*/
|
||||
significand_digits = jsonp_count_significand_digits(&lex->saved_text);
|
||||
}
|
||||
|
||||
if(c == 'E' || c == 'e') {
|
||||
c = lex_get_save(lex, error);
|
||||
if(c == '+' || c == '-')
|
||||
|
@ -561,27 +604,48 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
|
|||
|
||||
lex_unget_unsave(lex, c);
|
||||
|
||||
if(jsonp_strtod(&lex->saved_text, &value)) {
|
||||
error_set(error, lex, "real number overflow");
|
||||
goto out;
|
||||
if((flags & JSON_USE_BIGREAL_ALWAYS) ||
|
||||
((flags & JSON_USE_BIGREAL) && significand_digits+1 >= DBL_DIG)) {
|
||||
json_bigr_t bigvalue = NULL;
|
||||
saved_text = strbuffer_value(&lex->saved_text);
|
||||
bigvalue = ctx->bigreal.from_string_fn(saved_text, &ctx->memfuncs);
|
||||
lex->token = TOKEN_BIGREAL;
|
||||
lex->value.bigr = bigvalue;
|
||||
}
|
||||
else {
|
||||
double value;
|
||||
int rc;
|
||||
|
||||
rc = jsonp_strtod(&lex->saved_text, &value);
|
||||
if(errno == ERANGE && (flags & JSON_USE_BIGREAL)) {
|
||||
/* overflow or underflow */
|
||||
json_bigr_t bigvalue;
|
||||
saved_text = strbuffer_value(&lex->saved_text);
|
||||
bigvalue = ctx->bigreal.from_string_fn(saved_text, &ctx->memfuncs);
|
||||
lex->token = TOKEN_BIGREAL;
|
||||
lex->value.bigr = bigvalue;
|
||||
}
|
||||
else if(rc != 0) {
|
||||
error_set(error, lex, "real number overflow");
|
||||
goto out;
|
||||
}
|
||||
else {
|
||||
lex->token = TOKEN_REAL;
|
||||
lex->value.real = value;
|
||||
}
|
||||
}
|
||||
|
||||
lex->token = TOKEN_REAL;
|
||||
lex->value.real = value;
|
||||
return 0;
|
||||
|
||||
out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int lex_scan(lex_t *lex, json_error_t *error)
|
||||
static int lex_scan(lex_t *lex, size_t flags, json_error_t *error)
|
||||
{
|
||||
int c;
|
||||
|
||||
strbuffer_clear(&lex->saved_text);
|
||||
|
||||
if(lex->token == TOKEN_STRING)
|
||||
lex_free_string(lex);
|
||||
lex_clear(lex);
|
||||
|
||||
c = lex_get(lex, error);
|
||||
while(c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
|
@ -606,7 +670,7 @@ static int lex_scan(lex_t *lex, json_error_t *error)
|
|||
lex_scan_string(lex, error);
|
||||
|
||||
else if(l_isdigit(c) || c == '-') {
|
||||
if(lex_scan_number(lex, c, error))
|
||||
if(lex_scan_number(lex, c, flags, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -664,10 +728,29 @@ static int lex_init(lex_t *lex, get_func get, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void lex_clear(lex_t *lex)
|
||||
{
|
||||
if(lex->token == TOKEN_STRING) {
|
||||
lex_free_string(lex);
|
||||
}
|
||||
else if(lex->token == TOKEN_BIGINTEGER) {
|
||||
json_context_t *ctx = jsonp_context();
|
||||
if(ctx->have_bigint)
|
||||
ctx->bigint.delete_fn(lex->value.bigz, &ctx->memfuncs);
|
||||
lex->value.bigz = NULL;
|
||||
}
|
||||
else if(lex->token == TOKEN_BIGREAL) {
|
||||
json_context_t *ctx = jsonp_context();
|
||||
if(ctx->have_bigreal)
|
||||
ctx->bigreal.delete_fn(lex->value.bigr, &ctx->memfuncs);
|
||||
lex->value.bigr = NULL;
|
||||
}
|
||||
strbuffer_clear(&lex->saved_text);
|
||||
}
|
||||
|
||||
static void lex_close(lex_t *lex)
|
||||
{
|
||||
if(lex->token == TOKEN_STRING)
|
||||
lex_free_string(lex);
|
||||
lex_clear(lex);
|
||||
strbuffer_close(&lex->saved_text);
|
||||
}
|
||||
|
||||
|
@ -682,7 +765,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
|
|||
if(!object)
|
||||
return NULL;
|
||||
|
||||
lex_scan(lex, error);
|
||||
lex_scan(lex, flags, error);
|
||||
if(lex->token == '}')
|
||||
return object;
|
||||
|
||||
|
@ -713,14 +796,14 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
|
|||
}
|
||||
}
|
||||
|
||||
lex_scan(lex, error);
|
||||
lex_scan(lex, flags, error);
|
||||
if(lex->token != ':') {
|
||||
jsonp_free(key);
|
||||
error_set(error, lex, "':' expected");
|
||||
goto error;
|
||||
}
|
||||
|
||||
lex_scan(lex, error);
|
||||
lex_scan(lex, flags, error);
|
||||
value = parse_value(lex, flags, error);
|
||||
if(!value) {
|
||||
jsonp_free(key);
|
||||
|
@ -736,11 +819,11 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error)
|
|||
json_decref(value);
|
||||
jsonp_free(key);
|
||||
|
||||
lex_scan(lex, error);
|
||||
lex_scan(lex, flags, error);
|
||||
if(lex->token != ',')
|
||||
break;
|
||||
|
||||
lex_scan(lex, error);
|
||||
lex_scan(lex, flags, error);
|
||||
}
|
||||
|
||||
if(lex->token != '}') {
|
||||
|
@ -761,7 +844,7 @@ static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error)
|
|||
if(!array)
|
||||
return NULL;
|
||||
|
||||
lex_scan(lex, error);
|
||||
lex_scan(lex, flags, error);
|
||||
if(lex->token == ']')
|
||||
return array;
|
||||
|
||||
|
@ -776,11 +859,11 @@ static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error)
|
|||
}
|
||||
json_decref(elem);
|
||||
|
||||
lex_scan(lex, error);
|
||||
lex_scan(lex, flags, error);
|
||||
if(lex->token != ',')
|
||||
break;
|
||||
|
||||
lex_scan(lex, error);
|
||||
lex_scan(lex, flags, error);
|
||||
}
|
||||
|
||||
if(lex->token != ']') {
|
||||
|
@ -833,6 +916,16 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
|
|||
break;
|
||||
}
|
||||
|
||||
case TOKEN_BIGINTEGER: {
|
||||
json = json_biginteger(lex->value.bigz);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKEN_BIGREAL: {
|
||||
json = json_bigreal(lex->value.bigr);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOKEN_REAL: {
|
||||
json = json_real(lex->value.real);
|
||||
break;
|
||||
|
@ -875,9 +968,26 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
|
|||
|
||||
static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
json_t *result;
|
||||
|
||||
lex_scan(lex, error);
|
||||
if(flags & JSON_USE_BIGINT_ALWAYS)
|
||||
flags |= JSON_USE_BIGINT;
|
||||
if(flags & JSON_USE_BIGREAL_ALWAYS)
|
||||
flags |= JSON_USE_BIGREAL;
|
||||
|
||||
if((flags & JSON_USE_BIGINT) && !ctx->have_bigint) {
|
||||
error_set(error, lex,
|
||||
"Programming error: Not prepared to decode big integers");
|
||||
return NULL;
|
||||
}
|
||||
if((flags & JSON_USE_BIGREAL) && !ctx->have_bigreal) {
|
||||
error_set(error, lex,
|
||||
"Programming error: Not prepared to decode big reals");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lex_scan(lex, flags, error);
|
||||
if(!(flags & JSON_DECODE_ANY)) {
|
||||
if(lex->token != '[' && lex->token != '{') {
|
||||
error_set(error, lex, "'[' or '{' expected");
|
||||
|
@ -890,7 +1000,7 @@ static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error)
|
|||
return NULL;
|
||||
|
||||
if(!(flags & JSON_DISABLE_EOF_CHECK)) {
|
||||
lex_scan(lex, error);
|
||||
lex_scan(lex, flags, error);
|
||||
if(lex->token != TOKEN_EOF) {
|
||||
error_set(error, lex, "end of file expected");
|
||||
json_decref(result);
|
||||
|
|
94
src/memory.c
94
src/memory.c
|
@ -16,16 +16,49 @@
|
|||
#undef malloc
|
||||
#undef free
|
||||
|
||||
/* memory function pointers */
|
||||
static json_malloc_t do_malloc = malloc;
|
||||
static json_free_t do_free = free;
|
||||
/* current context */
|
||||
static json_context_t* jsonp_current_context_ptr = NULL;
|
||||
static json_context_t jsonp_current_context;
|
||||
|
||||
static void jsonp_overwrite_memset(void *ptr, size_t size)
|
||||
{
|
||||
if(size==0 || ptr==NULL)
|
||||
return;
|
||||
memset(ptr, 0, size);
|
||||
}
|
||||
|
||||
json_context_t *jsonp_context(void)
|
||||
{
|
||||
if(jsonp_current_context_ptr)
|
||||
return jsonp_current_context_ptr;
|
||||
|
||||
memset(&jsonp_current_context, 0, sizeof(json_context_t));
|
||||
|
||||
jsonp_current_context.memfuncs.malloc_fn = malloc;
|
||||
jsonp_current_context.memfuncs.free_fn = free;
|
||||
jsonp_current_context.memfuncs.realloc_fn = realloc;
|
||||
jsonp_current_context.memfuncs.overwrite_fn = jsonp_overwrite_memset;
|
||||
jsonp_current_context.memfuncs.strdup_fn = jsonp_strdup;
|
||||
|
||||
jsonp_current_context.have_bigint = 0;
|
||||
jsonp_current_context.have_bigreal = 0;
|
||||
|
||||
jsonp_current_context_ptr = &jsonp_current_context;
|
||||
return jsonp_current_context_ptr;
|
||||
}
|
||||
|
||||
/* memory functions */
|
||||
void jsonp_overwrite(void *ptr, size_t size)
|
||||
{
|
||||
jsonp_context()->memfuncs.overwrite_fn(ptr, size);
|
||||
}
|
||||
|
||||
void *jsonp_malloc(size_t size)
|
||||
{
|
||||
if(!size)
|
||||
return NULL;
|
||||
|
||||
return (*do_malloc)(size);
|
||||
return (jsonp_context()->memfuncs.malloc_fn)(size);
|
||||
}
|
||||
|
||||
void jsonp_free(void *ptr)
|
||||
|
@ -33,7 +66,7 @@ void jsonp_free(void *ptr)
|
|||
if(!ptr)
|
||||
return;
|
||||
|
||||
(*do_free)(ptr);
|
||||
(jsonp_context()->memfuncs.free_fn)(ptr);
|
||||
}
|
||||
|
||||
char *jsonp_strdup(const char *str)
|
||||
|
@ -56,6 +89,53 @@ char *jsonp_strndup(const char *str, size_t len)
|
|||
|
||||
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn)
|
||||
{
|
||||
do_malloc = malloc_fn;
|
||||
do_free = free_fn;
|
||||
if(malloc_fn == NULL)
|
||||
malloc_fn = malloc;
|
||||
if(free_fn == NULL)
|
||||
free_fn = free;
|
||||
jsonp_context()->memfuncs.malloc_fn = malloc_fn;
|
||||
jsonp_context()->memfuncs.free_fn = free_fn;
|
||||
if(malloc_fn == malloc)
|
||||
jsonp_context()->memfuncs.realloc_fn = realloc;
|
||||
else
|
||||
jsonp_context()->memfuncs.realloc_fn = NULL;
|
||||
}
|
||||
|
||||
void json_set_realloc_func(json_realloc_t realloc_fn)
|
||||
{
|
||||
jsonp_context()->memfuncs.realloc_fn \
|
||||
= realloc_fn ? realloc_fn : realloc;
|
||||
}
|
||||
|
||||
void json_set_overwrite_func(json_overwrite_t overwrite_fn)
|
||||
{
|
||||
jsonp_context()->memfuncs.overwrite_fn \
|
||||
= overwrite_fn ? overwrite_fn : jsonp_overwrite_memset;
|
||||
}
|
||||
|
||||
void json_set_biginteger_funcs(const json_bigint_funcs_t* functions)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
if(!functions) {
|
||||
ctx->have_bigint = 0;
|
||||
memset(&ctx->bigint, 0, sizeof(json_bigint_funcs_t));
|
||||
}
|
||||
else {
|
||||
ctx->have_bigint = 1;
|
||||
memcpy(&ctx->bigint, functions, sizeof(json_bigint_funcs_t));
|
||||
}
|
||||
}
|
||||
|
||||
void json_set_bigreal_funcs(const json_bigreal_funcs_t* functions)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
if(!functions) {
|
||||
ctx->have_bigreal = 0;
|
||||
memset(&ctx->bigreal, 0, sizeof(json_bigreal_funcs_t));
|
||||
}
|
||||
else {
|
||||
ctx->have_bigreal = 1;
|
||||
memcpy(&ctx->bigreal, functions, sizeof(json_bigreal_funcs_t));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,12 +41,14 @@ static const char * const type_names[] = {
|
|||
"real",
|
||||
"true",
|
||||
"false",
|
||||
"null"
|
||||
"null",
|
||||
"biginteger",
|
||||
"bigreal"
|
||||
};
|
||||
|
||||
#define type_name(x) type_names[json_typeof(x)]
|
||||
|
||||
static const char unpack_value_starters[] = "{[siIbfFOon";
|
||||
static const char unpack_value_starters[] = "{[siIbfFOonzr";
|
||||
|
||||
|
||||
static void scanner_init(scanner_t *s, json_error_t *error,
|
||||
|
@ -328,9 +330,15 @@ static json_t *pack(scanner_t *s, va_list *ap)
|
|||
case 'I': /* integer from json_int_t */
|
||||
return json_integer(va_arg(*ap, json_int_t));
|
||||
|
||||
case 'z': /* big integer */
|
||||
return json_biginteger(va_arg(*ap,json_bigz_const_t));
|
||||
|
||||
case 'f': /* real */
|
||||
return json_real(va_arg(*ap, double));
|
||||
|
||||
case 'r': /* big real */
|
||||
return json_bigreal(va_arg(*ap,json_bigr_const_t));
|
||||
|
||||
case 'O': /* a json_t object; increments refcount */
|
||||
return json_incref(va_arg(*ap, json_t *));
|
||||
|
||||
|
@ -517,6 +525,8 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
|
|||
|
||||
static int unpack(scanner_t *s, json_t *root, va_list *ap)
|
||||
{
|
||||
int do_incref = 0;
|
||||
|
||||
switch(token(s))
|
||||
{
|
||||
case '{':
|
||||
|
@ -592,6 +602,50 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap)
|
|||
|
||||
return 0;
|
||||
|
||||
case 'z':
|
||||
if(!json_is_biginteger(root)) {
|
||||
set_error(s,"<validation>", "Expected big integer, got %s",
|
||||
type_name(root));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(s->flags & JSON_VALIDATE_ONLY)) {
|
||||
json_bigz_t v;
|
||||
json_context_t *ctx = jsonp_context();
|
||||
if(!ctx->have_bigint) {
|
||||
set_error(s,"<validation>", "No big integer package registed, can not unpack value");
|
||||
return -1;
|
||||
}
|
||||
v = ctx->bigint.copy_fn(json_biginteger_value(root),
|
||||
&ctx->memfuncs);
|
||||
*va_arg(*ap, json_bigz_t*) = v;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'Z':
|
||||
if(!json_is_anyinteger(root)) {
|
||||
set_error(s,"<validation>", "Expected an integer, got %s",
|
||||
type_name(root));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(s->flags & JSON_VALIDATE_ONLY)) {
|
||||
json_bigz_t v;
|
||||
json_context_t *ctx = jsonp_context();
|
||||
if(!ctx->have_bigint) {
|
||||
set_error(s,"<validation>", "No big integer package registed, can not unpack value");
|
||||
return -1;
|
||||
}
|
||||
if(json_is_biginteger(root))
|
||||
v = ctx->bigint.copy_fn(json_biginteger_value(root),
|
||||
&ctx->memfuncs);
|
||||
else
|
||||
v = ctx->bigint.from_int_fn(json_integer_value(root),
|
||||
&ctx->memfuncs);
|
||||
*va_arg(*ap, json_bigz_t*) = v;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'b':
|
||||
if(root && !json_is_boolean(root)) {
|
||||
set_error(s, "<validation>", "Expected true or false, got %s",
|
||||
|
@ -623,7 +677,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap)
|
|||
return 0;
|
||||
|
||||
case 'F':
|
||||
if(root && !json_is_number(root)) {
|
||||
if((root && !json_is_number(root)) || json_is_bignumber(root)) {
|
||||
set_error(s, "<validation>", "Expected real or integer, got %s",
|
||||
type_name(root));
|
||||
return -1;
|
||||
|
@ -637,18 +691,75 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap)
|
|||
|
||||
return 0;
|
||||
|
||||
case 'r':
|
||||
if(!json_is_bigreal(root)) {
|
||||
set_error(s,"<validation>", "Expected big real, got %s",
|
||||
type_name(root));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(s->flags & JSON_VALIDATE_ONLY)) {
|
||||
json_bigr_t v;
|
||||
json_context_t *ctx = jsonp_context();
|
||||
if(!ctx->have_bigreal) {
|
||||
set_error(s,"<validation>", "No big real package registed, can not unpack value");
|
||||
return -1;
|
||||
}
|
||||
v = ctx->bigreal.copy_fn(json_bigreal_value(root),
|
||||
&ctx->memfuncs);
|
||||
*va_arg(*ap, json_bigr_t*) = v;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'R':
|
||||
if(!json_is_anyreal(root)) {
|
||||
set_error(s,"<validation>", "Expected a real, got %s",
|
||||
type_name(root));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!(s->flags & JSON_VALIDATE_ONLY)) {
|
||||
json_bigr_t v;
|
||||
json_context_t *ctx = jsonp_context();
|
||||
if(!ctx->have_bigreal) {
|
||||
set_error(s,"<validation>", "No big real package registed, can not unpack value");
|
||||
return -1;
|
||||
}
|
||||
if(json_is_bigreal(root))
|
||||
v = ctx->bigreal.copy_fn(json_bigreal_value(root),
|
||||
&ctx->memfuncs);
|
||||
else
|
||||
v = ctx->bigreal.from_real_fn(json_real_value(root),
|
||||
&ctx->memfuncs);
|
||||
*va_arg(*ap, json_bigz_t*) = v;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'V':
|
||||
case 'O':
|
||||
if(root && !(s->flags & JSON_VALIDATE_ONLY))
|
||||
json_incref(root);
|
||||
do_incref = 1;
|
||||
/* Fall through */
|
||||
|
||||
case 'v':
|
||||
case 'o':
|
||||
if(token(s) == 'V' || token(s) == 'v') {
|
||||
if(json_is_array(root) || json_is_object(root)) {
|
||||
set_error(s,"<validation>", "Expecting a scalar value, got %s",
|
||||
type_name(root));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(!(s->flags & JSON_VALIDATE_ONLY)) {
|
||||
json_t **target = va_arg(*ap, json_t**);
|
||||
json_t **target;
|
||||
|
||||
if(do_incref)
|
||||
json_incref(root);
|
||||
|
||||
target = va_arg(*ap, json_t**);
|
||||
if(root)
|
||||
*target = root;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case 'n':
|
||||
|
|
|
@ -132,3 +132,33 @@ int jsonp_dtostr(char *buffer, size_t size, double value)
|
|||
|
||||
return (int)length;
|
||||
}
|
||||
|
||||
#define l_isdigit(c) ('0' <= (c) && (c) <= '9')
|
||||
#define l_isdigit19(c) ('1' <= (c) && (c) <= '9')
|
||||
|
||||
int jsonp_count_significand_digits(strbuffer_t *strbuffer)
|
||||
{
|
||||
int digits = 0;
|
||||
const char* c;
|
||||
/* Skip leading zeros and signs */
|
||||
for( c=strbuffer->value; *c=='0' || *c=='-' || *c=='.'; c++ );
|
||||
|
||||
/* Count digits */
|
||||
while( l_isdigit(*c) || *c == '.' ) {
|
||||
if( l_isdigit19(*c) )
|
||||
digits++;
|
||||
else if( *c=='0' ) {
|
||||
const char* d;
|
||||
int zerorun=0;
|
||||
for( d=c; *d=='0' || *d=='.'; d++ )
|
||||
if( *d=='0' )
|
||||
zerorun++;
|
||||
if( l_isdigit19(*d) ) {
|
||||
digits += zerorun + 1;
|
||||
c = d;
|
||||
}
|
||||
}
|
||||
c++;
|
||||
}
|
||||
return digits;
|
||||
}
|
||||
|
|
254
src/value.c
254
src/value.c
|
@ -13,6 +13,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "jansson.h"
|
||||
#include "hashtable.h"
|
||||
|
@ -566,7 +567,7 @@ int json_array_extend(json_t *json, json_t *other_json)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int json_array_equal(json_t *array1, json_t *array2)
|
||||
static int json_array_equal(const json_t *array1, const json_t *array2)
|
||||
{
|
||||
size_t i, size;
|
||||
|
||||
|
@ -750,7 +751,7 @@ static void json_delete_string(json_string_t *string)
|
|||
jsonp_free(string);
|
||||
}
|
||||
|
||||
static int json_string_equal(json_t *string1, json_t *string2)
|
||||
static int json_string_equal(const json_t *string1, const json_t *string2)
|
||||
{
|
||||
json_string_t *s1, *s2;
|
||||
|
||||
|
@ -810,7 +811,7 @@ static void json_delete_integer(json_integer_t *integer)
|
|||
jsonp_free(integer);
|
||||
}
|
||||
|
||||
static int json_integer_equal(json_t *integer1, json_t *integer2)
|
||||
static int json_integer_equal(const json_t *integer1, const json_t *integer2)
|
||||
{
|
||||
return json_integer_value(integer1) == json_integer_value(integer2);
|
||||
}
|
||||
|
@ -821,6 +822,110 @@ static json_t *json_integer_copy(const json_t *integer)
|
|||
}
|
||||
|
||||
|
||||
/*** big integer ***/
|
||||
|
||||
json_t *json_biginteger(json_bigz_const_t value)
|
||||
{
|
||||
json_biginteger_t *bigint;
|
||||
json_context_t* ctx = jsonp_context();
|
||||
|
||||
if(!ctx->have_bigint)
|
||||
return NULL;
|
||||
|
||||
bigint = jsonp_malloc(sizeof(json_biginteger_t));
|
||||
if(!bigint)
|
||||
return NULL;
|
||||
json_init(&bigint->json, JSON_BIGINTEGER);
|
||||
|
||||
bigint->value = ctx->bigint.copy_fn(value, &ctx->memfuncs);
|
||||
return &bigint->json;
|
||||
}
|
||||
|
||||
json_bigz_const_t json_biginteger_value(const json_t *json)
|
||||
{
|
||||
if(!json_is_biginteger(json))
|
||||
return NULL;
|
||||
|
||||
return json_to_biginteger(json)->value;
|
||||
}
|
||||
|
||||
int json_biginteger_set(json_t* json, json_bigz_const_t value)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
|
||||
if(!ctx->have_bigint)
|
||||
return -1;
|
||||
|
||||
if(!json_is_biginteger(json))
|
||||
return -1;
|
||||
|
||||
json_to_biginteger(json)->value = ctx->bigint.copy_fn(value, &ctx->memfuncs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void json_delete_biginteger(json_biginteger_t *bigint)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
|
||||
if(ctx->have_bigint)
|
||||
ctx->bigint.delete_fn(bigint->value, &ctx->memfuncs);
|
||||
jsonp_free(bigint);
|
||||
}
|
||||
|
||||
static int json_biginteger_equal(const json_t* bigint1, const json_t* bigint2)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
|
||||
if(!ctx->have_bigint)
|
||||
return bigint1 == bigint2;
|
||||
return ctx->bigint.compare_fn(json_biginteger_value(bigint1),
|
||||
json_biginteger_value(bigint2),
|
||||
&ctx->memfuncs) == 0;
|
||||
}
|
||||
|
||||
static json_t* json_biginteger_copy(const json_t *bigint)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
|
||||
if(!ctx->have_bigint)
|
||||
return NULL;
|
||||
return ctx->bigint.copy_fn(json_biginteger_value(bigint),
|
||||
&ctx->memfuncs);
|
||||
}
|
||||
|
||||
static int json_anyinteger_equal(const json_t* int1, const json_t* int2)
|
||||
{
|
||||
if(json_is_integer(int1) && json_is_integer(int2))
|
||||
return json_integer_equal(int1, int2);
|
||||
else if(json_is_biginteger(int1) && json_is_biginteger(int2))
|
||||
return json_biginteger_equal(int1, int2);
|
||||
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
json_bigz_const_t i1;
|
||||
json_bigz_t i2;
|
||||
int eq;
|
||||
|
||||
if(!ctx->have_bigint)
|
||||
return int1 == int2;
|
||||
|
||||
if(json_is_biginteger(int1)) {
|
||||
assert(json_is_integer(int2));
|
||||
i1 = json_biginteger_value(int1);
|
||||
i2 = ctx->bigint.from_int_fn(json_integer_value(int2),&ctx->memfuncs);
|
||||
}
|
||||
else {
|
||||
assert(json_is_integer(int1));
|
||||
i1 = json_biginteger_value(int2);
|
||||
i2 = ctx->bigint.from_int_fn(json_integer_value(int1),&ctx->memfuncs);
|
||||
}
|
||||
eq = ctx->bigint.compare_fn(i1, i2, &ctx->memfuncs) == 0;
|
||||
ctx->bigint.delete_fn(i2, &ctx->memfuncs);
|
||||
return eq;
|
||||
}
|
||||
}
|
||||
|
||||
/*** real ***/
|
||||
|
||||
json_t *json_real(double value)
|
||||
|
@ -862,7 +967,7 @@ static void json_delete_real(json_real_t *real)
|
|||
jsonp_free(real);
|
||||
}
|
||||
|
||||
static int json_real_equal(json_t *real1, json_t *real2)
|
||||
static int json_real_equal(const json_t *real1, const json_t *real2)
|
||||
{
|
||||
return json_real_value(real1) == json_real_value(real2);
|
||||
}
|
||||
|
@ -873,6 +978,110 @@ static json_t *json_real_copy(const json_t *real)
|
|||
}
|
||||
|
||||
|
||||
/*** big real ***/
|
||||
|
||||
json_t *json_bigreal(json_bigr_const_t value)
|
||||
{
|
||||
json_bigreal_t *bigreal;
|
||||
json_context_t *ctx = jsonp_context();
|
||||
|
||||
if(!ctx->have_bigreal)
|
||||
return NULL;
|
||||
|
||||
bigreal = jsonp_malloc(sizeof(json_bigreal_t));
|
||||
if(!bigreal)
|
||||
return NULL;
|
||||
json_init(&bigreal->json, JSON_BIGREAL);
|
||||
|
||||
bigreal->value = ctx->bigreal.copy_fn(value, &ctx->memfuncs);
|
||||
return &bigreal->json;
|
||||
}
|
||||
|
||||
json_bigr_const_t json_bigreal_value(const json_t *json)
|
||||
{
|
||||
if(!json_is_bigreal(json))
|
||||
return NULL;
|
||||
|
||||
return json_to_bigreal(json)->value;
|
||||
}
|
||||
|
||||
int json_bigreal_set(json_t* json, json_bigr_const_t value)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
|
||||
if(!ctx->have_bigreal)
|
||||
return -1;
|
||||
|
||||
if(!json_is_bigreal(json))
|
||||
return -1;
|
||||
|
||||
json_to_bigreal(json)->value = ctx->bigreal.copy_fn(value, &ctx->memfuncs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void json_delete_bigreal(json_bigreal_t *bigreal)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
|
||||
if(ctx->have_bigreal)
|
||||
ctx->bigreal.delete_fn(bigreal->value, &ctx->memfuncs);
|
||||
jsonp_free(bigreal);
|
||||
}
|
||||
|
||||
static int json_bigreal_equal(const json_t* bigreal1, const json_t* bigreal2)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
|
||||
if(!ctx->have_bigreal)
|
||||
return bigreal1 == bigreal2;
|
||||
return ctx->bigreal.compare_fn(json_bigreal_value(bigreal1),
|
||||
json_bigreal_value(bigreal2),
|
||||
&ctx->memfuncs) == 0;
|
||||
}
|
||||
|
||||
static json_t* json_bigreal_copy(const json_t *bigreal)
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
|
||||
if(!ctx->have_bigreal)
|
||||
return NULL;
|
||||
return ctx->bigreal.copy_fn(json_bigreal_value(bigreal),
|
||||
&ctx->memfuncs);
|
||||
}
|
||||
|
||||
static int json_anyreal_equal(const json_t* real1, const json_t* real2)
|
||||
{
|
||||
if(json_is_real(real1) && json_is_real(real2))
|
||||
return json_real_equal(real1, real2);
|
||||
else if(json_is_bigreal(real1) && json_is_bigreal(real2))
|
||||
return json_bigreal_equal(real1, real2);
|
||||
|
||||
{
|
||||
json_context_t *ctx = jsonp_context();
|
||||
json_bigr_const_t r1;
|
||||
json_bigr_t r2;
|
||||
int eq;
|
||||
|
||||
if(!ctx->have_bigreal)
|
||||
return real1 == real2;
|
||||
|
||||
if(json_is_bigreal(real1)) {
|
||||
assert(json_is_real(real2));
|
||||
r1 = json_bigreal_value(real1);
|
||||
r2 = ctx->bigreal.from_real_fn(json_real_value(real2),&ctx->memfuncs);
|
||||
}
|
||||
else {
|
||||
assert(json_is_real(real1));
|
||||
r1 = json_bigreal_value(real2);
|
||||
r2 = ctx->bigreal.from_real_fn(json_real_value(real1),&ctx->memfuncs);
|
||||
}
|
||||
eq = ctx->bigreal.compare_fn(r1, r2, &ctx->memfuncs) == 0;
|
||||
ctx->bigreal.delete_fn(r2, &ctx->memfuncs);
|
||||
return eq;
|
||||
}
|
||||
}
|
||||
|
||||
/*** number ***/
|
||||
|
||||
double json_number_value(const json_t *json)
|
||||
|
@ -928,6 +1137,12 @@ void json_delete(json_t *json)
|
|||
else if(json_is_real(json))
|
||||
json_delete_real(json_to_real(json));
|
||||
|
||||
else if(json_is_biginteger(json))
|
||||
json_delete_biginteger(json_to_biginteger(json));
|
||||
|
||||
else if(json_is_bigreal(json))
|
||||
json_delete_bigreal(json_to_bigreal(json));
|
||||
|
||||
/* json_delete is not called for true, false or null */
|
||||
}
|
||||
|
||||
|
@ -939,8 +1154,17 @@ int json_equal(json_t *json1, json_t *json2)
|
|||
if(!json1 || !json2)
|
||||
return 0;
|
||||
|
||||
if(json_typeof(json1) != json_typeof(json2))
|
||||
return 0;
|
||||
if(json_typeof(json1) != json_typeof(json2)) {
|
||||
/* Types not equal, see if they are convertable */
|
||||
if(json_is_anyinteger(json1) && json_is_anyinteger(json2)) {
|
||||
return json_anyinteger_equal(json1, json2);
|
||||
}
|
||||
else if(json_is_anyreal(json1) && json_is_anyreal(json2)) {
|
||||
return json_anyreal_equal(json1, json2);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this covers true, false and null as they are singletons */
|
||||
if(json1 == json2)
|
||||
|
@ -961,6 +1185,12 @@ int json_equal(json_t *json1, json_t *json2)
|
|||
if(json_is_real(json1))
|
||||
return json_real_equal(json1, json2);
|
||||
|
||||
if(json_is_biginteger(json1))
|
||||
return json_biginteger_equal(json1, json2);
|
||||
|
||||
if(json_is_bigreal(json2))
|
||||
return json_bigreal_equal(json1, json2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -987,6 +1217,12 @@ json_t *json_copy(json_t *json)
|
|||
if(json_is_real(json))
|
||||
return json_real_copy(json);
|
||||
|
||||
if(json_is_biginteger(json))
|
||||
return json_biginteger_copy(json);
|
||||
|
||||
if(json_is_bigreal(json))
|
||||
return json_bigreal_copy(json);
|
||||
|
||||
if(json_is_true(json) || json_is_false(json) || json_is_null(json))
|
||||
return json;
|
||||
|
||||
|
@ -1016,6 +1252,12 @@ json_t *json_deep_copy(const json_t *json)
|
|||
if(json_is_real(json))
|
||||
return json_real_copy(json);
|
||||
|
||||
if(json_is_biginteger(json))
|
||||
return json_biginteger_copy(json);
|
||||
|
||||
if(json_is_bigreal(json))
|
||||
return json_bigreal_copy(json);
|
||||
|
||||
if(json_is_true(json) || json_is_false(json) || json_is_null(json))
|
||||
return (json_t *)json;
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
1 2 2
|
||||
invalid token near '0'
|
||||
numbers may not have unnecessary leading zeros near '0'
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
1 3 3
|
||||
invalid token near '-0'
|
||||
numbers may not have unnecessary leading zeros near '-0'
|
||||
|
|
Loading…
Reference in New Issue