diff options
author | Omar Kilani <omar@php.net> | 2005-12-06 06:23:24 +0000 |
---|---|---|
committer | Omar Kilani <omar@php.net> | 2005-12-06 06:23:24 +0000 |
commit | f54496cd39847bb831cd9eab8e8495d8ca85ce25 (patch) | |
tree | f26f1fba63d14e3688e53978d775d349caf6e306 | |
parent | a4861d1512f8f0e0512963f82640914fb3e4196b (diff) | |
download | php-git-f54496cd39847bb831cd9eab8e8495d8ca85ce25.tar.gz |
Add json extension to PECL.
32 files changed, 4433 insertions, 0 deletions
diff --git a/ext/json/config.m4 b/ext/json/config.m4 new file mode 100644 index 0000000000..4dae05bd75 --- /dev/null +++ b/ext/json/config.m4 @@ -0,0 +1,105 @@ +dnl +dnl $Id$ +dnl + +AC_DEFUN([PHP_JSON_ADD_SOURCES], [ + PHP_JSON_SOURCES="$PHP_JSON_SOURCES $1" +]) + +AC_DEFUN([PHP_JSON_ADD_BASE_SOURCES], [ + PHP_JSON_BASE_SOURCES="$PHP_JSON_BASE_SOURCES $1" +]) + +AC_DEFUN([PHP_JSON_ADD_BUILD_DIR], [ + PHP_JSON_EXTRA_BUILD_DIRS="$PHP_JSON_EXTRA_BUILD_DIRS $1" +]) + +AC_DEFUN([PHP_JSON_ADD_INCLUDE], [ + PHP_JSON_EXTRA_INCLUDES="$PHP_JSON_EXTRA_INCLUDES $1" +]) + +AC_DEFUN([PHP_JSON_ADD_CONFIG_HEADER], [ + PHP_JSON_EXTRA_CONFIG_HEADERS="$PHP_JSON_EXTRA_CONFIG_HEADERS $1" +]) + +AC_DEFUN([PHP_JSON_ADD_CFLAG], [ + PHP_JSON_CFLAGS="$PHP_JSON_CFLAGS $1" +]) + +AC_DEFUN([PHP_JSON_EXTENSION], [ + PHP_NEW_EXTENSION(json, $PHP_JSON_SOURCES, $ext_shared,, $PHP_JSON_CFLAGS) + PHP_SUBST(JSON_SHARED_LIBADD) + + for dir in $PHP_JSON_EXTRA_BUILD_DIRS; do + PHP_ADD_BUILD_DIR([$ext_builddir/$dir], 1) + done + + for dir in $PHP_JSON_EXTRA_INCLUDES; do + PHP_ADD_INCLUDE([$ext_srcdir/$dir]) + PHP_ADD_INCLUDE([$ext_builddir/$dir]) + done + + if test "$ext_shared" = "no"; then + PHP_ADD_SOURCES(PHP_EXT_DIR(json), $PHP_JSON_BASE_SOURCES,$PHP_JSON_CFLAGS) + out="php_config.h" + else + PHP_ADD_SOURCES_X(PHP_EXT_DIR(json),$PHP_JSON_BASE_SOURCES,$PHP_JSON_CFLAGS,shared_objects_json,yes) + if test -f "$ext_builddir/config.h.in"; then + out="$abs_builddir/config.h" + else + out="php_config.h" + fi + fi + + for cfg in $PHP_JSON_EXTRA_CONFIG_HEADERS; do + cat > $ext_builddir/$cfg <<EOF +#include "$out" +EOF + done +]) + +AC_DEFUN([PHP_JSON_SETUP_JSON_C], [ + dnl json-c is required and can not be disabled + dnl + dnl Bundled json-c + dnl + + PHP_JSON_ADD_BUILD_DIR([json_c]) + PHP_JSON_ADD_INCLUDE([json_c]) + PHP_JSON_ADD_CONFIG_HEADER([json_c/config.h]) + + PHP_JSON_ADD_SOURCES([ + json_c/ConvertUTF.c + json_c/debug.c + json_c/linkhash.c + json_c/printbuf.c + json_c/arraylist.c + json_c/json_object.c + json_c/json_tokener.c + json_c/ossupport.c + ]) + PHP_JSON_ADD_CFLAG([-DHAVE_CONFIG_H]) +]) + +dnl +dnl Main config +dnl + +PHP_ARG_WITH(json, whether to enable JavaScript Object Serialization support, +[ --with-json Enable JavaScript Object Serialization support]) + +if test "$PHP_JSON" != "no"; then + AC_DEFINE([HAVE_JSON],1,[whether to have JavaScript Object Serialization support]) + AC_HEADER_STDC + AC_CHECK_FUNCS([strndup vsnprintf vasprintf strncasecmp]) + AC_CHECK_HEADERS([stdarg.h]) + + PHP_JSON_ADD_BASE_SOURCES([json.c]) + + dnl json_c is required + PHP_JSON_SETUP_JSON_C + PHP_JSON_EXTENSION + dnl PHP_INSTALL_HEADERS([ext/json], [json_c]) +fi + +# vim600: sts=2 sw=2 et diff --git a/ext/json/config.w32 b/ext/json/config.w32 new file mode 100644 index 0000000000..d933c76994 --- /dev/null +++ b/ext/json/config.w32 @@ -0,0 +1,12 @@ +// $Id$ +// vim:ft=javascript + +ARG_WITH("json", "JavaScript Object Serialization support", "no"); + +if (PHP_JSON != "no") { + CHECK_HEADER_ADD_INCLUDE("json.h", "CFLAGS_JSON", configure_module_dirname + "/json_c"); + EXTENSION('json', 'json.c', PHP_JSON_SHARED, ""); + ADD_SOURCES(configure_module_dirname + "/json_c", "ConvertUTF.c debug.c linkhash.c \ + printbuf.c arraylist.c json_object.c json_tokener.c ossupport.c", "json"); +} + diff --git a/ext/json/json.c b/ext/json/json.c new file mode 100644 index 0000000000..001c5844ee --- /dev/null +++ b/ext/json/json.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2005 Omar Kilani <omar@rmilk.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_json.h" +#include "json.h" + +/* If you declare any globals in php_json.h uncomment this: +ZEND_DECLARE_MODULE_GLOBALS(json) +*/ + +/* True global resources - no need for thread safety here */ +static int le_json; + +/* {{{ json_functions[] + * + * Every user visible function must have an entry in json_functions[]. + */ +function_entry json_functions[] = { + PHP_FE(json_encode, NULL) + PHP_FE(json_decode, NULL) + {NULL, NULL, NULL} /* Must be the last line in json_functions[] */ +}; +/* }}} */ + +/* {{{ json_module_entry + */ +zend_module_entry json_module_entry = { +#if ZEND_MODULE_API_NO >= 20010901 + STANDARD_MODULE_HEADER, +#endif + "json", + json_functions, + PHP_MINIT(json), + PHP_MSHUTDOWN(json), + PHP_RINIT(json), + PHP_RSHUTDOWN(json), + PHP_MINFO(json), +#if ZEND_MODULE_API_NO >= 20010901 + PHP_JSON_VERSION, +#endif + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +#ifdef COMPILE_DL_JSON +ZEND_GET_MODULE(json) +#endif + +/* {{{ PHP_MINIT_FUNCTION + */ +PHP_MINIT_FUNCTION(json) +{ + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MSHUTDOWN_FUNCTION + */ +PHP_MSHUTDOWN_FUNCTION(json) +{ + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RINIT_FUNCTION + */ +PHP_RINIT_FUNCTION(json) +{ + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_RSHUTDOWN_FUNCTION + */ +PHP_RSHUTDOWN_FUNCTION(json) +{ + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MINFO_FUNCTION + */ +PHP_MINFO_FUNCTION(json) +{ + php_info_print_table_start(); + php_info_print_table_row(2, "json support", "enabled"); + php_info_print_table_row(2, "json version", PHP_JSON_VERSION); + php_info_print_table_row(2, "json-c version", JSON_C_VERSION); + php_info_print_table_end(); +} +/* }}} */ + +static struct json_object *json_encode_r(zval *val); + +static int json_determine_array_type(zval **val) { + int i; + HashTable *myht; + TSRMLS_FETCH(); + + if (Z_TYPE_PP(val) == IS_ARRAY) { + myht = HASH_OF(*val); + } else { + myht = Z_OBJPROP_PP(val); + return 1; + } + + i = myht ? zend_hash_num_elements(myht) : 0; + if (i > 0) { + char *key; + ulong index, idx; + uint key_len; + HashPosition pos; + + zend_hash_internal_pointer_reset_ex(myht, &pos); + idx = 0; + for (;; zend_hash_move_forward_ex(myht, &pos)) { + i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); + if (i == HASH_KEY_NON_EXISTANT) + break; + + if (i == HASH_KEY_IS_STRING) { + return 1; + } else { + if (index != idx) { + return 1; + } + } + idx++; + } + } + + return 0; +} + +static struct json_object *json_encode_array(zval **val) { + int i, r; + HashTable *myht; + struct json_object *obj; + TSRMLS_FETCH(); + + if (Z_TYPE_PP(val) == IS_ARRAY) { + myht = HASH_OF(*val); + r = json_determine_array_type(val); + } else { + myht = Z_OBJPROP_PP(val); + r = 1; + } + + if (r == 0 /* all keys numeric */) { + obj = json_object_new_array(); + } else { + obj = json_object_new_object(); + } + + i = myht ? zend_hash_num_elements(myht) : 0; + if (i > 0) { + char *key; + zval **data; + ulong index; + uint key_len; + HashPosition pos; + struct json_object *member; + char buffer[11]; + + zend_hash_internal_pointer_reset_ex(myht, &pos); + for (;; zend_hash_move_forward_ex(myht, &pos)) { + i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); + if (i == HASH_KEY_NON_EXISTANT) + break; + + if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) { + member = json_encode_r(*data); + if (r == 0) { + json_object_array_add(obj, member); + } else if (r == 1) { + if (i == HASH_KEY_IS_STRING) { + if (key[0] == '\0') { + /* Skip protected and private members. */ + if (member != NULL) + json_object_put(member); + continue; + } + + json_object_object_add(obj, key, member); + } else { + snprintf(buffer, sizeof(buffer), "%ld", index); + buffer[10] = 0; + json_object_object_add(obj, buffer, member); + } + } + } + } + } + + return obj; +} + +static struct json_object *json_encode_r(zval *val) { + struct json_object *jo; + + switch (Z_TYPE_P(val)) { + case IS_NULL: + jo = NULL; + break; + case IS_BOOL: + jo = json_object_new_boolean(Z_BVAL_P(val)); + break; + case IS_LONG: + jo = json_object_new_int(Z_LVAL_P(val)); + break; + case IS_DOUBLE: + jo = json_object_new_double(Z_DVAL_P(val)); + break; + case IS_STRING: + jo = json_object_new_string_len(Z_STRVAL_P(val), Z_STRLEN_P(val)); + break; + case IS_ARRAY: + jo = json_encode_array(&val); + break; + case IS_OBJECT: + jo = json_encode_array(&val); + break; + default: + zend_error(E_WARNING, "[json] (json_encode) type is unsupported\n"); + jo = NULL; + break; + } + + return jo; +} + +ZEND_FUNCTION(json_encode) +{ + zval *parameter; + struct json_object *jo; + char *s; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶meter) == FAILURE) { + return; + } + + jo = json_encode_r(parameter); + + s = estrdup(json_object_to_json_string(jo)); + + json_object_put(jo); + + RETURN_STRING(s, 0); +} + +static zval *json_decode_r(struct json_object *jo, zend_bool assoc) { + zval *return_value; + TSRMLS_FETCH(); + + MAKE_STD_ZVAL(return_value); + + switch (json_object_get_type(jo)) { + case json_type_boolean: + ZVAL_BOOL(return_value, json_object_get_boolean(jo)); + break; + case json_type_double: + ZVAL_DOUBLE(return_value, json_object_get_double(jo)); + break; + case json_type_int: + ZVAL_LONG(return_value, json_object_get_int(jo)); + break; + case json_type_object: { + zval *mval; + struct json_object_iter iter; + + if (assoc) { + array_init(return_value); + } else { + object_init(return_value); + } + + json_object_object_foreachC(jo, iter) { + if (iter.val) { + mval = json_decode_r(iter.val, assoc); + } else { + MAKE_STD_ZVAL(mval); + ZVAL_NULL(mval); + } + + if (assoc) { + add_assoc_zval(return_value, iter.key, mval); + } else { + add_property_zval(return_value, iter.key, mval); +#if PHP_MAJOR_VERSION >= 5 + ZVAL_DELREF(mval); +#endif + } + } + } + break; + case json_type_array: { + zval *mval; + struct json_object *val; + int i = 0, l; + + array_init(return_value); + l = json_object_array_length(jo); + for (i = 0; i < l; i++) { + val = json_object_array_get_idx(jo, i); + if (val) { + mval = json_decode_r(val, assoc); + } else { + MAKE_STD_ZVAL(mval); + ZVAL_NULL(mval); + } + add_index_zval(return_value, i, mval); + } + } + break; + case json_type_string: { + char *s = json_object_get_string(jo); + ZVAL_STRING(return_value, s, 1); + break; + } + + default: + ZVAL_NULL(return_value); + break; + } + + return return_value; +} + +ZEND_FUNCTION(json_decode) +{ + char *parameter; + int parameter_len; + zend_bool assoc = 0; /* return JS objects as PHP objects by default */ + struct json_object *jo; + zval *z; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", ¶meter, ¶meter_len, &assoc) == FAILURE) { + return; + } + + jo = json_tokener_parse(parameter); + if (!jo) { + RETURN_NULL(); + } + + z = json_decode_r(jo, assoc); + if (!z) { + RETURN_NULL(); + } + + json_object_put(jo); + + *return_value = *z; + + FREE_ZVAL(z); + + return; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/json/json.dsp b/ext/json/json.dsp new file mode 100644 index 0000000000..e465b44644 --- /dev/null +++ b/ext/json/json.dsp @@ -0,0 +1,199 @@ +# Microsoft Developer Studio Project File - Name="json" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=json - Win32 Debug_TS
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "json.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "json.mak" CFG="json - Win32 Debug_TS"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "json - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "json - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "json - Win32 Debug_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug_TS"
+# PROP BASE Intermediate_Dir "Debug_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug_TS"
+# PROP Intermediate_Dir "Debug_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "json_c" /D HAVE_JSON=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D ZEND_DEBUG=1 /D ZTS=1 /D COMPILE_DL_JSON=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"
+# ADD RSC /l 0x1009 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 iconv.lib php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_json.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
+
+!ELSEIF "$(CFG)" == "json - Win32 Release_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release_TS"
+# PROP BASE Intermediate_Dir "Release_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release_TS"
+# PROP Intermediate_Dir "Release_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "json_c" /D HAVE_JSON=1 /D "ZEND_WIN32" /D ZEND_DEBUG=0 /D "PHP_WIN32" /D ZTS=1 /D COMPILE_DL_JSON=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /D "HAVE_FCNTL_H" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"
+# ADD RSC /l 0x1009 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 iconv.lib php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_json.dll" /libpath:"..\..\Release_TS"
+
+!ENDIF
+
+# Begin Target
+
+# Name "json - Win32 Debug_TS"
+# Name "json - Win32 Release_TS"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=".\json.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\php_json.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Group "json_c"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\json_c\arraylist.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\arraylist.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\bits.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\ConvertUTF.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\ConvertUTF.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\debug.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\debug.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\json.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\json_object.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\json_object.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\json_object_private.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\json_tokener.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\json_tokener.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\json_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\json_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\linkhash.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\linkhash.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\ossupport.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\ossupport.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\printbuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\json_c\printbuf.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/ext/json/json_c/AUTHORS b/ext/json/json_c/AUTHORS new file mode 100644 index 0000000000..eb8e5533d5 --- /dev/null +++ b/ext/json/json_c/AUTHORS @@ -0,0 +1,4 @@ +Michael Clark <michael@metaparadigm.com> +C. Watford (christopher.watford@gmail.com) + +Omar Kilani (omar[at]rmilk[dot]com) diff --git a/ext/json/json_c/ConvertUTF.c b/ext/json/json_c/ConvertUTF.c new file mode 100644 index 0000000000..9b3deebd67 --- /dev/null +++ b/ext/json/json_c/ConvertUTF.c @@ -0,0 +1,539 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + June 2002: Tim Dodd added detection and handling of incomplete + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. + July 2003: slight mods to back out aggressive FFFE detection. + Jan 2004: updated switches in from-UTF8 conversions. + Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + + See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "ConvertUTF.h" +#ifdef CVTUTF_DEBUG +#include <stdio.h> +#endif + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG +if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); +} +#endif + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "isLegalUTF8" call can be turned + * into an inline function. + */ + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. + + --------------------------------------------------------------------- */ diff --git a/ext/json/json_c/ConvertUTF.h b/ext/json/json_c/ConvertUTF.h new file mode 100644 index 0000000000..e26491536f --- /dev/null +++ b/ext/json/json_c/ConvertUTF.h @@ -0,0 +1,149 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Header file. + + Several funtions are included here, forming a complete set of + conversions between the three formats. UTF-7 is not included + here, but is handled in a separate source file. + + Each of these routines takes pointers to input buffers and output + buffers. The input buffers are const. + + Each routine converts the text between *sourceStart and sourceEnd, + putting the result into the buffer between *targetStart and + targetEnd. Note: the end pointers are *after* the last item: e.g. + *(sourceEnd - 1) is the last item. + + The return result indicates whether the conversion was successful, + and if not, whether the problem was in the source or target buffers. + (Only the first encountered problem is indicated.) + + After the conversion, *sourceStart and *targetStart are both + updated to point to the end of last text successfully converted in + the respective buffers. + + Input parameters: + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. + + These conversion functions take a ConversionFlags argument. When this + flag is set to strict, both irregular sequences and isolated surrogates + will cause an error. When the flag is set to lenient, both irregular + sequences and isolated surrogates are converted. + + Whether the flag is strict or lenient, all illegal sequences will cause + an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>, + or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + must check for illegal sequences. + + When the flag is set to lenient, characters over 0x10FFFF are converted + to the replacement character; otherwise (when the flag is set to strict) + they constitute an error. + + Output parameters: + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. + + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +/* --------------------------------------------------------------------- + The following 4 definitions are compiler-specific. + The C standard does not guarantee that wchar_t has at least + 16 bits, so wchar_t is no less portable than unsigned short! + All should be unsigned values to avoid sign extension during + bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned long UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +#ifdef __cplusplus +} +#endif + +/* --------------------------------------------------------------------- */ diff --git a/ext/json/json_c/README.FORK b/ext/json/json_c/README.FORK new file mode 100644 index 0000000000..debf62a30b --- /dev/null +++ b/ext/json/json_c/README.FORK @@ -0,0 +1,11 @@ +json-c fork - Omar Kilani <omar[at]rmilk[dot]com> +---------------------------------------------------- + +As development on json-c has apparently seized, I have, in the course +of debugging the JSON PHP extension, modified the source herein to +address a variety of issues. As such, if you have any issues with +*this* copy of json-c, you should contact me at the address listed +above, instead of the original authors of this software. + +-- Omar Kilani + Fri, Jun 10 2005 diff --git a/ext/json/json_c/arraylist.c b/ext/json/json_c/arraylist.c new file mode 100644 index 0000000000..b0112a6743 --- /dev/null +++ b/ext/json/json_c/arraylist.c @@ -0,0 +1,98 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#if STDC_HEADERS || defined(_MSC_VER) +# include <stdlib.h> +# include <string.h> +#endif /* STDC_HEADERS */ + +#if HAVE_STRINGS_H +# include <strings.h> +#endif /* HAVE_STRINGS_H */ + +#include "bits.h" +#include "arraylist.h" + +struct array_list* +array_list_new(array_list_free_fn *free_fn) +{ + struct array_list *this; + + if(!(this = calloc(1, sizeof(struct array_list)))) return NULL; + this->size = ARRAY_LIST_DEFAULT_SIZE; + this->length = 0; + this->free_fn = free_fn; + if(!(this->array = calloc(sizeof(void*), this->size))) { + free(this); + return NULL; + } + return this; +} + +extern void +array_list_free(struct array_list *this) +{ + int i; + for(i = 0; i < this->length; i++) + if(this->array[i]) this->free_fn(this->array[i]); + free(this->array); + free(this); +} + +void* +array_list_get_idx(struct array_list *this, int i) +{ + if(i >= this->length) return NULL; + return this->array[i]; +} + +static int array_list_expand_internal(struct array_list *this, int max) +{ + void *t; + int new_size; + + if(max < this->size) return 0; + new_size = max(this->size << 1, max); + if(!(t = realloc(this->array, new_size*sizeof(void*)))) return -1; + this->array = t; + (void)memset(this->array + this->size, 0, (new_size-this->size)*sizeof(void*)); + this->size = new_size; + return 0; +} + +int +array_list_put_idx(struct array_list *this, int idx, void *data) +{ + if(array_list_expand_internal(this, idx)) return -1; + if(this->array[idx]) this->free_fn(this->array[idx]); + this->array[idx] = data; + if(this->length <= idx) this->length = idx + 1; + return 0; +} + +int +array_list_add(struct array_list *this, void *data) +{ + return array_list_put_idx(this, this->length, data); +} + +int +array_list_length(struct array_list *this) +{ + return this->length; +} diff --git a/ext/json/json_c/arraylist.h b/ext/json/json_c/arraylist.h new file mode 100644 index 0000000000..95cc3a9fa1 --- /dev/null +++ b/ext/json/json_c/arraylist.h @@ -0,0 +1,52 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _arraylist_h_ +#define _arraylist_h_ + +#define ARRAY_LIST_DEFAULT_SIZE 32 + +typedef void (array_list_free_fn) (void *data); + +struct array_list +{ + void **array; + int length; + int size; + array_list_free_fn *free_fn; +}; + +extern struct array_list* +array_list_new(array_list_free_fn *free_fn); + +extern void +array_list_free(struct array_list *al); + +extern void* +array_list_get_idx(struct array_list *al, int i); + +extern int +array_list_put_idx(struct array_list *al, int i, void *data); + +extern int +array_list_add(struct array_list *al, void *data); + +extern int +array_list_length(struct array_list *al); + +#endif diff --git a/ext/json/json_c/bits.h b/ext/json/json_c/bits.h new file mode 100644 index 0000000000..252a52b2ee --- /dev/null +++ b/ext/json/json_c/bits.h @@ -0,0 +1,47 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _bits_h_ +#define _bits_h_ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if STDC_HEADERS +# include <stddef.h> +#endif /* STDC_HEADERS */ + +/* CAW: wrapped in ifndef's to make win32 compliant +** this fails to take over GCC specifics, but this +** seems to be unimportant. + */ + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) +#define error_ptr(error) ((void*)error) +#define is_error(ptr) ((unsigned long)ptr > (unsigned long)-4000L) + +#endif diff --git a/ext/json/json_c/config.h b/ext/json/json_c/config.h new file mode 100644 index 0000000000..a69a281179 --- /dev/null +++ b/ext/json/json_c/config.h @@ -0,0 +1 @@ +#include "/home/omar/clean/php-json-ext-1.1.0/config.h" diff --git a/ext/json/json_c/config.h.win32 b/ext/json/json_c/config.h.win32 new file mode 100644 index 0000000000..895eace743 --- /dev/null +++ b/ext/json/json_c/config.h.win32 @@ -0,0 +1,101 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +/* config.h.win32 Generated by configure. */ + +#define PACKAGE_STRING "JSON C Library 0.2" +#define PACKAGE_BUGREPORT "michael@metaparadigm.com" +#define PACKAGE_NAME "JSON C Library" +#define PACKAGE_TARNAME "json-c" +#define PACKAGE_VERSION "0.2" + +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the <limits.h> header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `open' function. */ +#undef HAVE_OPEN + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRNDUP + +/* Define to 1 if you have the <stdarg.h> header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <syslog.h> header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 diff --git a/ext/json/json_c/debug.c b/ext/json/json_c/debug.c new file mode 100644 index 0000000000..79b60285af --- /dev/null +++ b/ext/json/json_c/debug.c @@ -0,0 +1,61 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "debug.h" + +static int _debug = 0; + +void mc_set_debug(int debug) { _debug = debug; } +int mc_get_debug() { return _debug; } + +void mc_abort(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + vprintf(msg, ap); + exit(1); +} + + +void mc_debug(const char *msg, ...) +{ + va_list ap; + if(_debug) { + va_start(ap, msg); + vprintf(msg, ap); + } +} + +void mc_error(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + vfprintf(stderr, msg, ap); +} + +void mc_info(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + vfprintf(stderr, msg, ap); +} diff --git a/ext/json/json_c/debug.h b/ext/json/json_c/debug.h new file mode 100644 index 0000000000..22e1ab10ab --- /dev/null +++ b/ext/json/json_c/debug.h @@ -0,0 +1,32 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +#define errstr strerror(errno) + +extern void mc_set_debug(int debug); +extern int mc_get_debug(); + +extern void mc_abort(const char *msg, ...); +extern void mc_debug(const char *msg, ...); +extern void mc_error(const char *msg, ...); +extern void mc_info(const char *msg, ...); + +#endif diff --git a/ext/json/json_c/json.h b/ext/json/json_c/json.h new file mode 100644 index 0000000000..94ce47dc5a --- /dev/null +++ b/ext/json/json_c/json.h @@ -0,0 +1,40 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _json_h_ +#define _json_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define JSON_C_VERSION "20051203" + +#include "bits.h" +#include "debug.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_util.h" +#include "json_object.h" +#include "json_tokener.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ext/json/json_c/json_object.c b/ext/json/json_c/json_object.c new file mode 100644 index 0000000000..5faf761391 --- /dev/null +++ b/ext/json/json_c/json_object.c @@ -0,0 +1,546 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * Copyright (c) 2005 Omar Kilani <omar@rmilk.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "debug.h" +#include "printbuf.h" +#include "linkhash.h" +#include "arraylist.h" +#include "json_object.h" +#include "ossupport.h" +#include "ConvertUTF.h" +#include "json_object_private.h" + + +/* #define REFCOUNT_DEBUG */ + +char *json_number_chars = "0123456789.+-e"; +char *json_hex_chars = "0123456789abcdef"; + +#ifdef REFCOUNT_DEBUG +static char* json_type_name[] = { + "null", + "boolean", + "double", + "int", + "object", + "array", + "string", +}; +#endif + +static void json_object_generic_delete(struct json_object* this); +static struct json_object* json_object_new(enum json_type o_type); + + +/* ref count debugging */ + +#ifdef REFCOUNT_DEBUG + +static struct lh_table *json_object_table; + +static void json_object_init() __attribute__ ((constructor)); +static void json_object_init() { + mc_debug("json_object_init: creating object table\n"); + json_object_table = lh_kptr_table_new(128, "json_object_table", NULL); +} + +static void json_object_fini() __attribute__ ((destructor)); +static void json_object_fini() { + struct lh_entry *ent; + if(mc_get_debug() && json_object_table->count) { + mc_debug("json_object_fini: %d referenced objects at exit\n", + json_object_table->count); + lh_foreach(json_object_table, ent) { + struct json_object* obj = (struct json_object*)ent->v; + mc_debug("\t%s:%p\n", json_type_name[obj->o_type], obj); + } + } + mc_debug("json_object_fini: freeing object table\n"); + lh_table_free(json_object_table); +} +#endif + + +/* string escaping */ + +static int json_escape_str(struct printbuf *pb, char *str) +{ + UTF16 target16 = 0, *target16ptr; + UTF8 uc, source[3], *sourceptr; + + int pos = 0, start_offset = 0, utfl = 0, utfi = 0; + char c; + do { + c = str[pos]; + switch(c) { + case '\b': + case '\n': + case '\r': + case '\t': + case '"': + case '\\': + case '/': + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + if(c == '\b') printbuf_memappend(pb, "\\b", 2); + else if(c == '\n') printbuf_memappend(pb, "\\n", 2); + else if(c == '\r') printbuf_memappend(pb, "\\r", 2); + else if(c == '\t') printbuf_memappend(pb, "\\t", 2); + else if(c == '"') printbuf_memappend(pb, "\\\"", 2); + else if(c == '\\') printbuf_memappend(pb, "\\\\", 2); + else if(c == '/') printbuf_memappend(pb, "\\/", 2); + start_offset = ++pos; + break; + default: + if(c && c < ' ') { + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + + uc = c; + + if ((uc & 0xE0) == 0xC0) { + // characters U-00000080 - U-000007FF, mask 110XXXXX, see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + utfl = 2; + } else if ((uc & 0xF0) == 0xE0) { + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + utfl = 3; + } else if ((uc & 0xF8) == 0xF0) { + // characters U-00010000 - U-001FFFFF, mask 11110XXX + utfl = 4; + } else if ((uc & 0xFC) == 0xF8) { + // characters U-00200000 - U-03FFFFFF, mask 111110XX + utfl = 5; + } else if ((uc & 0xFE) == 0xFC) { + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + utfl = 6; + } else { + utfl = -1; + } + + if (utfl >= 2) { + sourceptr = source; + target16ptr = &target16; + + source[0] = uc; + for (utfi = 1; utfi < utfl; utfi++) { + uc = str[++pos]; + source[utfi] = uc; + } + ConvertUTF8toUTF16((const UTF8 **) &sourceptr, sourceptr + utfl, &target16ptr, target16ptr + 1, strictConversion); + sprintbuf(pb, "\\u%04x", target16); + } + + start_offset = ++pos; + } else if(c) pos++; + } + } while(c); + if(pos - start_offset > 0) + printbuf_memappend(pb, str + start_offset, pos - start_offset); + return 0; +} + + +/* reference counting */ + +extern struct json_object* json_object_get(struct json_object *this) +{ + if(this) { + this->_ref_count++; + } + return this; +} + +extern void json_object_put(struct json_object *this) +{ + if(this) { + this->_ref_count--; + if(!this->_ref_count) this->_delete(this); + } +} + + +/* generic object construction and destruction parts */ + +static void json_object_generic_delete(struct json_object* this) +{ +#ifdef REFCOUNT_DEBUG + mc_debug("json_object_delete_%s: %p\n", + json_type_name[this->o_type], this); + lh_table_delete(json_object_table, this); +#endif + printbuf_free(this->_pb); + free(this); +} + +static struct json_object* json_object_new(enum json_type o_type) +{ + struct json_object *this = calloc(sizeof(struct json_object), 1); + if(!this) return NULL; + this->o_type = o_type; + this->_ref_count = 1; + this->_delete = &json_object_generic_delete; +#ifdef REFCOUNT_DEBUG + lh_table_insert(json_object_table, this, this); + mc_debug("json_object_new_%s: %p\n", json_type_name[this->o_type], this); +#endif + return this; +} + + +/* type checking functions */ + +int json_object_is_type(struct json_object *this, enum json_type type) +{ + return (this->o_type == type); +} + +enum json_type json_object_get_type(struct json_object *this) +{ + return this->o_type; +} + + +/* json_object_to_json_string */ + +char* json_object_to_json_string(struct json_object *this) +{ + if(!this) return "null"; + if(!this->_pb) { + if(!(this->_pb = printbuf_new())) return NULL; + } else { + printbuf_reset(this->_pb); + } + if(this->_to_json_string(this, this->_pb) < 0) return NULL; + return this->_pb->buf; +} + + +/* json_object_object */ + +static int json_object_object_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + int i=0; + struct json_object_iter iter; + sprintbuf(pb, "{"); + + /* CAW: scope operator to make ANSI correctness */ + /* CAW: switched to json_object_object_foreachC which uses an iterator struct */ + json_object_object_foreachC(this, iter) { + if(i) sprintbuf(pb, ","); + sprintbuf(pb, "\""); + json_escape_str(pb, iter.key); + sprintbuf(pb, "\":"); + if(iter.val == NULL) sprintbuf(pb, "null"); + else iter.val->_to_json_string(iter.val, pb); + i++; + } + + return sprintbuf(pb, "}"); +} + +static void json_object_lh_entry_free(struct lh_entry *ent) +{ + free(ent->k); + json_object_put((struct json_object*)ent->v); +} + +static void json_object_object_delete(struct json_object* this) +{ + lh_table_free(this->o.c_object); + json_object_generic_delete(this); +} + +struct json_object* json_object_new_object() +{ + struct json_object *this = json_object_new(json_type_object); + if(!this) return NULL; + this->_delete = &json_object_object_delete; + this->_to_json_string = &json_object_object_to_json_string; + this->o.c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTIRES, + NULL, &json_object_lh_entry_free); + return this; +} + +struct lh_table* json_object_get_object(struct json_object *this) +{ + if(!this) return NULL; + switch(this->o_type) { + case json_type_object: + return this->o.c_object; + default: + return NULL; + } +} + +void json_object_object_add(struct json_object* this, char *key, + struct json_object *val) +{ + lh_table_delete(this->o.c_object, key); + lh_table_insert(this->o.c_object, strdup(key), val); +} + +struct json_object* json_object_object_get(struct json_object* this, char *key) +{ + return (struct json_object*) lh_table_lookup(this->o.c_object, key); +} + +void json_object_object_del(struct json_object* this, char *key) +{ + lh_table_delete(this->o.c_object, key); +} + + +/* json_object_boolean */ + +static int json_object_boolean_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + if(this->o.c_boolean) return sprintbuf(pb, "true"); + else return sprintbuf(pb, "false"); +} + +struct json_object* json_object_new_boolean(boolean b) +{ + struct json_object *this = json_object_new(json_type_boolean); + if(!this) return NULL; + this->_to_json_string = &json_object_boolean_to_json_string; + this->o.c_boolean = b; + return this; +} + +boolean json_object_get_boolean(struct json_object *this) +{ + if(!this) return FALSE; + switch(this->o_type) { + case json_type_boolean: + return this->o.c_boolean; + case json_type_int: + return (this->o.c_int != 0); + case json_type_double: + return (this->o.c_double != 0); + case json_type_string: + if(strlen(this->o.c_string)) return TRUE; + default: + return TRUE; + } +} + + +/* json_object_int */ + +static int json_object_int_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + return sprintbuf(pb, "%d", this->o.c_int); +} + +struct json_object* json_object_new_int(int i) +{ + struct json_object *this = json_object_new(json_type_int); + if(!this) return NULL; + this->_to_json_string = &json_object_int_to_json_string; + this->o.c_int = i; + return this; +} + +int json_object_get_int(struct json_object *this) +{ + int cint; + + if(!this) return 0; + switch(this->o_type) { + case json_type_int: + return this->o.c_int; + case json_type_double: + return (int)this->o.c_double; + case json_type_boolean: + return this->o.c_boolean; + case json_type_string: + if(sscanf(this->o.c_string, "%d", &cint) == 1) return cint; + default: + return 0; + } +} + + +/* json_object_double */ + +static int json_object_double_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + return sprintbuf(pb, "%lf", this->o.c_double); +} + +struct json_object* json_object_new_double(double d) +{ + struct json_object *this = json_object_new(json_type_double); + if(!this) return NULL; + this->_to_json_string = &json_object_double_to_json_string; + this->o.c_double = d; + return this; +} + +double json_object_get_double(struct json_object *this) +{ + double cdouble; + + if(!this) return 0.0; + switch(this->o_type) { + case json_type_double: + return this->o.c_double; + case json_type_int: + return this->o.c_int; + case json_type_boolean: + return this->o.c_boolean; + case json_type_string: + if(sscanf(this->o.c_string, "%lf", &cdouble) == 1) return cdouble; + default: + return 0.0; + } +} + + +/* json_object_string */ + +static int json_object_string_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + sprintbuf(pb, "\""); + json_escape_str(pb, this->o.c_string); + sprintbuf(pb, "\""); + return 0; +} + +static void json_object_string_delete(struct json_object* this) +{ + free(this->o.c_string); + json_object_generic_delete(this); +} + +struct json_object* json_object_new_string(char *s) +{ + struct json_object *this = json_object_new(json_type_string); + if(!this) return NULL; + this->_delete = &json_object_string_delete; + this->_to_json_string = &json_object_string_to_json_string; + this->o.c_string = strdup(s); + return this; +} + +struct json_object* json_object_new_string_len(char *s, int len) +{ + struct json_object *this = json_object_new(json_type_string); + if(!this) return NULL; + this->_delete = &json_object_string_delete; + this->_to_json_string = &json_object_string_to_json_string; + this->o.c_string = strndup(s, len); + return this; +} + +char* json_object_get_string(struct json_object *this) +{ + if(!this) return NULL; + switch(this->o_type) { + case json_type_string: + return this->o.c_string; + default: + return json_object_to_json_string(this); + } +} + + +/* json_object_array */ + +static int json_object_array_to_json_string(struct json_object* this, + struct printbuf *pb) +{ + int i; + sprintbuf(pb, "["); + for(i=0; i < json_object_array_length(this); i++) { + struct json_object *val; + if(i) { sprintbuf(pb, ","); } + + + val = json_object_array_get_idx(this, i); + if(val == NULL) { sprintbuf(pb, "null"); } + else { val->_to_json_string(val, pb); } + } + return sprintbuf(pb, "]"); +} + +static void json_object_array_entry_free(void *data) +{ + json_object_put((struct json_object*)data); +} + +static void json_object_array_delete(struct json_object* this) +{ + array_list_free(this->o.c_array); + json_object_generic_delete(this); +} + +struct json_object* json_object_new_array() +{ + struct json_object *this = json_object_new(json_type_array); + if(!this) return NULL; + this->_delete = &json_object_array_delete; + this->_to_json_string = &json_object_array_to_json_string; + this->o.c_array = array_list_new(&json_object_array_entry_free); + return this; +} + +struct array_list* json_object_get_array(struct json_object *this) +{ + if(!this) return NULL; + switch(this->o_type) { + case json_type_array: + return this->o.c_array; + default: + return NULL; + } +} + +int json_object_array_length(struct json_object *this) +{ + return array_list_length(this->o.c_array); +} + +int json_object_array_add(struct json_object *this,struct json_object *val) +{ + return array_list_add(this->o.c_array, val); +} + +int json_object_array_put_idx(struct json_object *this, int idx, + struct json_object *val) +{ + return array_list_put_idx(this->o.c_array, idx, val); +} + +struct json_object* json_object_array_get_idx(struct json_object *this, + int idx) +{ + return (struct json_object*)array_list_get_idx(this->o.c_array, idx); +} + diff --git a/ext/json/json_c/json_object.h b/ext/json/json_c/json_object.h new file mode 100644 index 0000000000..2c915d75b2 --- /dev/null +++ b/ext/json/json_c/json_object.h @@ -0,0 +1,324 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _json_object_h_ +#define _json_object_h_ + +#define JSON_OBJECT_DEF_HASH_ENTIRES 16 + +#undef FALSE +#define FALSE ((boolean)0) + +#undef TRUE +#define TRUE ((boolean)1) + +extern char *json_number_chars; +extern char *json_hex_chars; + +/* forward structure definitions */ + +typedef unsigned char boolean; +struct printbuf; +struct lh_table; +struct array_list; +struct json_object; + +/* CAW: added for ANSI C iteration correctness */ +struct json_object_iter +{ + char *key; + struct json_object *val; + struct lh_entry *entry; +}; + +/* supported object types */ + +enum json_type { + json_type_null, + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string +}; + +/* reference counting functions */ + +/** + * Increment the reference count of json_object + * @param obj the json_object instance + */ +extern struct json_object* json_object_get(struct json_object *obj); + +/** + * Decrement the reference count of json_object and free if it reaches zero + * @param obj the json_object instance + */ +extern void json_object_put(struct json_object *obj); + + +/** + * Check if the json_object is of a given type + * @param obj the json_object instance + * @param type one of: + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string, + */ +extern int json_object_is_type(struct json_object *obj, enum json_type type); + +/** + * Get the type of the json_object + * @param obj the json_object instance + * @returns type being one of: + json_type_boolean, + json_type_double, + json_type_int, + json_type_object, + json_type_array, + json_type_string, + */ +extern enum json_type json_object_get_type(struct json_object *obj); + + +/** Stringify object to json format + * @param obj the json_object instance + * @returns a string in JSON format + */ +extern char* json_object_to_json_string(struct json_object *obj); + + +/* object type methods */ + +/** Create a new empty object + * @returns a json_object of type json_type_object + */ +extern struct json_object* json_object_new_object(); + +/** Get the hashtable of a json_object of type json_type_object + * @param obj the json_object instance + * @returns a linkhash + */ +extern struct lh_table* json_object_get_object(struct json_object *obj); + +/** Add an object field to a json_object of type json_type_object + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * @param obj the json_object instance + * @param key the object field name (a private copy will be duplicated) + * @param val a json_object or NULL member to associate with the given field + */ +extern void json_object_object_add(struct json_object* obj, char *key, + struct json_object *val); + +/** Get the json_object associate with a given object field + * @param obj the json_object instance + * @param key the object field name + * @returns the json_object associated with the given field name + */ +extern struct json_object* json_object_object_get(struct json_object* obj, + char *key); + +/** Delete the given json_object field + * + * The reference count will be decremented for the deleted object + * + * @param obj the json_object instance + * @param key the object field name + */ +extern void json_object_object_del(struct json_object* obj, char *key); + +/** Iterate through all keys and values of an object + * @param obj the json_object instance + * @param key the local name for the char* key variable defined in the body + * @param val the local name for the json_object* object variable defined in the body + */ +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) + +# define json_object_object_foreach(obj,key,val) \ + char *key; struct json_object *val; \ + for(struct lh_entry *entry = json_object_get_object(obj)->head; ({ if(entry) { key = (char*)entry->k; val = (struct json_object*)entry->v; } ; entry; }); entry = entry->next ) + +#else /* ANSI C or MSC */ + +# define json_object_object_foreach(obj,key,val) \ + char *key; struct json_object *val; struct lh_entry *entry; \ + for(entry = json_object_get_object(obj)->head; (entry ? (key = (char*)entry->k, val = (struct json_object*)entry->v, entry) : 0); entry = entry->next) + +#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */ + +/** Iterate through all keys and values of an object (ANSI C Safe) + * @param obj the json_object instance + * @param iter the object iterator + */ +#define json_object_object_foreachC(obj,iter) \ + for(iter.entry = json_object_get_object(obj)->head; (iter.entry ? (iter.key = (char*)iter.entry->k, iter.val = (struct json_object*)iter.entry->v, iter.entry) : 0); iter.entry = iter.entry->next) + +/* Array type methods */ + +/** Create a new empty json_object of type json_type_array + * @returns a json_object of type json_type_array + */ +extern struct json_object* json_object_new_array(); + +/** Get the arraylist of a json_object of type json_type_array + * @param obj the json_object instance + * @returns an arraylist + */ +extern struct array_list* json_object_get_array(struct json_object *obj); + +/** Get the length of a json_object of type json_type_array + * @param obj the json_object instance + * @returns an int + */ +extern int json_object_array_length(struct json_object *obj); + +/** Add an element to the end of a json_object of type json_type_array + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * @param obj the json_object instance + * @param val the json_object to be added + */ +extern int json_object_array_add(struct json_object *obj, + struct json_object *val); + +/** Insert or replace an element at a specified index in an array (a json_object of type json_type_array) + * + * The reference count will *not* be incremented. This is to make adding + * fields to objects in code more compact. If you want to retain a reference + * to an added object you must wrap the passed object with json_object_get + * + * The reference count of a replaced object will be decremented. + * + * The array size will be automatically be expanded to the size of the + * index if the index is larger than the current size. + * + * @param obj the json_object instance + * @param idx the index to insert the element at + * @param val the json_object to be added + */ +extern int json_object_array_put_idx(struct json_object *obj, int idx, + struct json_object *val); + +/** Get the element at specificed index of the array (a json_object of type json_type_array) + * @param obj the json_object instance + * @param idx the index to get the element at + * @returns the json_object at the specified index (or NULL) + */ +extern struct json_object* json_object_array_get_idx(struct json_object *obj, + int idx); + +/* boolean type methods */ + +/** Create a new empty json_object of type json_type_boolean + * @param b a boolean TRUE or FALSE (0 or 1) + * @returns a json_object of type json_type_boolean + */ +extern struct json_object* json_object_new_boolean(boolean b); + +/** Get the boolean value of a json_object + * + * The type is coerced to a boolean if the passed object is not a boolean. + * integer and double objects will return FALSE if there value is zero + * or TRUE otherwise. If the passed object is a string it will return + * TRUE if it has a non zero length. If any other object type is passed + * TRUE will be returned if the object is not NULL. + * + * @param obj the json_object instance + * @returns a boolean + */ +extern boolean json_object_get_boolean(struct json_object *obj); + + +/* int type methods */ + +/** Create a new empty json_object of type json_type_int + * @param i the integer + * @returns a json_object of type json_type_int + */ +extern struct json_object* json_object_new_int(int i); + +/** Get the int value of a json_object + * + * The type is coerced to a int if the passed object is not a int. + * double objects will return their integer conversion. Strings will be + * parsed as an integer. If no conversion exists then 0 is returned. + * + * @param obj the json_object instance + * @returns an int + */ +extern int json_object_get_int(struct json_object *obj); + + +/* double type methods */ + +/** Create a new empty json_object of type json_type_double + * @param d the double + * @returns a json_object of type json_type_double + */ +extern struct json_object* json_object_new_double(double d); + +/** Get the double value of a json_object + * + * The type is coerced to a double if the passed object is not a double. + * integer objects will return their dboule conversion. Strings will be + * parsed as a double. If no conversion exists then 0.0 is returned. + * + * @param obj the json_object instance + * @returns an double + */ +extern double json_object_get_double(struct json_object *obj); + + +/* string type methods */ + +/** Create a new empty json_object of type json_type_string + * + * A copy of the string is made and the memory is managed by the json_object + * + * @param s the string + * @returns a json_object of type json_type_string + */ +extern struct json_object* json_object_new_string(char *s); + +extern struct json_object* json_object_new_string_len(char *s, int len); + +/** Get the string value of a json_object + * + * If the passed object is not of type json_type_string then the JSON + * representation of the object is returned. + * + * The returned string memory is managed by the json_object and will + * be freed when the reference count of the json_object drops to zero. + * + * @param obj the json_object instance + * @returns a string + */ +extern char* json_object_get_string(struct json_object *obj); + +#endif diff --git a/ext/json/json_c/json_object_private.h b/ext/json/json_c/json_object_private.h new file mode 100644 index 0000000000..64cf6c1d88 --- /dev/null +++ b/ext/json/json_c/json_object_private.h @@ -0,0 +1,43 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _json_object_private_h_ +#define _json_object_private_h_ + +typedef void (json_object_delete_fn)(struct json_object *o); +typedef int (json_object_to_json_string_fn)(struct json_object *o, + struct printbuf *pb); + +struct json_object +{ + enum json_type o_type; + json_object_delete_fn *_delete; + json_object_to_json_string_fn *_to_json_string; + int _ref_count; + struct printbuf *_pb; + union data { + boolean c_boolean; + double c_double; + int c_int; + struct lh_table *c_object; + struct array_list *c_array; + char *c_string; + } o; +}; + +#endif diff --git a/ext/json/json_c/json_tokener.c b/ext/json/json_c/json_tokener.c new file mode 100644 index 0000000000..75be394a77 --- /dev/null +++ b/ext/json/json_c/json_tokener.c @@ -0,0 +1,450 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * Copyright (c) 2005 Omar Kilani <omar@rmilk.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> + +#include "bits.h" +#include "debug.h" +#include "printbuf.h" +#include "arraylist.h" +#include "json_object.h" +#include "ossupport.h" +#include "json_tokener.h" + +static struct json_object* json_tokener_do_parse(struct json_tokener *this, enum json_tokener_error *err); + +struct json_object* json_tokener_parse(char * s) +{ + struct json_tokener tok; + struct json_object* obj; + enum json_tokener_error err; + + tok.source = s; + tok.pos = 0; + tok.pb = printbuf_new(); + obj = json_tokener_do_parse(&tok, &err); + printbuf_free(tok.pb); + return obj; +} + +static struct json_object* json_tokener_do_parse(struct json_tokener *this, enum json_tokener_error *err) +{ + enum json_tokener_state state, saved_state; + struct json_object *current = NULL, *obj; + char *obj_field_name = NULL; + char quote_char; + int deemed_double, start_offset; + char c; + + *err = json_tokener_success; + state = json_tokener_state_eatws; + saved_state = json_tokener_state_start; + + do { + c = this->source[this->pos]; + switch(state) { + + case json_tokener_state_eatws: + if(isspace(c)) { + this->pos++; + } else if(c == '/') { + state = json_tokener_state_comment_start; + start_offset = this->pos++; + } else { + state = saved_state; + } + break; + + case json_tokener_state_start: + switch(c) { + case '{': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_object; + current = json_object_new_object(); + this->pos++; + break; + case '[': + state = json_tokener_state_eatws; + saved_state = json_tokener_state_array; + current = json_object_new_array(); + this->pos++; + break; + case 'N': + case 'n': + state = json_tokener_state_null; + start_offset = this->pos++; + break; + case '"': + case '\'': + quote_char = c; + printbuf_reset(this->pb); + state = json_tokener_state_string; + start_offset = ++this->pos; + break; + case 'T': + case 't': + case 'F': + case 'f': + state = json_tokener_state_boolean; + start_offset = this->pos++; + break; +#if defined(__GNUC__) + case '0' ... '9': +#else + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': +#endif + case '-': + deemed_double = 0; + state = json_tokener_state_number; + start_offset = this->pos++; + break; + default: + *err = json_tokener_error_parse_unexpected; + goto out; + } + break; + + case json_tokener_state_finish: + goto out; + + case json_tokener_state_null: + if(strncasecmp("null", this->source + start_offset, + this->pos - start_offset)) { + *err = json_tokener_error_parse_null; + return NULL; + } + if(this->pos - start_offset == 4) { + current = NULL; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + this->pos++; + } + break; + + case json_tokener_state_comment_start: + if(c == '*') { + state = json_tokener_state_comment; + } else if(c == '/') { + state = json_tokener_state_comment_eol; + } else { + *err = json_tokener_error_parse_comment; + goto out; + } + this->pos++; + break; + + case json_tokener_state_comment: + if(c == '*') state = json_tokener_state_comment_end; + this->pos++; + break; + + case json_tokener_state_comment_eol: + if(c == '\n') { + if(mc_get_debug()) { + char *tmp = strndup(this->source + start_offset, + this->pos - start_offset); + mc_debug("json_tokener_comment: %s\n", tmp); + free(tmp); + } + state = json_tokener_state_eatws; + } + this->pos++; + break; + + case json_tokener_state_comment_end: + if(c == '/') { + if(mc_get_debug()) { + char *tmp = strndup(this->source + start_offset, + this->pos - start_offset + 1); + mc_debug("json_tokener_comment: %s\n", tmp); + free(tmp); + } + state = json_tokener_state_eatws; + } else { + state = json_tokener_state_comment; + } + this->pos++; + break; + + case json_tokener_state_string: + if(c == quote_char) { + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset); + current = json_object_new_string(this->pb->buf); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == '\\') { + saved_state = json_tokener_state_string; + state = json_tokener_state_string_escape; + } + this->pos++; + break; + + case json_tokener_state_string_escape: + switch(c) { + case '"': + case '\\': + case '/': + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset - 1); + start_offset = this->pos++; + state = saved_state; + break; + case 'b': + case 'n': + case 'r': + case 't': + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset - 1); + if(c == 'b') printbuf_memappend(this->pb, "\b", 1); + else if(c == 'n') printbuf_memappend(this->pb, "\n", 1); + else if(c == 'r') printbuf_memappend(this->pb, "\r", 1); + else if(c == 't') printbuf_memappend(this->pb, "\t", 1); + start_offset = ++this->pos; + state = saved_state; + break; + case 'u': + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset - 1); + start_offset = ++this->pos; + state = json_tokener_state_escape_unicode; + break; + default: + *err = json_tokener_error_parse_string; + goto out; + } + break; + + case json_tokener_state_escape_unicode: + if(strchr(json_hex_chars, c)) { + this->pos++; + if(this->pos - start_offset == 4) { + unsigned char utf_out[3]; + unsigned int ucs_char = + (hexdigit(*(this->source + start_offset)) << 12) + + (hexdigit(*(this->source + start_offset + 1)) << 8) + + (hexdigit(*(this->source + start_offset + 2)) << 4) + + hexdigit(*(this->source + start_offset + 3)); + if (ucs_char < 0x80) { + utf_out[0] = ucs_char; + printbuf_memappend(this->pb, (char*)utf_out, 1); + } else if (ucs_char < 0x800) { + utf_out[0] = 0xc0 | (ucs_char >> 6); + utf_out[1] = 0x80 | (ucs_char & 0x3f); + printbuf_memappend(this->pb, (char*)utf_out, 2); + } else { + utf_out[0] = 0xe0 | (ucs_char >> 12); + utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f); + utf_out[2] = 0x80 | (ucs_char & 0x3f); + printbuf_memappend(this->pb, (char*)utf_out, 3); + } + start_offset = this->pos; + state = saved_state; + } + } else { + *err = json_tokener_error_parse_string; + goto out; + } + break; + + case json_tokener_state_boolean: + if(strncasecmp("true", this->source + start_offset, + this->pos - start_offset) == 0) { + if(this->pos - start_offset == 4) { + current = json_object_new_boolean(1); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + this->pos++; + } + } else if(strncasecmp("false", this->source + start_offset, + this->pos - start_offset) == 0) { + if(this->pos - start_offset == 5) { + current = json_object_new_boolean(0); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + this->pos++; + } + } else { + *err = json_tokener_error_parse_boolean; + goto out; + } + break; + + case json_tokener_state_number: + if(!c || !strchr(json_number_chars, c)) { + int numi; + double numd; + char *tmp = strndup(this->source + start_offset, + this->pos - start_offset); + if(!deemed_double && sscanf(tmp, "%d", &numi) == 1) { + current = json_object_new_int(numi); + } else if(deemed_double && sscanf(tmp, "%lf", &numd) == 1) { + current = json_object_new_double(numd); + } else { + free(tmp); + *err = json_tokener_error_parse_number; + goto out; + } + free(tmp); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + if(c == '.' || c == 'e') deemed_double = 1; + this->pos++; + } + break; + + case json_tokener_state_array: + if(c == ']') { + this->pos++; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else { + obj = json_tokener_do_parse(this, err); + if(*err != json_tokener_success) { + *err = json_tokener_error_parse_array; + goto out; + } + json_object_array_add(current, obj); + saved_state = json_tokener_state_array_sep; + state = json_tokener_state_eatws; + } + break; + + case json_tokener_state_array_sep: + if(c == ']') { + this->pos++; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == ',') { + this->pos++; + saved_state = json_tokener_state_array; + state = json_tokener_state_eatws; + } else { + json_object_put(current); + *err = json_tokener_error_parse_array; + return NULL; + } + break; + + case json_tokener_state_object: + state = json_tokener_state_object_field_start; + start_offset = this->pos; + break; + + case json_tokener_state_object_field_start: + if(c == '}') { + this->pos++; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if (c == '"' || c == '\'') { + quote_char = c; + printbuf_reset(this->pb); + state = json_tokener_state_object_field; + start_offset = ++this->pos; + } else { + *err = json_tokener_error_parse_object; + goto out; + } + break; + + case json_tokener_state_object_field: + if(c == quote_char) { + printbuf_memappend(this->pb, this->source + start_offset, + this->pos - start_offset); + obj_field_name = strdup(this->pb->buf); + saved_state = json_tokener_state_object_field_end; + state = json_tokener_state_eatws; + } else if(c == '\\') { + saved_state = json_tokener_state_object_field; + state = json_tokener_state_string_escape; + } + this->pos++; + break; + + case json_tokener_state_object_field_end: + if(c == ':') { + this->pos++; + saved_state = json_tokener_state_object_value; + state = json_tokener_state_eatws; + } else { + *err = json_tokener_error_parse_object; + return NULL; + } + break; + + case json_tokener_state_object_value: + obj = json_tokener_do_parse(this, err); + if(*err != json_tokener_success) { + *err = json_tokener_error_parse_object; + goto out; + } + json_object_object_add(current, obj_field_name, obj); + free(obj_field_name); + obj_field_name = NULL; + saved_state = json_tokener_state_object_sep; + state = json_tokener_state_eatws; + break; + + case json_tokener_state_object_sep: + if(c == '}') { + this->pos++; + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + } else if(c == ',') { + this->pos++; + saved_state = json_tokener_state_object; + state = json_tokener_state_eatws; + } else { + *err = json_tokener_error_parse_object; + goto out; + } + break; + + } + } while(c); + + if(state != json_tokener_state_finish && + saved_state != json_tokener_state_finish) + *err = json_tokener_error_parse_eof; + + out: + free(obj_field_name); + if(*err == json_tokener_success) return current; + mc_debug("json_tokener_do_parse: error=%d state=%d char=%c\n", + *err, state, c); + json_object_put(current); + return NULL; +} diff --git a/ext/json/json_c/json_tokener.h b/ext/json/json_c/json_tokener.h new file mode 100644 index 0000000000..c493b75715 --- /dev/null +++ b/ext/json/json_c/json_tokener.h @@ -0,0 +1,83 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _json_tokener_h_ +#define _json_tokener_h_ + +#include "json_object.h" + +enum json_tokener_error { + json_tokener_success, + json_tokener_error_parse_unexpected, + json_tokener_error_parse_null, + json_tokener_error_parse_boolean, + json_tokener_error_parse_number, + json_tokener_error_parse_array, + json_tokener_error_parse_object, + json_tokener_error_parse_string, + json_tokener_error_parse_comment, + json_tokener_error_parse_eof +}; + +enum json_tokener_state { + json_tokener_state_eatws, + json_tokener_state_start, + json_tokener_state_finish, + json_tokener_state_null, + json_tokener_state_comment_start, + json_tokener_state_comment, + json_tokener_state_comment_eol, + json_tokener_state_comment_end, + json_tokener_state_string, + json_tokener_state_string_escape, + json_tokener_state_escape_unicode, + json_tokener_state_boolean, + json_tokener_state_number, + json_tokener_state_array, + json_tokener_state_array_sep, + json_tokener_state_object, + json_tokener_state_object_field_start, + json_tokener_state_object_field, + json_tokener_state_object_field_end, + json_tokener_state_object_value, + json_tokener_state_object_sep +}; + +struct json_tokener +{ + char *source; + int pos; + struct printbuf *pb; +}; + +#if !HAVE_STRNCASECMP && defined(_MSC_VER) + /* MSC has the version as _strnicmp */ +#ifndef strncasecmp +# define strncasecmp _strnicmp +#endif +#elif !HAVE_STRNCASECMP +# error You do not have strncasecmp on your system. +#endif /* HAVE_STRNCASECMP */ + +#if !HAVE_STRNDUP + char* strndup(const char* str, size_t n); +#endif /* !HAVE_STRNDUP */ + +extern struct json_object* json_tokener_parse(char *s); + +#endif diff --git a/ext/json/json_c/json_util.c b/ext/json/json_c/json_util.c new file mode 100644 index 0000000000..5509a43b4e --- /dev/null +++ b/ext/json/json_c/json_util.c @@ -0,0 +1,123 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + + + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <errno.h> + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ + +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif /* HAVE_SYS_STAT_H */ + +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif /* HAVE_FCNTL_H */ + +#if HAVE_UNISTD_H +# include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# include <io.h> +#endif /* defined(WIN32) */ + +#include "bits.h" +#include "debug.h" +#include "printbuf.h" +#include "json_object.h" +#include "json_tokener.h" +#include "json_util.h" + +struct json_object* json_object_from_file(char *filename) +{ + struct printbuf *pb; + struct json_object *obj; + char buf[JSON_FILE_BUF_SIZE]; + int fd, ret; + + if((fd = open(filename, O_RDONLY)) < 0) { + mc_error("json_object_from_file: error reading file %s: %s\n", + filename, strerror(errno)); + return error_ptr(-1); + } + if(!(pb = printbuf_new())) { + mc_error("json_object_from_file: printbuf_new failed\n"); + return error_ptr(-1); + } + while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { + printbuf_memappend(pb, buf, ret); + } + close(fd); + if(ret < 0) { + mc_abort("json_object_from_file: error reading file %s: %s\n", + filename, strerror(errno)); + printbuf_free(pb); + return error_ptr(-1); + } + obj = json_tokener_parse(pb->buf); + printbuf_free(pb); + return obj; +} + +int json_object_to_file(char *filename, struct json_object *obj) +{ + char *json_str; + int fd, ret; + unsigned int wpos, wsize; + + if(!obj) { + mc_error("json_object_to_file: object is null\n"); + return -1; + } + + if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { + mc_error("json_object_to_file: error opening file %s: %s\n", + filename, strerror(errno)); + return -1; + } + + if(!(json_str = json_object_to_json_string(obj))) { return -1; } + + + wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ + wpos = 0; + while(wpos < wsize) { + if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { + close(fd); + mc_error("json_object_to_file: error writing file %s: %s\n", + filename, strerror(errno)); + return -1; + } + + /* because of the above check for ret < 0, we can safely cast and add */ + wpos += (unsigned int)ret; + } + + close(fd); + return 0; +} diff --git a/ext/json/json_c/json_util.h b/ext/json/json_c/json_util.h new file mode 100644 index 0000000000..86e897b341 --- /dev/null +++ b/ext/json/json_c/json_util.h @@ -0,0 +1,42 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _json_util_h_ +#define _json_util_h_ + + + +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# include <io.h> +#endif + +#include "json_object.h" + +#if !HAVE_OPEN && defined(WIN32) +# define open _open +#endif + +#define JSON_FILE_BUF_SIZE 4096 + +/* utlitiy functions */ +extern struct json_object* json_object_from_file(char *filename); +extern int json_object_to_file(char *filename, struct json_object *obj); + +#endif diff --git a/ext/json/json_c/linkhash.c b/ext/json/json_c/linkhash.c new file mode 100644 index 0000000000..aed97d1d37 --- /dev/null +++ b/ext/json/json_c/linkhash.c @@ -0,0 +1,224 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + + + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stddef.h> +#include <limits.h> + +#include "linkhash.h" + +void lh_abort(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + vprintf(msg, ap); + exit(1); +} + +unsigned long lh_ptr_hash(void *k) +{ + /* CAW: refactored to be 64bit nice */ + return (unsigned long)((((ptrdiff_t)k * LH_PRIME) >> 4) & ULONG_MAX); +} + +int lh_ptr_equal(void *k1, void *k2) +{ + return (k1 == k2); +} + +unsigned long lh_char_hash(void *k) +{ + unsigned int h = 0; + const char* data = k; + + while( *data!=0 ) h = h*129 + (unsigned int)(*data++) + LH_PRIME; + + return h; +} + +int lh_char_equal(void *k1, void *k2) +{ + return (strcmp((char*)k1, (char*)k2) == 0); +} + +struct lh_table* lh_table_new(int size, char *name, + lh_entry_free_fn *free_fn, + lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn) +{ + int i; + struct lh_table *t; + + t = calloc(1, sizeof(struct lh_table)); + if(!t) lh_abort("lh_table_new: calloc failed\n"); + t->count = 0; + t->size = size; + t->name = name; + t->table = calloc(size, sizeof(struct lh_entry)); + if(!t->table) lh_abort("lh_table_new: calloc failed\n"); + t->free_fn = free_fn; + t->hash_fn = hash_fn; + t->equal_fn = equal_fn; + for(i = 0; i < size; i++) t->table[i].k = LH_EMPTY; + return t; +} + +struct lh_table* lh_kchar_table_new(int size, char *name, + lh_entry_free_fn *free_fn) +{ + return lh_table_new(size, name, free_fn, lh_char_hash, lh_char_equal); +} + +struct lh_table* lh_kptr_table_new(int size, char *name, + lh_entry_free_fn *free_fn) +{ + return lh_table_new(size, name, free_fn, lh_ptr_hash, lh_ptr_equal); +} + +void lh_table_resize(struct lh_table *t, int new_size) +{ + struct lh_table *new_t; + struct lh_entry *ent; + + new_t = lh_table_new(new_size, t->name, NULL, t->hash_fn, t->equal_fn); + ent = t->head; + while(ent) { + lh_table_insert(new_t, ent->k, ent->v); + ent = ent->next; + } + free(t->table); + t->table = new_t->table; + t->size = new_size; + t->head = new_t->head; + t->tail = new_t->tail; + t->resizes++; + free(new_t); +} + +void lh_table_free(struct lh_table *t) +{ + struct lh_entry *c; + for(c = t->head; c != NULL; c = c->next) { + if(t->free_fn) { + t->free_fn(c); + } + } + free(t->table); + free(t); +} + + +int lh_table_insert(struct lh_table *t, void *k, void *v) +{ + unsigned long h, n; + + t->inserts++; + if(t->count > t->size * 0.66) lh_table_resize(t, t->size * 2); + + h = t->hash_fn(k); + n = h % t->size; + + while( 1 ) { + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) break; + t->collisions++; + if(++n == t->size) n = 0; + } + + t->table[n].k = k; + t->table[n].v = v; + t->count++; + + if(t->head == NULL) { + t->head = t->tail = &t->table[n]; + t->table[n].next = t->table[n].prev = NULL; + } else { + t->tail->next = &t->table[n]; + t->table[n].prev = t->tail; + t->table[n].next = NULL; + t->tail = &t->table[n]; + } + + return 0; +} + + +struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k) +{ + unsigned long h = t->hash_fn(k); + unsigned long n = h % t->size; + + t->lookups++; + while( 1 ) { + if(t->table[n].k == LH_EMPTY) return NULL; + if(t->table[n].k != LH_FREED && + t->equal_fn(t->table[n].k, k)) return &t->table[n]; + if(++n == t->size) n = 0; + } + return NULL; +} + + +void* lh_table_lookup(struct lh_table *t, void *k) +{ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if(e) return e->v; + return NULL; +} + + +int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) +{ + ptrdiff_t n = (ptrdiff_t)(e - t->table); /* CAW: fixed to be 64bit nice, still need the crazy negative case... */ + + /* CAW: this is bad, really bad, maybe stack goes other direction on this machine... */ + if(n < 0) { return -2; } + + if(t->table[n].k == LH_EMPTY || t->table[n].k == LH_FREED) return -1; + t->count--; + if(t->free_fn) t->free_fn(e); + t->table[n].v = NULL; + t->table[n].k = LH_FREED; + if(t->tail == &t->table[n] && t->head == &t->table[n]) { + t->head = t->tail = NULL; + } else if (t->head == &t->table[n]) { + t->head->next->prev = NULL; + t->head = t->head->next; + } else if (t->tail == &t->table[n]) { + t->tail->prev->next = NULL; + t->tail = t->tail->prev; + } else { + t->table[n].prev->next = t->table[n].next; + t->table[n].next->prev = t->table[n].prev; + } + t->table[n].next = t->table[n].prev = NULL; + return 0; +} + + +int lh_table_delete(struct lh_table *t, void *k) +{ + struct lh_entry *e = lh_table_lookup_entry(t, k); + if(!e) return -1; + return lh_table_delete_entry(t, e); +} + diff --git a/ext/json/json_c/linkhash.h b/ext/json/json_c/linkhash.h new file mode 100644 index 0000000000..ee872a3617 --- /dev/null +++ b/ext/json/json_c/linkhash.h @@ -0,0 +1,270 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _linkhash_h_ +#define _linkhash_h_ + + + +/** + * golden prime used in hash functions + */ +#define LH_PRIME 0x9e370001UL + +/** + * sentinel pointer value for empty slots + */ +#define LH_EMPTY (void*)-1 + +/** + * sentinel pointer value for freed slots + */ +#define LH_FREED (void*)-2 + +struct lh_entry; + +/** + * callback function prototypes + */ +typedef void (lh_entry_free_fn) (struct lh_entry *e); +/** + * callback function prototypes + */ +typedef unsigned long (lh_hash_fn) (void *k); +/** + * callback function prototypes + */ +typedef int (lh_equal_fn) (void *k1, void *k2); + +/** + * An entry in the hash table + */ +struct lh_entry { + /** + * The key. + */ + void *k; + /** + * The value. + */ + void *v; + /** + * The next entry + */ + struct lh_entry *next; + /** + * The previous entry. + */ + struct lh_entry *prev; +}; + + +/** + * The hash table structure. + */ +struct lh_table { + /** + * Size of our hash. + */ + int size; + /** + * Numbers of entries. + */ + int count; + + /** + * Number of collisions. + */ + int collisions; + + /** + * Number of resizes. + */ + int resizes; + + /** + * Number of lookups. + */ + int lookups; + + /** + * Number of inserts. + */ + int inserts; + + /** + * Number of deletes. + */ + int deletes; + + /** + * Name of the hash table. + */ + char *name; + + /** + * The first entry. + */ + struct lh_entry *head; + + /** + * The last entry. + */ + struct lh_entry *tail; + + struct lh_entry *table; + + /** + * A pointer onto the function responsible for freeing an entry. + */ + lh_entry_free_fn *free_fn; + lh_hash_fn *hash_fn; + lh_equal_fn *equal_fn; +}; + + +/** + * Pre-defined hash and equality functions + */ +extern unsigned long lh_ptr_hash(void *k); +extern int lh_ptr_equal(void *k1, void *k2); + +extern unsigned long lh_char_hash(void *k); +extern int lh_char_equal(void *k1, void *k2); + + +/** + * Convenience list iterator. + */ +#define lh_foreach(table, entry) \ +for(entry = table->head; entry; entry = entry->next) + +/** + * lh_foreach_safe allows calling of deletion routine while iterating. + */ +#define lh_foreach_safe(table, entry, tmp) \ +for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) + + + +/** + * Create a new linkhash table. + * @param size initial table size. The table is automatically resized + * although this incurs a performance penalty. + * @param name the table name. + * @param free_fn callback function used to free memory for entries + * when lh_table_free or lh_table_delete is called. + * If NULL is provided, then memory for keys and values + * must be freed by the caller. + * @param hash_fn function used to hash keys. 2 standard ones are defined: + * lh_ptr_hash and lh_char_hash for hashing pointer values + * and C strings respectively. + * @param equal_fn comparison function to compare keys. 2 standard ones defined: + * lh_ptr_hash and lh_char_hash for comparing pointer values + * and C strings respectively. + * @return a pointer onto the linkhash table. + */ +extern struct lh_table* lh_table_new(int size, char *name, + lh_entry_free_fn *free_fn, + lh_hash_fn *hash_fn, + lh_equal_fn *equal_fn); + +/** + * Convenience function to create a new linkhash + * table with char keys. + * @param size initial table size. + * @param name table name. + * @param free_fn callback function used to free memory for entries. + * @return a pointer onto the linkhash table. + */ +extern struct lh_table* lh_kchar_table_new(int size, char *name, + lh_entry_free_fn *free_fn); + + +/** + * Convenience function to create a new linkhash + * table with ptr keys. + * @param size initial table size. + * @param name table name. + * @param free_fn callback function used to free memory for entries. + * @return a pointer onto the linkhash table. + */ +extern struct lh_table* lh_kptr_table_new(int size, char *name, + lh_entry_free_fn *free_fn); + + +/** + * Free a linkhash table. + * If a callback free function is provided then it is called for all + * entries in the table. + * @param t table to free. + */ +extern void lh_table_free(struct lh_table *t); + + +/** + * Insert a record into the table. + * @param t the table to insert into. + * @param k a pointer to the key to insert. + * @param v a pointer to the value to insert. + */ +extern int lh_table_insert(struct lh_table *t, void *k, void *v); + + +/** + * Lookup a record into the table. + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @return a pointer to the record structure of the value or NULL if it does not exist. + */ +extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, void *k); + +/** + * Lookup a record into the table + * @param t the table to lookup + * @param k a pointer to the key to lookup + * @return a pointer to the found value or NULL if it does not exist. + */ +extern void* lh_table_lookup(struct lh_table *t, void *k); + + +/** + * Delete a record from the table. + * If a callback free function is provided then it is called for the + * for the item being deleted. + * @param t the table to delete from. + * @param e a pointer to the entry to delete. + * @return 0 if the item was deleted. + * @return -1 if it was not found. + */ +extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); + + +/** + * Delete a record from the table. + * If a callback free function is provided then it is called for the + * for the item being deleted. + * @param t the table to delete from. + * @param k a pointer to the key to delete. + * @return 0 if the item was deleted. + * @return -1 if it was not found. + */ +extern int lh_table_delete(struct lh_table *t, void *k); + + +#endif diff --git a/ext/json/json_c/ossupport.c b/ext/json/json_c/ossupport.c new file mode 100644 index 0000000000..45d8ef6201 --- /dev/null +++ b/ext/json/json_c/ossupport.c @@ -0,0 +1,45 @@ +/* + * $Id$ + * + * Copyright Marc Butler 2005. + * Marc Butler <marcbutler@acm.org> + * + * Copyright (c) 2005 Omar Kilani <omar@rmilk.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#include <string.h> +#include <stdlib.h> +#include "ossupport.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if (defined(HAVE_CONFIG_H) && !defined(HAVE_STRNDUP)) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(_MSC_VER) +/** + * Synthesize strndup for BSD. + */ +char *strndup(const char *s, size_t len) +{ + char *copy; + if (s == NULL) + return NULL; + copy = malloc(sizeof (char) * (len + 1)); + if (copy == NULL) + return NULL; + strncpy(copy, s, len); + copy[len] = '\0'; + return copy; +} +#endif /* !HAVE_STRNDUP || __APPLE_CC__ || __FreeBSD__ || __OpenBSD__ || __sun__*/ diff --git a/ext/json/json_c/ossupport.h b/ext/json/json_c/ossupport.h new file mode 100644 index 0000000000..84008104fb --- /dev/null +++ b/ext/json/json_c/ossupport.h @@ -0,0 +1,28 @@ +/* + * $Id$ + * + * Copyright Marc Butler 2005. + * Marc Butler <marcbutler@acm.org> + * + * Copyright (c) 2005 Omar Kilani <omar@rmilk.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _ossupport_h_ +#define _ossupport_h_ + +#if (defined(HAVE_CONFIG_H) && !defined(HAVE_STRNDUP)) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(_MSC_VER) +char * strndup(const char *s, size_t len); +#endif /* __APPLE_CC__ || __FreeBSD__ || __OpenBSD__ */ + +#endif diff --git a/ext/json/json_c/printbuf.c b/ext/json/json_c/printbuf.c new file mode 100644 index 0000000000..a7918cf1f4 --- /dev/null +++ b/ext/json/json_c/printbuf.c @@ -0,0 +1,154 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if HAVE_STDARG_H || defined(_MSC_VER) +# include <stdarg.h> +#else /* !HAVE_STDARG_H */ +# error Not enough var arg support! +#endif /* HAVE_STDARG_H */ + +#include "bits.h" +#include "debug.h" +#include "printbuf.h" + +struct printbuf* printbuf_new() +{ + struct printbuf *p; + + if(!(p = calloc(1, sizeof(struct printbuf)))) return NULL; + p->size = 32; + p->bpos = 0; + if(!(p->buf = malloc(p->size))) { + free(p); + return NULL; + } + return p; +} + + +int printbuf_memappend(struct printbuf *p, char *buf, int size) +{ + char *t; + if(p->size - p->bpos <= size) { + int new_size = max(p->size * 2, p->bpos + size + 8); +#ifdef PRINTBUF_DEBUG + mc_debug("printbuf_memappend: realloc " + "bpos=%d wrsize=%d old_size=%d new_size=%d\n", + p->bpos, size, p->size, new_size); +#endif /* PRINTBUF_DEBUG */ + if(!(t = realloc(p->buf, new_size))) return -1; + p->size = new_size; + p->buf = t; + } + memcpy(p->buf + p->bpos, buf, size); + p->bpos += size; + p->buf[p->bpos]= '\0'; + return size; +} + +#if !HAVE_VSNPRINTF && defined(WIN32) +# define vsnprintf _vsnprintf +#elif !HAVE_VSNPRINTF /* !HAVE_VSNPRINTF */ +# error Need vsnprintf! +#endif /* !HAVE_VSNPRINTF && defined(WIN32) */ + +#if !HAVE_VASPRINTF +/* CAW: compliant version of vasprintf */ +static int vasprintf(char **buf, const char *fmt, va_list ap) +{ +#if !(defined(WIN32) && defined(_MSC_VER) && _MSC_VER > 1200) + static char _T_emptybuffer = '\0'; +#endif /* !defined(WIN32) */ + int chars; + char *b; + + if(!buf) { return -1; } + +#if defined(WIN32) && defined(_MSC_VER) && _MSC_VER > 1200 + chars = _vscprintf(fmt, ap)+1; +#else /* !defined(WIN32) */ + /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite + our buffer like on some 64bit sun systems.... but hey, its time to move on */ + chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1; + if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */ +#endif /* defined(WIN32) */ + + b = (char*)malloc(sizeof(char)*chars); + if(!b) { return -1; } + + if((chars = vsprintf(b, fmt, ap)) < 0) + { + free(b); + } else { + *buf = b; + } + + return chars; +} +#endif /* !HAVE_VASPRINTF */ + +int sprintbuf(struct printbuf *p, const char *msg, ...) +{ + va_list ap; + char *t; + int size; + char buf[128]; + + /* user stack buffer first */ + va_start(ap, msg); + size = vsnprintf(buf, 128, msg, ap); + va_end(ap); + /* if string is greater than stack buffer, then use dynamic string + with vasprintf. Note: some implementation of vsnprintf return -1 + if output is truncated whereas some return the number of bytes that + would have been writen - this code handles both cases. */ + if(size == -1 || size > 127) { + int ret; + va_start(ap, msg); + if((size = vasprintf(&t, msg, ap)) == -1) return -1; + va_end(ap); + ret = printbuf_memappend(p, t, size); + free(t); + return ret; + } else { + return printbuf_memappend(p, buf, size); + } +} + +void printbuf_reset(struct printbuf *p) +{ + p->buf[0] = '\0'; + p->bpos = 0; +} + +void printbuf_free(struct printbuf *p) +{ + if(p) { + free(p->buf); + free(p); + } +} diff --git a/ext/json/json_c/printbuf.h b/ext/json/json_c/printbuf.h new file mode 100644 index 0000000000..53ae7492c9 --- /dev/null +++ b/ext/json/json_c/printbuf.h @@ -0,0 +1,45 @@ +/* + * $Id$ + * + * Copyright Metaparadigm Pte. Ltd. 2004. + * Michael Clark <michael@metaparadigm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +#ifndef _printbuf_h_ +#define _printbuf_h_ + +#undef PRINTBUF_DEBUG + +struct printbuf { + char *buf; + int bpos; + int size; +}; + +extern struct printbuf* +printbuf_new(); + +extern int +printbuf_memappend(struct printbuf *p, char *buf, int size); + +extern int +sprintbuf(struct printbuf *p, const char *msg, ...); + +extern void +printbuf_reset(struct printbuf *p); + +extern void +printbuf_free(struct printbuf *p); + +#endif diff --git a/ext/json/json_c/test1.c b/ext/json/json_c/test1.c new file mode 100644 index 0000000000..8e49d100a3 --- /dev/null +++ b/ext/json/json_c/test1.c @@ -0,0 +1,137 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "json.h" + +int main(int argc, char **argv) +{ + struct json_object *my_string, *my_int, *my_object, *my_array; + struct json_object *new_obj; + int i; + + my_string = json_object_new_string("\t"); + printf("my_string=%s\n", json_object_get_string(my_string)); + printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); + json_object_put(my_string); + + my_string = json_object_new_string("foo"); + printf("my_string=%s\n", json_object_get_string(my_string)); + printf("my_string.to_string()=%s\n", json_object_to_json_string(my_string)); + + my_int = json_object_new_int(9); + printf("my_int=%d\n", json_object_get_int(my_int)); + printf("my_int.to_string()=%s\n", json_object_to_json_string(my_int)); + + my_array = json_object_new_array(); + json_object_array_add(my_array, json_object_new_int(1)); + json_object_array_add(my_array, json_object_new_int(2)); + json_object_array_add(my_array, json_object_new_int(3)); + json_object_array_put_idx(my_array, 4, json_object_new_int(5)); + printf("my_array=\n"); + for(i=0; i < json_object_array_length(my_array); i++) { + struct json_object *obj = json_object_array_get_idx(my_array, i); + printf("\t[%d]=%s\n", i, json_object_to_json_string(obj)); + } + printf("my_array.to_string()=%s\n", json_object_to_json_string(my_array)); + + my_object = json_object_new_object(); + json_object_object_add(my_object, "abc", json_object_new_int(12)); + json_object_object_add(my_object, "foo", json_object_new_string("bar")); + json_object_object_add(my_object, "bool0", json_object_new_boolean(0)); + json_object_object_add(my_object, "bool1", json_object_new_boolean(1)); + json_object_object_add(my_object, "baz", json_object_new_string("bang")); + json_object_object_add(my_object, "baz", json_object_new_string("fark")); + json_object_object_del(my_object, "baz"); + json_object_object_add(my_object, "arr", my_array); + printf("my_object=\n"); + json_object_object_foreach(my_object, key, val) { + printf("\t%s: %s\n", key, json_object_to_json_string(val)); + } + printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); + + new_obj = json_tokener_parse("\"\003\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("/* hello */\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("// hello\n\"foo\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("\"\\u0041\\u0042\\u0043\""); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("null"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("True"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("12.3"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"\\nabc\\n\"]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[null]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("[\"abc\",null,\"def\",12]"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{}"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\" }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": \"bar\", \"baz\": null, \"bool0\": true }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"foo\": [null, \"foo\"] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ \"abc\": 12, \"foo\": \"bar\", \"bool0\": false, \"bool1\": true, \"arr\": [ 1, 2, 3, null, 5 ] }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("{ foo }"); + if(is_error(new_obj)) printf("got error as expected\n"); + + new_obj = json_tokener_parse("foo"); + if(is_error(new_obj)) printf("got error as expected\n"); + + json_object_put(my_string); + json_object_put(my_int); + json_object_put(my_object); + //json_object_put(my_array); + + return 0; +} diff --git a/ext/json/json_c/test2.c b/ext/json/json_c/test2.c new file mode 100644 index 0000000000..b7bdf62888 --- /dev/null +++ b/ext/json/json_c/test2.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "json.h" + + +int main(int argc, char **argv) +{ + struct json_object *new_obj; + + mc_set_debug(1); + + new_obj = json_tokener_parse("/* more difficult test case */ { \"glossary\": { \"title\": \"example glossary\", \"GlossDiv\": { \"title\": \"S\", \"GlossList\": [ { \"ID\": \"SGML\", \"SortAs\": \"SGML\", \"GlossTerm\": \"Standard Generalized Markup Language\", \"Acronym\": \"SGML\", \"Abbrev\": \"ISO 8879:1986\", \"GlossDef\": \"A meta-markup language, used to create markup languages such as DocBook.\", \"GlossSeeAlso\": [\"GML\", \"XML\", \"markup\"] } ] } } }"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + return 0; +} diff --git a/ext/json/php_json.h b/ext/json/php_json.h new file mode 100644 index 0000000000..b9f6321ca3 --- /dev/null +++ b/ext/json/php_json.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005 Omar Kilani <omar@rmilk.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public (LGPL) + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details: http://www.gnu.org/ + * + */ + +/* $Id$ */ + +#ifndef PHP_JSON_H +#define PHP_JSON_H + +#define PHP_JSON_VERSION "1.1.0" + +extern zend_module_entry json_module_entry; +#define phpext_json_ptr &json_module_entry + +#ifdef PHP_WIN32 +#define PHP_JSON_API __declspec(dllexport) +#else +#define PHP_JSON_API +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +PHP_MINIT_FUNCTION(json); +PHP_MSHUTDOWN_FUNCTION(json); +PHP_RINIT_FUNCTION(json); +PHP_RSHUTDOWN_FUNCTION(json); +PHP_MINFO_FUNCTION(json); + +PHP_FUNCTION(json_encode); +PHP_FUNCTION(json_decode); + +#ifdef ZTS +#define JSON_G(v) TSRMG(json_globals_id, zend_json_globals *, v) +#else +#define JSON_G(v) (json_globals.v) +#endif + +#endif /* PHP_JSON_H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ |