1
0
Fork 0
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:
Jonas Tärnström 2011-02-28 01:18:35 +01:00
parent f184c5744f
commit 46bd6170d4
7 changed files with 1579 additions and 0 deletions

20
msvc9/msvc9.sln Normal file
View File

@ -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

191
msvc9/msvc9.vcproj Normal file
View File

@ -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>

693
python/objToJSON.c Normal file
View File

@ -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;
}

15
python/setup.py Normal file
View File

@ -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"])])

21
python/ujson.c Normal file
View File

@ -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);
}

390
ultrajson.c Normal file
View File

@ -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;
}

249
ultrajson.h Normal file
View File

@ -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