aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/ujson/py3
diff options
context:
space:
mode:
authorvitalyisaev <vitalyisaev@ydb.tech>2023-11-30 13:26:22 +0300
committervitalyisaev <vitalyisaev@ydb.tech>2023-11-30 15:44:45 +0300
commit0a98fece5a9b54f16afeb3a94b3eb3105e9c3962 (patch)
tree291d72dbd7e9865399f668c84d11ed86fb190bbf /contrib/python/ujson/py3
parentcb2c8d75065e5b3c47094067cb4aa407d4813298 (diff)
downloadydb-0a98fece5a9b54f16afeb3a94b3eb3105e9c3962.tar.gz
YQ Connector:Use docker-compose in integrational tests
Diffstat (limited to 'contrib/python/ujson/py3')
-rw-r--r--contrib/python/ujson/py3/lib/ultrajson.h333
-rw-r--r--contrib/python/ujson/py3/lib/ultrajsondec.c907
-rw-r--r--contrib/python/ujson/py3/lib/ultrajsonenc.c1029
-rw-r--r--contrib/python/ujson/py3/python/JSONtoObj.c252
-rw-r--r--contrib/python/ujson/py3/python/objToJSON.c1168
-rw-r--r--contrib/python/ujson/py3/python/py_defines.h53
-rw-r--r--contrib/python/ujson/py3/python/ujson.c113
-rw-r--r--contrib/python/ujson/py3/python/version.h39
-rw-r--r--contrib/python/ujson/py3/ya.make30
9 files changed, 3924 insertions, 0 deletions
diff --git a/contrib/python/ujson/py3/lib/ultrajson.h b/contrib/python/ujson/py3/lib/ultrajson.h
new file mode 100644
index 0000000000..92902b4910
--- /dev/null
+++ b/contrib/python/ujson/py3/lib/ultrajson.h
@@ -0,0 +1,333 @@
+/*
+Developed by ESN, an Electronic Arts Inc. studio.
+Copyright (c) 2014, Electronic Arts Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of ESN, Electronic Arts Inc. nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS INC. BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Portions of code from MODP_ASCII - Ascii transformations (upper/lower, etc)
+http://code.google.com/p/stringencoders/
+Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
+
+Numeric decoder derived from from TCL library
+http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+*/
+
+/*
+Ultra fast JSON encoder and decoder
+Developed by Jonas Tarnstrom (jonas@esn.me).
+
+Encoder notes:
+------------------
+
+:: Cyclic references ::
+Cyclic referenced objects are not detected.
+Set JSONObjectEncoder.recursionMax to suitable value or make sure input object
+tree doesn't have cyclic references.
+
+*/
+
+#ifndef __ULTRAJSON_H__
+#define __ULTRAJSON_H__
+
+#include <stdio.h>
+#include <wchar.h>
+
+// Don't output any extra whitespaces when encoding
+#define JSON_NO_EXTRA_WHITESPACE
+
+// Max decimals to encode double floating point numbers with
+#ifndef JSON_DOUBLE_MAX_DECIMALS
+#define JSON_DOUBLE_MAX_DECIMALS 15
+#endif
+
+// Max recursion depth, default for encoder
+#ifndef JSON_MAX_RECURSION_DEPTH
+#define JSON_MAX_RECURSION_DEPTH 1024
+#endif
+
+// Max recursion depth, default for decoder
+#ifndef JSON_MAX_OBJECT_DEPTH
+#define JSON_MAX_OBJECT_DEPTH 1024
+#endif
+
+/*
+Dictates and limits how much stack space for buffers UltraJSON will use before resorting to provided heap functions */
+#ifndef JSON_MAX_STACK_BUFFER_SIZE
+#define JSON_MAX_STACK_BUFFER_SIZE 131072
+#endif
+
+#ifdef _WIN32
+
+typedef __int64 JSINT64;
+typedef unsigned __int64 JSUINT64;
+
+typedef __int32 JSINT32;
+typedef unsigned __int32 JSUINT32;
+typedef unsigned __int8 JSUINT8;
+typedef unsigned __int16 JSUTF16;
+typedef unsigned __int32 JSUTF32;
+typedef __int64 JSLONG;
+
+#define EXPORTFUNCTION __declspec(dllexport)
+
+#define FASTCALL_MSVC __fastcall
+#define FASTCALL_ATTR
+#define INLINE_PREFIX __inline
+
+#else
+
+#include <stdint.h>
+typedef int64_t JSINT64;
+typedef uint64_t JSUINT64;
+
+typedef int32_t JSINT32;
+typedef uint32_t JSUINT32;
+
+#define FASTCALL_MSVC
+
+#if !defined __x86_64__
+#define FASTCALL_ATTR __attribute__((fastcall))
+#else
+#define FASTCALL_ATTR
+#endif
+
+
+#if defined(__clang__)
+#define INLINE_PREFIX inline __attribute__((always_inline))
+#else
+#define INLINE_PREFIX static inline
+#endif
+
+typedef uint8_t JSUINT8;
+typedef uint16_t JSUTF16;
+typedef uint32_t JSUTF32;
+
+typedef int64_t JSLONG;
+
+#define EXPORTFUNCTION
+#endif
+
+#if !(defined(__LITTLE_ENDIAN__) || defined(__BIG_ENDIAN__))
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define __LITTLE_ENDIAN__
+#else
+
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define __BIG_ENDIAN__
+#endif
+
+#endif
+
+#endif
+
+#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+#error "Endianess not supported"
+#endif
+
+enum JSTYPES
+{
+ JT_NULL, // NULL
+ JT_TRUE, // boolean true
+ JT_FALSE, // boolean false
+ JT_INT, // (JSINT32 (signed 32-bit))
+ JT_LONG, // (JSINT64 (signed 64-bit))
+ JT_ULONG, // (JSUINT64 (unsigned 64-bit))
+ JT_DOUBLE, // (double)
+ JT_UTF8, // (char 8-bit)
+ JT_RAW, // (raw char 8-bit)
+ JT_ARRAY, // Array structure
+ JT_OBJECT, // Key/Value structure
+ JT_INVALID, // Internal, do not return nor expect
+};
+
+typedef void * JSOBJ;
+typedef void * JSITER;
+
+typedef struct __JSONTypeContext
+{
+ int type;
+ void *prv;
+ void *encoder_prv;
+} JSONTypeContext;
+
+/*
+Function pointer declarations, suitable for implementing UltraJSON */
+typedef int (*JSPFN_ITERNEXT)(JSOBJ obj, JSONTypeContext *tc);
+typedef void (*JSPFN_ITEREND)(JSOBJ obj, JSONTypeContext *tc);
+typedef JSOBJ (*JSPFN_ITERGETVALUE)(JSOBJ obj, JSONTypeContext *tc);
+typedef char *(*JSPFN_ITERGETNAME)(JSOBJ obj, JSONTypeContext *tc, size_t *outLen);
+typedef void *(*JSPFN_MALLOC)(size_t size);
+typedef void (*JSPFN_FREE)(void *pptr);
+typedef void *(*JSPFN_REALLOC)(void *base, size_t size);
+
+
+struct __JSONObjectEncoder;
+
+typedef struct __JSONObjectEncoder
+{
+ void (*beginTypeContext)(JSOBJ obj, JSONTypeContext *tc, struct __JSONObjectEncoder *enc);
+ void (*endTypeContext)(JSOBJ obj, JSONTypeContext *tc);
+ const char *(*getStringValue)(JSOBJ obj, JSONTypeContext *tc, size_t *_outLen);
+ JSINT64 (*getLongValue)(JSOBJ obj, JSONTypeContext *tc);
+ JSUINT64 (*getUnsignedLongValue)(JSOBJ obj, JSONTypeContext *tc);
+ JSINT32 (*getIntValue)(JSOBJ obj, JSONTypeContext *tc);
+ double (*getDoubleValue)(JSOBJ obj, JSONTypeContext *tc);
+
+ /*
+ Retrieve next object in an iteration. Should return 0 to indicate iteration has reached end or 1 if there are more items.
+ Implementor is responsible for keeping state of the iteration. Use ti->prv fields for this
+ */
+ JSPFN_ITERNEXT iterNext;
+
+ /*
+ Ends the iteration of an iteratable object.
+ Any iteration state stored in ti->prv can be freed here
+ */
+ JSPFN_ITEREND iterEnd;
+
+ /*
+ Returns a reference to the value object of an iterator
+ The is responsible for the life-cycle of the returned string. Use iterNext/iterEnd and ti->prv to keep track of current object
+ */
+ JSPFN_ITERGETVALUE iterGetValue;
+
+ /*
+ Return name of iterator.
+ The is responsible for the life-cycle of the returned string. Use iterNext/iterEnd and ti->prv to keep track of current object
+ */
+ JSPFN_ITERGETNAME iterGetName;
+
+ /*
+ Release a value as indicated by setting ti->release = 1 in the previous getValue call.
+ The ti->prv array should contain the necessary context to release the value
+ */
+ void (*releaseObject)(JSOBJ obj);
+
+ /* Library functions
+ Set to NULL to use STDLIB malloc,realloc,free */
+ JSPFN_MALLOC malloc;
+ JSPFN_REALLOC realloc;
+ JSPFN_FREE free;
+
+ /*
+ Configuration for max recursion, set to 0 to use default (see JSON_MAX_RECURSION_DEPTH)*/
+ int recursionMax;
+
+ /*
+ Configuration for max decimals of double floating point numbers to encode (0-9) */
+ int doublePrecision;
+
+ /*
+ If true output will be ASCII with all characters above 127 encoded as \uXXXX. If false output will be UTF-8 or what ever charset strings are brought as */
+ int forceASCII;
+
+ /*
+ If true, '<', '>', and '&' characters will be encoded as \u003c, \u003e, and \u0026, respectively. If false, no special encoding will be used. */
+ int encodeHTMLChars;
+
+ /*
+ If true, '/' will be encoded as \/. If false, no escaping. */
+ int escapeForwardSlashes;
+
+ /*
+ If true, dictionaries are iterated through in sorted key order. */
+ int sortKeys;
+
+ /*
+ Configuration for spaces of indent */
+ int indent;
+
+ /*
+ Private pointer to be used by the caller. Passed as encoder_prv in JSONTypeContext */
+ void *prv;
+
+ /*
+ Set to an error message if error occured */
+ const char *errorMsg;
+ JSOBJ errorObj;
+
+ /* Buffer stuff */
+ char *start;
+ char *offset;
+ char *end;
+ int heap;
+ int level;
+
+} JSONObjectEncoder;
+
+
+/*
+Encode an object structure into JSON.
+
+Arguments:
+obj - An anonymous type representing the object
+enc - Function definitions for querying JSOBJ type
+buffer - Preallocated buffer to store result in. If NULL function allocates own buffer
+cbBuffer - Length of buffer (ignored if buffer is NULL)
+
+Returns:
+Encoded JSON object as a null terminated char string.
+
+NOTE:
+If the supplied buffer wasn't enough to hold the result the function will allocate a new buffer.
+Life cycle of the provided buffer must still be handled by caller.
+
+If the return value doesn't equal the specified buffer caller must release the memory using
+JSONObjectEncoder.free or free() as specified when calling this function.
+*/
+EXPORTFUNCTION char *JSON_EncodeObject(JSOBJ obj, JSONObjectEncoder *enc, char *buffer, size_t cbBuffer);
+
+
+
+typedef struct __JSONObjectDecoder
+{
+ JSOBJ (*newString)(void *prv, wchar_t *start, wchar_t *end);
+ void (*objectAddKey)(void *prv, JSOBJ obj, JSOBJ name, JSOBJ value);
+ void (*arrayAddItem)(void *prv, JSOBJ obj, JSOBJ value);
+ JSOBJ (*newTrue)(void *prv);
+ JSOBJ (*newFalse)(void *prv);
+ JSOBJ (*newNull)(void *prv);
+ JSOBJ (*newObject)(void *prv);
+ JSOBJ (*newArray)(void *prv);
+ JSOBJ (*newInt)(void *prv, JSINT32 value);
+ JSOBJ (*newLong)(void *prv, JSINT64 value);
+ JSOBJ (*newUnsignedLong)(void *prv, JSUINT64 value);
+ JSOBJ (*newDouble)(void *prv, double value);
+ void (*releaseObject)(void *prv, JSOBJ obj);
+ JSPFN_MALLOC malloc;
+ JSPFN_FREE free;
+ JSPFN_REALLOC realloc;
+ char *errorStr;
+ char *errorOffset;
+ int preciseFloat;
+ void *prv;
+} JSONObjectDecoder;
+
+EXPORTFUNCTION JSOBJ JSON_DecodeObject(JSONObjectDecoder *dec, const char *buffer, size_t cbBuffer);
+
+#endif
diff --git a/contrib/python/ujson/py3/lib/ultrajsondec.c b/contrib/python/ujson/py3/lib/ultrajsondec.c
new file mode 100644
index 0000000000..21a732eceb
--- /dev/null
+++ b/contrib/python/ujson/py3/lib/ultrajsondec.c
@@ -0,0 +1,907 @@
+/*
+Developed by ESN, an Electronic Arts Inc. studio.
+Copyright (c) 2014, Electronic Arts Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of ESN, Electronic Arts Inc. nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS INC. BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Portions of code from MODP_ASCII - Ascii transformations (upper/lower, etc)
+http://code.google.com/p/stringencoders/
+Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
+
+Numeric decoder derived from from TCL library
+http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
+* Copyright (c) 1988-1993 The Regents of the University of California.
+* Copyright (c) 1994 Sun Microsystems, Inc.
+*/
+
+#include "ultrajson.h"
+#include <math.h>
+#include <assert.h>
+#include <string.h>
+#include <limits.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+
+struct DecoderState
+{
+ char *start;
+ char *end;
+ wchar_t *escStart;
+ wchar_t *escEnd;
+ int escHeap;
+ int lastType;
+ JSUINT32 objDepth;
+ void *prv;
+ JSONObjectDecoder *dec;
+};
+
+JSOBJ FASTCALL_MSVC decode_any( struct DecoderState *ds) FASTCALL_ATTR;
+typedef JSOBJ (*PFN_DECODER)( struct DecoderState *ds);
+
+static JSOBJ SetError( struct DecoderState *ds, int offset, const char *message)
+{
+ ds->dec->errorOffset = ds->start + offset;
+ ds->dec->errorStr = (char *) message;
+ return NULL;
+}
+
+double createDouble(double intNeg, double intValue, double frcValue, int frcDecimalCount)
+{
+ static const double g_pow10[] = {1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001,0.0000001, 0.00000001, 0.000000001, 0.0000000001, 0.00000000001, 0.000000000001, 0.0000000000001, 0.00000000000001, 0.000000000000001};
+ return (intValue + (frcValue * g_pow10[frcDecimalCount])) * intNeg;
+}
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decodePreciseFloat(struct DecoderState *ds)
+{
+ char *end;
+ double value;
+ errno = 0;
+
+ value = strtod(ds->start, &end);
+
+ if (errno == ERANGE)
+ {
+ return SetError(ds, -1, "Range error when decoding numeric as double");
+ }
+
+ ds->start = end;
+ return ds->dec->newDouble(ds->prv, value);
+}
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric (struct DecoderState *ds)
+{
+ int intNeg = 1;
+ int mantSize = 0;
+ JSUINT64 intValue;
+ JSUINT64 prevIntValue;
+ int chr;
+ int decimalCount = 0;
+ double frcValue = 0.0;
+ double expNeg;
+ double expValue;
+ char *offset = ds->start;
+
+ JSUINT64 overflowLimit = LLONG_MAX;
+
+ if (*(offset) == '-')
+ {
+ offset ++;
+ intNeg = -1;
+ overflowLimit = LLONG_MIN;
+ }
+
+ // Scan integer part
+ intValue = 0;
+
+ while (1)
+ {
+ chr = (int) (unsigned char) *(offset);
+
+ switch (chr)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ //PERF: Don't do 64-bit arithmetic here unless we know we have to
+ prevIntValue = intValue;
+ intValue = intValue * 10ULL + (JSLONG) (chr - 48);
+
+ if (intNeg == 1 && prevIntValue > intValue)
+ {
+ return SetError(ds, -1, "Value is too big!");
+ }
+ else if (intNeg == -1 && intValue > overflowLimit)
+ {
+ return SetError(ds, -1, overflowLimit == LLONG_MAX ? "Value is too big!" : "Value is too small");
+ }
+
+ offset ++;
+ mantSize ++;
+ break;
+ }
+ case '.':
+ {
+ offset ++;
+ goto DECODE_FRACTION;
+ break;
+ }
+ case 'e':
+ case 'E':
+ {
+ offset ++;
+ goto DECODE_EXPONENT;
+ break;
+ }
+
+ default:
+ {
+ goto BREAK_INT_LOOP;
+ break;
+ }
+ }
+ }
+
+BREAK_INT_LOOP:
+
+ ds->lastType = JT_INT;
+ ds->start = offset;
+
+ if (intNeg == 1 && (intValue & 0x8000000000000000ULL) != 0)
+ {
+ return ds->dec->newUnsignedLong(ds->prv, intValue);
+ }
+ else if ((intValue >> 31))
+ {
+ return ds->dec->newLong(ds->prv, (JSINT64) (intValue * (JSINT64) intNeg));
+ }
+ else
+ {
+ return ds->dec->newInt(ds->prv, (JSINT32) (intValue * intNeg));
+ }
+
+DECODE_FRACTION:
+
+ if (ds->dec->preciseFloat)
+ {
+ return decodePreciseFloat(ds);
+ }
+
+ // Scan fraction part
+ frcValue = 0.0;
+ for (;;)
+ {
+ chr = (int) (unsigned char) *(offset);
+
+ switch (chr)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ if (decimalCount < JSON_DOUBLE_MAX_DECIMALS)
+ {
+ frcValue = frcValue * 10.0 + (double) (chr - 48);
+ decimalCount ++;
+ }
+ offset ++;
+ break;
+ }
+ case 'e':
+ case 'E':
+ {
+ offset ++;
+ goto DECODE_EXPONENT;
+ break;
+ }
+ default:
+ {
+ goto BREAK_FRC_LOOP;
+ }
+ }
+ }
+
+BREAK_FRC_LOOP:
+ //FIXME: Check for arithemtic overflow here
+ ds->lastType = JT_DOUBLE;
+ ds->start = offset;
+ return ds->dec->newDouble (ds->prv, createDouble( (double) intNeg, (double) intValue, frcValue, decimalCount));
+
+DECODE_EXPONENT:
+ if (ds->dec->preciseFloat)
+ {
+ return decodePreciseFloat(ds);
+ }
+
+ expNeg = 1.0;
+
+ if (*(offset) == '-')
+ {
+ expNeg = -1.0;
+ offset ++;
+ }
+ else
+ if (*(offset) == '+')
+ {
+ expNeg = +1.0;
+ offset ++;
+ }
+
+ expValue = 0.0;
+
+ for (;;)
+ {
+ chr = (int) (unsigned char) *(offset);
+
+ switch (chr)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ expValue = expValue * 10.0 + (double) (chr - 48);
+ offset ++;
+ break;
+ }
+ default:
+ {
+ goto BREAK_EXP_LOOP;
+ }
+ }
+ }
+
+BREAK_EXP_LOOP:
+ //FIXME: Check for arithemtic overflow here
+ ds->lastType = JT_DOUBLE;
+ ds->start = offset;
+ return ds->dec->newDouble (ds->prv, createDouble( (double) intNeg, (double) intValue , frcValue, decimalCount) * pow(10.0, expValue * expNeg));
+}
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_true ( struct DecoderState *ds)
+{
+ char *offset = ds->start;
+ offset ++;
+
+ if (*(offset++) != 'r')
+ goto SETERROR;
+ if (*(offset++) != 'u')
+ goto SETERROR;
+ if (*(offset++) != 'e')
+ goto SETERROR;
+
+ ds->lastType = JT_TRUE;
+ ds->start = offset;
+ return ds->dec->newTrue(ds->prv);
+
+SETERROR:
+ return SetError(ds, -1, "Unexpected character found when decoding 'true'");
+}
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_false ( struct DecoderState *ds)
+{
+ char *offset = ds->start;
+ offset ++;
+
+ if (*(offset++) != 'a')
+ goto SETERROR;
+ if (*(offset++) != 'l')
+ goto SETERROR;
+ if (*(offset++) != 's')
+ goto SETERROR;
+ if (*(offset++) != 'e')
+ goto SETERROR;
+
+ ds->lastType = JT_FALSE;
+ ds->start = offset;
+ return ds->dec->newFalse(ds->prv);
+
+SETERROR:
+ return SetError(ds, -1, "Unexpected character found when decoding 'false'");
+}
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_null ( struct DecoderState *ds)
+{
+ char *offset = ds->start;
+ offset ++;
+
+ if (*(offset++) != 'u')
+ goto SETERROR;
+ if (*(offset++) != 'l')
+ goto SETERROR;
+ if (*(offset++) != 'l')
+ goto SETERROR;
+
+ ds->lastType = JT_NULL;
+ ds->start = offset;
+ return ds->dec->newNull(ds->prv);
+
+SETERROR:
+ return SetError(ds, -1, "Unexpected character found when decoding 'null'");
+}
+
+FASTCALL_ATTR void FASTCALL_MSVC SkipWhitespace(struct DecoderState *ds)
+{
+ char *offset = ds->start;
+
+ for (;;)
+ {
+ switch (*offset)
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ offset ++;
+ break;
+
+ default:
+ ds->start = offset;
+ return;
+ }
+ }
+}
+
+enum DECODESTRINGSTATE
+{
+ DS_ISNULL = 0x32,
+ DS_ISQUOTE,
+ DS_ISESCAPE,
+ DS_UTFLENERROR,
+
+};
+
+static const JSUINT8 g_decoderLookup[256] =
+{
+ /* 0x00 */ DS_ISNULL, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0x10 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0x20 */ 1, 1, DS_ISQUOTE, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, DS_ISESCAPE, 1, 1, 1,
+ /* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0x80 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0x90 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0xa0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0xb0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0xc0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ /* 0xd0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ /* 0xe0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ /* 0xf0 */ 4, 4, 4, 4, 4, 4, 4, 4, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR, DS_UTFLENERROR,
+};
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_string ( struct DecoderState *ds)
+{
+ JSUTF16 sur[2] = { 0 };
+ int iSur = 0;
+ int index;
+ wchar_t *escOffset;
+ wchar_t *escStart;
+ size_t escLen = (ds->escEnd - ds->escStart);
+ JSUINT8 *inputOffset;
+ JSUINT8 oct;
+ JSUTF32 ucs;
+ ds->lastType = JT_INVALID;
+ ds->start ++;
+
+ if ( (size_t) (ds->end - ds->start) > escLen)
+ {
+ size_t newSize = (ds->end - ds->start);
+
+ if (ds->escHeap)
+ {
+ if (newSize > (SIZE_MAX / sizeof(wchar_t)))
+ {
+ return SetError(ds, -1, "Could not reserve memory block");
+ }
+ escStart = (wchar_t *)ds->dec->realloc(ds->escStart, newSize * sizeof(wchar_t));
+ if (!escStart)
+ {
+ ds->dec->free(ds->escStart);
+ return SetError(ds, -1, "Could not reserve memory block");
+ }
+ ds->escStart = escStart;
+ }
+ else
+ {
+ wchar_t *oldStart = ds->escStart;
+ if (newSize > (SIZE_MAX / sizeof(wchar_t)))
+ {
+ return SetError(ds, -1, "Could not reserve memory block");
+ }
+ ds->escStart = (wchar_t *) ds->dec->malloc(newSize * sizeof(wchar_t));
+ if (!ds->escStart)
+ {
+ return SetError(ds, -1, "Could not reserve memory block");
+ }
+ ds->escHeap = 1;
+ memcpy(ds->escStart, oldStart, escLen * sizeof(wchar_t));
+ }
+
+ ds->escEnd = ds->escStart + newSize;
+ }
+
+ escOffset = ds->escStart;
+ inputOffset = (JSUINT8 *) ds->start;
+
+ for (;;)
+ {
+ switch (g_decoderLookup[(JSUINT8)(*inputOffset)])
+ {
+ case DS_ISNULL:
+ {
+ return SetError(ds, -1, "Unmatched ''\"' when when decoding 'string'");
+ }
+ case DS_ISQUOTE:
+ {
+ ds->lastType = JT_UTF8;
+ inputOffset ++;
+ ds->start += ( (char *) inputOffset - (ds->start));
+ return ds->dec->newString(ds->prv, ds->escStart, escOffset);
+ }
+ case DS_UTFLENERROR:
+ {
+ return SetError (ds, -1, "Invalid UTF-8 sequence length when decoding 'string'");
+ }
+ case DS_ISESCAPE:
+ inputOffset ++;
+ switch (*inputOffset)
+ {
+ case '\\': *(escOffset++) = L'\\'; inputOffset++; continue;
+ case '\"': *(escOffset++) = L'\"'; inputOffset++; continue;
+ case '/': *(escOffset++) = L'/'; inputOffset++; continue;
+ case 'b': *(escOffset++) = L'\b'; inputOffset++; continue;
+ case 'f': *(escOffset++) = L'\f'; inputOffset++; continue;
+ case 'n': *(escOffset++) = L'\n'; inputOffset++; continue;
+ case 'r': *(escOffset++) = L'\r'; inputOffset++; continue;
+ case 't': *(escOffset++) = L'\t'; inputOffset++; continue;
+
+ case 'u':
+ {
+ int index;
+ inputOffset ++;
+
+ for (index = 0; index < 4; index ++)
+ {
+ switch (*inputOffset)
+ {
+ case '\0': return SetError (ds, -1, "Unterminated unicode escape sequence when decoding 'string'");
+ default: return SetError (ds, -1, "Unexpected character in unicode escape sequence when decoding 'string'");
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ sur[iSur] = (sur[iSur] << 4) + (JSUTF16) (*inputOffset - '0');
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ sur[iSur] = (sur[iSur] << 4) + 10 + (JSUTF16) (*inputOffset - 'a');
+ break;
+
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ sur[iSur] = (sur[iSur] << 4) + 10 + (JSUTF16) (*inputOffset - 'A');
+ break;
+ }
+
+ inputOffset ++;
+ }
+
+ if (iSur == 0)
+ {
+ if((sur[iSur] & 0xfc00) == 0xd800)
+ {
+ // First of a surrogate pair, continue parsing
+ iSur ++;
+ break;
+ }
+ (*escOffset++) = (wchar_t) sur[iSur];
+ iSur = 0;
+ }
+ else
+ {
+ // Decode pair
+ if ((sur[1] & 0xfc00) != 0xdc00)
+ {
+ return SetError (ds, -1, "Unpaired high surrogate when decoding 'string'");
+ }
+#if WCHAR_MAX == 0xffff
+ (*escOffset++) = (wchar_t) sur[0];
+ (*escOffset++) = (wchar_t) sur[1];
+#else
+ (*escOffset++) = (wchar_t) 0x10000 + (((sur[0] - 0xd800) << 10) | (sur[1] - 0xdc00));
+#endif
+ iSur = 0;
+ }
+ break;
+ }
+
+ case '\0': return SetError(ds, -1, "Unterminated escape sequence when decoding 'string'");
+ default: return SetError(ds, -1, "Unrecognized escape sequence when decoding 'string'");
+ }
+ break;
+
+ case 1:
+ {
+ *(escOffset++) = (wchar_t) (*inputOffset++);
+ break;
+ }
+
+ case 2:
+ {
+ ucs = (*inputOffset++) & 0x1f;
+ ucs <<= 6;
+ if (((*inputOffset) & 0x80) != 0x80)
+ {
+ return SetError(ds, -1, "Invalid octet in UTF-8 sequence when decoding 'string'");
+ }
+ ucs |= (*inputOffset++) & 0x3f;
+ if (ucs < 0x80) return SetError (ds, -1, "Overlong 2 byte UTF-8 sequence detected when decoding 'string'");
+ *(escOffset++) = (wchar_t) ucs;
+ break;
+ }
+
+ case 3:
+ {
+ JSUTF32 ucs = 0;
+ ucs |= (*inputOffset++) & 0x0f;
+
+ for (index = 0; index < 2; index ++)
+ {
+ ucs <<= 6;
+ oct = (*inputOffset++);
+
+ if ((oct & 0x80) != 0x80)
+ {
+ return SetError(ds, -1, "Invalid octet in UTF-8 sequence when decoding 'string'");
+ }
+
+ ucs |= oct & 0x3f;
+ }
+
+ if (ucs < 0x800) return SetError (ds, -1, "Overlong 3 byte UTF-8 sequence detected when encoding string");
+ *(escOffset++) = (wchar_t) ucs;
+ break;
+ }
+
+ case 4:
+ {
+ JSUTF32 ucs = 0;
+ ucs |= (*inputOffset++) & 0x07;
+
+ for (index = 0; index < 3; index ++)
+ {
+ ucs <<= 6;
+ oct = (*inputOffset++);
+
+ if ((oct & 0x80) != 0x80)
+ {
+ return SetError(ds, -1, "Invalid octet in UTF-8 sequence when decoding 'string'");
+ }
+
+ ucs |= oct & 0x3f;
+ }
+
+ if (ucs < 0x10000) return SetError (ds, -1, "Overlong 4 byte UTF-8 sequence detected when decoding 'string'");
+
+#if WCHAR_MAX == 0xffff
+ if (ucs >= 0x10000)
+ {
+ ucs -= 0x10000;
+ *(escOffset++) = (wchar_t) (ucs >> 10) + 0xd800;
+ *(escOffset++) = (wchar_t) (ucs & 0x3ff) + 0xdc00;
+ }
+ else
+ {
+ *(escOffset++) = (wchar_t) ucs;
+ }
+#else
+ *(escOffset++) = (wchar_t) ucs;
+#endif
+ break;
+ }
+ }
+ }
+}
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_array(struct DecoderState *ds)
+{
+ JSOBJ itemValue;
+ JSOBJ newObj;
+ int len;
+ ds->objDepth++;
+ if (ds->objDepth > JSON_MAX_OBJECT_DEPTH) {
+ return SetError(ds, -1, "Reached object decoding depth limit");
+ }
+
+ newObj = ds->dec->newArray(ds->prv);
+ len = 0;
+
+ ds->lastType = JT_INVALID;
+ ds->start ++;
+
+ for (;;)
+ {
+ SkipWhitespace(ds);
+
+ if ((*ds->start) == ']')
+ {
+ ds->objDepth--;
+ if (len == 0)
+ {
+ ds->start ++;
+ return newObj;
+ }
+
+ ds->dec->releaseObject(ds->prv, newObj);
+ return SetError(ds, -1, "Unexpected character found when decoding array value (1)");
+ }
+
+ itemValue = decode_any(ds);
+
+ if (itemValue == NULL)
+ {
+ ds->dec->releaseObject(ds->prv, newObj);
+ return NULL;
+ }
+
+ ds->dec->arrayAddItem (ds->prv, newObj, itemValue);
+
+ SkipWhitespace(ds);
+
+ switch (*(ds->start++))
+ {
+ case ']':
+ {
+ ds->objDepth--;
+ return newObj;
+ }
+ case ',':
+ break;
+
+ default:
+ ds->dec->releaseObject(ds->prv, newObj);
+ return SetError(ds, -1, "Unexpected character found when decoding array value (2)");
+ }
+
+ len ++;
+ }
+}
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_object( struct DecoderState *ds)
+{
+ JSOBJ itemName;
+ JSOBJ itemValue;
+ JSOBJ newObj;
+
+ ds->objDepth++;
+ if (ds->objDepth > JSON_MAX_OBJECT_DEPTH) {
+ return SetError(ds, -1, "Reached object decoding depth limit");
+ }
+
+ newObj = ds->dec->newObject(ds->prv);
+
+ ds->start ++;
+
+ for (;;)
+ {
+ SkipWhitespace(ds);
+
+ if ((*ds->start) == '}')
+ {
+ ds->objDepth--;
+ ds->start ++;
+ return newObj;
+ }
+
+ ds->lastType = JT_INVALID;
+ itemName = decode_any(ds);
+
+ if (itemName == NULL)
+ {
+ ds->dec->releaseObject(ds->prv, newObj);
+ return NULL;
+ }
+
+ if (ds->lastType != JT_UTF8)
+ {
+ ds->dec->releaseObject(ds->prv, newObj);
+ ds->dec->releaseObject(ds->prv, itemName);
+ return SetError(ds, -1, "Key name of object must be 'string' when decoding 'object'");
+ }
+
+ SkipWhitespace(ds);
+
+ if (*(ds->start++) != ':')
+ {
+ ds->dec->releaseObject(ds->prv, newObj);
+ ds->dec->releaseObject(ds->prv, itemName);
+ return SetError(ds, -1, "No ':' found when decoding object value");
+ }
+
+ SkipWhitespace(ds);
+
+ itemValue = decode_any(ds);
+
+ if (itemValue == NULL)
+ {
+ ds->dec->releaseObject(ds->prv, newObj);
+ ds->dec->releaseObject(ds->prv, itemName);
+ return NULL;
+ }
+
+ ds->dec->objectAddKey (ds->prv, newObj, itemName, itemValue);
+
+ SkipWhitespace(ds);
+
+ switch (*(ds->start++))
+ {
+ case '}':
+ {
+ ds->objDepth--;
+ return newObj;
+ }
+ case ',':
+ break;
+
+ default:
+ ds->dec->releaseObject(ds->prv, newObj);
+ return SetError(ds, -1, "Unexpected character in found when decoding object value");
+ }
+ }
+}
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_any(struct DecoderState *ds)
+{
+ for (;;)
+ {
+ switch (*ds->start)
+ {
+ case '\"':
+ return decode_string (ds);
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ return decode_numeric (ds);
+
+ case '[': return decode_array (ds);
+ case '{': return decode_object (ds);
+ case 't': return decode_true (ds);
+ case 'f': return decode_false (ds);
+ case 'n': return decode_null (ds);
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ // White space
+ ds->start ++;
+ break;
+
+ default:
+ return SetError(ds, -1, "Expected object or value");
+ }
+ }
+}
+
+JSOBJ JSON_DecodeObject(JSONObjectDecoder *dec, const char *buffer, size_t cbBuffer)
+{
+ /*
+ FIXME: Base the size of escBuffer of that of cbBuffer so that the unicode escaping doesn't run into the wall each time */
+ struct DecoderState ds;
+ wchar_t escBuffer[(JSON_MAX_STACK_BUFFER_SIZE / sizeof(wchar_t))];
+ JSOBJ ret;
+
+ ds.start = (char *) buffer;
+ ds.end = ds.start + cbBuffer;
+
+ ds.escStart = escBuffer;
+ ds.escEnd = ds.escStart + (JSON_MAX_STACK_BUFFER_SIZE / sizeof(wchar_t));
+ ds.escHeap = 0;
+ ds.prv = dec->prv;
+ ds.dec = dec;
+ ds.dec->errorStr = NULL;
+ ds.dec->errorOffset = NULL;
+ ds.objDepth = 0;
+
+ ds.dec = dec;
+
+ ret = decode_any (&ds);
+
+ if (ds.escHeap)
+ {
+ dec->free(ds.escStart);
+ }
+
+ if (!(dec->errorStr))
+ {
+ if ((ds.end - ds.start) > 0)
+ {
+ SkipWhitespace(&ds);
+ }
+
+ if (ds.start != ds.end && ret)
+ {
+ dec->releaseObject(ds.prv, ret);
+ return SetError(&ds, -1, "Trailing data");
+ }
+ }
+
+ return ret;
+}
diff --git a/contrib/python/ujson/py3/lib/ultrajsonenc.c b/contrib/python/ujson/py3/lib/ultrajsonenc.c
new file mode 100644
index 0000000000..ed6645a760
--- /dev/null
+++ b/contrib/python/ujson/py3/lib/ultrajsonenc.c
@@ -0,0 +1,1029 @@
+/*
+Developed by ESN, an Electronic Arts Inc. studio.
+Copyright (c) 2014, Electronic Arts Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of ESN, Electronic Arts Inc. nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS INC. BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Portions of code from MODP_ASCII - Ascii transformations (upper/lower, etc)
+http://code.google.com/p/stringencoders/
+Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
+
+Numeric decoder derived from from TCL library
+http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+*/
+
+#include "ultrajson.h"
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <float.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#if ( (defined(_WIN32) || defined(WIN32) ) && ( defined(_MSC_VER) ) )
+#define snprintf sprintf_s
+#endif
+
+/*
+Worst cases being:
+
+Control characters (ASCII < 32)
+0x00 (1 byte) input => \u0000 output (6 bytes)
+1 * 6 => 6 (6 bytes required)
+
+or UTF-16 surrogate pairs
+4 bytes input in UTF-8 => \uXXXX\uYYYY (12 bytes).
+
+4 * 6 => 24 bytes (12 bytes required)
+
+The extra 2 bytes are for the quotes around the string
+
+*/
+#define RESERVE_STRING(_len) (2 + ((_len) * 6))
+
+static const double g_pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000};
+static const char g_hexChars[] = "0123456789abcdef";
+static const char g_escapeChars[] = "0123456789\\b\\t\\n\\f\\r\\\"\\\\\\/";
+
+/*
+FIXME: While this is fine dandy and working it's a magic value mess which probably only the author understands.
+Needs a cleanup and more documentation */
+
+/*
+Table for pure ascii output escaping all characters above 127 to \uXXXX */
+static const JSUINT8 g_asciiOutputTable[256] =
+{
+/* 0x00 */ 0, 30, 30, 30, 30, 30, 30, 30, 10, 12, 14, 30, 16, 18, 30, 30,
+/* 0x10 */ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+/* 0x20 */ 1, 1, 20, 1, 1, 1, 29, 1, 1, 1, 1, 1, 1, 1, 1, 24,
+/* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 29, 1, 29, 1,
+/* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 1, 1, 1,
+/* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x80 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0x90 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0xa0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0xb0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+/* 0xc0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+/* 0xd0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+/* 0xe0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+/* 0xf0 */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1
+};
+
+static void SetError (JSOBJ obj, JSONObjectEncoder *enc, const char *message)
+{
+ enc->errorMsg = message;
+ enc->errorObj = obj;
+}
+
+/*
+FIXME: Keep track of how big these get across several encoder calls and try to make an estimate
+That way we won't run our head into the wall each call */
+void Buffer_Realloc (JSONObjectEncoder *enc, size_t cbNeeded)
+{
+ size_t curSize = enc->end - enc->start;
+ size_t newSize = curSize * 2;
+ size_t offset = enc->offset - enc->start;
+
+ while (newSize < curSize + cbNeeded)
+ {
+ newSize *= 2;
+ }
+
+ if (enc->heap)
+ {
+ enc->start = (char *) enc->realloc (enc->start, newSize);
+ if (!enc->start)
+ {
+ SetError (NULL, enc, "Could not reserve memory block");
+ return;
+ }
+ }
+ else
+ {
+ char *oldStart = enc->start;
+ enc->heap = 1;
+ enc->start = (char *) enc->malloc (newSize);
+ if (!enc->start)
+ {
+ SetError (NULL, enc, "Could not reserve memory block");
+ return;
+ }
+ memcpy (enc->start, oldStart, offset);
+ }
+ enc->offset = enc->start + offset;
+ enc->end = enc->start + newSize;
+}
+
+FASTCALL_ATTR INLINE_PREFIX void FASTCALL_MSVC Buffer_AppendShortHexUnchecked (char *outputOffset, unsigned short value)
+{
+ *(outputOffset++) = g_hexChars[(value & 0xf000) >> 12];
+ *(outputOffset++) = g_hexChars[(value & 0x0f00) >> 8];
+ *(outputOffset++) = g_hexChars[(value & 0x00f0) >> 4];
+ *(outputOffset++) = g_hexChars[(value & 0x000f) >> 0];
+}
+
+int Buffer_EscapeStringUnvalidated (JSONObjectEncoder *enc, const char *io, const char *end)
+{
+ char *of = (char *) enc->offset;
+
+ for (;;)
+ {
+ switch (*io)
+ {
+ case 0x00:
+ {
+ if (io < end)
+ {
+ *(of++) = '\\';
+ *(of++) = 'u';
+ *(of++) = '0';
+ *(of++) = '0';
+ *(of++) = '0';
+ *(of++) = '0';
+ break;
+ }
+ else
+ {
+ enc->offset += (of - enc->offset);
+ return TRUE;
+ }
+ }
+ case '\"': (*of++) = '\\'; (*of++) = '\"'; break;
+ case '\\': (*of++) = '\\'; (*of++) = '\\'; break;
+ case '\b': (*of++) = '\\'; (*of++) = 'b'; break;
+ case '\f': (*of++) = '\\'; (*of++) = 'f'; break;
+ case '\n': (*of++) = '\\'; (*of++) = 'n'; break;
+ case '\r': (*of++) = '\\'; (*of++) = 'r'; break;
+ case '\t': (*of++) = '\\'; (*of++) = 't'; break;
+
+ case '/':
+ {
+ if (enc->escapeForwardSlashes)
+ {
+ (*of++) = '\\';
+ (*of++) = '/';
+ }
+ else
+ {
+ // Same as default case below.
+ (*of++) = (*io);
+ }
+ break;
+ }
+ case 0x26: // '&'
+ case 0x3c: // '<'
+ case 0x3e: // '>'
+ {
+ if (enc->encodeHTMLChars)
+ {
+ // Fall through to \u00XX case below.
+ }
+ else
+ {
+ // Same as default case below.
+ (*of++) = (*io);
+ break;
+ }
+ }
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x0b:
+ case 0x0e:
+ case 0x0f:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ {
+ *(of++) = '\\';
+ *(of++) = 'u';
+ *(of++) = '0';
+ *(of++) = '0';
+ *(of++) = g_hexChars[ (unsigned char) (((*io) & 0xf0) >> 4)];
+ *(of++) = g_hexChars[ (unsigned char) ((*io) & 0x0f)];
+ break;
+ }
+ default: (*of++) = (*io); break;
+ }
+ io++;
+ }
+}
+
+int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, const char *io, const char *end)
+{
+ JSUTF32 ucs;
+ char *of = (char *) enc->offset;
+
+ for (;;)
+ {
+ JSUINT8 utflen = g_asciiOutputTable[(unsigned char) *io];
+
+ switch (utflen)
+ {
+ case 0:
+ {
+ if (io < end)
+ {
+ *(of++) = '\\';
+ *(of++) = 'u';
+ *(of++) = '0';
+ *(of++) = '0';
+ *(of++) = '0';
+ *(of++) = '0';
+ io ++;
+ continue;
+ }
+ else
+ {
+ enc->offset += (of - enc->offset);
+ return TRUE;
+ }
+ }
+
+ case 1:
+ {
+ *(of++)= (*io++);
+ continue;
+ }
+
+ case 2:
+ {
+ JSUTF32 in;
+ JSUTF16 in16;
+
+ if (end - io < 1)
+ {
+ enc->offset += (of - enc->offset);
+ SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
+ return FALSE;
+ }
+
+ memcpy(&in16, io, sizeof(JSUTF16));
+ in = (JSUTF32) in16;
+
+#ifdef __LITTLE_ENDIAN__
+ ucs = ((in & 0x1f) << 6) | ((in >> 8) & 0x3f);
+#else
+ ucs = ((in & 0x1f00) >> 2) | (in & 0x3f);
+#endif
+
+ if (ucs < 0x80)
+ {
+ enc->offset += (of - enc->offset);
+ SetError (obj, enc, "Overlong 2 byte UTF-8 sequence detected when encoding string");
+ return FALSE;
+ }
+
+ io += 2;
+ break;
+ }
+
+ case 3:
+ {
+ JSUTF32 in;
+ JSUTF16 in16;
+ JSUINT8 in8;
+
+ if (end - io < 2)
+ {
+ enc->offset += (of - enc->offset);
+ SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
+ return FALSE;
+ }
+
+ memcpy(&in16, io, sizeof(JSUTF16));
+ memcpy(&in8, io + 2, sizeof(JSUINT8));
+#ifdef __LITTLE_ENDIAN__
+ in = (JSUTF32) in16;
+ in |= in8 << 16;
+ ucs = ((in & 0x0f) << 12) | ((in & 0x3f00) >> 2) | ((in & 0x3f0000) >> 16);
+#else
+ in = in16 << 8;
+ in |= in8;
+ ucs = ((in & 0x0f0000) >> 4) | ((in & 0x3f00) >> 2) | (in & 0x3f);
+#endif
+
+ if (ucs < 0x800)
+ {
+ enc->offset += (of - enc->offset);
+ SetError (obj, enc, "Overlong 3 byte UTF-8 sequence detected when encoding string");
+ return FALSE;
+ }
+
+ io += 3;
+ break;
+ }
+ case 4:
+ {
+ JSUTF32 in;
+
+ if (end - io < 3)
+ {
+ enc->offset += (of - enc->offset);
+ SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
+ return FALSE;
+ }
+
+ memcpy(&in, io, sizeof(JSUTF32));
+#ifdef __LITTLE_ENDIAN__
+ ucs = ((in & 0x07) << 18) | ((in & 0x3f00) << 4) | ((in & 0x3f0000) >> 10) | ((in & 0x3f000000) >> 24);
+#else
+ ucs = ((in & 0x07000000) >> 6) | ((in & 0x3f0000) >> 4) | ((in & 0x3f00) >> 2) | (in & 0x3f);
+#endif
+ if (ucs < 0x10000)
+ {
+ enc->offset += (of - enc->offset);
+ SetError (obj, enc, "Overlong 4 byte UTF-8 sequence detected when encoding string");
+ return FALSE;
+ }
+
+ io += 4;
+ break;
+ }
+
+
+ case 5:
+ case 6:
+ {
+ enc->offset += (of - enc->offset);
+ SetError (obj, enc, "Unsupported UTF-8 sequence length when encoding string");
+ return FALSE;
+ }
+
+ case 29:
+ {
+ if (enc->encodeHTMLChars)
+ {
+ // Fall through to \u00XX case 30 below.
+ }
+ else
+ {
+ // Same as case 1 above.
+ *(of++) = (*io++);
+ continue;
+ }
+ }
+
+ case 30:
+ {
+ // \uXXXX encode
+ *(of++) = '\\';
+ *(of++) = 'u';
+ *(of++) = '0';
+ *(of++) = '0';
+ *(of++) = g_hexChars[ (unsigned char) (((*io) & 0xf0) >> 4)];
+ *(of++) = g_hexChars[ (unsigned char) ((*io) & 0x0f)];
+ io ++;
+ continue;
+ }
+ case 10:
+ case 12:
+ case 14:
+ case 16:
+ case 18:
+ case 20:
+ case 22:
+ {
+ *(of++) = *( (char *) (g_escapeChars + utflen + 0));
+ *(of++) = *( (char *) (g_escapeChars + utflen + 1));
+ io ++;
+ continue;
+ }
+ case 24:
+ {
+ if (enc->escapeForwardSlashes)
+ {
+ *(of++) = *( (char *) (g_escapeChars + utflen + 0));
+ *(of++) = *( (char *) (g_escapeChars + utflen + 1));
+ io ++;
+ }
+ else
+ {
+ // Same as case 1 above.
+ *(of++) = (*io++);
+ }
+ continue;
+ }
+ // This can never happen, it's here to make L4 VC++ happy
+ default:
+ {
+ ucs = 0;
+ break;
+ }
+ }
+
+ /*
+ If the character is a UTF8 sequence of length > 1 we end up here */
+ if (ucs >= 0x10000)
+ {
+ ucs -= 0x10000;
+ *(of++) = '\\';
+ *(of++) = 'u';
+ Buffer_AppendShortHexUnchecked(of, (unsigned short) (ucs >> 10) + 0xd800);
+ of += 4;
+
+ *(of++) = '\\';
+ *(of++) = 'u';
+ Buffer_AppendShortHexUnchecked(of, (unsigned short) (ucs & 0x3ff) + 0xdc00);
+ of += 4;
+ }
+ else
+ {
+ *(of++) = '\\';
+ *(of++) = 'u';
+ Buffer_AppendShortHexUnchecked(of, (unsigned short) ucs);
+ of += 4;
+ }
+ }
+}
+
+#define Buffer_Reserve(__enc, __len) \
+ if ( (size_t) ((__enc)->end - (__enc)->offset) < (size_t) (__len)) \
+ { \
+ Buffer_Realloc((__enc), (__len));\
+ } \
+
+
+#define Buffer_AppendCharUnchecked(__enc, __chr) \
+ *((__enc)->offset++) = __chr; \
+
+FASTCALL_ATTR INLINE_PREFIX void FASTCALL_MSVC strreverse(char* begin, char* end)
+{
+ char aux;
+ while (end > begin)
+ aux = *end, *end-- = *begin, *begin++ = aux;
+}
+
+void Buffer_AppendIndentNewlineUnchecked(JSONObjectEncoder *enc)
+{
+ if (enc->indent > 0) Buffer_AppendCharUnchecked(enc, '\n');
+}
+
+void Buffer_AppendIndentUnchecked(JSONObjectEncoder *enc, JSINT32 value)
+{
+ int i;
+ if (enc->indent > 0)
+ while (value-- > 0)
+ for (i = 0; i < enc->indent; i++)
+ Buffer_AppendCharUnchecked(enc, ' ');
+}
+
+void Buffer_AppendIntUnchecked(JSONObjectEncoder *enc, JSINT32 value)
+{
+ char* wstr;
+ JSUINT32 uvalue = (value < 0) ? -value : value;
+
+ wstr = enc->offset;
+ // Conversion. Number is reversed.
+
+ do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
+ if (value < 0) *wstr++ = '-';
+
+ // Reverse string
+ strreverse(enc->offset,wstr - 1);
+ enc->offset += (wstr - (enc->offset));
+}
+
+void Buffer_AppendLongUnchecked(JSONObjectEncoder *enc, JSINT64 value)
+{
+ char* wstr;
+ JSUINT64 uvalue = (value < 0) ? -value : value;
+
+ wstr = enc->offset;
+ // Conversion. Number is reversed.
+
+ do *wstr++ = (char)(48 + (uvalue % 10ULL)); while(uvalue /= 10ULL);
+ if (value < 0) *wstr++ = '-';
+
+ // Reverse string
+ strreverse(enc->offset,wstr - 1);
+ enc->offset += (wstr - (enc->offset));
+}
+
+void Buffer_AppendUnsignedLongUnchecked(JSONObjectEncoder *enc, JSUINT64 value)
+{
+ char* wstr;
+ JSUINT64 uvalue = value;
+
+ wstr = enc->offset;
+ // Conversion. Number is reversed.
+
+ do *wstr++ = (char)(48 + (uvalue % 10ULL)); while(uvalue /= 10ULL);
+
+ // Reverse string
+ strreverse(enc->offset,wstr - 1);
+ enc->offset += (wstr - (enc->offset));
+}
+
+int Buffer_AppendDoubleUnchecked(JSOBJ obj, JSONObjectEncoder *enc, double value)
+{
+ /* if input is larger than thres_max, revert to exponential */
+ const double thres_max = (double) 1e16 - 1;
+ int count;
+ double diff = 0.0;
+ char* str = enc->offset;
+ char* wstr = str;
+ unsigned long long whole;
+ double tmp;
+ unsigned long long frac;
+ int neg;
+ double pow10;
+
+ if (value == HUGE_VAL || value == -HUGE_VAL)
+ {
+ SetError (obj, enc, "Invalid Inf value when encoding double");
+ return FALSE;
+ }
+
+ if (!(value == value))
+ {
+ SetError (obj, enc, "Invalid Nan value when encoding double");
+ return FALSE;
+ }
+
+ /* we'll work in positive values and deal with the
+ negative sign issue later */
+ neg = 0;
+ if (value < 0)
+ {
+ neg = 1;
+ value = -value;
+ }
+
+ pow10 = g_pow10[enc->doublePrecision];
+
+ whole = (unsigned long long) value;
+ tmp = (value - whole) * pow10;
+ frac = (unsigned long long)(tmp);
+ diff = tmp - frac;
+
+ if (diff > 0.5)
+ {
+ ++frac;
+ /* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
+ if (frac >= pow10)
+ {
+ frac = 0;
+ ++whole;
+ }
+ }
+ else
+ if (diff == 0.5 && ((frac == 0) || (frac & 1)))
+ {
+ /* if halfway, round up if odd, OR
+ if last digit is 0. That last part is strange */
+ ++frac;
+ }
+
+ /* for very large numbers switch back to native sprintf for exponentials.
+ anyone want to write code to replace this? */
+ /*
+ normal printf behavior is to print EVERY whole number digit
+ which can be 100s of characters overflowing your buffers == bad
+ */
+ if (value > thres_max)
+ {
+ enc->offset += snprintf(str, enc->end - enc->offset, "%.15e", neg ? -value : value);
+ return TRUE;
+ }
+
+ if (enc->doublePrecision == 0)
+ {
+ diff = value - whole;
+
+ if (diff > 0.5)
+ {
+ /* greater than 0.5, round up, e.g. 1.6 -> 2 */
+ ++whole;
+ }
+ else
+ if (diff == 0.5 && (whole & 1))
+ {
+ /* exactly 0.5 and ODD, then round up */
+ /* 1.5 -> 2, but 2.5 -> 2 */
+ ++whole;
+ }
+
+ //vvvvvvvvvvvvvvvvvvv Diff from modp_dto2
+ }
+ else
+ if (frac)
+ {
+ count = enc->doublePrecision;
+ // now do fractional part, as an unsigned number
+ // we know it is not 0 but we can have leading zeros, these
+ // should be removed
+ while (!(frac % 10))
+ {
+ --count;
+ frac /= 10;
+ }
+ //^^^^^^^^^^^^^^^^^^^ Diff from modp_dto2
+
+ // now do fractional part, as an unsigned number
+ do
+ {
+ --count;
+ *wstr++ = (char)(48 + (frac % 10));
+ } while (frac /= 10);
+ // add extra 0s
+ while (count-- > 0)
+ {
+ *wstr++ = '0';
+ }
+ // add decimal
+ *wstr++ = '.';
+ }
+ else
+ {
+ *wstr++ = '0';
+ *wstr++ = '.';
+ }
+
+ // do whole part
+ // Take care of sign
+ // Conversion. Number is reversed.
+ do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10);
+
+ if (neg)
+ {
+ *wstr++ = '-';
+ }
+ strreverse(str, wstr-1);
+ enc->offset += (wstr - (enc->offset));
+
+ return TRUE;
+}
+
+/*
+FIXME:
+Handle integration functions returning NULL here */
+
+/*
+FIXME:
+Perhaps implement recursion detection */
+
+void encode(JSOBJ obj, JSONObjectEncoder *enc, const char *name, size_t cbName)
+{
+ const char *value;
+ char *objName;
+ int count;
+ JSOBJ iterObj;
+ size_t szlen;
+ JSONTypeContext tc;
+
+ if (enc->level > enc->recursionMax)
+ {
+ SetError (obj, enc, "Maximum recursion level reached");
+ return;
+ }
+
+ /*
+ This reservation must hold
+
+ length of _name as encoded worst case +
+ maxLength of double to string OR maxLength of JSLONG to string
+ */
+
+ Buffer_Reserve(enc, 256 + RESERVE_STRING(cbName));
+ if (enc->errorMsg)
+ {
+ return;
+ }
+
+ if (name)
+ {
+ Buffer_AppendCharUnchecked(enc, '\"');
+
+ if (enc->forceASCII)
+ {
+ if (!Buffer_EscapeStringValidated(obj, enc, name, name + cbName))
+ {
+ return;
+ }
+ }
+ else
+ {
+ if (!Buffer_EscapeStringUnvalidated(enc, name, name + cbName))
+ {
+ return;
+ }
+ }
+
+ Buffer_AppendCharUnchecked(enc, '\"');
+
+ Buffer_AppendCharUnchecked (enc, ':');
+#ifdef JSON_NO_EXTRA_WHITESPACE
+ if (enc->indent)
+ {
+ Buffer_AppendCharUnchecked (enc, ' ');
+ }
+#else
+ Buffer_AppendCharUnchecked (enc, ' ');
+#endif
+ }
+
+ tc.encoder_prv = enc->prv;
+ enc->beginTypeContext(obj, &tc, enc);
+
+ switch (tc.type)
+ {
+ case JT_INVALID:
+ {
+ return;
+ }
+
+ case JT_ARRAY:
+ {
+ count = 0;
+
+ Buffer_AppendCharUnchecked (enc, '[');
+ Buffer_AppendIndentNewlineUnchecked (enc);
+
+ while (enc->iterNext(obj, &tc))
+ {
+ if (count > 0)
+ {
+ Buffer_AppendCharUnchecked (enc, ',');
+#ifndef JSON_NO_EXTRA_WHITESPACE
+ Buffer_AppendCharUnchecked (buffer, ' ');
+#endif
+ Buffer_AppendIndentNewlineUnchecked (enc);
+ }
+
+ iterObj = enc->iterGetValue(obj, &tc);
+
+ enc->level ++;
+ Buffer_AppendIndentUnchecked (enc, enc->level);
+ encode (iterObj, enc, NULL, 0);
+ count ++;
+ }
+
+ enc->iterEnd(obj, &tc);
+ Buffer_AppendIndentNewlineUnchecked (enc);
+ Buffer_AppendIndentUnchecked (enc, enc->level);
+ Buffer_AppendCharUnchecked (enc, ']');
+ break;
+ }
+
+ case JT_OBJECT:
+ {
+ count = 0;
+
+ Buffer_AppendCharUnchecked (enc, '{');
+ Buffer_AppendIndentNewlineUnchecked (enc);
+
+ while (enc->iterNext(obj, &tc))
+ {
+ if (count > 0)
+ {
+ Buffer_AppendCharUnchecked (enc, ',');
+#ifndef JSON_NO_EXTRA_WHITESPACE
+ Buffer_AppendCharUnchecked (enc, ' ');
+#endif
+ Buffer_AppendIndentNewlineUnchecked (enc);
+ }
+
+ iterObj = enc->iterGetValue(obj, &tc);
+ objName = enc->iterGetName(obj, &tc, &szlen);
+
+ enc->level ++;
+ Buffer_AppendIndentUnchecked (enc, enc->level);
+ encode (iterObj, enc, objName, szlen);
+ count ++;
+ }
+
+ enc->iterEnd(obj, &tc);
+ Buffer_AppendIndentNewlineUnchecked (enc);
+ Buffer_AppendIndentUnchecked (enc, enc->level);
+ Buffer_AppendCharUnchecked (enc, '}');
+ break;
+ }
+
+ case JT_LONG:
+ {
+ Buffer_AppendLongUnchecked (enc, enc->getLongValue(obj, &tc));
+ break;
+ }
+
+ case JT_ULONG:
+ {
+ Buffer_AppendUnsignedLongUnchecked (enc, enc->getUnsignedLongValue(obj, &tc));
+ break;
+ }
+
+ case JT_INT:
+ {
+ Buffer_AppendIntUnchecked (enc, enc->getIntValue(obj, &tc));
+ break;
+ }
+
+ case JT_TRUE:
+ {
+ Buffer_AppendCharUnchecked (enc, 't');
+ Buffer_AppendCharUnchecked (enc, 'r');
+ Buffer_AppendCharUnchecked (enc, 'u');
+ Buffer_AppendCharUnchecked (enc, 'e');
+ break;
+ }
+
+ case JT_FALSE:
+ {
+ Buffer_AppendCharUnchecked (enc, 'f');
+ Buffer_AppendCharUnchecked (enc, 'a');
+ Buffer_AppendCharUnchecked (enc, 'l');
+ Buffer_AppendCharUnchecked (enc, 's');
+ Buffer_AppendCharUnchecked (enc, 'e');
+ break;
+ }
+
+
+ case JT_NULL:
+ {
+ Buffer_AppendCharUnchecked (enc, 'n');
+ Buffer_AppendCharUnchecked (enc, 'u');
+ Buffer_AppendCharUnchecked (enc, 'l');
+ Buffer_AppendCharUnchecked (enc, 'l');
+ break;
+ }
+
+ case JT_DOUBLE:
+ {
+ if (!Buffer_AppendDoubleUnchecked (obj, enc, enc->getDoubleValue(obj, &tc)))
+ {
+ enc->endTypeContext(obj, &tc);
+ enc->level --;
+ return;
+ }
+ break;
+ }
+
+ case JT_UTF8:
+ {
+ value = enc->getStringValue(obj, &tc, &szlen);
+ if(!value)
+ {
+ SetError(obj, enc, "utf-8 encoding error");
+ return;
+ }
+
+ Buffer_Reserve(enc, RESERVE_STRING(szlen));
+ if (enc->errorMsg)
+ {
+ enc->endTypeContext(obj, &tc);
+ return;
+ }
+ Buffer_AppendCharUnchecked (enc, '\"');
+
+ if (enc->forceASCII)
+ {
+ if (!Buffer_EscapeStringValidated(obj, enc, value, value + szlen))
+ {
+ enc->endTypeContext(obj, &tc);
+ enc->level --;
+ return;
+ }
+ }
+ else
+ {
+ if (!Buffer_EscapeStringUnvalidated(enc, value, value + szlen))
+ {
+ enc->endTypeContext(obj, &tc);
+ enc->level --;
+ return;
+ }
+ }
+
+ Buffer_AppendCharUnchecked (enc, '\"');
+ break;
+ }
+
+ case JT_RAW:
+ {
+ value = enc->getStringValue(obj, &tc, &szlen);
+ if(!value)
+ {
+ SetError(obj, enc, "utf-8 encoding error");
+ return;
+ }
+
+ Buffer_Reserve(enc, RESERVE_STRING(szlen));
+ if (enc->errorMsg)
+ {
+ enc->endTypeContext(obj, &tc);
+ return;
+ }
+
+ memcpy(enc->offset, value, szlen);
+ enc->offset += szlen;
+
+ break;
+ }
+ }
+
+ enc->endTypeContext(obj, &tc);
+ enc->level --;
+}
+
+char *JSON_EncodeObject(JSOBJ obj, JSONObjectEncoder *enc, char *_buffer, size_t _cbBuffer)
+{
+ enc->malloc = enc->malloc ? enc->malloc : malloc;
+ enc->free = enc->free ? enc->free : free;
+ enc->realloc = enc->realloc ? enc->realloc : realloc;
+ enc->errorMsg = NULL;
+ enc->errorObj = NULL;
+ enc->level = 0;
+
+ if (enc->recursionMax < 1)
+ {
+ enc->recursionMax = JSON_MAX_RECURSION_DEPTH;
+ }
+
+ if (enc->doublePrecision < 0 ||
+ enc->doublePrecision > JSON_DOUBLE_MAX_DECIMALS)
+ {
+ enc->doublePrecision = JSON_DOUBLE_MAX_DECIMALS;
+ }
+
+ if (_buffer == NULL)
+ {
+ _cbBuffer = 32768;
+ enc->start = (char *) enc->malloc (_cbBuffer);
+ if (!enc->start)
+ {
+ SetError(obj, enc, "Could not reserve memory block");
+ return NULL;
+ }
+ enc->heap = 1;
+ }
+ else
+ {
+ enc->start = _buffer;
+ enc->heap = 0;
+ }
+
+ enc->end = enc->start + _cbBuffer;
+ enc->offset = enc->start;
+
+ encode (obj, enc, NULL, 0);
+
+ Buffer_Reserve(enc, 1);
+ if (enc->errorMsg)
+ {
+ return NULL;
+ }
+ Buffer_AppendCharUnchecked(enc, '\0');
+
+ return enc->start;
+}
diff --git a/contrib/python/ujson/py3/python/JSONtoObj.c b/contrib/python/ujson/py3/python/JSONtoObj.c
new file mode 100644
index 0000000000..79d9f1af6e
--- /dev/null
+++ b/contrib/python/ujson/py3/python/JSONtoObj.c
@@ -0,0 +1,252 @@
+/*
+Developed by ESN, an Electronic Arts Inc. studio.
+Copyright (c) 2014, Electronic Arts Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of ESN, Electronic Arts Inc. nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS INC. BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Portions of code from MODP_ASCII - Ascii transformations (upper/lower, etc)
+http://code.google.com/p/stringencoders/
+Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
+
+Numeric decoder derived from from TCL library
+http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+*/
+
+#include "py_defines.h"
+#include <ultrajson.h>
+
+
+//#define PRINTMARK() fprintf(stderr, "%s: MARK(%d)\n", __FILE__, __LINE__)
+#define PRINTMARK()
+
+void Object_objectAddKey(void *prv, JSOBJ obj, JSOBJ name, JSOBJ value)
+{
+ PyDict_SetItem (obj, name, value);
+ Py_DECREF( (PyObject *) name);
+ Py_DECREF( (PyObject *) value);
+ return;
+}
+
+void Object_arrayAddItem(void *prv, JSOBJ obj, JSOBJ value)
+{
+ PyList_Append(obj, value);
+ Py_DECREF( (PyObject *) value);
+ return;
+}
+
+JSOBJ Object_newString(void *prv, wchar_t *start, wchar_t *end)
+{
+ return PyUnicode_FromWideChar (start, (end - start));
+}
+
+JSOBJ Object_newTrue(void *prv)
+{
+ Py_RETURN_TRUE;
+}
+
+JSOBJ Object_newFalse(void *prv)
+{
+ Py_RETURN_FALSE;
+}
+
+JSOBJ Object_newNull(void *prv)
+{
+ Py_RETURN_NONE;
+}
+
+JSOBJ Object_newObject(void *prv)
+{
+ return PyDict_New();
+}
+
+JSOBJ Object_newArray(void *prv)
+{
+ return PyList_New(0);
+}
+
+JSOBJ Object_newInteger(void *prv, JSINT32 value)
+{
+ return PyInt_FromLong( (long) value);
+}
+
+JSOBJ Object_newLong(void *prv, JSINT64 value)
+{
+ return PyLong_FromLongLong (value);
+}
+
+JSOBJ Object_newUnsignedLong(void *prv, JSUINT64 value)
+{
+ return PyLong_FromUnsignedLongLong (value);
+}
+
+JSOBJ Object_newDouble(void *prv, double value)
+{
+ return PyFloat_FromDouble(value);
+}
+
+static void Object_releaseObject(void *prv, JSOBJ obj)
+{
+ Py_DECREF( ((PyObject *)obj));
+}
+
+static char *g_kwlist[] = {"obj", "precise_float", NULL};
+
+PyObject* JSONToObj(PyObject* self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *ret;
+ PyObject *sarg;
+ PyObject *arg;
+ PyObject *opreciseFloat = NULL;
+ JSONObjectDecoder decoder =
+ {
+ Object_newString,
+ Object_objectAddKey,
+ Object_arrayAddItem,
+ Object_newTrue,
+ Object_newFalse,
+ Object_newNull,
+ Object_newObject,
+ Object_newArray,
+ Object_newInteger,
+ Object_newLong,
+ Object_newUnsignedLong,
+ Object_newDouble,
+ Object_releaseObject,
+ PyObject_Malloc,
+ PyObject_Free,
+ PyObject_Realloc
+ };
+
+ decoder.preciseFloat = 0;
+ decoder.prv = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", g_kwlist, &arg, &opreciseFloat))
+ {
+ return NULL;
+ }
+
+ if (opreciseFloat && PyObject_IsTrue(opreciseFloat))
+ {
+ decoder.preciseFloat = 1;
+ }
+
+ if (PyString_Check(arg))
+ {
+ sarg = arg;
+ }
+ else
+ if (PyUnicode_Check(arg))
+ {
+ sarg = PyUnicode_AsUTF8String(arg);
+ if (sarg == NULL)
+ {
+ //Exception raised above us by codec according to docs
+ return NULL;
+ }
+ }
+ else
+ {
+ PyErr_Format(PyExc_TypeError, "Expected String or Unicode");
+ return NULL;
+ }
+
+ decoder.errorStr = NULL;
+ decoder.errorOffset = NULL;
+
+ ret = JSON_DecodeObject(&decoder, PyString_AS_STRING(sarg), PyString_GET_SIZE(sarg));
+
+ if (sarg != arg)
+ {
+ Py_DECREF(sarg);
+ }
+
+ if (decoder.errorStr)
+ {
+ /*
+ FIXME: It's possible to give a much nicer error message here with actual failing element in input etc*/
+
+ PyErr_Format (PyExc_ValueError, "%s", decoder.errorStr);
+
+ if (ret)
+ {
+ Py_DECREF( (PyObject *) ret);
+ }
+
+ return NULL;
+ }
+
+ return ret;
+}
+
+PyObject* JSONFileToObj(PyObject* self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *read;
+ PyObject *string;
+ PyObject *result;
+ PyObject *file = NULL;
+ PyObject *argtuple;
+
+ if (!PyArg_ParseTuple (args, "O", &file))
+ {
+ return NULL;
+ }
+
+ if (!PyObject_HasAttrString (file, "read"))
+ {
+ PyErr_Format (PyExc_TypeError, "expected file");
+ return NULL;
+ }
+
+ read = PyObject_GetAttrString (file, "read");
+
+ if (!PyCallable_Check (read)) {
+ Py_XDECREF(read);
+ PyErr_Format (PyExc_TypeError, "expected file");
+ return NULL;
+ }
+
+ string = PyObject_CallObject (read, NULL);
+ Py_XDECREF(read);
+
+ if (string == NULL)
+ {
+ return NULL;
+ }
+
+ argtuple = PyTuple_Pack(1, string);
+
+ result = JSONToObj (self, argtuple, kwargs);
+
+ Py_XDECREF(argtuple);
+ Py_XDECREF(string);
+
+ if (result == NULL) {
+ return NULL;
+ }
+
+ return result;
+}
diff --git a/contrib/python/ujson/py3/python/objToJSON.c b/contrib/python/ujson/py3/python/objToJSON.c
new file mode 100644
index 0000000000..b3a821e7ae
--- /dev/null
+++ b/contrib/python/ujson/py3/python/objToJSON.c
@@ -0,0 +1,1168 @@
+/*
+Developed by ESN, an Electronic Arts Inc. studio.
+Copyright (c) 2014, Electronic Arts Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of ESN, Electronic Arts Inc. nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS INC. BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Portions of code from MODP_ASCII - Ascii transformations (upper/lower, etc)
+http://code.google.com/p/stringencoders/
+Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
+
+Numeric decoder derived from from TCL library
+http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
+* Copyright (c) 1988-1993 The Regents of the University of California.
+* Copyright (c) 1994 Sun Microsystems, Inc.
+*/
+
+#include "py_defines.h"
+#include <stdio.h>
+#include <datetime.h>
+#include <ultrajson.h>
+
+#define EPOCH_ORD 719163
+static PyObject* type_decimal = NULL;
+
+typedef void *(*PFN_PyTypeToJSON)(JSOBJ obj, JSONTypeContext *ti, void *outValue, size_t *_outLen);
+
+#if (PY_VERSION_HEX < 0x02050000)
+typedef ssize_t Py_ssize_t;
+#endif
+
+typedef struct __TypeContext
+{
+ JSPFN_ITEREND iterEnd;
+ JSPFN_ITERNEXT iterNext;
+ JSPFN_ITERGETNAME iterGetName;
+ JSPFN_ITERGETVALUE iterGetValue;
+ PFN_PyTypeToJSON PyTypeToJSON;
+ PyObject *newObj;
+ PyObject *dictObj;
+ Py_ssize_t index;
+ Py_ssize_t size;
+ PyObject *itemValue;
+ PyObject *itemName;
+ PyObject *attrList;
+ PyObject *iterator;
+
+ union
+ {
+ PyObject *rawJSONValue;
+ JSINT64 longValue;
+ JSUINT64 unsignedLongValue;
+ };
+} TypeContext;
+
+#define GET_TC(__ptrtc) ((TypeContext *)((__ptrtc)->prv))
+
+struct PyDictIterState
+{
+ PyObject *keys;
+ size_t i;
+ size_t sz;
+};
+
+//#define PRINTMARK() fprintf(stderr, "%s: MARK(%d)\n", __FILE__, __LINE__)
+#define PRINTMARK()
+
+void initObjToJSON(void)
+{
+ PyObject* mod_decimal = PyImport_ImportModule("decimal");
+ if (mod_decimal)
+ {
+ type_decimal = PyObject_GetAttrString(mod_decimal, "Decimal");
+ Py_INCREF(type_decimal);
+ Py_DECREF(mod_decimal);
+ }
+ else
+ PyErr_Clear();
+
+ PyDateTime_IMPORT;
+}
+
+#ifdef _LP64
+static void *PyIntToINT64(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ PyObject *obj = (PyObject *) _obj;
+ *((JSINT64 *) outValue) = PyInt_AS_LONG (obj);
+ return NULL;
+}
+#else
+static void *PyIntToINT32(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ PyObject *obj = (PyObject *) _obj;
+ *((JSINT32 *) outValue) = PyInt_AS_LONG (obj);
+ return NULL;
+}
+#endif
+
+static void *PyLongToINT64(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ *((JSINT64 *) outValue) = GET_TC(tc)->longValue;
+ return NULL;
+}
+
+static void *PyLongToUINT64(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ *((JSUINT64 *) outValue) = GET_TC(tc)->unsignedLongValue;
+ return NULL;
+}
+
+static void *PyFloatToDOUBLE(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ PyObject *obj = (PyObject *) _obj;
+ *((double *) outValue) = PyFloat_AsDouble (obj);
+ return NULL;
+}
+
+static void *PyStringToUTF8(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ PyObject *obj = (PyObject *) _obj;
+ *_outLen = PyString_GET_SIZE(obj);
+ return PyString_AS_STRING(obj);
+}
+
+static void *PyUnicodeToUTF8(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ PyObject *obj = (PyObject *) _obj;
+ PyObject *newObj;
+#if (PY_VERSION_HEX >= 0x03030000)
+ if(PyUnicode_IS_COMPACT_ASCII(obj))
+ {
+ Py_ssize_t len;
+ char *data = PyUnicode_AsUTF8AndSize(obj, &len);
+ *_outLen = len;
+ return data;
+ }
+#endif
+ newObj = PyUnicode_AsUTF8String(obj);
+ if(!newObj)
+ {
+ return NULL;
+ }
+
+ GET_TC(tc)->newObj = newObj;
+
+ *_outLen = PyString_GET_SIZE(newObj);
+ return PyString_AS_STRING(newObj);
+}
+
+static void *PyRawJSONToUTF8(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ PyObject *obj = GET_TC(tc)->rawJSONValue;
+ if (PyUnicode_Check(obj)) {
+ return PyUnicodeToUTF8(obj, tc, outValue, _outLen);
+ }
+ else {
+ return PyStringToUTF8(obj, tc, outValue, _outLen);
+ }
+}
+
+static void *PyDateTimeToINT64(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ PyObject *obj = (PyObject *) _obj;
+ PyObject *date, *ord, *utcoffset;
+ int y, m, d, h, mn, s, days;
+
+ utcoffset = PyObject_CallMethod(obj, "utcoffset", NULL);
+ if(utcoffset != Py_None){
+ obj = PyNumber_Subtract(obj, utcoffset);
+ }
+
+ y = PyDateTime_GET_YEAR(obj);
+ m = PyDateTime_GET_MONTH(obj);
+ d = PyDateTime_GET_DAY(obj);
+ h = PyDateTime_DATE_GET_HOUR(obj);
+ mn = PyDateTime_DATE_GET_MINUTE(obj);
+ s = PyDateTime_DATE_GET_SECOND(obj);
+
+ date = PyDate_FromDate(y, m, 1);
+ ord = PyObject_CallMethod(date, "toordinal", NULL);
+ days = PyInt_AS_LONG(ord) - EPOCH_ORD + d - 1;
+ Py_DECREF(date);
+ Py_DECREF(ord);
+ *( (JSINT64 *) outValue) = (((JSINT64) ((days * 24 + h) * 60 + mn)) * 60 + s);
+ return NULL;
+}
+
+static void *PyDateToINT64(JSOBJ _obj, JSONTypeContext *tc, void *outValue, size_t *_outLen)
+{
+ PyObject *obj = (PyObject *) _obj;
+ PyObject *date, *ord;
+ int y, m, d, days;
+
+ y = PyDateTime_GET_YEAR(obj);
+ m = PyDateTime_GET_MONTH(obj);
+ d = PyDateTime_GET_DAY(obj);
+
+ date = PyDate_FromDate(y, m, 1);
+ ord = PyObject_CallMethod(date, "toordinal", NULL);
+ days = PyInt_AS_LONG(ord) - EPOCH_ORD + d - 1;
+ Py_DECREF(date);
+ Py_DECREF(ord);
+ *( (JSINT64 *) outValue) = ((JSINT64) days * 86400);
+
+ return NULL;
+}
+
+int Tuple_iterNext(JSOBJ obj, JSONTypeContext *tc)
+{
+ PyObject *item;
+
+ if (GET_TC(tc)->index >= GET_TC(tc)->size)
+ {
+ return 0;
+ }
+
+ item = PyTuple_GET_ITEM (obj, GET_TC(tc)->index);
+
+ GET_TC(tc)->itemValue = item;
+ GET_TC(tc)->index ++;
+ return 1;
+}
+
+void Tuple_iterEnd(JSOBJ obj, JSONTypeContext *tc)
+{
+}
+
+JSOBJ Tuple_iterGetValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ return GET_TC(tc)->itemValue;
+}
+
+char *Tuple_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
+{
+ return NULL;
+}
+
+int Iter_iterNext(JSOBJ obj, JSONTypeContext *tc)
+{
+ PyObject *item;
+
+ if (GET_TC(tc)->itemValue)
+ {
+ Py_DECREF(GET_TC(tc)->itemValue);
+ GET_TC(tc)->itemValue = NULL;
+ }
+
+ if (GET_TC(tc)->iterator == NULL)
+ {
+ return 0;
+ }
+
+ item = PyIter_Next(GET_TC(tc)->iterator);
+
+ if (item == NULL)
+ {
+ return 0;
+ }
+
+ GET_TC(tc)->itemValue = item;
+ return 1;
+}
+
+void Iter_iterEnd(JSOBJ obj, JSONTypeContext *tc)
+{
+ if (GET_TC(tc)->itemValue)
+ {
+ Py_DECREF(GET_TC(tc)->itemValue);
+ GET_TC(tc)->itemValue = NULL;
+ }
+
+ if (GET_TC(tc)->iterator)
+ {
+ Py_DECREF(GET_TC(tc)->iterator);
+ GET_TC(tc)->iterator = NULL;
+ }
+}
+
+JSOBJ Iter_iterGetValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ return GET_TC(tc)->itemValue;
+}
+
+char *Iter_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
+{
+ return NULL;
+}
+
+void Dir_iterEnd(JSOBJ obj, JSONTypeContext *tc)
+{
+ if (GET_TC(tc)->itemValue)
+ {
+ Py_DECREF(GET_TC(tc)->itemValue);
+ GET_TC(tc)->itemValue = NULL;
+ }
+
+ if (GET_TC(tc)->itemName)
+ {
+ Py_DECREF(GET_TC(tc)->itemName);
+ GET_TC(tc)->itemName = NULL;
+ }
+
+ Py_DECREF( (PyObject *) GET_TC(tc)->attrList);
+ PRINTMARK();
+}
+
+int Dir_iterNext(JSOBJ _obj, JSONTypeContext *tc)
+{
+ PyObject *obj = (PyObject *) _obj;
+ PyObject *itemValue = GET_TC(tc)->itemValue;
+ PyObject *itemName = GET_TC(tc)->itemName;
+ PyObject* attr;
+ PyObject* attrName;
+ char* attrStr;
+
+ if (itemValue)
+ {
+ Py_DECREF(GET_TC(tc)->itemValue);
+ GET_TC(tc)->itemValue = itemValue = NULL;
+ }
+
+ if (itemName)
+ {
+ Py_DECREF(GET_TC(tc)->itemName);
+ GET_TC(tc)->itemName = itemName = NULL;
+ }
+
+ for (; GET_TC(tc)->index < GET_TC(tc)->size; GET_TC(tc)->index ++)
+ {
+ attrName = PyList_GET_ITEM(GET_TC(tc)->attrList, GET_TC(tc)->index);
+#if PY_MAJOR_VERSION >= 3
+ attr = PyUnicode_AsUTF8String(attrName);
+#else
+ attr = attrName;
+ Py_INCREF(attr);
+#endif
+ attrStr = PyString_AS_STRING(attr);
+
+ if (attrStr[0] == '_')
+ {
+ PRINTMARK();
+ Py_DECREF(attr);
+ continue;
+ }
+
+ itemValue = PyObject_GetAttr(obj, attrName);
+ if (itemValue == NULL)
+ {
+ PyErr_Clear();
+ Py_DECREF(attr);
+ PRINTMARK();
+ continue;
+ }
+
+ if (PyCallable_Check(itemValue))
+ {
+ Py_DECREF(itemValue);
+ Py_DECREF(attr);
+ PRINTMARK();
+ continue;
+ }
+
+ PRINTMARK();
+ itemName = attr;
+ break;
+ }
+
+ if (itemName == NULL)
+ {
+ GET_TC(tc)->index = GET_TC(tc)->size;
+ GET_TC(tc)->itemValue = NULL;
+ return 0;
+ }
+
+ GET_TC(tc)->itemName = itemName;
+ GET_TC(tc)->itemValue = itemValue;
+ GET_TC(tc)->index ++;
+
+ PRINTMARK();
+ return 1;
+}
+
+JSOBJ Dir_iterGetValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ PRINTMARK();
+ return GET_TC(tc)->itemValue;
+}
+
+char *Dir_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
+{
+ PRINTMARK();
+ *outLen = PyString_GET_SIZE(GET_TC(tc)->itemName);
+ return PyString_AS_STRING(GET_TC(tc)->itemName);
+}
+
+int List_iterNext(JSOBJ obj, JSONTypeContext *tc)
+{
+ if (GET_TC(tc)->index >= GET_TC(tc)->size)
+ {
+ PRINTMARK();
+ return 0;
+ }
+
+ GET_TC(tc)->itemValue = PyList_GET_ITEM (obj, GET_TC(tc)->index);
+ GET_TC(tc)->index ++;
+ return 1;
+}
+
+void List_iterEnd(JSOBJ obj, JSONTypeContext *tc)
+{
+}
+
+JSOBJ List_iterGetValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ return GET_TC(tc)->itemValue;
+}
+
+char *List_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
+{
+ return NULL;
+}
+
+//=============================================================================
+// Dict iteration functions
+// itemName might converted to string (Python_Str). Do refCounting
+// itemValue is borrowed from object (which is dict). No refCounting
+//=============================================================================
+
+int Dict_iterNext(JSOBJ obj, JSONTypeContext *tc)
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject* itemNameTmp;
+#endif
+
+ if (GET_TC(tc)->itemName)
+ {
+ Py_DECREF(GET_TC(tc)->itemName);
+ GET_TC(tc)->itemName = NULL;
+ }
+
+
+ if (!PyDict_Next ( (PyObject *)GET_TC(tc)->dictObj, &GET_TC(tc)->index, &GET_TC(tc)->itemName, &GET_TC(tc)->itemValue))
+ {
+ PRINTMARK();
+ return 0;
+ }
+
+ if (PyUnicode_Check(GET_TC(tc)->itemName))
+ {
+ GET_TC(tc)->itemName = PyUnicode_AsUTF8String (GET_TC(tc)->itemName);
+ }
+ else
+ if (!PyString_Check(GET_TC(tc)->itemName))
+ {
+ GET_TC(tc)->itemName = PyObject_Str(GET_TC(tc)->itemName);
+#if PY_MAJOR_VERSION >= 3
+ itemNameTmp = GET_TC(tc)->itemName;
+ GET_TC(tc)->itemName = PyUnicode_AsUTF8String (GET_TC(tc)->itemName);
+ Py_DECREF(itemNameTmp);
+#endif
+ }
+ else
+ {
+ Py_INCREF(GET_TC(tc)->itemName);
+ }
+ PRINTMARK();
+ return 1;
+}
+
+void Dict_iterEnd(JSOBJ obj, JSONTypeContext *tc)
+{
+ if (GET_TC(tc)->itemName)
+ {
+ Py_DECREF(GET_TC(tc)->itemName);
+ GET_TC(tc)->itemName = NULL;
+ }
+ Py_DECREF(GET_TC(tc)->dictObj);
+ PRINTMARK();
+}
+
+JSOBJ Dict_iterGetValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ return GET_TC(tc)->itemValue;
+}
+
+char *Dict_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
+{
+ *outLen = PyString_GET_SIZE(GET_TC(tc)->itemName);
+ return PyString_AS_STRING(GET_TC(tc)->itemName);
+}
+
+int SortedDict_iterNext(JSOBJ obj, JSONTypeContext *tc)
+{
+ PyObject *items = NULL, *item = NULL, *key = NULL, *value = NULL;
+ Py_ssize_t i, nitems;
+#if PY_MAJOR_VERSION >= 3
+ PyObject* keyTmp;
+#endif
+
+ // Upon first call, obtain a list of the keys and sort them. This follows the same logic as the
+ // stanard library's _json.c sort_keys handler.
+ if (GET_TC(tc)->newObj == NULL)
+ {
+ // Obtain the list of keys from the dictionary.
+ items = PyMapping_Keys(GET_TC(tc)->dictObj);
+ if (items == NULL)
+ {
+ goto error;
+ }
+ else if (!PyList_Check(items))
+ {
+ PyErr_SetString(PyExc_ValueError, "keys must return list");
+ goto error;
+ }
+
+ // Sort the list.
+ if (PyList_Sort(items) < 0)
+ {
+ goto error;
+ }
+
+ // Obtain the value for each key, and pack a list of (key, value) 2-tuples.
+ nitems = PyList_GET_SIZE(items);
+ for (i = 0; i < nitems; i++)
+ {
+ key = PyList_GET_ITEM(items, i);
+ value = PyDict_GetItem(GET_TC(tc)->dictObj, key);
+
+ // Subject the key to the same type restrictions and conversions as in Dict_iterGetValue.
+ if (PyUnicode_Check(key))
+ {
+ key = PyUnicode_AsUTF8String(key);
+ }
+ else if (!PyString_Check(key))
+ {
+ key = PyObject_Str(key);
+#if PY_MAJOR_VERSION >= 3
+ keyTmp = key;
+ key = PyUnicode_AsUTF8String(key);
+ Py_DECREF(keyTmp);
+#endif
+ }
+ else
+ {
+ Py_INCREF(key);
+ }
+
+ item = PyTuple_Pack(2, key, value);
+ if (item == NULL)
+ {
+ goto error;
+ }
+ if (PyList_SetItem(items, i, item))
+ {
+ goto error;
+ }
+ Py_DECREF(key);
+ }
+
+ // Store the sorted list of tuples in the newObj slot.
+ GET_TC(tc)->newObj = items;
+ GET_TC(tc)->size = nitems;
+ }
+
+ if (GET_TC(tc)->index >= GET_TC(tc)->size)
+ {
+ PRINTMARK();
+ return 0;
+ }
+
+ item = PyList_GET_ITEM(GET_TC(tc)->newObj, GET_TC(tc)->index);
+ GET_TC(tc)->itemName = PyTuple_GET_ITEM(item, 0);
+ GET_TC(tc)->itemValue = PyTuple_GET_ITEM(item, 1);
+ GET_TC(tc)->index++;
+ return 1;
+
+error:
+ Py_XDECREF(item);
+ Py_XDECREF(key);
+ Py_XDECREF(value);
+ Py_XDECREF(items);
+ return -1;
+}
+
+void SortedDict_iterEnd(JSOBJ obj, JSONTypeContext *tc)
+{
+ GET_TC(tc)->itemName = NULL;
+ GET_TC(tc)->itemValue = NULL;
+ Py_DECREF(GET_TC(tc)->dictObj);
+ PRINTMARK();
+}
+
+JSOBJ SortedDict_iterGetValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ return GET_TC(tc)->itemValue;
+}
+
+char *SortedDict_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
+{
+ *outLen = PyString_GET_SIZE(GET_TC(tc)->itemName);
+ return PyString_AS_STRING(GET_TC(tc)->itemName);
+}
+
+
+void SetupDictIter(PyObject *dictObj, TypeContext *pc, JSONObjectEncoder *enc)
+{
+ if (enc->sortKeys) {
+ pc->iterEnd = SortedDict_iterEnd;
+ pc->iterNext = SortedDict_iterNext;
+ pc->iterGetValue = SortedDict_iterGetValue;
+ pc->iterGetName = SortedDict_iterGetName;
+ }
+ else {
+ pc->iterEnd = Dict_iterEnd;
+ pc->iterNext = Dict_iterNext;
+ pc->iterGetValue = Dict_iterGetValue;
+ pc->iterGetName = Dict_iterGetName;
+ }
+ pc->dictObj = dictObj;
+ pc->index = 0;
+}
+
+void Object_beginTypeContext (JSOBJ _obj, JSONTypeContext *tc, JSONObjectEncoder *enc)
+{
+ PyObject *obj, *exc, *iter;
+ TypeContext *pc;
+ PRINTMARK();
+ if (!_obj) {
+ tc->type = JT_INVALID;
+ return;
+ }
+
+ obj = (PyObject*) _obj;
+
+ tc->prv = PyObject_Malloc(sizeof(TypeContext));
+ pc = (TypeContext *) tc->prv;
+ if (!pc)
+ {
+ tc->type = JT_INVALID;
+ PyErr_NoMemory();
+ return;
+ }
+ pc->newObj = NULL;
+ pc->dictObj = NULL;
+ pc->itemValue = NULL;
+ pc->itemName = NULL;
+ pc->iterator = NULL;
+ pc->attrList = NULL;
+ pc->index = 0;
+ pc->size = 0;
+ pc->longValue = 0;
+ pc->rawJSONValue = NULL;
+
+ if (PyIter_Check(obj))
+ {
+ PRINTMARK();
+ goto ISITERABLE;
+ }
+
+ if (PyBool_Check(obj))
+ {
+ PRINTMARK();
+ tc->type = (obj == Py_True) ? JT_TRUE : JT_FALSE;
+ return;
+ }
+ else
+ if (PyLong_Check(obj))
+ {
+ PRINTMARK();
+ pc->PyTypeToJSON = PyLongToINT64;
+ tc->type = JT_LONG;
+ GET_TC(tc)->longValue = PyLong_AsLongLong(obj);
+
+ exc = PyErr_Occurred();
+ if (!exc)
+ {
+ return;
+ }
+
+ if (exc && PyErr_ExceptionMatches(PyExc_OverflowError))
+ {
+ PyErr_Clear();
+ pc->PyTypeToJSON = PyLongToUINT64;
+ tc->type = JT_ULONG;
+ GET_TC(tc)->unsignedLongValue = PyLong_AsUnsignedLongLong(obj);
+
+ exc = PyErr_Occurred();
+ if (exc && PyErr_ExceptionMatches(PyExc_OverflowError))
+ {
+ PRINTMARK();
+ goto INVALID;
+ }
+ }
+
+ return;
+ }
+ else
+ if (PyInt_Check(obj))
+ {
+ PRINTMARK();
+#ifdef _LP64
+ pc->PyTypeToJSON = PyIntToINT64; tc->type = JT_LONG;
+#else
+ pc->PyTypeToJSON = PyIntToINT32; tc->type = JT_INT;
+#endif
+ return;
+ }
+ else
+ if (PyString_Check(obj))
+ {
+ PRINTMARK();
+ pc->PyTypeToJSON = PyStringToUTF8; tc->type = JT_UTF8;
+ return;
+ }
+ else
+ if (PyUnicode_Check(obj))
+ {
+ PRINTMARK();
+ pc->PyTypeToJSON = PyUnicodeToUTF8; tc->type = JT_UTF8;
+ return;
+ }
+ else
+ if (PyFloat_Check(obj) || (type_decimal && PyObject_IsInstance(obj, type_decimal)))
+ {
+ PRINTMARK();
+ pc->PyTypeToJSON = PyFloatToDOUBLE; tc->type = JT_DOUBLE;
+ return;
+ }
+ else
+ if (PyDateTime_Check(obj))
+ {
+ PRINTMARK();
+ pc->PyTypeToJSON = PyDateTimeToINT64; tc->type = JT_LONG;
+ return;
+ }
+ else
+ if (PyDate_Check(obj))
+ {
+ PRINTMARK();
+ pc->PyTypeToJSON = PyDateToINT64; tc->type = JT_LONG;
+ return;
+ }
+ else
+ if (obj == Py_None)
+ {
+ PRINTMARK();
+ tc->type = JT_NULL;
+ return;
+ }
+
+ISITERABLE:
+ if (PyDict_Check(obj))
+ {
+ PRINTMARK();
+ tc->type = JT_OBJECT;
+ SetupDictIter(obj, pc, enc);
+ Py_INCREF(obj);
+ return;
+ }
+ else
+ if (PyList_Check(obj))
+ {
+ PRINTMARK();
+ tc->type = JT_ARRAY;
+ pc->iterEnd = List_iterEnd;
+ pc->iterNext = List_iterNext;
+ pc->iterGetValue = List_iterGetValue;
+ pc->iterGetName = List_iterGetName;
+ GET_TC(tc)->index = 0;
+ GET_TC(tc)->size = PyList_GET_SIZE( (PyObject *) obj);
+ return;
+ }
+ else
+ if (PyTuple_Check(obj))
+ {
+ PRINTMARK();
+ tc->type = JT_ARRAY;
+ pc->iterEnd = Tuple_iterEnd;
+ pc->iterNext = Tuple_iterNext;
+ pc->iterGetValue = Tuple_iterGetValue;
+ pc->iterGetName = Tuple_iterGetName;
+ GET_TC(tc)->index = 0;
+ GET_TC(tc)->size = PyTuple_GET_SIZE( (PyObject *) obj);
+ GET_TC(tc)->itemValue = NULL;
+
+ return;
+ }
+ /*
+ else
+ if (PyAnySet_Check(obj))
+ {
+ PRINTMARK();
+ tc->type = JT_ARRAY;
+ pc->iterBegin = NULL;
+ pc->iterEnd = Iter_iterEnd;
+ pc->iterNext = Iter_iterNext;
+ pc->iterGetValue = Iter_iterGetValue;
+ pc->iterGetName = Iter_iterGetName;
+ return;
+ }
+ */
+
+ if (PyObject_HasAttrString(obj, "toDict"))
+ {
+ PyObject* toDictFunc = PyObject_GetAttrString(obj, "toDict");
+ PyObject* tuple = PyTuple_New(0);
+ PyObject* toDictResult = PyObject_Call(toDictFunc, tuple, NULL);
+ Py_DECREF(tuple);
+ Py_DECREF(toDictFunc);
+
+ if (toDictResult == NULL)
+ {
+ goto INVALID;
+ }
+
+ if (!PyDict_Check(toDictResult))
+ {
+ Py_DECREF(toDictResult);
+ tc->type = JT_NULL;
+ return;
+ }
+
+ PRINTMARK();
+ tc->type = JT_OBJECT;
+ SetupDictIter(toDictResult, pc, enc);
+ return;
+ }
+ else
+ if (PyObject_HasAttrString(obj, "__json__"))
+ {
+ PyObject* toJSONFunc = PyObject_GetAttrString(obj, "__json__");
+ PyObject* tuple = PyTuple_New(0);
+ PyObject* toJSONResult = PyObject_Call(toJSONFunc, tuple, NULL);
+ Py_DECREF(tuple);
+ Py_DECREF(toJSONFunc);
+
+ if (toJSONResult == NULL)
+ {
+ goto INVALID;
+ }
+
+ if (PyErr_Occurred())
+ {
+ Py_DECREF(toJSONResult);
+ goto INVALID;
+ }
+
+ if (!PyString_Check(toJSONResult) && !PyUnicode_Check(toJSONResult))
+ {
+ Py_DECREF(toJSONResult);
+ PyErr_Format (PyExc_TypeError, "expected string");
+ goto INVALID;
+ }
+
+ PRINTMARK();
+ pc->PyTypeToJSON = PyRawJSONToUTF8;
+ tc->type = JT_RAW;
+ GET_TC(tc)->rawJSONValue = toJSONResult;
+ return;
+ }
+
+ PRINTMARK();
+ PyErr_Clear();
+
+ iter = PyObject_GetIter(obj);
+
+ if (iter != NULL)
+ {
+ PRINTMARK();
+ tc->type = JT_ARRAY;
+ pc->iterator = iter;
+ pc->iterEnd = Iter_iterEnd;
+ pc->iterNext = Iter_iterNext;
+ pc->iterGetValue = Iter_iterGetValue;
+ pc->iterGetName = Iter_iterGetName;
+ return;
+ }
+
+ PRINTMARK();
+ PyErr_Clear();
+
+ PRINTMARK();
+ tc->type = JT_OBJECT;
+ GET_TC(tc)->attrList = PyObject_Dir(obj);
+
+ if (GET_TC(tc)->attrList == NULL)
+ {
+ PyErr_Clear();
+ goto INVALID;
+ }
+
+ GET_TC(tc)->index = 0;
+ GET_TC(tc)->size = PyList_GET_SIZE(GET_TC(tc)->attrList);
+ PRINTMARK();
+
+ pc->iterEnd = Dir_iterEnd;
+ pc->iterNext = Dir_iterNext;
+ pc->iterGetValue = Dir_iterGetValue;
+ pc->iterGetName = Dir_iterGetName;
+ return;
+
+INVALID:
+ PRINTMARK();
+ tc->type = JT_INVALID;
+ PyObject_Free(tc->prv);
+ tc->prv = NULL;
+ return;
+}
+
+void Object_endTypeContext(JSOBJ obj, JSONTypeContext *tc)
+{
+ Py_XDECREF(GET_TC(tc)->newObj);
+
+ if (tc->type == JT_RAW)
+ {
+ Py_XDECREF(GET_TC(tc)->rawJSONValue);
+ }
+ PyObject_Free(tc->prv);
+ tc->prv = NULL;
+}
+
+const char *Object_getStringValue(JSOBJ obj, JSONTypeContext *tc, size_t *_outLen)
+{
+ return GET_TC(tc)->PyTypeToJSON (obj, tc, NULL, _outLen);
+}
+
+JSINT64 Object_getLongValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ JSINT64 ret;
+ GET_TC(tc)->PyTypeToJSON (obj, tc, &ret, NULL);
+ return ret;
+}
+
+JSUINT64 Object_getUnsignedLongValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ JSUINT64 ret;
+ GET_TC(tc)->PyTypeToJSON (obj, tc, &ret, NULL);
+ return ret;
+}
+
+JSINT32 Object_getIntValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ JSINT32 ret;
+ GET_TC(tc)->PyTypeToJSON (obj, tc, &ret, NULL);
+ return ret;
+}
+
+double Object_getDoubleValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ double ret;
+ GET_TC(tc)->PyTypeToJSON (obj, tc, &ret, NULL);
+ return ret;
+}
+
+static void Object_releaseObject(JSOBJ _obj)
+{
+ Py_DECREF( (PyObject *) _obj);
+}
+
+int Object_iterNext(JSOBJ obj, JSONTypeContext *tc)
+{
+ return GET_TC(tc)->iterNext(obj, tc);
+}
+
+void Object_iterEnd(JSOBJ obj, JSONTypeContext *tc)
+{
+ GET_TC(tc)->iterEnd(obj, tc);
+}
+
+JSOBJ Object_iterGetValue(JSOBJ obj, JSONTypeContext *tc)
+{
+ return GET_TC(tc)->iterGetValue(obj, tc);
+}
+
+char *Object_iterGetName(JSOBJ obj, JSONTypeContext *tc, size_t *outLen)
+{
+ return GET_TC(tc)->iterGetName(obj, tc, outLen);
+}
+
+PyObject* objToJSON(PyObject* self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "obj", "ensure_ascii", "double_precision", "encode_html_chars", "escape_forward_slashes", "sort_keys", "indent", NULL };
+
+ char buffer[65536];
+ char *ret;
+ PyObject *newobj;
+ PyObject *oinput = NULL;
+ PyObject *oensureAscii = NULL;
+ PyObject *oencodeHTMLChars = NULL;
+ PyObject *oescapeForwardSlashes = NULL;
+ PyObject *osortKeys = NULL;
+
+ JSONObjectEncoder encoder =
+ {
+ Object_beginTypeContext,
+ Object_endTypeContext,
+ Object_getStringValue,
+ Object_getLongValue,
+ Object_getUnsignedLongValue,
+ Object_getIntValue,
+ Object_getDoubleValue,
+ Object_iterNext,
+ Object_iterEnd,
+ Object_iterGetValue,
+ Object_iterGetName,
+ Object_releaseObject,
+ PyObject_Malloc,
+ PyObject_Realloc,
+ PyObject_Free,
+ -1, //recursionMax
+ 10, // default double precision setting
+ 1, //forceAscii
+ 0, //encodeHTMLChars
+ 1, //escapeForwardSlashes
+ 0, //sortKeys
+ 0, //indent
+ NULL, //prv
+ };
+
+
+ PRINTMARK();
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OiOOOi", kwlist, &oinput, &oensureAscii, &encoder.doublePrecision, &oencodeHTMLChars, &oescapeForwardSlashes, &osortKeys, &encoder.indent))
+ {
+ return NULL;
+ }
+
+ if (oensureAscii != NULL && !PyObject_IsTrue(oensureAscii))
+ {
+ encoder.forceASCII = 0;
+ }
+
+ if (oencodeHTMLChars != NULL && PyObject_IsTrue(oencodeHTMLChars))
+ {
+ encoder.encodeHTMLChars = 1;
+ }
+
+ if (oescapeForwardSlashes != NULL && !PyObject_IsTrue(oescapeForwardSlashes))
+ {
+ encoder.escapeForwardSlashes = 0;
+ }
+
+ if (osortKeys != NULL && PyObject_IsTrue(osortKeys))
+ {
+ encoder.sortKeys = 1;
+ }
+
+ PRINTMARK();
+ ret = JSON_EncodeObject (oinput, &encoder, buffer, sizeof (buffer));
+ PRINTMARK();
+
+ if (PyErr_Occurred())
+ {
+ return NULL;
+ }
+
+ if (encoder.errorMsg)
+ {
+ if (ret != buffer)
+ {
+ encoder.free (ret);
+ }
+
+ PyErr_Format (PyExc_OverflowError, "%s", encoder.errorMsg);
+ return NULL;
+ }
+
+ newobj = PyString_FromString (ret);
+
+ if (ret != buffer)
+ {
+ encoder.free (ret);
+ }
+
+ PRINTMARK();
+
+ return newobj;
+}
+
+PyObject* objToJSONFile(PyObject* self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *data;
+ PyObject *file;
+ PyObject *string;
+ PyObject *write;
+ PyObject *argtuple;
+ PyObject *write_result;
+
+ PRINTMARK();
+
+ if (!PyArg_ParseTuple (args, "OO", &data, &file))
+ {
+ return NULL;
+ }
+
+ if (!PyObject_HasAttrString (file, "write"))
+ {
+ PyErr_Format (PyExc_TypeError, "expected file");
+ return NULL;
+ }
+
+ write = PyObject_GetAttrString (file, "write");
+
+ if (!PyCallable_Check (write))
+ {
+ Py_XDECREF(write);
+ PyErr_Format (PyExc_TypeError, "expected file");
+ return NULL;
+ }
+
+ argtuple = PyTuple_Pack(1, data);
+
+ string = objToJSON (self, argtuple, kwargs);
+
+ if (string == NULL)
+ {
+ Py_XDECREF(write);
+ Py_XDECREF(argtuple);
+ return NULL;
+ }
+
+ Py_XDECREF(argtuple);
+
+ argtuple = PyTuple_Pack (1, string);
+ if (argtuple == NULL)
+ {
+ Py_XDECREF(write);
+ return NULL;
+ }
+
+ write_result = PyObject_CallObject (write, argtuple);
+ if (write_result == NULL)
+ {
+ Py_XDECREF(write);
+ Py_XDECREF(argtuple);
+ return NULL;
+ }
+
+ Py_DECREF(write_result);
+ Py_XDECREF(write);
+ Py_DECREF(argtuple);
+ Py_XDECREF(string);
+
+ PRINTMARK();
+
+ Py_RETURN_NONE;
+}
diff --git a/contrib/python/ujson/py3/python/py_defines.h b/contrib/python/ujson/py3/python/py_defines.h
new file mode 100644
index 0000000000..2b38b41bdb
--- /dev/null
+++ b/contrib/python/ujson/py3/python/py_defines.h
@@ -0,0 +1,53 @@
+/*
+Developed by ESN, an Electronic Arts Inc. studio.
+Copyright (c) 2014, Electronic Arts Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of ESN, Electronic Arts Inc. nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS INC. BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Portions of code from MODP_ASCII - Ascii transformations (upper/lower, etc)
+http://code.google.com/p/stringencoders/
+Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
+
+Numeric decoder derived from from TCL library
+http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+*/
+
+#include <Python.h>
+
+#if PY_MAJOR_VERSION >= 3
+
+#define PyInt_Check PyLong_Check
+#define PyInt_AS_LONG PyLong_AsLong
+#define PyInt_FromLong PyLong_FromLong
+
+#define PyString_Check PyBytes_Check
+#define PyString_GET_SIZE PyBytes_GET_SIZE
+#define PyString_AS_STRING PyBytes_AS_STRING
+
+#define PyString_FromString PyUnicode_FromString
+
+#endif
diff --git a/contrib/python/ujson/py3/python/ujson.c b/contrib/python/ujson/py3/python/ujson.c
new file mode 100644
index 0000000000..d0b15c65cf
--- /dev/null
+++ b/contrib/python/ujson/py3/python/ujson.c
@@ -0,0 +1,113 @@
+/*
+Developed by ESN, an Electronic Arts Inc. studio.
+Copyright (c) 2014, Electronic Arts Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of ESN, Electronic Arts Inc. nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS INC. BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Portions of code from MODP_ASCII - Ascii transformations (upper/lower, etc)
+http://code.google.com/p/stringencoders/
+Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
+
+Numeric decoder derived from from TCL library
+http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
+* Copyright (c) 1988-1993 The Regents of the University of California.
+* Copyright (c) 1994 Sun Microsystems, Inc.
+*/
+
+#include "py_defines.h"
+#include "version.h"
+
+/* objToJSON */
+PyObject* objToJSON(PyObject* self, PyObject *args, PyObject *kwargs);
+void initObjToJSON(void);
+
+/* JSONToObj */
+PyObject* JSONToObj(PyObject* self, PyObject *args, PyObject *kwargs);
+
+/* objToJSONFile */
+PyObject* objToJSONFile(PyObject* self, PyObject *args, PyObject *kwargs);
+
+/* JSONFileToObj */
+PyObject* JSONFileToObj(PyObject* self, PyObject *args, PyObject *kwargs);
+
+
+#define ENCODER_HELP_TEXT "Use ensure_ascii=false to output UTF-8. Pass in double_precision to alter the maximum digit precision of doubles. Set encode_html_chars=True to encode < > & as unicode escape sequences. Set escape_forward_slashes=False to prevent escaping / characters."
+
+static PyMethodDef ujsonMethods[] = {
+ {"encode", (PyCFunction) objToJSON, METH_VARARGS | METH_KEYWORDS, "Converts arbitrary object recursively into JSON. " ENCODER_HELP_TEXT},
+ {"decode", (PyCFunction) JSONToObj, METH_VARARGS | METH_KEYWORDS, "Converts JSON as string to dict object structure. Use precise_float=True to use high precision float decoder."},
+ {"dumps", (PyCFunction) objToJSON, METH_VARARGS | METH_KEYWORDS, "Converts arbitrary object recursively into JSON. " ENCODER_HELP_TEXT},
+ {"loads", (PyCFunction) JSONToObj, METH_VARARGS | METH_KEYWORDS, "Converts JSON as string to dict object structure. Use precise_float=True to use high precision float decoder."},
+ {"dump", (PyCFunction) objToJSONFile, METH_VARARGS | METH_KEYWORDS, "Converts arbitrary object recursively into JSON file. " ENCODER_HELP_TEXT},
+ {"load", (PyCFunction) JSONFileToObj, METH_VARARGS | METH_KEYWORDS, "Converts JSON as file to dict object structure. Use precise_float=True to use high precision float decoder."},
+ {NULL, NULL, 0, NULL} /* Sentinel */
+};
+
+#if PY_MAJOR_VERSION >= 3
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "ujson",
+ 0, /* m_doc */
+ -1, /* m_size */
+ ujsonMethods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL /* m_free */
+};
+
+#define PYMODINITFUNC PyObject *PyInit_ujson(void)
+#define PYMODULE_CREATE() PyModule_Create(&moduledef)
+#define MODINITERROR return NULL
+
+#else
+
+#define PYMODINITFUNC PyMODINIT_FUNC initujson(void)
+#define PYMODULE_CREATE() Py_InitModule("ujson", ujsonMethods)
+#define MODINITERROR return
+
+#endif
+
+PYMODINITFUNC
+{
+ PyObject *module;
+ PyObject *version_string;
+
+ initObjToJSON();
+ module = PYMODULE_CREATE();
+
+ if (module == NULL)
+ {
+ MODINITERROR;
+ }
+
+ version_string = PyString_FromString (UJSON_VERSION);
+ PyModule_AddObject (module, "__version__", version_string);
+
+#if PY_MAJOR_VERSION >= 3
+ return module;
+#endif
+}
diff --git a/contrib/python/ujson/py3/python/version.h b/contrib/python/ujson/py3/python/version.h
new file mode 100644
index 0000000000..f0ce6bb733
--- /dev/null
+++ b/contrib/python/ujson/py3/python/version.h
@@ -0,0 +1,39 @@
+/*
+Developed by ESN, an Electronic Arts Inc. studio.
+Copyright (c) 2014, Electronic Arts Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of ESN, Electronic Arts Inc. nor the
+names of its contributors may be used to endorse or promote products
+derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS INC. BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Portions of code from MODP_ASCII - Ascii transformations (upper/lower, etc)
+http://code.google.com/p/stringencoders/
+Copyright (c) 2007 Nick Galbreath -- nickg [at] modp [dot] com. All rights reserved.
+
+Numeric decoder derived from from TCL library
+http://www.opensource.apple.com/source/tcl/tcl-14/tcl/license.terms
+ * Copyright (c) 1988-1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+*/
+
+#define UJSON_VERSION "1.35"
diff --git a/contrib/python/ujson/py3/ya.make b/contrib/python/ujson/py3/ya.make
new file mode 100644
index 0000000000..668463b313
--- /dev/null
+++ b/contrib/python/ujson/py3/ya.make
@@ -0,0 +1,30 @@
+PY3_LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+VERSION(1.35+dev)
+
+NO_COMPILER_WARNINGS()
+NO_UTIL()
+
+PY_REGISTER(ujson)
+
+ADDINCL(
+ contrib/python/ujson/py3/lib
+ contrib/python/ujson/py3/python
+)
+
+SRCS(
+ lib/ultrajsondec.c
+ lib/ultrajsonenc.c
+ python/JSONtoObj.c
+ python/objToJSON.c
+ python/ujson.c
+)
+
+PY_SRCS(
+ TOP_LEVEL
+ ujson.pyi
+)
+
+END()