Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #48 from Komnomnomnom/pandas-changes

Fixes and enhancements from the pandas project
  • Loading branch information...
commit 640f6dae2eed597ee21abde1cbb27e9bec7dd789 2 parents fd13812 + fd3e969
@jskorpan jskorpan authored
View
593 lib/ultrajson.h
@@ -1,298 +1,295 @@
-/*
-Copyright (c) 2011, Jonas Tarnstrom and ESN Social Software AB
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- This product includes software developed by ESN Social Software AB (www.esn.me).
-4. Neither the name of the ESN Social Software AB 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 ESN SOCIAL SOFTWARE AB ''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 ESN SOCIAL SOFTWARE AB 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.
-
-*/
-
-/*
-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>
-
-//#define JSON_DECODE_NUMERIC_AS_DOUBLE
-
-// 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 9
-#endif
-
-// Max recursion depth, default for encoder
-#ifndef JSON_MAX_RECURSION_DEPTH
-#define JSON_MAX_RECURSION_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 unsigned __int32 uint32_t;
-typedef __int32 JSINT32;
-typedef uint32_t 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 <sys/types.h>
-typedef int64_t JSINT64;
-typedef u_int64_t JSUINT64;
-
-typedef int32_t JSINT32;
-typedef u_int32_t JSUINT32;
-
-#define FASTCALL_MSVC
-#define FASTCALL_ATTR __attribute__((fastcall))
-#define INLINE_PREFIX inline
-
-typedef u_int32_t uint32_t;
-
-typedef u_int8_t JSUINT8;
-typedef u_int16_t JSUTF16;
-typedef u_int32_t JSUTF32;
-
-typedef int64_t JSLONG;
-
-#define EXPORTFUNCTION
-#endif
-
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-#define __LITTLE_ENDIAN__
-#else
-
-#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-#define __BIG_ENDIAN__
-#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_DOUBLE, //(double)
- JT_UTF8, //(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[32];
-} JSONTypeContext;
-
-/*
-Function pointer declarations, suitable for implementing UltraJSON */
-typedef void (*JSPFN_ITERBEGIN)(JSOBJ obj, JSONTypeContext *tc);
-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);
-
-typedef struct __JSONObjectEncoder
-{
- void (*beginTypeContext)(JSOBJ obj, JSONTypeContext *tc);
- void (*endTypeContext)(JSOBJ obj, JSONTypeContext *tc);
- const char *(*getStringValue)(JSOBJ obj, JSONTypeContext *tc, size_t *_outLen);
- JSINT64 (*getLongValue)(JSOBJ obj, JSONTypeContext *tc);
- JSINT32 (*getIntValue)(JSOBJ obj, JSONTypeContext *tc);
- double (*getDoubleValue)(JSOBJ obj, JSONTypeContext *tc);
-
- /*
- Begin iteration of an iteratable object (JS_ARRAY or JS_OBJECT)
- Implementor should setup iteration state in ti->prv
- */
- JSPFN_ITERBEGIN iterBegin;
-
- /*
- 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 poiunt 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;
-
-
- /*
- 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)(wchar_t *start, wchar_t *end);
- void (*objectAddKey)(JSOBJ obj, JSOBJ name, JSOBJ value);
- void (*arrayAddItem)(JSOBJ obj, JSOBJ value);
- JSOBJ (*newTrue)(void);
- JSOBJ (*newFalse)(void);
- JSOBJ (*newNull)(void);
- JSOBJ (*newObject)(void);
- JSOBJ (*newArray)(void);
- JSOBJ (*newInt)(JSINT32 value);
- JSOBJ (*newLong)(JSINT64 value);
- JSOBJ (*newDouble)(double value);
- void (*releaseObject)(JSOBJ obj);
- JSPFN_MALLOC malloc;
- JSPFN_FREE free;
- JSPFN_REALLOC realloc;
-
- char *errorStr;
- char *errorOffset;
-
-
-
-} JSONObjectDecoder;
-
-EXPORTFUNCTION JSOBJ JSON_DecodeObject(JSONObjectDecoder *dec, const char *buffer, size_t cbBuffer);
-
-#endif
+/*
+Copyright (c) 2011, Jonas Tarnstrom and ESN Social Software AB
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by ESN Social Software AB (www.esn.me).
+4. Neither the name of the ESN Social Software AB 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 ESN SOCIAL SOFTWARE AB ''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 ESN SOCIAL SOFTWARE AB 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.
+
+*/
+
+/*
+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>
+
+//#define JSON_DECODE_NUMERIC_AS_DOUBLE
+
+// 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
+
+/*
+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 <sys/types.h>
+typedef int64_t JSINT64;
+typedef u_int64_t JSUINT64;
+
+typedef int32_t JSINT32;
+typedef u_int32_t JSUINT32;
+
+#define FASTCALL_MSVC
+#define FASTCALL_ATTR __attribute__((fastcall))
+#define INLINE_PREFIX inline
+
+typedef u_int8_t JSUINT8;
+typedef u_int16_t JSUTF16;
+typedef u_int32_t JSUTF32;
+
+typedef int64_t JSLONG;
+
+#define EXPORTFUNCTION
+#endif
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define __LITTLE_ENDIAN__
+#else
+
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define __BIG_ENDIAN__
+#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_DOUBLE, //(double)
+ JT_UTF8, //(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;
+} JSONTypeContext;
+
+/*
+Function pointer declarations, suitable for implementing UltraJSON */
+typedef void (*JSPFN_ITERBEGIN)(JSOBJ obj, JSONTypeContext *tc);
+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);
+
+typedef struct __JSONObjectEncoder
+{
+ void (*beginTypeContext)(JSOBJ obj, JSONTypeContext *tc);
+ void (*endTypeContext)(JSOBJ obj, JSONTypeContext *tc);
+ const char *(*getStringValue)(JSOBJ obj, JSONTypeContext *tc, size_t *_outLen);
+ JSINT64 (*getLongValue)(JSOBJ obj, JSONTypeContext *tc);
+ JSINT32 (*getIntValue)(JSOBJ obj, JSONTypeContext *tc);
+ double (*getDoubleValue)(JSOBJ obj, JSONTypeContext *tc);
+
+ /*
+ Begin iteration of an iteratable object (JS_ARRAY or JS_OBJECT)
+ Implementor should setup iteration state in ti->prv
+ */
+ JSPFN_ITERBEGIN iterBegin;
+
+ /*
+ 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 poiunt 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;
+
+
+ /*
+ 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)(wchar_t *start, wchar_t *end);
+ void (*objectAddKey)(JSOBJ obj, JSOBJ name, JSOBJ value);
+ void (*arrayAddItem)(JSOBJ obj, JSOBJ value);
+ JSOBJ (*newTrue)(void);
+ JSOBJ (*newFalse)(void);
+ JSOBJ (*newNull)(void);
+ JSOBJ (*newObject)(void);
+ JSOBJ (*newArray)(void);
+ JSOBJ (*newInt)(JSINT32 value);
+ JSOBJ (*newLong)(JSINT64 value);
+ JSOBJ (*newDouble)(double value);
+ void (*releaseObject)(JSOBJ obj);
+ JSPFN_MALLOC malloc;
+ JSPFN_FREE free;
+ JSPFN_REALLOC realloc;
+
+ char *errorStr;
+ char *errorOffset;
+
+
+
+} JSONObjectDecoder;
+
+EXPORTFUNCTION JSOBJ JSON_DecodeObject(JSONObjectDecoder *dec, const char *buffer, size_t cbBuffer);
+
+#endif
View
1,662 lib/ultrajsondec.c
@@ -1,827 +1,835 @@
-/*
-Copyright (c) 2011, Jonas Tarnstrom and ESN Social Software AB
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- This product includes software developed by ESN Social Software AB (www.esn.me).
-4. Neither the name of the ESN Social Software AB 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 ESN SOCIAL SOFTWARE AB ''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 ESN SOCIAL SOFTWARE AB 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.
-
-*/
-
-#include "ultrajson.h"
-#include <math.h>
-#include <assert.h>
-#include <string.h>
-#include <limits.h>
-#include <wchar.h>
-
-struct DecoderState
-{
- char *start;
- char *end;
- wchar_t *escStart;
- wchar_t *escEnd;
- int escHeap;
- int lastType;
- JSONObjectDecoder *dec;
-};
-
-JSOBJ FASTCALL_MSVC decode_any( struct DecoderState *ds) FASTCALL_ATTR;
-typedef JSOBJ (*PFN_DECODER)( struct DecoderState *ds);
-#define RETURN_JSOBJ_NULLCHECK(_expr) return(_expr);
-
-double createDouble(double intNeg, double intValue, double frcValue, int frcDecimalCount)
-{
- static const double g_pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
-
- return (intValue + (frcValue / g_pow10[frcDecimalCount])) * intNeg;
-}
-
-static JSOBJ SetError( struct DecoderState *ds, int offset, const char *message)
-{
- ds->dec->errorOffset = ds->start + offset;
- ds->dec->errorStr = (char *) message;
- return NULL;
-}
-
-
-FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric ( struct DecoderState *ds)
-{
-#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
- double intNeg = 1;
- double intValue;
-#else
- int intNeg = 1;
- JSLONG intValue;
-#endif
-
- double expNeg;
- int chr;
- int decimalCount = 0;
- double frcValue = 0.0;
- double expValue;
- char *offset = ds->start;
-
- if (*(offset) == '-')
- {
- offset ++;
- intNeg = -1;
- }
-
- // 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':
- //FIXME: Check for arithemtic overflow here
- //PERF: Don't do 64-bit arithmetic here unless we know we have to
-#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
- intValue = intValue * 10.0 + (double) (chr - 48);
-#else
- intValue = intValue * 10LL + (JSLONG) (chr - 48);
-#endif
- offset ++;
- 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 input string is LONGLONG_MIN here the value is already negative so we should not flip it
-
-#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
-#else
- if (intValue < 0)
- {
- intNeg = 1;
- }
-#endif
-
- //dbg1 = (intValue * intNeg);
- //dbg2 = (JSLONG) dbg1;
-
-#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
- if (intValue > (double) INT_MAX || intValue < (double) INT_MIN)
-#else
- if ( (intValue >> 31))
-#endif
- {
- RETURN_JSOBJ_NULLCHECK(ds->dec->newLong( (JSINT64) (intValue * (JSINT64) intNeg)));
- }
- else
- {
- RETURN_JSOBJ_NULLCHECK(ds->dec->newInt( (JSINT32) (intValue * intNeg)));
- }
-
-
-
-DECODE_FRACTION:
-
- // Scan fraction part
- frcValue = 0.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':
- 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:
-
- if (intValue < 0)
- {
- intNeg = 1;
- }
-
- //FIXME: Check for arithemtic overflow here
- ds->lastType = JT_DOUBLE;
- ds->start = offset;
- RETURN_JSOBJ_NULLCHECK(ds->dec->newDouble (createDouble( (double) intNeg, (double) intValue, frcValue, decimalCount)));
-
-DECODE_EXPONENT:
- expNeg = 1.0;
-
- if (*(offset) == '-')
- {
- expNeg = -1.0;
- offset ++;
- }
- else
- if (*(offset) == '+')
- {
- expNeg = +1.0;
- offset ++;
- }
-
- expValue = 0.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':
- expValue = expValue * 10.0 + (double) (chr - 48);
- offset ++;
- break;
-
- default:
- goto BREAK_EXP_LOOP;
-
- }
- }
-
-BREAK_EXP_LOOP:
-
-#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
-#else
- if (intValue < 0)
- {
- intNeg = 1;
- }
-#endif
-
- //FIXME: Check for arithemtic overflow here
- ds->lastType = JT_DOUBLE;
- ds->start = offset;
- RETURN_JSOBJ_NULLCHECK(ds->dec->newDouble (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_JSOBJ_NULLCHECK(ds->dec->newTrue());
-
-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_JSOBJ_NULLCHECK(ds->dec->newFalse());
-
-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_JSOBJ_NULLCHECK(ds->dec->newNull());
-
-SETERROR:
- return SetError(ds, -1, "Unexpected character found when decoding 'null'");
-}
-
-FASTCALL_ATTR void FASTCALL_MSVC SkipWhitespace(struct DecoderState *ds)
-{
- char *offset = ds->start;
-
- while (1)
- {
- 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;
- size_t escLen = (ds->escEnd - ds->escStart);
- JSUINT8 *inputOffset;
- JSUINT8 oct;
- JSUTF32 ucs;
- ds->lastType = JT_INVALID;
- ds->start ++;
-
- if ( (ds->end - ds->start) > escLen)
- {
- size_t newSize = (ds->end - ds->start);
-
- if (ds->escHeap)
- {
- ds->escStart = (wchar_t *) ds->dec->realloc (ds->escStart, newSize * sizeof(wchar_t));
- }
- else
- {
- wchar_t *oldStart = ds->escStart;
- ds->escHeap = 1;
- ds->escStart = (wchar_t *) ds->dec->malloc (newSize * sizeof(wchar_t));
- memcpy (ds->escStart, oldStart, escLen * sizeof(wchar_t));
- }
-
- ds->escEnd = ds->escStart + newSize;
- }
-
- escOffset = ds->escStart;
- inputOffset = ds->start;
-
- while(1)
- {
- 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_JSOBJ_NULLCHECK(ds->dec->newString(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++) = (ucs >> 10) + 0xd800;
- *(escOffset++) = (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 = ds->dec->newArray();
-
- ds->lastType = JT_INVALID;
- ds->start ++;
-
- while (1)//(*ds->start) != '\0')
- {
- SkipWhitespace(ds);
-
- if ((*ds->start) == ']')
- {
- *ds->start ++;
- return newObj;
- }
-
- itemValue = decode_any(ds);
-
- if (itemValue == NULL)
- {
- ds->dec->releaseObject(newObj);
- return NULL;
- }
-
- ds->dec->arrayAddItem (newObj, itemValue);
-
- SkipWhitespace(ds);
-
- switch (*(ds->start++))
- {
- case ']':
- return newObj;
-
- case ',':
- break;
-
- default:
- ds->dec->releaseObject(newObj);
- return SetError(ds, -1, "Unexpected character in found when decoding array value");
- }
- }
-
- ds->dec->releaseObject(newObj);
- return SetError(ds, -1, "Unmatched ']' when decoding 'array'");
-}
-
-
-
-FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_object( struct DecoderState *ds)
-{
- JSOBJ itemName;
- JSOBJ itemValue;
- JSOBJ newObj = ds->dec->newObject();
-
- ds->start ++;
-
- while (1)
- {
- SkipWhitespace(ds);
-
- if ((*ds->start) == '}')
- {
- ds->start ++;
- return newObj;
- }
-
- ds->lastType = JT_INVALID;
- itemName = decode_any(ds);
-
- if (itemName == NULL)
- {
- ds->dec->releaseObject(newObj);
- return NULL;
- }
-
- if (ds->lastType != JT_UTF8)
- {
- ds->dec->releaseObject(newObj);
- ds->dec->releaseObject(itemName);
- return SetError(ds, -1, "Key name of object must be 'string' when decoding 'object'");
- }
-
- SkipWhitespace(ds);
-
- if (*(ds->start++) != ':')
- {
- ds->dec->releaseObject(newObj);
- ds->dec->releaseObject(itemName);
- return SetError(ds, -1, "No ':' found when decoding object value");
- }
-
- SkipWhitespace(ds);
-
- itemValue = decode_any(ds);
-
- if (itemValue == NULL)
- {
- ds->dec->releaseObject(newObj);
- ds->dec->releaseObject(itemName);
- return NULL;
- }
-
- ds->dec->objectAddKey (newObj, itemName, itemValue);
-
- SkipWhitespace(ds);
-
- switch (*(ds->start++))
- {
- case '}':
- return newObj;
-
- case ',':
- break;
-
- default:
- ds->dec->releaseObject(newObj);
- return SetError(ds, -1, "Unexpected character in found when decoding object value");
- }
- }
-
- ds->dec->releaseObject(newObj);
- return SetError(ds, -1, "Unmatched '}' when decoding object");
-}
-
-FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_any(struct DecoderState *ds)
-{
- while (1)
- {
- 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.dec = dec;
- ds.dec->errorStr = NULL;
- ds.dec->errorOffset = NULL;
-
- ds.dec = dec;
-
- ret = decode_any (&ds);
-
- if (ds.escHeap)
- {
- dec->free(ds.escStart);
- }
- return ret;
-}
+/*
+Copyright (c) 2011, Jonas Tarnstrom and ESN Social Software AB
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by ESN Social Software AB (www.esn.me).
+4. Neither the name of the ESN Social Software AB 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 ESN SOCIAL SOFTWARE AB ''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 ESN SOCIAL SOFTWARE AB 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.
+
+*/
+
+#include "ultrajson.h"
+#include <math.h>
+#include <assert.h>
+#include <string.h>
+#include <limits.h>
+#include <wchar.h>
+
+struct DecoderState
+{
+ char *start;
+ char *end;
+ wchar_t *escStart;
+ wchar_t *escEnd;
+ int escHeap;
+ int lastType;
+ JSONObjectDecoder *dec;
+};
+
+JSOBJ FASTCALL_MSVC decode_any( struct DecoderState *ds) FASTCALL_ATTR;
+typedef JSOBJ (*PFN_DECODER)( struct DecoderState *ds);
+#define RETURN_JSOBJ_NULLCHECK(_expr) return(_expr);
+
+double createDouble(double intNeg, double intValue, double frcValue, int frcDecimalCount)
+{
+ static const double g_pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000};
+
+ return (intValue + (frcValue / g_pow10[frcDecimalCount])) * intNeg;
+}
+
+static JSOBJ SetError( struct DecoderState *ds, int offset, const char *message)
+{
+ ds->dec->errorOffset = ds->start + offset;
+ ds->dec->errorStr = (char *) message;
+ return NULL;
+}
+
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_numeric ( struct DecoderState *ds)
+{
+#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
+ double intNeg = 1;
+ double intValue;
+#else
+ int intNeg = 1;
+ JSLONG intValue;
+#endif
+
+ double expNeg;
+ int chr;
+ int decimalCount = 0;
+ double frcValue = 0.0;
+ double expValue;
+ char *offset = ds->start;
+
+ if (*(offset) == '-')
+ {
+ offset ++;
+ intNeg = -1;
+ }
+
+ // 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':
+ //FIXME: Check for arithemtic overflow here
+ //PERF: Don't do 64-bit arithmetic here unless we know we have to
+#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
+ intValue = intValue * 10.0 + (double) (chr - 48);
+#else
+ intValue = intValue * 10LL + (JSLONG) (chr - 48);
+#endif
+ offset ++;
+ 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 input string is LONGLONG_MIN here the value is already negative so we should not flip it
+
+#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
+#else
+ if (intValue < 0)
+ {
+ intNeg = 1;
+ }
+#endif
+
+ //dbg1 = (intValue * intNeg);
+ //dbg2 = (JSLONG) dbg1;
+
+#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
+ if (intValue > (double) INT_MAX || intValue < (double) INT_MIN)
+#else
+ if ( (intValue >> 31))
+#endif
+ {
+ RETURN_JSOBJ_NULLCHECK(ds->dec->newLong( (JSINT64) (intValue * (JSINT64) intNeg)));
+ }
+ else
+ {
+ RETURN_JSOBJ_NULLCHECK(ds->dec->newInt( (JSINT32) (intValue * intNeg)));
+ }
+
+
+
+DECODE_FRACTION:
+
+ // Scan fraction part
+ frcValue = 0.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':
+ 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:
+
+ if (intValue < 0)
+ {
+ intNeg = 1;
+ }
+
+ //FIXME: Check for arithemtic overflow here
+ ds->lastType = JT_DOUBLE;
+ ds->start = offset;
+ RETURN_JSOBJ_NULLCHECK(ds->dec->newDouble (createDouble( (double) intNeg, (double) intValue, frcValue, decimalCount)));
+
+DECODE_EXPONENT:
+ expNeg = 1.0;
+
+ if (*(offset) == '-')
+ {
+ expNeg = -1.0;
+ offset ++;
+ }
+ else
+ if (*(offset) == '+')
+ {
+ expNeg = +1.0;
+ offset ++;
+ }
+
+ expValue = 0.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':
+ expValue = expValue * 10.0 + (double) (chr - 48);
+ offset ++;
+ break;
+
+ default:
+ goto BREAK_EXP_LOOP;
+
+ }
+ }
+
+BREAK_EXP_LOOP:
+
+#ifdef JSON_DECODE_NUMERIC_AS_DOUBLE
+#else
+ if (intValue < 0)
+ {
+ intNeg = 1;
+ }
+#endif
+
+ //FIXME: Check for arithemtic overflow here
+ ds->lastType = JT_DOUBLE;
+ ds->start = offset;
+ RETURN_JSOBJ_NULLCHECK(ds->dec->newDouble (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_JSOBJ_NULLCHECK(ds->dec->newTrue());
+
+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_JSOBJ_NULLCHECK(ds->dec->newFalse());
+
+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_JSOBJ_NULLCHECK(ds->dec->newNull());
+
+SETERROR:
+ return SetError(ds, -1, "Unexpected character found when decoding 'null'");
+}
+
+FASTCALL_ATTR void FASTCALL_MSVC SkipWhitespace(struct DecoderState *ds)
+{
+ char *offset = ds->start;
+
+ while (1)
+ {
+ 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;
+ size_t escLen = (ds->escEnd - ds->escStart);
+ JSUINT8 *inputOffset;
+ JSUINT8 oct;
+ JSUTF32 ucs;
+ ds->lastType = JT_INVALID;
+ ds->start ++;
+
+ if ( (ds->end - ds->start) > escLen)
+ {
+ size_t newSize = (ds->end - ds->start);
+
+ if (ds->escHeap)
+ {
+ ds->escStart = (wchar_t *) ds->dec->realloc (ds->escStart, newSize * sizeof(wchar_t));
+ if (!ds->escStart)
+ {
+ return SetError(ds, -1, "Could not reserve memory block");
+ }
+ }
+ else
+ {
+ wchar_t *oldStart = ds->escStart;
+ ds->escHeap = 1;
+ ds->escStart = (wchar_t *) ds->dec->malloc (newSize * sizeof(wchar_t));
+ if (!ds->escStart)
+ {
+ return SetError(ds, -1, "Could not reserve memory block");
+ }
+ memcpy (ds->escStart, oldStart, escLen * sizeof(wchar_t));
+ }
+
+ ds->escEnd = ds->escStart + newSize;
+ }
+
+ escOffset = ds->escStart;
+ inputOffset = ds->start;
+
+ while(1)
+ {
+ 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_JSOBJ_NULLCHECK(ds->dec->newString(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++) = (ucs >> 10) + 0xd800;
+ *(escOffset++) = (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 = ds->dec->newArray();
+
+ ds->lastType = JT_INVALID;
+ ds->start ++;
+
+ while (1)//(*ds->start) != '\0')
+ {
+ SkipWhitespace(ds);
+
+ if ((*ds->start) == ']')
+ {
+ ds->start++;
+ return newObj;
+ }
+
+ itemValue = decode_any(ds);
+
+ if (itemValue == NULL)
+ {
+ ds->dec->releaseObject(newObj);
+ return NULL;
+ }
+
+ ds->dec->arrayAddItem (newObj, itemValue);
+
+ SkipWhitespace(ds);
+
+ switch (*(ds->start++))
+ {
+ case ']':
+ return newObj;
+
+ case ',':
+ break;
+
+ default:
+ ds->dec->releaseObject(newObj);
+ return SetError(ds, -1, "Unexpected character in found when decoding array value");
+ }
+ }
+
+ ds->dec->releaseObject(newObj);
+ return SetError(ds, -1, "Unmatched ']' when decoding 'array'");
+}
+
+
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_object( struct DecoderState *ds)
+{
+ JSOBJ itemName;
+ JSOBJ itemValue;
+ JSOBJ newObj = ds->dec->newObject();
+
+ ds->start ++;
+
+ while (1)
+ {
+ SkipWhitespace(ds);
+
+ if ((*ds->start) == '}')
+ {
+ ds->start ++;
+ return newObj;
+ }
+
+ ds->lastType = JT_INVALID;
+ itemName = decode_any(ds);
+
+ if (itemName == NULL)
+ {
+ ds->dec->releaseObject(newObj);
+ return NULL;
+ }
+
+ if (ds->lastType != JT_UTF8)
+ {
+ ds->dec->releaseObject(newObj);
+ ds->dec->releaseObject(itemName);
+ return SetError(ds, -1, "Key name of object must be 'string' when decoding 'object'");
+ }
+
+ SkipWhitespace(ds);
+
+ if (*(ds->start++) != ':')
+ {
+ ds->dec->releaseObject(newObj);
+ ds->dec->releaseObject(itemName);
+ return SetError(ds, -1, "No ':' found when decoding object value");
+ }
+
+ SkipWhitespace(ds);
+
+ itemValue = decode_any(ds);
+
+ if (itemValue == NULL)
+ {
+ ds->dec->releaseObject(newObj);
+ ds->dec->releaseObject(itemName);
+ return NULL;
+ }
+
+ ds->dec->objectAddKey (newObj, itemName, itemValue);
+
+ SkipWhitespace(ds);
+
+ switch (*(ds->start++))
+ {
+ case '}':
+ return newObj;
+
+ case ',':
+ break;
+
+ default:
+ ds->dec->releaseObject(newObj);
+ return SetError(ds, -1, "Unexpected character in found when decoding object value");
+ }
+ }
+
+ ds->dec->releaseObject(newObj);
+ return SetError(ds, -1, "Unmatched '}' when decoding object");
+}
+
+FASTCALL_ATTR JSOBJ FASTCALL_MSVC decode_any(struct DecoderState *ds)
+{
+ while (1)
+ {
+ 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.dec = dec;
+ ds.dec->errorStr = NULL;
+ ds.dec->errorOffset = NULL;
+
+ ds.dec = dec;
+
+ ret = decode_any (&ds);
+
+ if (ds.escHeap)
+ {
+ dec->free(ds.escStart);
+ }
+ return ret;
+}
View
1,747 lib/ultrajsonenc.c
@@ -1,857 +1,890 @@
-/*
-Copyright (c) 2011, Jonas Tarnstrom and ESN Social Software AB
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-3. All advertising materials mentioning features or use of this software
- must display the following acknowledgement:
- This product includes software developed by ESN Social Software AB (www.esn.me).
-4. Neither the name of the ESN Social Software AB 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 ESN SOCIAL SOFTWARE AB ''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 ESN SOCIAL SOFTWARE AB 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.
-
-*/
-
-#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
-
-static const double g_pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
-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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24,
-/* 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, 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);
- }
- else
- {
- char *oldStart = enc->start;
- enc->heap = 1;
- enc->start = (char *) enc->malloc (newSize);
- 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 (JSOBJ obj, JSONObjectEncoder *enc, const char *io, const char *end)
-{
- char *of = (char *) enc->offset;
-
- while (1)
- {
- 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 '/': (*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 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++;
- }
-
- return FALSE;
-}
-
-
-/*
-FIXME:
-This code only works with Little and Big Endian
-
-FIXME: The JSON spec says escape "/" but non of the others do and we don't
-want to be left alone doing it so we don't :)
-
-*/
-int Buffer_EscapeStringValidated (JSOBJ obj, JSONObjectEncoder *enc, const char *io, const char *end)
-{
- JSUTF32 ucs;
- char *of = (char *) enc->offset;
-
- while (1)
- {
-
- //JSUINT8 chr = (unsigned char) *io;
- 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;
-
- if (io + 1 > end)
- {
- enc->offset += (of - enc->offset);
- SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
- return FALSE;
- }
-
- in = *((JSUTF16 *) io);
-
-#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;
-
- if (io + 2 > end)
- {
- enc->offset += (of - enc->offset);
- SetError (obj, enc, "Unterminated UTF-8 sequence when encoding string");
- return FALSE;
- }
-
-#ifdef __LITTLE_ENDIAN__
- in = *((JSUTF16 *) io);
- in |= *((JSUINT8 *) io + 2) << 16;
- ucs = ((in & 0x0f) << 12) | ((in & 0x3f00) >> 2) | ((in & 0x3f0000) >> 16);
-#else
- in = *((JSUTF16 *) io) << 8;
- in |= *((JSUINT8 *) io + 2);
- ucs = ((in & 0x0f0000) >> 4) | ((in & 0x3f00) >> 2) | (in & 0x3f);
-#endif