mirror of
https://github.com/ultrajson/ultrajson.git
synced 2024-05-19 13:26:25 +02:00
- Initial commit for Windows
This commit is contained in:
parent
f184c5744f
commit
46bd6170d4
|
@ -0,0 +1,20 @@
|
|||

|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual Studio 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dll", "msvc9.vcproj", "{6C9C8F34-FA23-43CB-9405-E2FC0BD7BED6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{6C9C8F34-FA23-43CB-9405-E2FC0BD7BED6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{6C9C8F34-FA23-43CB-9405-E2FC0BD7BED6}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{6C9C8F34-FA23-43CB-9405-E2FC0BD7BED6}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{6C9C8F34-FA23-43CB-9405-E2FC0BD7BED6}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,191 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9,00"
|
||||
Name="libultrajson"
|
||||
ProjectGUID="{6C9C8F34-FA23-43CB-9405-E2FC0BD7BED6}"
|
||||
RootNamespace="msvc9"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MSVC9_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="4"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="2"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MSVC9_EXPORTS"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\ultrajson.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\ultrajson.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -0,0 +1,693 @@
|
|||
#include <Python.h>
|
||||
#include <datetime.h>
|
||||
#include "../ultrajson.h"
|
||||
|
||||
static PyObject* meth_timegm;
|
||||
static PyObject* mod_calendar;
|
||||
|
||||
enum PRIVATE
|
||||
{
|
||||
PRV_CONV_FUNC, // Function pointer to converter function
|
||||
PRV_CONV_NEWOBJ, // Any new PyObject created by converter function that should be released by releaseValue
|
||||
PRV_ITER_BEGIN_FUNC, // Function pointer to iterBegin for specific type
|
||||
PRV_ITER_END_FUNC, // Function pointer to iterEnd for specific type
|
||||
PRV_ITER_NEXT_FUNC, // Function pointer to iterNext for specific type
|
||||
PRV_ITER_GETVALUE_FUNC,
|
||||
PRV_ITER_GETNAME_FUNC,
|
||||
PRV_ITER_INDEX, // Index in the iteration list
|
||||
PRV_ITER_SIZE, // Size of the iteration list
|
||||
PRV_ITER_ITEM, // Current iter item
|
||||
PRV_ITER_ITEM_NAME, // Name of iter item
|
||||
PRV_ITER_ITEM_VALUE, // Value of iteritem
|
||||
PRV_ITER_DICTITEMS,
|
||||
PRV_ITER_DICTOBJ,
|
||||
PRV_ITER_ATTRLIST,
|
||||
};
|
||||
|
||||
struct PyDictIterState
|
||||
{
|
||||
PyObject *keys;
|
||||
size_t i;
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
|
||||
//#define PRINTMARK() fprintf(stderr, "%s: MARK(%d)\n", __FILE__, __LINE__)
|
||||
#define PRINTMARK()
|
||||
|
||||
void initObjToJSON()
|
||||
{
|
||||
//FIXME: DECREF on these?
|
||||
PyDateTime_IMPORT;
|
||||
|
||||
/*
|
||||
FIXME: Find the direct function pointer here instead and use it when time conversion is performed */
|
||||
|
||||
meth_timegm = PyString_FromString("timegm");
|
||||
mod_calendar = PyImport_ImportModule("calendar");
|
||||
|
||||
Py_INCREF(mod_calendar);
|
||||
|
||||
}
|
||||
|
||||
|
||||
typedef void *(*PFN_PyTypeToJSON)(JSOBJ obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen);
|
||||
|
||||
static void *PyNoneToNULL(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *PyBoolToBOOLEAN(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
//FIXME: Perhaps we can use the PyBoolObject->ival directly here?
|
||||
*((int *) outValue) = (obj == Py_True) ? 1 : 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *PyIntToINTEGER(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
*((JSLONG *) outValue) = PyInt_AS_LONG (obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *PyLongToINTEGER(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
*((JSLONG *) outValue) = PyLong_AsLongLong (obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *PyLongToUTF8(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
PyObject *newobj;
|
||||
char *ret;
|
||||
PRINTMARK();
|
||||
|
||||
|
||||
newobj = PyObject_Str(obj);
|
||||
|
||||
if (newobj)
|
||||
{
|
||||
ti->prv[PRV_CONV_NEWOBJ] = newobj;
|
||||
ti->release = 1;
|
||||
*_outLen = PyString_GET_SIZE(newobj);
|
||||
//fprintf (stderr, "%s: Object %p needs release!\n", __FUNCTION__, newobj);
|
||||
ret = PyString_AS_STRING(newobj);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = "";
|
||||
*_outLen = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *PyFloatToDOUBLE(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
*((double *) outValue) = PyFloat_AS_DOUBLE (obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *PyStringToUTF8(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
*_outLen = PyString_GET_SIZE(obj);
|
||||
return PyString_AS_STRING(obj);
|
||||
}
|
||||
|
||||
static void *PyUnicodeToUTF8(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
PyObject *newObj = PyUnicode_EncodeUTF8 (PyUnicode_AS_UNICODE(obj), PyUnicode_GET_SIZE(obj), NULL);
|
||||
ti->release = 1;
|
||||
ti->prv[PRV_CONV_NEWOBJ] = (void *) newObj;
|
||||
|
||||
*_outLen = PyString_GET_SIZE(newObj);
|
||||
return PyString_AS_STRING(newObj);
|
||||
}
|
||||
|
||||
static void *PyDateTimeToINTEGER(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
|
||||
PyObject* timetuple = PyObject_CallMethod(obj, "utctimetuple", NULL);
|
||||
PyObject* unixTimestamp = PyObject_CallMethodObjArgs(mod_calendar, meth_timegm, timetuple, NULL);
|
||||
|
||||
*( (JSLONG *) outValue) = PyLong_AsLongLong (unixTimestamp);
|
||||
Py_DECREF(timetuple);
|
||||
Py_DECREF(unixTimestamp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *PyDateToINTEGER(JSOBJ _obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
|
||||
PyObject* timetuple = PyTuple_New(6);
|
||||
PyObject* year = PyObject_GetAttrString(obj, "year");
|
||||
PyObject* month = PyObject_GetAttrString(obj, "month");
|
||||
PyObject* day = PyObject_GetAttrString(obj, "day");
|
||||
PyObject* unixTimestamp;
|
||||
|
||||
PyTuple_SET_ITEM(timetuple, 0, year);
|
||||
PyTuple_SET_ITEM(timetuple, 1, month);
|
||||
PyTuple_SET_ITEM(timetuple, 2, day);
|
||||
PyTuple_SET_ITEM(timetuple, 3, PyInt_FromLong(0));
|
||||
PyTuple_SET_ITEM(timetuple, 4, PyInt_FromLong(0));
|
||||
PyTuple_SET_ITEM(timetuple, 5, PyInt_FromLong(0));
|
||||
|
||||
unixTimestamp = PyObject_CallMethodObjArgs(mod_calendar, meth_timegm, timetuple, NULL);
|
||||
|
||||
*( (JSLONG *) outValue) = PyLong_AsLongLong (unixTimestamp);
|
||||
Py_DECREF(timetuple);
|
||||
Py_DECREF(unixTimestamp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Tuple iteration functions
|
||||
// itemValue is borrowed reference, no ref counting
|
||||
//=============================================================================
|
||||
void Tuple_iterBegin(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
ti->prv[PRV_ITER_INDEX] = (void *) 0;
|
||||
ti->prv[PRV_ITER_SIZE] = (void *) PyTuple_GET_SIZE( (PyObject *) obj);
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = NULL;
|
||||
}
|
||||
|
||||
int Tuple_iterNext(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
size_t i = (size_t) ti->prv[PRV_ITER_INDEX];
|
||||
size_t sz = (size_t) ti->prv[PRV_ITER_SIZE];
|
||||
PyObject *item;
|
||||
|
||||
if (i >= sz)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = PyTuple_GET_ITEM (obj, i);
|
||||
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = item;
|
||||
i ++;
|
||||
ti->prv[PRV_ITER_INDEX] = (void *) i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Tuple_iterEnd(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
}
|
||||
|
||||
JSOBJ Tuple_iterGetValue(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
PyObject *curr = (PyObject *) ti->prv[PRV_ITER_ITEM_VALUE];
|
||||
return curr;
|
||||
}
|
||||
|
||||
char *Tuple_iterGetName(JSOBJ obj, JSTYPEINFO *ti, size_t *outLen)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Dir iteration functions
|
||||
// itemName ref is borrowed from PyObject_Dir (attrList). No refcount
|
||||
// itemValue ref is from PyObject_GetAttr. Ref counted
|
||||
//=============================================================================
|
||||
void Dir_iterBegin(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
PyObject* attrList = PyObject_Dir(obj);
|
||||
ti->prv[PRV_ITER_INDEX] = (void *) 0;
|
||||
ti->prv[PRV_ITER_SIZE] = (void *) PyList_GET_SIZE(attrList);
|
||||
ti->prv[PRV_ITER_ITEM] = NULL;
|
||||
ti->prv[PRV_ITER_ITEM_NAME] = NULL;
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = NULL;
|
||||
ti->prv[PRV_ITER_ATTRLIST] = attrList;
|
||||
PRINTMARK();
|
||||
}
|
||||
|
||||
void Dir_iterEnd(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
PyObject *itemValue = (PyObject *) ti->prv[PRV_ITER_ITEM_VALUE];
|
||||
|
||||
if (itemValue)
|
||||
{
|
||||
Py_DECREF(itemValue);
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = itemValue = NULL;
|
||||
}
|
||||
|
||||
Py_DECREF( (PyObject *) ti->prv[PRV_ITER_ATTRLIST]);
|
||||
PRINTMARK();
|
||||
}
|
||||
|
||||
int Dir_iterNext(JSOBJ _obj, JSTYPEINFO *ti)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
size_t i = (size_t) ti->prv[PRV_ITER_INDEX];
|
||||
size_t sz = (size_t) ti->prv[PRV_ITER_SIZE];
|
||||
PyObject *attrList = (PyObject *) ti->prv[PRV_ITER_ATTRLIST];
|
||||
PyObject *itemName = NULL;
|
||||
PyObject *itemValue = (PyObject *) ti->prv[PRV_ITER_ITEM_VALUE];
|
||||
|
||||
if (itemValue)
|
||||
{
|
||||
Py_DECREF(itemValue);
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = itemValue = NULL;
|
||||
}
|
||||
|
||||
//fprintf (stderr, "%s: ti=%p obj=%p, i=%u, sz=%u\n", __FUNCTION__, ti, _obj, i, sz);
|
||||
|
||||
for (; i < sz; i ++)
|
||||
{
|
||||
PyObject* attr = PyList_GET_ITEM(attrList, i);
|
||||
char* attrStr = PyString_AS_STRING(attr);
|
||||
|
||||
if (attrStr[0] == '_')
|
||||
{
|
||||
PRINTMARK();
|
||||
continue;
|
||||
}
|
||||
|
||||
itemValue = PyObject_GetAttr(obj, attr);
|
||||
if (itemValue == NULL)
|
||||
{
|
||||
PyErr_Clear();
|
||||
PRINTMARK();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PyCallable_Check(itemValue))
|
||||
{
|
||||
Py_DECREF(itemValue);
|
||||
PRINTMARK();
|
||||
continue;
|
||||
}
|
||||
|
||||
PRINTMARK();
|
||||
itemName = attr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (itemName == NULL)
|
||||
{
|
||||
i = sz;
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ti->prv[PRV_ITER_ITEM_NAME] = itemName;
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = itemValue;
|
||||
ti->prv[PRV_ITER_INDEX] = (void *) (i + 1);
|
||||
PRINTMARK();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
JSOBJ Dir_iterGetValue(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
PRINTMARK();
|
||||
return (PyObject *) ti->prv[PRV_ITER_ITEM_VALUE];
|
||||
}
|
||||
|
||||
char *Dir_iterGetName(JSOBJ obj, JSTYPEINFO *ti, size_t *outLen)
|
||||
{
|
||||
PyObject *curr = (PyObject *) ti->prv[PRV_ITER_ITEM_NAME];
|
||||
PRINTMARK();
|
||||
*outLen = PyString_GET_SIZE(curr);
|
||||
return PyString_AS_STRING(curr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// List iteration functions
|
||||
// itemValue is borrowed from object (which is list). No refcounting
|
||||
//=============================================================================
|
||||
void List_iterBegin(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
ti->prv[PRV_ITER_INDEX] = (void *) 0;
|
||||
ti->prv[PRV_ITER_SIZE] = (void *) PyList_GET_SIZE( (PyObject *) obj);
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = NULL;
|
||||
}
|
||||
|
||||
int List_iterNext(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
size_t i = (size_t) ti->prv[PRV_ITER_INDEX];
|
||||
size_t sz = (size_t) ti->prv[PRV_ITER_SIZE];
|
||||
PyObject *item;
|
||||
|
||||
if (i >= sz)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = PyList_GET_ITEM (obj, i);
|
||||
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = item;
|
||||
i ++;
|
||||
ti->prv[PRV_ITER_INDEX] = (void *) i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void List_iterEnd(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
}
|
||||
|
||||
JSOBJ List_iterGetValue(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
return (PyObject *) ti->prv[PRV_ITER_ITEM_VALUE];
|
||||
}
|
||||
|
||||
char *List_iterGetName(JSOBJ obj, JSTYPEINFO *ti, 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
|
||||
//=============================================================================
|
||||
void Dict_iterBegin(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
ti->prv[PRV_ITER_INDEX] = (void *) 0;
|
||||
ti->prv[PRV_ITER_ITEM_NAME] = NULL;
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = NULL;
|
||||
PRINTMARK();
|
||||
}
|
||||
|
||||
int Dict_iterNext(JSOBJ _obj, JSTYPEINFO *ti)
|
||||
{
|
||||
size_t i = (size_t) ti->prv[PRV_ITER_INDEX];
|
||||
PyObject *obj = (PyObject *) ti->prv[PRV_ITER_DICTOBJ];
|
||||
PyObject *itemName = (PyObject *) ti->prv[PRV_ITER_ITEM_NAME];
|
||||
PyObject *itemValue;
|
||||
|
||||
//fprintf (stderr, "%s: ti=%p obj=%p, i=%u, sz=%u\n", __FUNCTION__, ti, _obj, i, sz);
|
||||
if (itemName)
|
||||
{
|
||||
Py_DECREF(itemName);
|
||||
ti->prv[PRV_ITER_ITEM_NAME] = itemName = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (!PyDict_Next (obj, &((size_t) ti->prv[PRV_ITER_INDEX]), &itemName, &itemValue))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!PyString_Check(itemName))
|
||||
itemName = PyObject_Str(itemName);
|
||||
else
|
||||
Py_INCREF(itemName);
|
||||
|
||||
ti->prv[PRV_ITER_ITEM_NAME] = itemName;
|
||||
ti->prv[PRV_ITER_ITEM_VALUE] = itemValue;
|
||||
|
||||
PRINTMARK();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Dict_iterEnd(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
PyObject *itemName = (PyObject *) ti->prv[PRV_ITER_ITEM_NAME];
|
||||
|
||||
if (itemName)
|
||||
{
|
||||
Py_DECREF(itemName);
|
||||
ti->prv[PRV_ITER_ITEM_NAME] = itemName = NULL;
|
||||
}
|
||||
Py_DECREF( (PyObject *) ti->prv[PRV_ITER_DICTOBJ]);
|
||||
PRINTMARK();
|
||||
}
|
||||
|
||||
JSOBJ Dict_iterGetValue(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
return (PyObject *) ti->prv[PRV_ITER_ITEM_VALUE];
|
||||
}
|
||||
|
||||
char *Dict_iterGetName(JSOBJ obj, JSTYPEINFO *ti, size_t *outLen)
|
||||
{
|
||||
PyObject *curr = (PyObject *) ti->prv[PRV_ITER_ITEM_NAME];
|
||||
*outLen = PyString_GET_SIZE(curr);
|
||||
return PyString_AS_STRING(curr);
|
||||
}
|
||||
|
||||
|
||||
static void Object_getType(JSOBJ _obj, JSTYPEINFO *ti)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
PyObject *toDictFunc;
|
||||
|
||||
if (PyIter_Check(obj))
|
||||
{
|
||||
goto ISITERABLE;
|
||||
}
|
||||
|
||||
if (PyInt_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = (void *) PyIntToINTEGER; ti->type = JT_INTEGER;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (PyLong_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = (void *) PyLongToINTEGER; ti->type = JT_INTEGER;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (PyString_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = (void *) PyStringToUTF8; ti->type = JT_UTF8;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (PyUnicode_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = (void *) PyUnicodeToUTF8; ti->type = JT_UTF8;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (PyBool_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = NULL;
|
||||
ti->type = (obj == Py_True) ? JT_TRUE : JT_FALSE;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (PyFloat_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = (void *) PyFloatToDOUBLE; ti->type = JT_DOUBLE;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (PyDateTime_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = (void *) PyDateTimeToINTEGER; ti->type = JT_INTEGER;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (PyDate_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = (void *) PyDateToINTEGER; ti->type = JT_INTEGER;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (obj == Py_None)
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = NULL; ti->type = JT_NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ISITERABLE:
|
||||
|
||||
if (PyDict_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = NULL; ti->type = JT_OBJECT;
|
||||
ti->prv[PRV_ITER_BEGIN_FUNC] = Dict_iterBegin;
|
||||
ti->prv[PRV_ITER_END_FUNC] = Dict_iterEnd;
|
||||
ti->prv[PRV_ITER_NEXT_FUNC] = Dict_iterNext;
|
||||
ti->prv[PRV_ITER_GETVALUE_FUNC] = Dict_iterGetValue;
|
||||
ti->prv[PRV_ITER_GETNAME_FUNC] = Dict_iterGetName;
|
||||
ti->prv[PRV_ITER_DICTOBJ] = obj;
|
||||
Py_INCREF(obj);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (PyList_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = NULL; ti->type = JT_ARRAY;
|
||||
ti->prv[PRV_ITER_BEGIN_FUNC] = List_iterBegin;
|
||||
ti->prv[PRV_ITER_END_FUNC] = List_iterEnd;
|
||||
ti->prv[PRV_ITER_NEXT_FUNC] = List_iterNext;
|
||||
ti->prv[PRV_ITER_GETVALUE_FUNC] = List_iterGetValue;
|
||||
ti->prv[PRV_ITER_GETNAME_FUNC] = List_iterGetName;
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (PyTuple_Check(obj))
|
||||
{
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = NULL; ti->type = JT_ARRAY;
|
||||
ti->prv[PRV_ITER_BEGIN_FUNC] = Tuple_iterBegin;
|
||||
ti->prv[PRV_ITER_END_FUNC] = Tuple_iterEnd;
|
||||
ti->prv[PRV_ITER_NEXT_FUNC] = Tuple_iterNext;
|
||||
ti->prv[PRV_ITER_GETVALUE_FUNC] = Tuple_iterGetValue;
|
||||
ti->prv[PRV_ITER_GETNAME_FUNC] = Tuple_iterGetName;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
toDictFunc = PyObject_GetAttrString(obj, "toDict");
|
||||
|
||||
if (toDictFunc)
|
||||
{
|
||||
PyObject* tuple = PyTuple_New(0);
|
||||
PyObject* toDictResult = PyObject_Call(toDictFunc, tuple, NULL);
|
||||
Py_DECREF(tuple);
|
||||
Py_DECREF(toDictFunc);
|
||||
|
||||
if (toDictResult == NULL)
|
||||
{
|
||||
PyErr_Clear();
|
||||
ti->prv[PRV_CONV_FUNC] = NULL; ti->type = JT_NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PyDict_Check(toDictResult))
|
||||
{
|
||||
Py_DECREF(toDictResult);
|
||||
ti->prv[PRV_CONV_FUNC] = NULL; ti->type = JT_NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
PRINTMARK();
|
||||
ti->prv[PRV_CONV_FUNC] = NULL; ti->type = JT_OBJECT;
|
||||
ti->prv[PRV_ITER_BEGIN_FUNC] = Dict_iterBegin;
|
||||
ti->prv[PRV_ITER_END_FUNC] = Dict_iterEnd;
|
||||
ti->prv[PRV_ITER_NEXT_FUNC] = Dict_iterNext;
|
||||
ti->prv[PRV_ITER_GETVALUE_FUNC] = Dict_iterGetValue;
|
||||
ti->prv[PRV_ITER_GETNAME_FUNC] = Dict_iterGetName;
|
||||
ti->prv[PRV_ITER_DICTOBJ] = toDictResult;
|
||||
return;
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
|
||||
ti->prv[PRV_CONV_FUNC] = NULL; ti->type = JT_OBJECT;
|
||||
ti->prv[PRV_ITER_BEGIN_FUNC] = Dir_iterBegin;
|
||||
ti->prv[PRV_ITER_END_FUNC] = Dir_iterEnd;
|
||||
ti->prv[PRV_ITER_NEXT_FUNC] = Dir_iterNext;
|
||||
ti->prv[PRV_ITER_GETVALUE_FUNC] = Dir_iterGetValue;
|
||||
ti->prv[PRV_ITER_GETNAME_FUNC] = Dir_iterGetName;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void *Object_getValue(JSOBJ obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen)
|
||||
{
|
||||
void *ret;
|
||||
PFN_PyTypeToJSON pfnFunc = (PFN_PyTypeToJSON) ti->prv[PRV_CONV_FUNC];
|
||||
PRINTMARK();
|
||||
ret = pfnFunc (obj, ti, outValue, _outLen);
|
||||
PRINTMARK();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Object_releaseObject(JSOBJ *_obj)
|
||||
{
|
||||
PyObject *obj = (PyObject *) _obj;
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
|
||||
void Object_releaseValue(JSTYPEINFO *ti)
|
||||
{
|
||||
PyObject *obj = (PyObject *) ti->prv[PRV_CONV_NEWOBJ];
|
||||
//fprintf (stderr, "%s: Object %p was released!\n", __FUNCTION__, obj);
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
|
||||
void Object_iterBegin(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
JSPFN_ITERBEGIN pfnFunc = (JSPFN_ITERBEGIN) ti->prv[PRV_ITER_BEGIN_FUNC];
|
||||
pfnFunc (obj, ti);
|
||||
}
|
||||
|
||||
int Object_iterNext(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
JSPFN_ITERNEXT pfnFunc = (JSPFN_ITERNEXT) ti->prv[PRV_ITER_NEXT_FUNC];
|
||||
return pfnFunc (obj, ti);
|
||||
}
|
||||
|
||||
void Object_iterEnd(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
JSPFN_ITEREND pfnFunc = (JSPFN_ITEREND) ti->prv[PRV_ITER_END_FUNC];
|
||||
pfnFunc (obj, ti);
|
||||
}
|
||||
|
||||
JSOBJ Object_iterGetValue(JSOBJ obj, JSTYPEINFO *ti)
|
||||
{
|
||||
JSPFN_ITERGETVALUE pfnFunc = (JSPFN_ITERGETVALUE) ti->prv[PRV_ITER_GETVALUE_FUNC];
|
||||
return pfnFunc (obj, ti);
|
||||
}
|
||||
|
||||
char *Object_iterGetName(JSOBJ obj, JSTYPEINFO *ti, size_t *outLen)
|
||||
{
|
||||
JSPFN_ITERGETNAME pfnFunc = (JSPFN_ITERGETNAME) ti->prv[PRV_ITER_GETNAME_FUNC];
|
||||
return pfnFunc (obj, ti, outLen);
|
||||
}
|
||||
|
||||
|
||||
static JSONObjectEncoder g_encState =
|
||||
{
|
||||
Object_getType, //void (*getType)(JSOBJ obj, JSTYPEINFO *ti);
|
||||
Object_getValue, //void *(*getValue)(JSOBJ obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen);
|
||||
Object_iterBegin, //JSPFN_ITERBEGIN iterBegin;
|
||||
Object_iterNext, //JSPFN_ITERNEXT iterNext;
|
||||
Object_iterEnd, //JSPFN_ITEREND iterEnd;
|
||||
Object_iterGetValue, //JSPFN_ITERGETVALUE iterGetValue;
|
||||
Object_iterGetName, //JSPFN_ITERGETNAME iterGetName;
|
||||
Object_releaseValue, //void (*releaseValue)(JSTYPEINFO *ti);
|
||||
PyObject_Malloc, //JSPFN_MALLOC malloc;
|
||||
PyObject_Realloc, //JSPFN_REALLOC realloc;
|
||||
PyObject_Free//JSPFN_FREE free;
|
||||
};
|
||||
|
||||
|
||||
PyObject* objToJSON(PyObject* self, PyObject *arg)
|
||||
{
|
||||
char buffer[65536];
|
||||
char *ret;
|
||||
PyObject *newobj;
|
||||
|
||||
//FIXME: Add support for max recursion to eliminiate OOM scenario on cyclic references
|
||||
ret = JSON_EncodeObject (arg, &g_encState, buffer, sizeof (buffer));
|
||||
newobj = PyString_FromString (ret);
|
||||
|
||||
if (ret != buffer)
|
||||
{
|
||||
g_encState.free (ret);
|
||||
}
|
||||
|
||||
return newobj;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
from distutils.core import setup, Extension
|
||||
import distutils.sysconfig
|
||||
|
||||
module1 = Extension('ujson',
|
||||
sources = ['ujson.c', 'objToJSON.c'],
|
||||
include_dirs = ['../'],
|
||||
library_dirs = ['./lib/'],
|
||||
libraries=['libultrajson'])
|
||||
|
||||
setup (name = 'ujson',
|
||||
version = '1.0',
|
||||
description = 'UltraJSON',
|
||||
ext_modules = [module1],
|
||||
data_files = [(distutils.sysconfig.get_python_lib(), ["./lib/libultrajson.dll"])])
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#include <Python.h>
|
||||
|
||||
/* objToJSON */
|
||||
PyObject* objToJSON(PyObject* self, PyObject *arg);
|
||||
void initObjToJSON();
|
||||
|
||||
|
||||
static PyMethodDef ujsonMethods[] = {
|
||||
{"encode", objToJSON, METH_O, "Converts arbitrary object recursivly into JSON as string"},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
|
||||
PyMODINIT_FUNC
|
||||
initujson(void)
|
||||
{
|
||||
initObjToJSON();
|
||||
Py_InitModule("ujson", ujsonMethods);
|
||||
|
||||
}
|
|
@ -0,0 +1,390 @@
|
|||
/*
|
||||
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 SHALLESN 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.
|
||||
*/
|
||||
|
||||
#include "ultrajson.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define INLINEFUNCTION __inline
|
||||
#else
|
||||
#error "Fix inline definition for non MSVC"
|
||||
#endif
|
||||
|
||||
typedef struct _Buffer
|
||||
{
|
||||
char *start;
|
||||
char *offset;
|
||||
char *end;
|
||||
int heap;
|
||||
JSPFN_MALLOC malloc;
|
||||
JSPFN_REALLOC realloc;
|
||||
JSPFN_FREE free;
|
||||
|
||||
} Buffer;
|
||||
|
||||
static void Buffer_Realloc (Buffer *buffer);
|
||||
|
||||
#define FastMemCopy memcpy
|
||||
|
||||
#define Buffer_AppendEscape(__buffer, __pstr, __len) \
|
||||
while ((__buffer)->offset + ((__len * 2) + 2) > (__buffer)->end) \
|
||||
{ \
|
||||
Buffer_Realloc((__buffer)); \
|
||||
} \
|
||||
*((__buffer)->offset++) = '\"'; \
|
||||
Buffer_Escape((__buffer), (char *)__pstr, __len); \
|
||||
*((__buffer)->offset++) = '\"';
|
||||
|
||||
#define Buffer_AppendEscapeUnchecked(__buffer, __pstr, __len) \
|
||||
*((__buffer)->offset++) = '\"'; \
|
||||
Buffer_Escape((__buffer), (char *)__pstr, __len); \
|
||||
*((__buffer)->offset++) = '\"';
|
||||
|
||||
|
||||
#define Buffer_Append(__buffer, __pstr, __len) \
|
||||
while ((__buffer)->offset + __len > (__buffer)->end) \
|
||||
{ \
|
||||
Buffer_Realloc((__buffer)); \
|
||||
} \
|
||||
FastMemCopy ((__buffer)->offset, __pstr, __len); \
|
||||
(__buffer)->offset += __len;
|
||||
|
||||
#define Buffer_AppendUnchecked(__buffer, __pstr, __len) \
|
||||
FastMemCopy ((__buffer)->offset, __pstr, __len); \
|
||||
(__buffer)->offset += __len;
|
||||
|
||||
|
||||
#define Buffer_AppendCharUnchecked(__buffer, __chr) \
|
||||
*((__buffer)->offset++) = __chr; \
|
||||
|
||||
#define Buffer_Reserve(__buffer, __len) \
|
||||
while ((__buffer)->offset + (__len) > (__buffer)->end) \
|
||||
{ \
|
||||
Buffer_Realloc((__buffer)); \
|
||||
} \
|
||||
|
||||
INLINEFUNCTION static void strreverse(char* begin, char* end)
|
||||
{
|
||||
char aux;
|
||||
while (end > begin)
|
||||
aux = *end, *end-- = *begin, *begin++ = aux;
|
||||
}
|
||||
|
||||
INLINEFUNCTION void Buffer_AppendIntUnchecked(Buffer *buffer, JSLONG value)
|
||||
{
|
||||
char* wstr;
|
||||
JSULONG uvalue = (value < 0) ? -value : value;
|
||||
|
||||
// Reserve space
|
||||
//FIXME: 33 seems a bit magic?
|
||||
/*
|
||||
while(buffer->offset + 33 > buffer->end)
|
||||
{
|
||||
Buffer_Realloc(buffer);
|
||||
}*/
|
||||
|
||||
wstr = buffer->offset;
|
||||
|
||||
|
||||
// Conversion. Number is reversed.
|
||||
do *wstr++ = (char)(48 + (uvalue % 10)); while(uvalue /= 10);
|
||||
if (value < 0) *wstr++ = '-';
|
||||
|
||||
// Reverse string
|
||||
strreverse(buffer->offset,wstr - 1);
|
||||
buffer->offset += (wstr - 1 - (buffer->offset));
|
||||
}
|
||||
|
||||
|
||||
|
||||
INLINEFUNCTION void Buffer_AppendDoubleUnchecked(Buffer *buffer, double fp)
|
||||
{
|
||||
char intPart_reversed[64];
|
||||
int i, charCount = 0;
|
||||
double fp_int, fp_frac;
|
||||
|
||||
fp_frac = modf(fp,&fp_int); //Separate integer/fractional parts
|
||||
|
||||
while (fp_int > 0) //Convert integer part, if any
|
||||
{
|
||||
intPart_reversed[charCount++] = '0' + (int)fmod(fp_int,10.0);
|
||||
fp_int = floor(fp_int/10.0);
|
||||
}
|
||||
|
||||
for (i=0; i<charCount; i++) //Reverse the integer part, if any
|
||||
*(buffer->offset++) = intPart_reversed[charCount-i-1];
|
||||
|
||||
*(buffer->offset++) = '.'; //Decimal point
|
||||
|
||||
i = 0;
|
||||
|
||||
while (fp_frac > 0 && i < JSON_DOUBLE_MAX_DECIMALS) //Convert fractional part, if any
|
||||
{
|
||||
fp_frac*=10;
|
||||
fp_frac = modf(fp_frac,&fp_int);
|
||||
*(buffer->offset++) = '0' + (int)fp_int;
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
|
||||
static void Buffer_Realloc (Buffer *buffer)
|
||||
{
|
||||
size_t newSize = buffer->end - buffer->start;
|
||||
size_t offset = buffer->offset - buffer->start;
|
||||
newSize *= 2;
|
||||
|
||||
if (buffer->heap)
|
||||
{
|
||||
buffer->start = (char *) buffer->realloc (buffer->start, newSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *oldStart = buffer->start;
|
||||
buffer->heap = 1;
|
||||
buffer->start = (char *) buffer->malloc (newSize);
|
||||
memcpy (buffer->start, oldStart, offset);
|
||||
}
|
||||
buffer->offset = buffer->start + offset;
|
||||
buffer->end = buffer->start + newSize;
|
||||
|
||||
}
|
||||
|
||||
static char g_escapeLookup[] = {
|
||||
/* 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f */
|
||||
/* 0x00 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 'b', 't', 'n', '\0', 'f', 'r', '\0', '\0',
|
||||
/* 0x10 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0x20 */ '\0', '\0', '\"', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0x30 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0x40 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0x50 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\\', '\0', '\0', '\0',
|
||||
/* 0x60 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0x70 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0x80 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0x90 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0xa0 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0xb0 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0xc0 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0xd0 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
/* 0xe0 */ '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
|
||||
};
|
||||
|
||||
static void Buffer_Escape (Buffer *buffer, char *inputOffset, size_t len)
|
||||
{
|
||||
char *inputEnd = inputOffset + len;
|
||||
char output;
|
||||
|
||||
while (inputOffset < inputEnd)
|
||||
{
|
||||
output = g_escapeLookup[(unsigned char) *(inputOffset)];
|
||||
|
||||
if (output == '\0')
|
||||
{
|
||||
*(buffer->offset++) = *(inputOffset++);
|
||||
}
|
||||
else
|
||||
{
|
||||
*(buffer->offset++) = '\\';
|
||||
*(buffer->offset++) = output;
|
||||
inputOffset ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void encode(char *_name, size_t _cbName, int level, JSOBJ obj, JSONObjectEncoder *def, Buffer *buffer, int insideList)
|
||||
{
|
||||
JSTYPEINFO ti;
|
||||
size_t szlen;
|
||||
const char *name = (insideList || level == 0) ? NULL : _name;
|
||||
|
||||
Buffer_Reserve(buffer, 100 + (_cbName * 2));
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
Buffer_AppendEscapeUnchecked (buffer, name, _cbName);
|
||||
Buffer_AppendCharUnchecked (buffer, ':');
|
||||
Buffer_AppendCharUnchecked (buffer, ' ');
|
||||
}
|
||||
|
||||
ti.release = 0;
|
||||
def->getType(obj, &ti);
|
||||
|
||||
switch (ti.type)
|
||||
{
|
||||
case JT_ARRAY:
|
||||
{
|
||||
int count = 0;
|
||||
JSOBJ iterObj;
|
||||
def->iterBegin(obj, &ti);
|
||||
|
||||
Buffer_AppendCharUnchecked (buffer, '[');
|
||||
|
||||
while (def->iterNext(obj, &ti))
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
Buffer_AppendCharUnchecked (buffer, ',');
|
||||
Buffer_AppendCharUnchecked (buffer, ' ');
|
||||
}
|
||||
|
||||
iterObj = def->iterGetValue(obj, &ti);
|
||||
encode (NULL, 0, level + 1, iterObj, def, buffer, 1);
|
||||
count ++;
|
||||
}
|
||||
|
||||
def->iterEnd(obj, &ti);
|
||||
Buffer_AppendCharUnchecked (buffer, ']');
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_OBJECT:
|
||||
{
|
||||
int count = 0;
|
||||
JSOBJ iterObj;
|
||||
char *objName;
|
||||
def->iterBegin(obj, &ti);
|
||||
|
||||
Buffer_AppendCharUnchecked (buffer, '{');
|
||||
|
||||
while (def->iterNext(obj, &ti))
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
Buffer_AppendCharUnchecked (buffer, ',');
|
||||
Buffer_AppendCharUnchecked (buffer, ' ');
|
||||
}
|
||||
|
||||
iterObj = def->iterGetValue(obj, &ti);
|
||||
objName = def->iterGetName(obj, &ti, &szlen);
|
||||
|
||||
encode (objName, szlen, level + 1, iterObj, def, buffer, 0);
|
||||
count ++;
|
||||
}
|
||||
|
||||
def->iterEnd(obj, &ti);
|
||||
Buffer_AppendCharUnchecked (buffer, '}');
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_INTEGER:
|
||||
{
|
||||
JSLONG value;
|
||||
def->getValue(obj, &ti, &value, &szlen);
|
||||
Buffer_AppendIntUnchecked (buffer, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_TRUE:
|
||||
{
|
||||
//Buffer_AppendUnchecked (buffer, "true", 4);
|
||||
Buffer_AppendCharUnchecked (buffer, 't');
|
||||
Buffer_AppendCharUnchecked (buffer, 'r');
|
||||
Buffer_AppendCharUnchecked (buffer, 'u');
|
||||
Buffer_AppendCharUnchecked (buffer, 'e');
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_FALSE:
|
||||
{
|
||||
//Buffer_AppendUnchecked (buffer, "false", 5);
|
||||
Buffer_AppendCharUnchecked (buffer, 'f');
|
||||
Buffer_AppendCharUnchecked (buffer, 'a');
|
||||
Buffer_AppendCharUnchecked (buffer, 'l');
|
||||
Buffer_AppendCharUnchecked (buffer, 's');
|
||||
Buffer_AppendCharUnchecked (buffer, 'e');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case JT_NULL:
|
||||
{
|
||||
//Buffer_AppendUnchecked(buffer, "null", 4);
|
||||
Buffer_AppendCharUnchecked (buffer, 'n');
|
||||
Buffer_AppendCharUnchecked (buffer, 'u');
|
||||
Buffer_AppendCharUnchecked (buffer, 'l');
|
||||
Buffer_AppendCharUnchecked (buffer, 'l');
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_DOUBLE:
|
||||
{
|
||||
double value;
|
||||
def->getValue(obj, &ti, &value, &szlen);
|
||||
Buffer_AppendDoubleUnchecked (buffer, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case JT_UTF8:
|
||||
{
|
||||
char *value;
|
||||
value = (char *) def->getValue(obj, &ti, &value, &szlen);
|
||||
Buffer_AppendEscape(buffer, value, szlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ti.release)
|
||||
{
|
||||
def->releaseValue(&ti);
|
||||
}
|
||||
}
|
||||
|
||||
char *JSON_EncodeObject(JSOBJ obj, JSONObjectEncoder *def, char *_buffer, size_t _cbBuffer)
|
||||
{
|
||||
Buffer buffer;
|
||||
|
||||
buffer.malloc = def->malloc ? def->malloc : malloc;
|
||||
buffer.free = def->free ? def->free : free;
|
||||
buffer.realloc = def->realloc ? def->realloc : realloc;
|
||||
|
||||
if (_buffer == NULL)
|
||||
{
|
||||
_cbBuffer = 32768;
|
||||
buffer.start = (char *) buffer.malloc (_cbBuffer);
|
||||
buffer.heap = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.start = _buffer;
|
||||
buffer.heap = 0;
|
||||
}
|
||||
|
||||
buffer.end = buffer.start + _cbBuffer;
|
||||
buffer.offset = buffer.start;
|
||||
|
||||
encode(NULL, 0, 0, obj, def, &buffer, 0);
|
||||
|
||||
Buffer_Append(&buffer, "\0", 1);
|
||||
//return buffer.start;
|
||||
return buffer.start;
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
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 SHALLESN 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Ultra fast JSON encoder
|
||||
Developed by Jonas Tärnström (jonas@esn.me).
|
||||
|
||||
Notes:
|
||||
|
||||
:: Float poing valus ::
|
||||
All floating point values are converted as doubles using an optimized algorithm which is close but not entirely IEEE complaint.
|
||||
Known issues with floating point to string conversion:
|
||||
x) NaN, -Inf or Inf are not supported
|
||||
x) Exponents are not supported
|
||||
x) Max 10 decimals are converted
|
||||
x) Result might differ in general from IEEE complaint conversion
|
||||
|
||||
:: Strings ::
|
||||
Characters are assumed to be 1 octet and be ASCII < 127. This makes ISO-8859-* or UTF8 suitable as input data.
|
||||
|
||||
The following characters are escaped:
|
||||
\"
|
||||
\\
|
||||
\/
|
||||
\b
|
||||
\f
|
||||
\n
|
||||
\r
|
||||
\t
|
||||
|
||||
All other characters are accepted making control characters harmful if present in the string octet stream.
|
||||
The JSON '\uXXXX' conversion is not implemented
|
||||
|
||||
:: Integers ::
|
||||
All integers are converted as signed 64-bit. See JSLONG
|
||||
|
||||
How to implement:
|
||||
|
||||
1. Add ultrajson.c and ultrajson.h to your project or makefile
|
||||
2. Fill out JSONObjectEncoder
|
||||
3. Call JSON_EncodeObject with root object and a suitable buffer size
|
||||
|
||||
Encoding in details:
|
||||
|
||||
1. encode(obj):
|
||||
1. call getType(obj)
|
||||
2. if JT_ARRAY:
|
||||
call iterBegin
|
||||
while iterNext
|
||||
call iterGetValue
|
||||
call encode(value)
|
||||
if ti->release is 1:
|
||||
call releaseValue
|
||||
call iterEnd
|
||||
|
||||
3. if JT_OBJECT:
|
||||
call iterBegin
|
||||
while iterNext
|
||||
call iterGetName
|
||||
call iterGetValue
|
||||
call encode (value, name)
|
||||
call iterEnd
|
||||
|
||||
4. if JT_*:
|
||||
call getValue
|
||||
writeOutput
|
||||
|
||||
5. if ti->release is 1:
|
||||
call releaseValue
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __ULTRAJSON_H__
|
||||
#define __ULTRAJSON_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef JSON_DOUBLE_MAX_DECIMALS
|
||||
#define JSON_DOUBLE_MAX_DECIMALS 10
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef __int64 JSLONG;
|
||||
typedef unsigned __int64 JSULONG;
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
typedef int64_t JSLONG;
|
||||
typedef u_int64_t JSULONG;
|
||||
#endif
|
||||
|
||||
enum JSTYPES
|
||||
{
|
||||
JT_NULL, // NULL
|
||||
JT_TRUE, //boolean true
|
||||
JT_FALSE, //boolean false
|
||||
JT_INTEGER, //(JSLONG (signed 64-bit))
|
||||
JT_DOUBLE, //(double)
|
||||
JT_UTF8, //(char)
|
||||
JT_ARRAY, // Array structure
|
||||
JT_OBJECT, // Key/Value structure
|
||||
};
|
||||
|
||||
typedef void * JSOBJ;
|
||||
typedef void * JSITER;
|
||||
|
||||
typedef struct __JSTYPEINFO
|
||||
{
|
||||
// If release=1, the releaseValue function will be called with the JSTYPEINFO as argument
|
||||
int release;
|
||||
// Type of value see JSTYPES
|
||||
int type;
|
||||
// Private fields to be used by the implementor for state keeping, life cycle etc
|
||||
void *prv[32];
|
||||
} JSTYPEINFO;
|
||||
|
||||
/*
|
||||
Function pointer declarations, suitable for implementing Ultra JSON */
|
||||
typedef void (*JSPFN_ITERBEGIN)(JSOBJ obj, JSTYPEINFO *ti);
|
||||
typedef int (*JSPFN_ITERNEXT)(JSOBJ obj, JSTYPEINFO *ti);
|
||||
typedef void (*JSPFN_ITEREND)(JSOBJ obj, JSTYPEINFO *ti);
|
||||
typedef JSOBJ (*JSPFN_ITERGETVALUE)(JSOBJ obj, JSTYPEINFO *ti);
|
||||
typedef char *(*JSPFN_ITERGETNAME)(JSOBJ obj, JSTYPEINFO *ti, 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
|
||||
{
|
||||
/*
|
||||
Return type of object as JSTYPES enum
|
||||
Implementors should setup necessary pointers or state in ti->prv
|
||||
*/
|
||||
void (*getType)(JSOBJ obj, JSTYPEINFO *ti);
|
||||
|
||||
/*
|
||||
Get value of object of a specific type
|
||||
|
||||
JT_NULL : getValue is never called for this type
|
||||
JT_TRUE : getValue is never called for this type
|
||||
JT_FALSE : getValue is never called for this type
|
||||
JT_ARRAY : getValue is never called for this type
|
||||
JT_OBJECT : getValue is never called for this type
|
||||
JT_INTEGER, : return NULL, outValue points to a "JSLONG" (64-bit signed), _outLen is ignored
|
||||
JT_DOUBLE, : return NULL, outValue points to a "double", _outLen is ignored
|
||||
JT_BOOLEAN, : return NULL, outValue points to an "int", _outLen is ignored
|
||||
|
||||
JT_UTF8, :
|
||||
return pointer to the string buffer
|
||||
outValue is ignored
|
||||
set _outLen to length of returned string buffer (in bytes without trailing '\0')
|
||||
|
||||
If it's required that returned resources are freed or released, set ti->release to 1 and releaseValue will be called with JSTYPEINFO as argument.
|
||||
Use ti->prv fields to store state for this
|
||||
*/
|
||||
void *(*getValue)(JSOBJ obj, JSTYPEINFO *ti, void *outValue, size_t *_outLen);
|
||||
|
||||
/*
|
||||
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 (*releaseValue)(JSTYPEINFO *ti);
|
||||
|
||||
/* Library functions
|
||||
Set to NULL to use STDLIB malloc,realloc,free */
|
||||
JSPFN_MALLOC malloc;
|
||||
JSPFN_REALLOC realloc;
|
||||
JSPFN_FREE free;
|
||||
|
||||
} JSONObjectEncoder;
|
||||
|
||||
/*
|
||||
Encode an object structure into JSON.
|
||||
|
||||
Arguments:
|
||||
obj - An anonymous type representing the object
|
||||
def - 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.
|
||||
*/
|
||||
__declspec(dllexport) char *JSON_EncodeObject(JSOBJ obj, JSONObjectEncoder *def, char *buffer, size_t cbBuffer);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue