]> granicus.if.org Git - php/commitdiff
Add json extension to PECL.
authorOmar Kilani <omar@php.net>
Tue, 6 Dec 2005 06:23:24 +0000 (06:23 +0000)
committerOmar Kilani <omar@php.net>
Tue, 6 Dec 2005 06:23:24 +0000 (06:23 +0000)
32 files changed:
ext/json/config.m4 [new file with mode: 0644]
ext/json/config.w32 [new file with mode: 0644]
ext/json/json.c [new file with mode: 0644]
ext/json/json.dsp [new file with mode: 0644]
ext/json/json_c/AUTHORS [new file with mode: 0644]
ext/json/json_c/ConvertUTF.c [new file with mode: 0644]
ext/json/json_c/ConvertUTF.h [new file with mode: 0644]
ext/json/json_c/README.FORK [new file with mode: 0644]
ext/json/json_c/arraylist.c [new file with mode: 0644]
ext/json/json_c/arraylist.h [new file with mode: 0644]
ext/json/json_c/bits.h [new file with mode: 0644]
ext/json/json_c/config.h [new file with mode: 0644]
ext/json/json_c/config.h.win32 [new file with mode: 0644]
ext/json/json_c/debug.c [new file with mode: 0644]
ext/json/json_c/debug.h [new file with mode: 0644]
ext/json/json_c/json.h [new file with mode: 0644]
ext/json/json_c/json_object.c [new file with mode: 0644]
ext/json/json_c/json_object.h [new file with mode: 0644]
ext/json/json_c/json_object_private.h [new file with mode: 0644]
ext/json/json_c/json_tokener.c [new file with mode: 0644]
ext/json/json_c/json_tokener.h [new file with mode: 0644]
ext/json/json_c/json_util.c [new file with mode: 0644]
ext/json/json_c/json_util.h [new file with mode: 0644]
ext/json/json_c/linkhash.c [new file with mode: 0644]
ext/json/json_c/linkhash.h [new file with mode: 0644]
ext/json/json_c/ossupport.c [new file with mode: 0644]
ext/json/json_c/ossupport.h [new file with mode: 0644]
ext/json/json_c/printbuf.c [new file with mode: 0644]
ext/json/json_c/printbuf.h [new file with mode: 0644]
ext/json/json_c/test1.c [new file with mode: 0644]
ext/json/json_c/test2.c [new file with mode: 0644]
ext/json/php_json.h [new file with mode: 0644]

diff --git a/ext/json/config.m4 b/ext/json/config.m4
new file mode 100644 (file)
index 0000000..4dae05b
--- /dev/null
@@ -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 (file)
index 0000000..d933c76
--- /dev/null
@@ -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 (file)
index 0000000..001c584
--- /dev/null
@@ -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", &parameter) == 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", &parameter, &parameter_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 (file)
index 0000000..e465b44
--- /dev/null
@@ -0,0 +1,199 @@
+# Microsoft Developer Studio Project File - Name="json" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102\r
+\r
+CFG=json - Win32 Debug_TS\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "json.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "json.mak" CFG="json - Win32 Debug_TS"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "json - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE "json - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+CPP=cl.exe\r
+MTL=midl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "json - Win32 Debug_TS"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug_TS"\r
+# PROP BASE Intermediate_Dir "Debug_TS"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug_TS"\r
+# PROP Intermediate_Dir "Debug_TS"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# 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\r
+# 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\r
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"\r
+# ADD RSC /l 0x1009 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# 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\r
+# 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"\r
+\r
+!ELSEIF  "$(CFG)" == "json - Win32 Release_TS"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release_TS"\r
+# PROP BASE Intermediate_Dir "Release_TS"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release_TS"\r
+# PROP Intermediate_Dir "Release_TS"\r
+# PROP Ignore_Export_Lib 0\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /c\r
+# 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\r
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32\r
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"\r
+# ADD RSC /l 0x1009 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LINK32=link.exe\r
+# 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\r
+# 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"\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "json - Win32 Debug_TS"\r
+# Name "json - Win32 Release_TS"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Source File\r
+\r
+SOURCE=".\json.c"\r
+# End Source File\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Source File\r
+\r
+SOURCE=.\php_json.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "Resource Files"\r
+\r
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+# End Group\r
+# Begin Group "json_c"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\arraylist.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\arraylist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\bits.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\ConvertUTF.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\ConvertUTF.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\debug.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\debug.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\json.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\json_object.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\json_object.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\json_object_private.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\json_tokener.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\json_tokener.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\json_util.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\json_util.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\linkhash.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\linkhash.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\ossupport.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\ossupport.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\printbuf.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\json_c\printbuf.h\r
+# End Source File\r
+# End Group\r
+# End Target\r
+# End Project\r
diff --git a/ext/json/json_c/AUTHORS b/ext/json/json_c/AUTHORS
new file mode 100644 (file)
index 0000000..eb8e553
--- /dev/null
@@ -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 (file)
index 0000000..9b3deeb
--- /dev/null
@@ -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 (file)
index 0000000..e264915
--- /dev/null
@@ -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 (file)
index 0000000..debf62a
--- /dev/null
@@ -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 (file)
index 0000000..b0112a6
--- /dev/null
@@ -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 (file)
index 0000000..95cc3a9
--- /dev/null
@@ -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 (file)
index 0000000..252a52b
--- /dev/null
@@ -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 (file)
index 0000000..a69a281
--- /dev/null
@@ -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 (file)
index 0000000..895eace
--- /dev/null
@@ -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 (file)
index 0000000..79b6028
--- /dev/null
@@ -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 (file)
index 0000000..22e1ab1
--- /dev/null
@@ -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 (file)
index 0000000..94ce47d
--- /dev/null
@@ -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 (file)
index 0000000..5faf761
--- /dev/null
@@ -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 (file)
index 0000000..2c915d7
--- /dev/null
@@ -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 (file)
index 0000000..64cf6c1
--- /dev/null
@@ -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 (file)
index 0000000..75be394
--- /dev/null
@@ -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 (file)
index 0000000..c493b75
--- /dev/null
@@ -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 (file)
index 0000000..5509a43
--- /dev/null
@@ -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 (file)
index 0000000..86e897b
--- /dev/null
@@ -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 (file)
index 0000000..aed97d1
--- /dev/null
@@ -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 (file)
index 0000000..ee872a3
--- /dev/null
@@ -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 (file)
index 0000000..45d8ef6
--- /dev/null
@@ -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 (file)
index 0000000..8400810
--- /dev/null
@@ -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 (file)
index 0000000..a7918cf
--- /dev/null
@@ -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 (file)
index 0000000..53ae749
--- /dev/null
@@ -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 (file)
index 0000000..8e49d10
--- /dev/null
@@ -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 (file)
index 0000000..b7bdf62
--- /dev/null
@@ -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 (file)
index 0000000..b9f6321
--- /dev/null
@@ -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
+ */