]> granicus.if.org Git - php/commitdiff
This commit was manufactured by cvs2svn to create branch 'PHP_5_2'.
authorSVN Migration <svn@php.net>
Fri, 5 May 2006 15:49:42 +0000 (15:49 +0000)
committerSVN Migration <svn@php.net>
Fri, 5 May 2006 15:49:42 +0000 (15:49 +0000)
46 files changed:
ext/filter/CREDITS [new file with mode: 0644]
ext/filter/callback_filter.c [new file with mode: 0644]
ext/filter/config.m4 [new file with mode: 0644]
ext/filter/config.w32 [new file with mode: 0644]
ext/filter/sanitizing_filters.c [new file with mode: 0644]
ext/filter/tests/001.phpt [new file with mode: 0644]
ext/filter/tests/002.phpt [new file with mode: 0644]
ext/filter/tests/003.phpt [new file with mode: 0644]
ext/filter/tests/004.phpt [new file with mode: 0644]
ext/filter/tests/005.phpt [new file with mode: 0644]
ext/filter/tests/006.phpt [new file with mode: 0644]
ext/filter/tests/007.phpt [new file with mode: 0644]
ext/filter/tests/008.phpt [new file with mode: 0644]
ext/filter/tests/009.phpt [new file with mode: 0644]
ext/filter/tests/011.phpt [new file with mode: 0644]
ext/filter/tests/012.phpt [new file with mode: 0644]
ext/filter/tests/014.phpt [new file with mode: 0644]
ext/filter/tests/020.phpt [new file with mode: 0644]
ext/filter/tests/021.phpt [new file with mode: 0644]
ext/filter/tests/022.phpt [new file with mode: 0644]
ext/filter/tests/023.phpt [new file with mode: 0644]
ext/filter/tests/024.phpt [new file with mode: 0644]
ext/filter/tests/025.phpt [new file with mode: 0644]
ext/filter/tests/026.phpt [new file with mode: 0644]
ext/filter/tests/027.phpt [new file with mode: 0644]
ext/filter/tests/028.phpt [new file with mode: 0644]
ext/filter/tests/029.phpt [new file with mode: 0644]
ext/filter/tests/filter_data.phpt [new file with mode: 0644]
ext/json/JSON_parser.c [new file with mode: 0644]
ext/json/JSON_parser.h [new file with mode: 0644]
ext/json/README [new file with mode: 0644]
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/package.xml [new file with mode: 0644]
ext/json/php_json.h [new file with mode: 0644]
ext/json/tests/fail001.phpt [new file with mode: 0644]
ext/json/tests/pass001.1.phpt [new file with mode: 0644]
ext/json/tests/pass001.phpt [new file with mode: 0644]
ext/json/tests/pass002.phpt [new file with mode: 0644]
ext/json/tests/pass003.phpt [new file with mode: 0644]
ext/json/utf8_decode.c [new file with mode: 0644]
ext/json/utf8_decode.h [new file with mode: 0644]
ext/json/utf8_to_utf16.c [new file with mode: 0644]
ext/json/utf8_to_utf16.h [new file with mode: 0644]

diff --git a/ext/filter/CREDITS b/ext/filter/CREDITS
new file mode 100644 (file)
index 0000000..fade411
--- /dev/null
@@ -0,0 +1,2 @@
+Input Filter
+Rasmus Lerdorf, Derick Rethans
diff --git a/ext/filter/callback_filter.c b/ext/filter/callback_filter.c
new file mode 100644 (file)
index 0000000..5ce17fe
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+  +----------------------------------------------------------------------+
+  | PHP Version 5                                                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 1997-2006 The PHP Group                                |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt                                  |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Derick Rethans <derick@php.net>                             |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php_filter.h"
+
+void php_filter_callback(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       char *name = NULL;
+       zval *retval_ptr;
+       zval ***args;
+       int status;
+
+       if (!option_array || !zend_is_callable(option_array, IS_CALLABLE_CHECK_NO_ACCESS, &name)) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "First argument is expected to be a valid callback");
+               if (name) {
+                       efree(name);
+               }
+               zval_dtor(value);
+               Z_TYPE_P(value) = IS_NULL;
+               return;
+       }
+       efree(name);
+
+       args = safe_emalloc(sizeof(zval **), 1, 0);
+       args[0] = &value;
+       
+       status = call_user_function_ex(EG(function_table), NULL, option_array, &retval_ptr, 1, args, 0, NULL TSRMLS_CC);
+
+       if (status == SUCCESS && retval_ptr != NULL) {
+               zval_dtor(value);
+               *value = *retval_ptr;
+               zval_copy_ctor(value);
+       } else {
+               zval_dtor(value);
+               Z_TYPE_P(value) = IS_NULL;
+       }
+
+       if (retval_ptr) {
+               zval_ptr_dtor(&retval_ptr);
+       }
+       efree(args);
+}
+
+/*
+ * 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
+ */
diff --git a/ext/filter/config.m4 b/ext/filter/config.m4
new file mode 100644 (file)
index 0000000..0db0375
--- /dev/null
@@ -0,0 +1,95 @@
+dnl $Id$
+dnl config.m4 for input filtering extension
+
+PHP_ARG_ENABLE(filter, whether to enable input filter support,
+[  --disable-filter        Disable input filter support], yes)
+
+PHP_ARG_WITH(pcre-dir, pcre install prefix,
+[  --with-pcre-dir           FILTER: pcre install prefix], no, no)
+
+if test "$PHP_FILTER" != "no"; then
+
+  dnl Check if configure is the PHP core configure
+  if test -n "$PHP_VERSION"; then
+    dnl This extension can not be build as shared when in PHP core
+    ext_shared=no
+  else
+    dnl This is PECL build, check if bundled PCRE library is used
+    old_CPPFLAGS=$CPPFLAGS
+    CPPFLAGS=$INCLUDES
+    AC_EGREP_CPP(yes,[
+#include <main/php_config.h>
+#if defined(HAVE_BUNDLED_PCRE) && !defined(COMPILE_DL_PCRE)
+yes
+#endif
+    ],[
+      PHP_PCRE_REGEX=yes
+    ],[
+      AC_EGREP_CPP(yes,[
+#include <main/php_config.h>
+#if defined(HAVE_PCRE) && !defined(COMPILE_DL_PCRE)
+yes
+#endif
+      ],[
+        PHP_PCRE_REGEX=pecl
+      ],[
+        PHP_PCRE_REGEX=no
+      ])
+    ])
+    CPPFLAGS=$old_CPPFLAGS
+  fi
+
+  if test "$PHP_PCRE_REGEX" != "yes"; then
+    dnl
+    dnl If PCRE extension is enabled we can use the already found paths,
+    dnl otherwise we have to detect them here:
+    dnl
+    if test "$PHP_PCRE_REGEX" = "no" || test "$PHP_PCRE_REGEX" = "pecl"; then
+      dnl Set the PCRE search dirs correctly
+      case "$PHP_PCRE_DIR" in
+        yes|no)
+          PCRE_SEARCH_DIR="/usr/local /usr"
+          ;;
+        *)
+          PCRE_SEARCH_DIR="$PHP_PCRE_DIR"
+          ;;
+      esac
+
+      for i in $PCRE_SEARCH_DIR; do
+        if test -f $i/include/pcre/pcre.h; then
+          PCRE_INCDIR=$i/include/pcre
+          break
+        elif test -f $i/include/pcre.h; then
+          PCRE_INCDIR=$i/include
+          break
+        elif test -f $i/pcre.h; then
+          PCRE_INCDIR=$i
+          break
+        fi
+      done
+
+      if test -z "$PCRE_INCDIR"; then
+        AC_MSG_ERROR([Could not find pcre.h anywhere under $PCRE_SEARCH_DIR])
+      fi
+
+      for j in $PCRE_SEARCH_DIR/$PHP_LIBDIR $PCRE_SEARCH_DIR; do
+        if test -f $j/libpcre.a || test -f $j/libpcre.$SHLIB_SUFFIX_NAME; then
+          PCRE_LIBDIR=$j
+          break
+        fi
+      done
+    
+      if test -z "$PCRE_LIBDIR" ; then
+        AC_MSG_ERROR([Could not find libpcre.(a|$SHLIB_SUFFIX_NAME) anywhere under $PCRE_SEARCH_DIR])
+      fi
+    fi
+
+    PHP_ADD_LIBRARY_WITH_PATH(pcre, $PCRE_LIBDIR, FILTER_SHARED_LIBADD)
+    PHP_ADD_INCLUDE($PCRE_INCDIR)
+  fi
+
+  PHP_NEW_EXTENSION(filter, filter.c sanitizing_filters.c logical_filters.c callback_filter.c, $ext_shared)
+  PHP_SUBST(FILTER_SHARED_LIBADD)
+
+  PHP_INSTALL_HEADERS([$ext_srcdir/php_filter.h])
+fi
diff --git a/ext/filter/config.w32 b/ext/filter/config.w32
new file mode 100644 (file)
index 0000000..083555a
--- /dev/null
@@ -0,0 +1,8 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_ENABLE("filter", "Filter Support", "yes");
+
+if (PHP_FILTER == "yes") {
+       EXTENSION("filter", "filter.c sanitizing_filters.c logical_filters.c callback_filter.c");
+}
diff --git a/ext/filter/sanitizing_filters.c b/ext/filter/sanitizing_filters.c
new file mode 100644 (file)
index 0000000..50d17eb
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+  +----------------------------------------------------------------------+
+  | PHP Version 5                                                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 1997-2006 The PHP Group                                |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt                                  |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Authors: Derick Rethans <derick@php.net>                             |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php_filter.h"
+#include "filter_private.h"
+#include "ext/standard/php_smart_str.h"
+
+/* {{{ STRUCTS */
+typedef unsigned long filter_map[256];
+/* }}} */
+
+/* {{{ HELPER FUNCTIONS */
+static void php_filter_encode_html(zval *value, char* chars, int encode_nul)
+{
+       register int x, y;
+       smart_str str = {0};
+       int len = Z_STRLEN_P(value);
+       char *s = Z_STRVAL_P(value);
+
+       if (Z_STRLEN_P(value) == 0) {
+               return;
+       }
+
+       for (x = 0, y = 0; len--; x++, y++) {
+               if (strchr(chars, s[x]) || (encode_nul && s[x] == 0)) {
+                       smart_str_appendl(&str, "&#", 2);
+                       smart_str_append_long(&str, s[x]);
+                       smart_str_appendc(&str, ';');
+               } else {
+                       smart_str_appendc(&str, s[x]);
+               }
+       }
+       smart_str_0(&str);
+       efree(Z_STRVAL_P(value));
+       Z_STRVAL_P(value) = str.c;
+       Z_STRLEN_P(value) = str.len;
+}
+
+static void php_filter_encode_html_high_low(zval *value, long flags)
+{
+       register int x, y;
+       smart_str str = {0};
+       int len = Z_STRLEN_P(value);
+       unsigned char *s = Z_STRVAL_P(value);
+
+       if (Z_STRLEN_P(value) == 0) {
+               return;
+       }
+       
+       for (x = 0, y = 0; len--; x++, y++) {
+               if (((flags & FILTER_FLAG_ENCODE_LOW) && (s[x] < 32)) || ((flags & FILTER_FLAG_ENCODE_HIGH) && (s[x] > 127))) {
+                       smart_str_appendl(&str, "&#", 2);
+                       smart_str_append_long(&str, s[x]);
+                       smart_str_appendc(&str, ';');
+               } else {
+                       smart_str_appendc(&str, s[x]);
+               }
+       }
+       smart_str_0(&str);
+       efree(Z_STRVAL_P(value));
+       Z_STRVAL_P(value) = str.c;
+       Z_STRLEN_P(value) = str.len;
+}
+
+static unsigned char hexchars[] = "0123456789ABCDEF";
+
+#define LOWALPHA    "abcdefghijklmnopqrstuvwxyz"
+#define HIALPHA     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define DIGIT       "0123456789"
+
+#define DEFAULT_URL_ENCODE    LOWALPHA HIALPHA DIGIT "-._"
+
+static void php_filter_encode_url(zval *value, char* chars, int high, int low, int encode_nul)
+{
+       register int x, y;
+       unsigned char *str;
+       int len = Z_STRLEN_P(value);
+       char *s = Z_STRVAL_P(value);
+
+       str = (unsigned char *) safe_emalloc(3, len, 1);
+       for (x = 0, y = 0; len--; x++, y++) {
+               str[y] = (unsigned char) s[x];
+
+               if ((strlen(chars) && !strchr(chars, str[y])) || (high && str[y] > 127) || (low && str[y] < 32) || (encode_nul && str[y] == 0)) {
+                       str[y++] = '%';
+                       str[y++] = hexchars[(unsigned char) s[x] >> 4];
+                       str[y] = hexchars[(unsigned char) s[x] & 15];
+               }
+       }
+       str[y] = '\0';
+       efree(Z_STRVAL_P(value));
+       Z_STRVAL_P(value) = str;
+       Z_STRLEN_P(value) = y;
+}
+
+static void php_filter_strip(zval *value, long flags)
+{
+       unsigned char *buf, *str;
+       int   i, c;
+       
+       /* Optimization for if no strip flags are set */
+       if (! ((flags & FILTER_FLAG_STRIP_LOW) || (flags & FILTER_FLAG_STRIP_HIGH)) ) {
+               return;
+       }
+
+       str = Z_STRVAL_P(value);
+       buf = safe_emalloc(1, Z_STRLEN_P(value) + 1, 1);
+       c = 0;
+       for (i = 0; i < Z_STRLEN_P(value); i++) {
+               if ((str[i] > 127) && (flags & FILTER_FLAG_STRIP_HIGH)) {
+               } else if ((str[i] < 32) && (flags & FILTER_FLAG_STRIP_LOW)) {
+               } else {
+                       buf[c] = str[i];
+                       ++c;
+               }
+       }
+       /* update zval string data */
+       buf[c] = '\0';
+       efree(Z_STRVAL_P(value));
+       Z_STRVAL_P(value) = buf;
+       Z_STRLEN_P(value) = c;
+}
+/* }}} */
+
+/* {{{ FILTER MAP HELPERS */
+static void filter_map_init(filter_map *map)
+{
+       memset(map, 0, sizeof(filter_map));
+}
+
+static void filter_map_update(filter_map *map, int flag, unsigned char *allowed_list)
+{
+       int l, i;
+
+       l = strlen(allowed_list);
+       for (i = 0; i < l; ++i) {
+               (*map)[allowed_list[i]] = flag;
+       }
+}
+
+static void filter_map_apply(zval *value, filter_map *map)
+{
+       unsigned char *buf, *str;
+       int   i, c;
+       
+       str = Z_STRVAL_P(value);
+       buf = safe_emalloc(1, Z_STRLEN_P(value) + 1, 1);
+       c = 0;
+       for (i = 0; i < Z_STRLEN_P(value); i++) {
+               if ((*map)[str[i]]) {
+                       buf[c] = str[i];
+                       ++c;
+               }
+       }
+       /* update zval string data */
+       buf[c] = '\0';
+       efree(Z_STRVAL_P(value));
+       Z_STRVAL_P(value) = buf;
+       Z_STRLEN_P(value) = c;
+}
+/* }}} */
+
+
+/* {{{ php_filter_string */
+void php_filter_string(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       size_t new_len;
+       
+       /* strip tags, implicitly also removes \0 chars */
+       new_len = php_strip_tags(Z_STRVAL_P(value), Z_STRLEN_P(value), NULL, NULL, 0);
+       Z_STRLEN_P(value) = new_len;
+
+       if (new_len == 0) {
+               zval_dtor(value);
+               ZVAL_EMPTY_STRING(value);
+               return;
+       }
+
+       if (! (flags & FILTER_FLAG_NO_ENCODE_QUOTES)) {
+               /* encode ' and " to numerical entity */
+               php_filter_encode_html(value, "'\"", 0);
+       }
+       /* strip high/strip low ( see flags )*/
+       php_filter_strip(value, flags);
+
+       /* encode low/encode high flags */
+       php_filter_encode_html_high_low(value, flags);
+
+       /* also all the flags - & encode as %xx */
+       if (flags & FILTER_FLAG_ENCODE_AMP) {
+               php_filter_encode_html(value, "&", 0);
+       }
+}
+/* }}} */
+
+/* {{{ php_filter_encoded */
+void php_filter_encoded(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       /* apply strip_high and strip_low filters */
+       php_filter_strip(value, flags);
+       /* urlencode */
+       php_filter_encode_url(value, DEFAULT_URL_ENCODE, flags & FILTER_FLAG_ENCODE_HIGH, flags & FILTER_FLAG_ENCODE_LOW, 1);
+}
+/* }}} */
+
+/* {{{ php_filter_special_chars */
+void php_filter_special_chars(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       /* encodes ' " < > & \0 to numerical entities */
+       php_filter_encode_html(value, "'\"<>&", 1);
+       /* if strip low is not set, then we encode them as &#xx; */
+       php_filter_strip(value, flags);
+       php_filter_encode_html_high_low(value, FILTER_FLAG_ENCODE_LOW | flags);
+}
+/* }}} */
+
+/* {{{ php_filter_unsafe_raw */
+void php_filter_unsafe_raw(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       /* Only if no flags are set (optimization) */
+       if (flags != 0 && Z_STRLEN_P(value) > 0) {
+               php_filter_strip(value, flags);
+               if (flags & FILTER_FLAG_ENCODE_AMP) {
+                       php_filter_encode_html(value, "&", 0);
+               }
+               php_filter_encode_html_high_low(value, flags);
+       }
+}
+/* }}} */
+
+/* {{{ php_filter_email */
+#define SAFE        "$-_.+"
+#define EXTRA       "!*'(),"
+#define NATIONAL    "{}|\\^~[]`"
+#define PUNCTUATION "<>#%\""
+#define RESERVED    ";/?:@&="
+
+void php_filter_email(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       /* Check section 6 of rfc 822 http://www.faqs.org/rfcs/rfc822.html */
+       unsigned char *allowed_list = LOWALPHA HIALPHA DIGIT "!#$%&'*+-/=?^_`{|}~@.[]";
+       filter_map     map;
+
+       filter_map_init(&map);
+       filter_map_update(&map, 1, allowed_list);
+       filter_map_apply(value, &map);
+}
+/* }}} */
+
+/* {{{ php_filter_url */
+void php_filter_url(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       /* Strip all chars not part of section 5 of
+        * http://www.faqs.org/rfcs/rfc1738.html */
+       unsigned char *allowed_list = LOWALPHA HIALPHA DIGIT SAFE EXTRA NATIONAL PUNCTUATION RESERVED;
+       filter_map     map;
+
+       filter_map_init(&map);
+       filter_map_update(&map, 1, allowed_list);
+       filter_map_apply(value, &map);
+}
+/* }}} */
+
+/* {{{ php_filter_number_int */
+void php_filter_number_int(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       /* strip everything [^0-9+-] */
+       unsigned char *allowed_list = "+-" DIGIT;
+       filter_map     map;
+
+       filter_map_init(&map);
+       filter_map_update(&map, 1, allowed_list);
+       filter_map_apply(value, &map);
+}
+/* }}} */
+
+/* {{{ php_filter_number_float */
+void php_filter_number_float(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       /* strip everything [^0-9+-] */
+       unsigned char *allowed_list = "+-" DIGIT;
+       filter_map     map;
+
+       filter_map_init(&map);
+       filter_map_update(&map, 1, allowed_list);
+
+       /* depending on flags, strip '.', 'e', ",", "'" */
+       if (flags & FILTER_FLAG_ALLOW_FRACTION) {
+               filter_map_update(&map, 2, ".");
+       }
+       if (flags & FILTER_FLAG_ALLOW_THOUSAND) {
+               filter_map_update(&map, 3, ",");
+       }
+       if (flags & FILTER_FLAG_ALLOW_SCIENTIFIC) {
+               filter_map_update(&map, 4, "eE");
+       }
+       filter_map_apply(value, &map);
+}
+/* }}} */
+
+/* {{{ php_filter_magic_quotes */
+void php_filter_magic_quotes(PHP_INPUT_FILTER_PARAM_DECL)
+{
+       char *buf;
+       int   len;
+       
+       /* just call php_addslashes quotes */
+       buf = php_addslashes(Z_STRVAL_P(value), Z_STRLEN_P(value), &len, 0 TSRMLS_CC);
+
+       efree(Z_STRVAL_P(value));
+       Z_STRVAL_P(value) = buf;
+       Z_STRLEN_P(value) = len;
+}
+/* }}} */
+
+/*
+ * 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
+ */
diff --git a/ext/filter/tests/001.phpt b/ext/filter/tests/001.phpt
new file mode 100644 (file)
index 0000000..2755a57
--- /dev/null
@@ -0,0 +1,8 @@
+--TEST--
+Simple GET test
+--GET--
+a=1
+--FILE--
+<?php echo $_GET['a']; ?>
+--EXPECT--
+1
diff --git a/ext/filter/tests/002.phpt b/ext/filter/tests/002.phpt
new file mode 100644 (file)
index 0000000..7136b25
--- /dev/null
@@ -0,0 +1,11 @@
+--TEST--
+GET test with 2 values and an empty one
+--GET--
+a=1&b=&c=3
+--FILE--
+<?php echo $_GET['a'];
+echo $_GET['b']; 
+echo $_GET['c'];
+?>
+--EXPECT--
+13
diff --git a/ext/filter/tests/003.phpt b/ext/filter/tests/003.phpt
new file mode 100644 (file)
index 0000000..43e6cd9
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+GET/POST/REQUEST Test
+--POST--
+d=4&e=5
+--GET--
+a=1&b=&c=3
+--FILE--
+<?php echo $_GET['a'];
+echo $_GET['b']; 
+echo $_GET['c'];
+echo $_POST['d'];
+echo $_POST['e'];
+echo "\n";
+echo $_REQUEST['a'];
+echo $_REQUEST['b'];
+echo $_REQUEST['c'];
+echo $_REQUEST['d'];
+echo $_REQUEST['e'];
+?>
+--EXPECT--
+1345
+1345
diff --git a/ext/filter/tests/004.phpt b/ext/filter/tests/004.phpt
new file mode 100644 (file)
index 0000000..05ea952
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+GET/POST/REQUEST Test with filtered data
+--INI--
+filter.default=special_chars
+--POST--
+d="quotes"&e=\slash
+--GET--
+a=O'Henry&b=&c=<b>Bold</b>
+--FILE--
+<?php echo $_GET['a'];
+echo $_GET['b']; 
+echo $_GET['c'];
+echo $_POST['d'];
+echo $_POST['e'];
+echo "\n";
+echo $_REQUEST['a'];
+echo $_REQUEST['b'];
+echo $_REQUEST['c'];
+echo $_REQUEST['d'];
+echo $_REQUEST['e'];
+?>
+--EXPECT--
+O&#39;HenryBold&quot;quotes&quot;\slash
+O&#39;HenryBold&quot;quotes&quot;\slash
diff --git a/ext/filter/tests/005.phpt b/ext/filter/tests/005.phpt
new file mode 100644 (file)
index 0000000..f443791
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+GET/REQUEST Test with fifa example data
+--INI--
+filter.default=stripped
+--GET--
+id=f03_photos&pgurl=http%3A//fifaworldcup.yahoo.com/03/en/photozone/index.html
+--FILE--
+<?php 
+echo $_GET['id'];
+echo "\n";
+echo $_GET['pgurl']; 
+echo "\n";
+echo $_REQUEST['id'];
+echo "\n";
+echo $_REQUEST['pgurl']; 
+?>
+--EXPECT--
+f03_photos
+http://fifaworldcup.yahoo.com/03/en/photozone/index.html
+f03_photos
+http://fifaworldcup.yahoo.com/03/en/photozone/index.html
diff --git a/ext/filter/tests/006.phpt b/ext/filter/tests/006.phpt
new file mode 100644 (file)
index 0000000..189579a
--- /dev/null
@@ -0,0 +1,10 @@
+--TEST--
+filter() test
+--POST--
+foo=<b>abc</b>
+--FILE--
+<?php 
+echo input_get(INPUT_POST, 'foo', FILTER_SANITIZE_STRIPPED);
+?>
+--EXPECT--
+abc
diff --git a/ext/filter/tests/007.phpt b/ext/filter/tests/007.phpt
new file mode 100644 (file)
index 0000000..ffc7278
--- /dev/null
@@ -0,0 +1,68 @@
+--TEST--
+input_has_variable()
+--GET--
+a=qwe&abc=<a>href</a>
+--POST--
+b=qwe&bbc=<a>href</a>
+--FILE--
+<?php
+
+var_dump(input_has_variable(INPUT_GET, "a"));
+var_dump(input_has_variable(INPUT_GET, "abc"));
+var_dump(input_has_variable(INPUT_GET, "nonex"));
+var_dump(input_has_variable(INPUT_GET, " "));
+var_dump(input_has_variable(INPUT_GET, ""));
+var_dump(input_has_variable(INPUT_GET, array()));
+
+var_dump(input_has_variable(INPUT_POST, "b"));
+var_dump(input_has_variable(INPUT_POST, "bbc"));
+var_dump(input_has_variable(INPUT_POST, "nonex"));
+var_dump(input_has_variable(INPUT_POST, " "));
+var_dump(input_has_variable(INPUT_POST, ""));
+var_dump(input_has_variable(INPUT_POST, array()));
+
+var_dump(input_has_variable(-1, ""));
+var_dump(input_has_variable("", ""));
+var_dump(input_has_variable(array(), array()));
+var_dump(input_has_variable(array(), ""));
+var_dump(input_has_variable("", array()));
+
+echo "Done\n";
+?>
+--EXPECTF--    
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+PHP Warning:  input_has_variable() expects parameter 2 to be string, array given in %s on line %d
+
+Warning: input_has_variable() expects parameter 2 to be string, array given in %s on line %d
+NULL
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+PHP Warning:  input_has_variable() expects parameter 2 to be string, array given in %s on line %d
+
+Warning: input_has_variable() expects parameter 2 to be string, array given in %s on line %d
+NULL
+bool(false)
+PHP Warning:  input_has_variable() expects parameter 1 to be long, string given in %s on line %d
+
+Warning: input_has_variable() expects parameter 1 to be long, string given in %s on line %d
+NULL
+PHP Warning:  input_has_variable() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: input_has_variable() expects parameter 1 to be long, array given in %s on line %d
+NULL
+PHP Warning:  input_has_variable() expects parameter 1 to be long, array given in %s on line %d
+
+Warning: input_has_variable() expects parameter 1 to be long, array given in %s on line %d
+NULL
+PHP Warning:  input_has_variable() expects parameter 1 to be long, string given in %s on line %d
+
+Warning: input_has_variable() expects parameter 1 to be long, string given in %s on line %d
+NULL
+Done
diff --git a/ext/filter/tests/008.phpt b/ext/filter/tests/008.phpt
new file mode 100644 (file)
index 0000000..eb6963c
--- /dev/null
@@ -0,0 +1,88 @@
+--TEST--
+input_filters_list()
+--FILE--
+<?php
+
+var_dump(input_filters_list());
+var_dump(input_filters_list(array()));
+
+echo "Done\n";
+?>
+--EXPECTF--    
+array(18) {
+  [0]=>
+  string(3) "int"
+  [1]=>
+  string(7) "boolean"
+  [2]=>
+  string(5) "float"
+  [3]=>
+  string(15) "validate_regexp"
+  [4]=>
+  string(12) "validate_url"
+  [5]=>
+  string(14) "validate_email"
+  [6]=>
+  string(11) "validate_ip"
+  [7]=>
+  string(6) "string"
+  [8]=>
+  string(8) "stripped"
+  [9]=>
+  string(7) "encoded"
+  [10]=>
+  string(13) "special_chars"
+  [11]=>
+  string(10) "unsafe_raw"
+  [12]=>
+  string(5) "email"
+  [13]=>
+  string(3) "url"
+  [14]=>
+  string(10) "number_int"
+  [15]=>
+  string(12) "number_float"
+  [16]=>
+  string(12) "magic_quotes"
+  [17]=>
+  string(8) "callback"
+}
+array(18) {
+  [0]=>
+  string(3) "int"
+  [1]=>
+  string(7) "boolean"
+  [2]=>
+  string(5) "float"
+  [3]=>
+  string(15) "validate_regexp"
+  [4]=>
+  string(12) "validate_url"
+  [5]=>
+  string(14) "validate_email"
+  [6]=>
+  string(11) "validate_ip"
+  [7]=>
+  string(6) "string"
+  [8]=>
+  string(8) "stripped"
+  [9]=>
+  string(7) "encoded"
+  [10]=>
+  string(13) "special_chars"
+  [11]=>
+  string(10) "unsafe_raw"
+  [12]=>
+  string(5) "email"
+  [13]=>
+  string(3) "url"
+  [14]=>
+  string(10) "number_int"
+  [15]=>
+  string(12) "number_float"
+  [16]=>
+  string(12) "magic_quotes"
+  [17]=>
+  string(8) "callback"
+}
+Done
diff --git a/ext/filter/tests/009.phpt b/ext/filter/tests/009.phpt
new file mode 100644 (file)
index 0000000..c33fe8a
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+input_name_to_filter()
+--FILE--
+<?php
+
+var_dump(input_name_to_filter("stripped"));
+var_dump(input_name_to_filter("string"));
+var_dump(input_name_to_filter("url"));
+var_dump(input_name_to_filter("int"));
+var_dump(input_name_to_filter("none"));
+var_dump(input_name_to_filter(array()));
+var_dump(input_name_to_filter(-1));
+var_dump(input_name_to_filter(0,0,0));
+
+echo "Done\n";
+?>
+--EXPECTF--    
+int(513)
+int(513)
+int(518)
+int(257)
+NULL
+
+Warning: input_name_to_filter() expects parameter 1 to be string, array given in %s on line %d
+NULL
+NULL
+
+Warning: input_name_to_filter() expects exactly 1 parameter, 3 given in %s on line %d
+NULL
+Done
diff --git a/ext/filter/tests/011.phpt b/ext/filter/tests/011.phpt
new file mode 100644 (file)
index 0000000..0d3fa42
--- /dev/null
@@ -0,0 +1,49 @@
+--TEST--
+input_get()
+--GET--
+a=<b>test</b>&b=http://example.com
+--POST--
+c=<p>string</p>&d=12345.7
+--FILE--
+<?php
+
+var_dump(input_get(INPUT_GET, "a", FILTER_SANITIZE_STRIPPED));
+var_dump(input_get(INPUT_GET, "b", FILTER_SANITIZE_URL));
+var_dump(input_get(INPUT_GET, "a", FILTER_SANITIZE_SPECIAL_CHARS, array(1,2,3,4,5)));
+var_dump(input_get(INPUT_GET, "b", FILTER_VALIDATE_FLOAT, new stdClass));
+var_dump(input_get(INPUT_POST, "c", FILTER_SANITIZE_STRIPPED, array(5,6,7,8)));
+var_dump(input_get(INPUT_POST, "d", FILTER_VALIDATE_FLOAT));
+var_dump(input_get(INPUT_POST, "c", FILTER_SANITIZE_SPECIAL_CHARS));
+var_dump(input_get(INPUT_POST, "d", FILTER_VALIDATE_INT));
+
+var_dump(input_get(new stdClass, "d"));
+
+var_dump(input_get(INPUT_POST, "c", "", ""));
+var_dump(input_get("", "", "", "", ""));
+var_dump(input_get(0, 0, 0, 0, 0));
+
+echo "Done\n";
+?>
+--EXPECTF--    
+string(4) "test"
+string(18) "http://example.com"
+string(27) "&#60;b&#62;test&#60;/b&#62;"
+NULL
+string(6) "string"
+float(12345.7)
+string(29) "&#60;p&#62;string&#60;/p&#62;"
+NULL
+PHP Warning:  input_get() expects parameter 1 to be long, object given in %s on line %d
+
+Warning: input_get() expects parameter 1 to be long, object given in %s on line %d
+NULL
+PHP Warning:  input_get() expects parameter 3 to be long, string given in %s on line %d
+
+Warning: input_get() expects parameter 3 to be long, string given in %s on line %d
+NULL
+PHP Warning:  input_get() expects parameter 1 to be long, string given in %s on line %d
+
+Warning: input_get() expects parameter 1 to be long, string given in %s on line %d
+NULL
+bool(false)
+Done
diff --git a/ext/filter/tests/012.phpt b/ext/filter/tests/012.phpt
new file mode 100644 (file)
index 0000000..77c1880
--- /dev/null
@@ -0,0 +1,16 @@
+--TEST--
+input_get()
+--FILE--
+<?php
+
+var_dump(input_get(INPUT_GET, "test"));
+var_dump(input_get(INPUT_POST, "test"));
+var_dump(input_get(INPUT_COOKIE, ""));
+
+echo "Done\n";
+?>
+--EXPECT--     
+bool(false)
+bool(false)
+bool(false)
+Done
diff --git a/ext/filter/tests/014.phpt b/ext/filter/tests/014.phpt
new file mode 100644 (file)
index 0000000..f31fe6e
--- /dev/null
@@ -0,0 +1,41 @@
+--TEST--
+filter_data() and FILTER_VALIDATE_BOOLEAN
+--FILE--
+<?php
+
+var_dump(filter_data("no", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data(new stdClass, FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("yes", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("true", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("false", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("off", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("on", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("0", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("1", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("NONE", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data(-1, FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("000000", FILTER_VALIDATE_BOOLEAN));
+var_dump(filter_data("111111", FILTER_VALIDATE_BOOLEAN));
+       
+
+echo "Done\n";
+?>
+--EXPECTF--    
+bool(false)
+
+Notice: Object of class stdClass to string conversion in %s on line %d
+NULL
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+NULL
+bool(false)
+NULL
+NULL
+NULL
+Done
diff --git a/ext/filter/tests/020.phpt b/ext/filter/tests/020.phpt
new file mode 100644 (file)
index 0000000..914c199
--- /dev/null
@@ -0,0 +1,18 @@
+--TEST--
+filter_data() and FILTER_SANITIZE_MAGIC_QUOTES
+--FILE--
+<?php
+
+var_dump(filter_data("test'asd'asd'' asd\'\"asdfasdf", FILTER_SANITIZE_MAGIC_QUOTES));
+var_dump(filter_data("'", FILTER_SANITIZE_MAGIC_QUOTES));
+var_dump(filter_data("", FILTER_SANITIZE_MAGIC_QUOTES));
+var_dump(filter_data(-1, FILTER_SANITIZE_MAGIC_QUOTES));
+
+echo "Done\n";
+?>
+--EXPECT--     
+string(36) "test\'asd\'asd\'\' asd\\\'\"asdfasdf"
+string(2) "\'"
+string(0) ""
+string(2) "-1"
+Done
diff --git a/ext/filter/tests/021.phpt b/ext/filter/tests/021.phpt
new file mode 100644 (file)
index 0000000..697fdd6
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+filter_data() and FILTER_SANITIZE_NUMBER_*
+--FILE--
+<?php
+
+var_dump(filter_data("qwertyu123456dfghj", FILTER_SANITIZE_NUMBER_INT));
+var_dump(filter_data("asd123123.asd123.23", FILTER_SANITIZE_NUMBER_INT));
+var_dump(filter_data("123,23", FILTER_SANITIZE_NUMBER_INT));
+var_dump(filter_data("", FILTER_SANITIZE_NUMBER_INT));
+var_dump(filter_data("0", FILTER_SANITIZE_NUMBER_INT));
+var_dump(filter_data("asd123.2asd", FILTER_SANITIZE_NUMBER_INT));
+var_dump(filter_data("qwertyuiop", FILTER_SANITIZE_NUMBER_INT));
+var_dump(filter_data("123.4", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+var_dump(filter_data("123,4", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+var_dump(filter_data("123.4", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_THOUSAND));
+var_dump(filter_data("123,4", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_THOUSAND));
+var_dump(filter_data("123.4e", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_SCIENTIFIC));
+var_dump(filter_data("123,4E", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_SCIENTIFIC));
+var_dump(filter_data("qwe123,4qwe", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+var_dump(filter_data("werty65456.34", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+var_dump(filter_data("234.56fsfd", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+var_dump(filter_data("", FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
+
+echo "Done\n";
+?>
+--EXPECT--     
+string(6) "123456"
+string(11) "12312312323"
+string(5) "12323"
+string(0) ""
+string(1) "0"
+string(4) "1232"
+string(0) ""
+string(5) "123.4"
+string(4) "1234"
+string(4) "1234"
+string(5) "123,4"
+string(5) "1234e"
+string(5) "1234E"
+string(4) "1234"
+string(8) "65456.34"
+string(6) "234.56"
+string(0) ""
+Done
diff --git a/ext/filter/tests/022.phpt b/ext/filter/tests/022.phpt
new file mode 100644 (file)
index 0000000..28ad64e
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+filter_data() and FILTER_SANITIZE_EMAIL
+--FILE--
+<?php
+
+var_dump(filter_data("a@b.c", FILTER_SANITIZE_EMAIL));
+var_dump(filter_data("a[!@#$%^&*()@a@#$%^&*(.com@#$%^&*(", FILTER_SANITIZE_EMAIL));
+var_dump(filter_data("white space here \ \ \" som more", FILTER_SANITIZE_EMAIL));
+var_dump(filter_data("", FILTER_SANITIZE_EMAIL));
+var_dump(filter_data("123456789000000", FILTER_SANITIZE_EMAIL));
+       
+echo "Done\n";
+?>
+--EXPECTF--    
+string(5) "a@b.c"
+string(30) "a[!@#$%^&*@a@#$%^&*.com@#$%^&*"
+string(21) "whitespaceheresommore"
+string(0) ""
+string(15) "123456789000000"
+Done
diff --git a/ext/filter/tests/023.phpt b/ext/filter/tests/023.phpt
new file mode 100644 (file)
index 0000000..21fdc49
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+filter_data() and FILTER_UNSAFE_RAW
+--FILE--
+<?php
+
+var_dump(filter_data("}\"<p>test para</p>", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP));
+var_dump(filter_data("a[!@#<b>$%^&*()@a@#$%^&*(.<br>com@#$%^&*(", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP));
+var_dump(filter_data("white space here \ \ \" some more", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP));
+var_dump(filter_data("", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP));
+var_dump(filter_data("             123456789000000       <qwertyuiop> ", FILTER_UNSAFE_RAW, FILTER_FLAG_ENCODE_AMP));
+       
+echo "Done\n";
+?>
+--EXPECT--     
+string(18) "}"<p>test para</p>"
+string(53) "a[!@#<b>$%^&#38;*()@a@#$%^&#38;*(.<br>com@#$%^&#38;*("
+string(32) "white space here \ \ " some more"
+string(0) ""
+string(48) "             123456789000000       <qwertyuiop> "
+Done
diff --git a/ext/filter/tests/024.phpt b/ext/filter/tests/024.phpt
new file mode 100644 (file)
index 0000000..d405af3
--- /dev/null
@@ -0,0 +1,18 @@
+--TEST--
+filter_data() and FILTER_SANITIZE_ENCODED
+--FILE--
+<?php
+
+var_dump(filter_data("\"<br>blah</ph>", FILTER_SANITIZE_ENCODED));
+var_dump(filter_data("", FILTER_SANITIZE_ENCODED));
+var_dump(filter_data("  text here  ", FILTER_SANITIZE_ENCODED));
+var_dump(filter_data("!@#$%^&*()QWERTYUIOP{ASDFGHJKL:\"ZXCVBNM<>?", FILTER_SANITIZE_ENCODED));
+
+echo "Done\n";
+?>
+--EXPECT--     
+string(26) "%22%3Cbr%3Eblah%3C%2Fph%3E"
+string(0) ""
+string(23) "%20%20text%20here%20%20"
+string(74) "%21%40%23%24%25%5E%26%2A%28%29QWERTYUIOP%7BASDFGHJKL%3A%22ZXCVBNM%3C%3E%3F"
+Done
diff --git a/ext/filter/tests/025.phpt b/ext/filter/tests/025.phpt
new file mode 100644 (file)
index 0000000..c770fb8
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+filter_data() and FILTER_SANITIZE_STRING
+--FILE--
+<?php
+
+var_dump(filter_data("", FILTER_SANITIZE_STRING));
+var_dump(filter_data("<>", FILTER_SANITIZE_STRING));
+var_dump(filter_data("<>!@#$%^&*()'\"", FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES));
+var_dump(filter_data("<>!@#$%^&*()'\"", FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_AMP));
+var_dump(filter_data("<>`1234567890", FILTER_SANITIZE_STRING));
+var_dump(filter_data("`123`", FILTER_SANITIZE_STRING));
+var_dump(filter_data(".", FILTER_SANITIZE_STRING));
+
+echo "Done\n";
+?>
+--EXPECT--     
+string(0) ""
+string(0) ""
+string(12) "!@#$%^&*()'""
+string(32) "!@#$%^&#38;*()&#38;#39;&#38;#34;"
+string(11) "`1234567890"
+string(5) "`123`"
+string(1) "."
+Done
diff --git a/ext/filter/tests/026.phpt b/ext/filter/tests/026.phpt
new file mode 100644 (file)
index 0000000..b53dcb1
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+filter_data() and FILTER_SANITIZE_STRIPPED
+--FILE--
+<?php
+
+var_dump(filter_data("<p>Let me <font color=\"#000000\">see</font> you <br /><b>Stripped</b> down to the bone</p>", FILTER_SANITIZE_STRIPPED));
+var_dump(filter_data("!@#$%^&*()><<>+_\"'<br><p /><li />", FILTER_SANITIZE_STRIPPED));
+var_dump(filter_data("", FILTER_SANITIZE_STRIPPED));
+
+var_dump(filter_data("<p>Let me <font color=\"#000000\">see</font> you <br /><b>Stripped</b> down to the bone</p>", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_LOW));
+var_dump(filter_data("!@#$%^&*()><<>+_\"'<br><p /><li />", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_LOW));
+var_dump(filter_data("", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_LOW));
+
+var_dump(filter_data("<p>Let me <font color=\"#000000\">see</font> you <br /><b>Stripped</b> down to the bone</p>", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_HIGH));
+var_dump(filter_data("!@#$%^&*()><<>+_\"'<br><p /><li />", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_HIGH));
+var_dump(filter_data("", FILTER_SANITIZE_STRIPPED, FILTER_FLAG_STRIP_HIGH));
+
+echo "Done\n";
+?>
+--EXPECTF--    
+string(40) "Let me see you Stripped down to the bone"
+string(11) "!@#$%^&*()>"
+string(0) ""
+string(40) "Let me see you Stripped down to the bone"
+string(11) "!@#$%^&*()>"
+string(0) ""
+string(40) "Let me see you Stripped down to the bone"
+string(11) "!@#$%^&*()>"
+string(0) ""
+Done
diff --git a/ext/filter/tests/027.phpt b/ext/filter/tests/027.phpt
new file mode 100644 (file)
index 0000000..048dc36
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+filter_data() and FILTER_SANITIZE_ENCODED
+--FILE--
+<?php
+
+var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_ENCODED));
+var_dump(filter_data("<data&sons>", FILTER_SANITIZE_ENCODED));
+var_dump(filter_data("", FILTER_SANITIZE_ENCODED));
+
+var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_LOW));
+var_dump(filter_data("<data&sons>", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_LOW));
+var_dump(filter_data("", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_LOW));
+
+var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_HIGH));
+var_dump(filter_data("<data&sons>", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_HIGH));
+var_dump(filter_data("", FILTER_SANITIZE_ENCODED, FILTER_FLAG_ENCODE_HIGH));
+
+echo "Done\n";
+?>
+--EXPECT--     
+string(75) "%3F%3E%3C%21%40%23%24%25%5E%26%2A%28%29%7D%7B%7EQwertyuilfdsasdfgmnbvcxcvbn"
+string(17) "%3Cdata%26sons%3E"
+string(0) ""
+string(75) "%3F%3E%3C%21%40%23%24%25%5E%26%2A%28%29%7D%7B%7EQwertyuilfdsasdfgmnbvcxcvbn"
+string(17) "%3Cdata%26sons%3E"
+string(0) ""
+string(75) "%3F%3E%3C%21%40%23%24%25%5E%26%2A%28%29%7D%7B%7EQwertyuilfdsasdfgmnbvcxcvbn"
+string(17) "%3Cdata%26sons%3E"
+string(0) ""
+Done
diff --git a/ext/filter/tests/028.phpt b/ext/filter/tests/028.phpt
new file mode 100644 (file)
index 0000000..1d0d2e2
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+filter_data() and FILTER_SANITIZE_SPECIAL_CHARS
+--FILE--
+<?php
+
+var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_SPECIAL_CHARS));
+var_dump(filter_data("<data&sons>", FILTER_SANITIZE_SPECIAL_CHARS));
+var_dump(filter_data("", FILTER_SANITIZE_SPECIAL_CHARS));
+
+var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_LOW));
+var_dump(filter_data("<data&sons>", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_LOW));
+var_dump(filter_data("", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_LOW));
+
+var_dump(filter_data("?><!@#$%^&*()}{~Qwertyuilfdsasdfgmnbvcxcvbn", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH));
+var_dump(filter_data("<data&sons>", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH));
+var_dump(filter_data("", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH));
+
+var_dump(filter_data("кириллица", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH));
+var_dump(filter_data("кириллица", FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_LOW));
+
+echo "Done\n";
+?>
+--EXPECT--     
+string(55) "?&#62;&#60;!@#$%^&#38;*()}{~Qwertyuilfdsasdfgmnbvcxcvbn"
+string(23) "&#60;data&#38;sons&#62;"
+string(0) ""
+string(55) "?&#62;&#60;!@#$%^&#38;*()}{~Qwertyuilfdsasdfgmnbvcxcvbn"
+string(23) "&#60;data&#38;sons&#62;"
+string(0) ""
+string(55) "?&#62;&#60;!@#$%^&#38;*()}{~Qwertyuilfdsasdfgmnbvcxcvbn"
+string(23) "&#60;data&#38;sons&#62;"
+string(0) ""
+string(108) "&#208;&#186;&#208;&#184;&#209;&#128;&#208;&#184;&#208;&#187;&#208;&#187;&#208;&#184;&#209;&#134;&#208;&#176;"
+string(18) "кириллица"
+Done
diff --git a/ext/filter/tests/029.phpt b/ext/filter/tests/029.phpt
new file mode 100644 (file)
index 0000000..f60c42e
--- /dev/null
@@ -0,0 +1,103 @@
+--TEST--
+filter_data() and FILTER_CALLBACK
+--FILE--
+<?php
+
+/* Simple callback function */
+function test($var) {
+       return strtoupper($var);
+}
+       
+var_dump(filter_data("data", FILTER_CALLBACK, "test"));
+var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, "test"));
+var_dump(filter_data("", FILTER_CALLBACK, "test"));
+var_dump(filter_data("qwe", FILTER_CALLBACK, "no such func"));
+var_dump(filter_data("qwe", FILTER_CALLBACK, ""));
+var_dump(filter_data("qwe", FILTER_CALLBACK));
+
+/* Simple class method callback */
+class test_class {
+       static function test ($var) {
+               return strtolower($var);
+       }
+}
+
+var_dump(filter_data("dAtA", FILTER_CALLBACK, array("test_class", "test")));
+var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, array("test_class","test")));
+var_dump(filter_data("", FILTER_CALLBACK, array("test_class","test")));
+
+/* empty function without return value */
+function test1($var) {
+}
+       
+var_dump(filter_data("data", FILTER_CALLBACK, "test1"));
+var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, "test1"));
+var_dump(filter_data("", FILTER_CALLBACK, "test1"));
+
+/* attempting to change data by reference */
+function test2(&$var) {
+       $var = 1;
+}
+       
+var_dump(filter_data("data", FILTER_CALLBACK, "test2"));
+var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, "test2"));
+var_dump(filter_data("", FILTER_CALLBACK, "test2"));
+
+/* unsetting data */
+function test3(&$var) {
+       unset($var);
+}
+       
+var_dump(filter_data("data", FILTER_CALLBACK, "test3"));
+var_dump(filter_data("~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?\"}{:", FILTER_CALLBACK, "test3"));
+var_dump(filter_data("", FILTER_CALLBACK, "test3"));
+
+/* unset data and return value */
+function test4(&$var) {
+       unset($var);
+       return 1;
+}
+       
+var_dump(filter_data("data", FILTER_CALLBACK, "test4"));
+
+/* thrown exception in the callback */
+function test5(&$var) {
+       throw new Exception("test");
+}
+
+try {
+       var_dump(filter_data("data", FILTER_CALLBACK, "test5"));
+} catch (Exception $e) {
+       var_dump($e->getMessage());
+}
+
+echo "Done\n";
+?>
+--EXPECTF--    
+string(4) "DATA"
+string(46) "~!@#$%^&*()_QWERTYUIOPASDFGHJKLZXCVBNM<>>?"}{:"
+string(0) ""
+
+Warning: filter_data(): First argument is expected to be a valid callback in %s on line %d
+NULL
+
+Warning: filter_data(): First argument is expected to be a valid callback in %s on line %d
+NULL
+
+Warning: filter_data(): First argument is expected to be a valid callback in %s on line %d
+NULL
+string(4) "data"
+string(46) "~!@#$%^&*()_qwertyuiopasdfghjklzxcvbnm<>>?"}{:"
+string(0) ""
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+NULL
+int(1)
+string(4) "test"
+Done
diff --git a/ext/filter/tests/filter_data.phpt b/ext/filter/tests/filter_data.phpt
new file mode 100644 (file)
index 0000000..e907d02
--- /dev/null
@@ -0,0 +1,71 @@
+--TEST--
+Simple filter_data() tests
+--FILE--
+<?php
+
+/* Integer */
+$data = "-123";   var_dump(filter_data($data, FILTER_VALIDATE_INT));
+$data = "0";      var_dump(filter_data($data, FILTER_VALIDATE_INT));
+$data = "123";    var_dump(filter_data($data, FILTER_VALIDATE_INT));
+$data = -123;     var_dump(filter_data($data, FILTER_VALIDATE_INT));
+$data = 0;        var_dump(filter_data($data, FILTER_VALIDATE_INT));
+$data = 123;      var_dump(filter_data($data, FILTER_VALIDATE_INT));
+$data = "";       var_dump(filter_data($data, FILTER_VALIDATE_INT));
+echo "\n";
+
+/* Float */
+$data = "-0.123"; var_dump(filter_data($data, FILTER_VALIDATE_FLOAT));
+$data = "0.00";   var_dump(filter_data($data, FILTER_VALIDATE_FLOAT));
+$data = "1.23";   var_dump(filter_data($data, FILTER_VALIDATE_FLOAT));
+$data = -1.23;    var_dump(filter_data($data, FILTER_VALIDATE_FLOAT));
+$data = 0.0;      var_dump(filter_data($data, FILTER_VALIDATE_FLOAT));
+$data = 1.23;     var_dump(filter_data($data, FILTER_VALIDATE_FLOAT));
+$data = "";       var_dump(filter_data($data, FILTER_VALIDATE_FLOAT));
+echo "\n";
+
+/* Boolean */
+$data = "on";     var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = "off";    var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = "yes";    var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = "no";     var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = "true";   var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = "false";  var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = "1";      var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = "0";      var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = 1;        var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = 0;        var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = true;     var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = false;    var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+$data = "";       var_dump(filter_data($data, FILTER_VALIDATE_BOOLEAN));
+
+?>
+--EXPECT--
+int(-123)
+int(0)
+int(123)
+int(-123)
+int(0)
+int(123)
+int(0)
+
+float(-0.123)
+float(0)
+float(1.23)
+float(-1.23)
+float(0)
+float(1.23)
+float(0)
+
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(false)
diff --git a/ext/json/JSON_parser.c b/ext/json/JSON_parser.c
new file mode 100644 (file)
index 0000000..adb9743
--- /dev/null
@@ -0,0 +1,757 @@
+/* JSON_parser.c */
+
+/* 2005-12-30 */
+
+/*
+Copyright (c) 2005 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+
+#include "JSON_parser.h"
+#include <stdio.h>
+
+#define true  1
+#define false 0
+
+/*
+    Characters are mapped into these 32 symbol classes. This allows for
+    significant reductions in the size of the state transition table.
+*/
+
+/* error */
+#define S_ERR -1
+
+/* space */
+#define S_SPA 0
+
+/* other whitespace */
+#define S_WSP 1
+
+/* {  */
+#define S_LBE 2
+
+/* } */
+#define S_RBE 3
+
+/* [ */
+#define S_LBT 4
+
+/* ] */
+#define S_RBT 5
+
+/* : */
+#define S_COL 6
+
+/* , */
+#define S_COM 7
+
+/* " */
+#define S_QUO 8
+
+/* \ */
+#define S_BAC 9
+
+/* / */
+#define S_SLA 10
+
+/* + */
+#define S_PLU 11
+
+/* - */
+#define S_MIN 12
+
+/* . */
+#define S_DOT 13
+
+/* 0 */
+#define S_ZER 14
+
+/* 123456789 */
+#define S_DIG 15
+
+/* a */
+#define S__A_ 16
+
+/* b */
+#define S__B_ 17
+
+/* c */
+#define S__C_ 18
+
+/* d */
+#define S__D_ 19
+
+/* e */
+#define S__E_ 20
+
+/* f */
+#define S__F_ 21
+
+/* l */
+#define S__L_ 22
+
+/* n */
+#define S__N_ 23
+
+/* r */
+#define S__R_ 24
+
+/* s */
+#define S__S_ 25
+
+/* t */
+#define S__T_ 26
+
+/* u */
+#define S__U_ 27
+
+/* ABCDF */
+#define S_A_F 28
+
+/* E */
+#define S_E   29
+
+/* everything else */
+#define S_ETC 30
+
+
+/*
+    This table maps the 128 ASCII characters into the 32 character classes.
+    The remaining Unicode characters should be mapped to S_ETC.
+*/
+static int ascii_class[128] = {
+    S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR,
+    S_ERR, S_WSP, S_WSP, S_ERR, S_ERR, S_WSP, S_ERR, S_ERR,
+    S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR,
+    S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR, S_ERR,
+
+    S_SPA, S_ETC, S_QUO, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC,
+    S_ETC, S_ETC, S_ETC, S_PLU, S_COM, S_MIN, S_DOT, S_SLA,
+    S_ZER, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG, S_DIG,
+    S_DIG, S_DIG, S_COL, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC,
+
+    S_ETC, S_A_F, S_A_F, S_A_F, S_A_F, S_E  , S_A_F, S_ETC,
+    S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC,
+    S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC, S_ETC,
+    S_ETC, S_ETC, S_ETC, S_LBT, S_BAC, S_RBT, S_ETC, S_ETC,
+
+    S_ETC, S__A_, S__B_, S__C_, S__D_, S__E_, S__F_, S_ETC,
+    S_ETC, S_ETC, S_ETC, S_ETC, S__L_, S_ETC, S__N_, S_ETC,
+    S_ETC, S_ETC, S__R_, S__S_, S__T_, S__U_, S_ETC, S_ETC,
+    S_ETC, S_ETC, S_ETC, S_LBE, S_ETC, S_RBE, S_ETC, S_ETC
+};
+
+
+/*
+    The state transition table takes the current state and the current symbol,
+    and returns either a new state or an action. A new state is a number between
+    0 and 29. An action is a negative number between -1 and -9. A JSON text is
+    accepted if the end of the text is in state 9 and mode is MODE_DONE.
+*/
+static int state_transition_table[30][31] = {
+/* 0*/ { 0, 0,-8,-1,-6,-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,-9,-1,-1,-1,-1, 3,-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,-8,-1,-6,-5,-1,-1, 3,-1,-1,-1,20,-1,21,22,-1,-1,-1,-1,-1,13,-1,17,-1,-1,10,-1,-1,-1,-1},
+/* 3*/ { 3,-1, 3, 3, 3, 3, 3, 3,-4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
+/* 4*/ {-1,-1,-1,-1,-1,-1,-1,-1, 3, 3, 3,-1,-1,-1,-1,-1,-1, 3,-1,-1,-1, 3,-1, 3, 3,-1, 3, 5,-1,-1,-1},
+/* 5*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 6, 6, 6, 6, 6, 6, 6, 6,-1,-1,-1,-1,-1,-1, 6, 6,-1},
+/* 6*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 7, 7, 7, 7, 7, 7, 7, 7,-1,-1,-1,-1,-1,-1, 7, 7,-1},
+/* 7*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 8, 8, 8, 8, 8, 8, 8, 8,-1,-1,-1,-1,-1,-1, 8, 8,-1},
+/* 8*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 3, 3, 3, 3, 3, 3, 3, 3,-1,-1,-1,-1,-1,-1, 3, 3,-1},
+/* 9*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*10*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,-1,-1,-1,-1,-1,-1},
+/*11*/ {-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,12,-1,-1,-1},
+/*12*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*13*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*14*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,15,-1,-1,-1,-1,-1,-1,-1,-1},
+/*15*/ {-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,16,-1,-1,-1,-1,-1},
+/*16*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*17*/ {-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,18,-1,-1,-1},
+/*18*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,19,-1,-1,-1,-1,-1,-1,-1,-1},
+/*19*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1},
+/*20*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,22,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*21*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,23,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*22*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,23,22,22,-1,-1,-1,-1,24,-1,-1,-1,-1,-1,-1,-1,-1,24,-1},
+/*23*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,23,23,-1,-1,-1,-1,24,-1,-1,-1,-1,-1,-1,-1,-1,24,-1},
+/*24*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,25,25,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*25*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*26*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*27*/ {27,27,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
+/*28*/ {28,28,-8,-1,-6,-1,-1,-1, 3,-1,-1,-1,20,-1,21,22,-1,-1,-1,-1,-1,13,-1,17,-1,-1,10,-1,-1,-1,-1},
+/*29*/ {29,29,-1,-1,-1,-1,-1,-1, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
+};
+
+#define JSON_PARSER_MAX_DEPTH 20
+
+
+/*
+   A stack maintains the states of nested structures.
+*/
+
+typedef struct json_parser
+{
+    int the_stack[JSON_PARSER_MAX_DEPTH];
+    zval *the_zstack[JSON_PARSER_MAX_DEPTH];
+    int the_top;
+} json_parser;
+
+
+/*
+    These modes can be pushed on the PDA stack.
+*/
+#define MODE_DONE   1
+#define MODE_KEY    2
+#define MODE_OBJECT 3
+#define MODE_ARRAY  4
+
+/*
+    Push a mode onto the stack. Return false if there is overflow.
+*/
+static int
+push(json_parser *json, zval *z, int mode)
+{
+    json->the_top += 1;
+    if (json->the_top >= JSON_PARSER_MAX_DEPTH) {
+        return false;
+    }
+
+    json->the_stack[json->the_top] = mode;
+    return true;
+}
+
+
+/*
+    Pop the stack, assuring that the current mode matches the expectation.
+    Return false if there is underflow or if the modes mismatch.
+*/
+static int
+pop(json_parser *json, zval *z, int mode)
+{
+    if (json->the_top < 0 || json->the_stack[json->the_top] != mode) {
+        return false;
+    }
+    json->the_stack[json->the_top] = 0;
+    json->the_top -= 1;
+
+    return true;
+}
+
+
+static int dehexchar(char c)
+{
+    if (c >= '0' && c <= '9')
+    {
+        return c - '0';
+    }
+    else if (c >= 'A' && c <= 'F')
+    {
+        return c - ('A' - 10);
+    }
+    else if (c >= 'a' && c <= 'f')
+    {
+        return c - ('a' - 10);
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+
+static void json_create_zval(zval **z, smart_str *buf, int type)
+{
+    ALLOC_INIT_ZVAL(*z);
+
+    if (type == IS_LONG)
+    {
+        ZVAL_LONG(*z, atol(buf->c));
+    }
+    else if (type == IS_DOUBLE)
+    {
+        ZVAL_DOUBLE(*z, atof(buf->c));
+    }
+    else if (type == IS_STRING)
+    {
+        ZVAL_STRINGL(*z, buf->c, buf->len, 1);
+    }
+    else if (type == IS_BOOL)
+    {
+        ZVAL_BOOL(*z, (*(buf->c) == 't'));
+    }
+    else /* type == IS_NULL) || type unknown */
+    {
+        ZVAL_NULL(*z);
+    }
+}
+
+
+static void utf16_to_utf8(smart_str *buf, unsigned short utf16)
+{
+    if (utf16 < 0x80)
+    {
+        smart_str_appendc(buf, (unsigned char) utf16);
+    }
+    else if (utf16 < 0x800)
+    {
+        smart_str_appendc(buf, 0xc0 | (utf16 >> 6));
+        smart_str_appendc(buf, 0x80 | (utf16 & 0x3f));
+    }
+    else
+    {
+        smart_str_appendc(buf, 0xe0 | (utf16 >> 12));
+        smart_str_appendc(buf, 0x80 | ((utf16 >> 6) & 0x3f));
+        smart_str_appendc(buf, 0x80 | (utf16 & 0x3f));
+    }
+}
+
+static void attach_zval(json_parser *json, int up, int cur, smart_str *key, int assoc TSRMLS_DC)
+{
+    zval *root = json->the_zstack[up];
+    zval *child =  json->the_zstack[cur];
+    int up_mode = json->the_stack[up];
+
+    if (up_mode == MODE_ARRAY)
+    {
+        add_next_index_zval(root, child);
+    }
+    else if (up_mode == MODE_OBJECT)
+    {
+        if (!assoc)
+        {
+            add_property_zval(root, key->c, child);
+#if PHP_MAJOR_VERSION >= 5
+            ZVAL_DELREF(child);
+#endif
+        }
+        else
+        {
+            add_assoc_zval(root, key->c, child);
+        }
+        key->len = 0;
+    }
+}
+
+
+#define FREE_BUFFERS() do { smart_str_free(&buf); smart_str_free(&key); } while (0);
+#define SWAP_BUFFERS(from, to) do { \
+        char *t1 = from.c; \
+        int t2 = from.a; \
+        from.c = to.c; \
+        from.a = to.a; \
+        to.c = t1; \
+        to.a = t2; \
+        to.len = from.len; \
+        from.len = 0; \
+        } while(0);
+#define JSON_RESET_TYPE() do { type = -1; } while(0);
+#define JSON(x) the_json.x
+
+
+/*
+    The JSON_parser takes a UTF-16 encoded string and determines if it is a
+    syntactically correct JSON text. Along the way, it creates a PHP variable.
+
+    It is implemented as a Pushdown Automaton; that means it is a finite state
+    machine with a stack.
+*/
+int
+JSON_parser(zval *z, unsigned short p[], int length, int assoc TSRMLS_DC)
+{
+    int b;  /* the next character */
+    int c;  /* the next character class */
+    int s;  /* the next state */
+    json_parser the_json; /* the parser state */
+    int the_state = 0;
+    int the_index;
+
+    smart_str buf = {0};
+    smart_str key = {0};
+
+    int type = -1;
+    unsigned short utf16;
+
+    JSON(the_top) = -1;
+    push(&the_json, z, MODE_DONE);
+
+    for (the_index = 0; the_index < length; the_index += 1) {
+        b = p[the_index];
+        if ((b & 127) == b) {
+            c = ascii_class[b];
+            if (c <= S_ERR) {
+                FREE_BUFFERS();
+                return false;
+            }
+        } else {
+            c = S_ETC;
+        }
+/*
+    Get the next state from the transition table.
+*/
+        s = state_transition_table[the_state][c];
+        if (s < 0) {
+/*
+    Perform one of the predefined actions.
+*/
+            switch (s) {
+/*
+    empty }
+*/
+            case -9:
+                if (!pop(&the_json, z, MODE_KEY)) {
+                    FREE_BUFFERS();
+                    return false;
+                }
+                the_state = 9;
+                break;
+/*
+    {
+*/
+            case -8:
+                if (!push(&the_json, z, MODE_KEY)) {
+                    FREE_BUFFERS();
+                    return false;
+                }
+
+                the_state = 1;
+                if (JSON(the_top) > 0)
+                {
+                    zval *obj;
+
+                    if (JSON(the_top) == 1)
+                    {
+                        obj = z;
+                    }
+                    else
+                    {
+                        ALLOC_INIT_ZVAL(obj);
+                    }
+
+                    if (!assoc)
+                    {
+                        object_init(obj);
+                    }
+                    else
+                    {
+                        array_init(obj);
+                    }
+
+                    JSON(the_zstack)[JSON(the_top)] = obj;
+
+                    if (JSON(the_top) > 1)
+                    {
+                        attach_zval(&the_json, JSON(the_top-1), JSON(the_top), &key, assoc TSRMLS_CC);
+                    }
+
+                    JSON_RESET_TYPE();
+                }
+
+                break;
+/*
+    }
+*/
+            case -7:
+                if (type != -1 &&
+                    (JSON(the_stack)[JSON(the_top)] == MODE_OBJECT ||
+                     JSON(the_stack)[JSON(the_top)] == MODE_ARRAY))
+                {
+                    zval *mval;
+                    smart_str_0(&buf);
+
+                    json_create_zval(&mval, &buf, type);
+
+                    if (!assoc)
+                    {
+                        add_property_zval(JSON(the_zstack)[JSON(the_top)], key.c, mval);
+#if PHP_MAJOR_VERSION >= 5
+                        ZVAL_DELREF(mval);
+#endif
+                    }
+                    else
+                    {
+                        add_assoc_zval(JSON(the_zstack)[JSON(the_top)], key.c, mval);
+                    }
+                    key.len = 0;
+                    buf.len = 0;
+                    JSON_RESET_TYPE();
+                }
+
+
+                if (!pop(&the_json, z, MODE_OBJECT)) {
+                    FREE_BUFFERS();
+                    return false;
+                }
+                the_state = 9;
+                break;
+/*
+    [
+*/
+            case -6:
+                if (!push(&the_json, z, MODE_ARRAY)) {
+                    FREE_BUFFERS();
+                    return false;
+                }
+                the_state = 2;
+
+                if (JSON(the_top) > 0)
+                {
+                    zval *arr;
+
+                    if (JSON(the_top) == 1)
+                    {
+                        arr = z;
+                    }
+                    else
+                    {
+                        ALLOC_INIT_ZVAL(arr);
+                    }
+
+                    array_init(arr);
+                    JSON(the_zstack)[JSON(the_top)] = arr;
+
+                    if (JSON(the_top) > 1)
+                    {
+                        attach_zval(&the_json, JSON(the_top-1), JSON(the_top), &key, assoc TSRMLS_CC);
+                    }
+
+                    JSON_RESET_TYPE();
+                }
+
+                break;
+/*
+    ]
+*/
+            case -5:
+            {
+                if (type != -1 &&
+                    (JSON(the_stack)[JSON(the_top)] == MODE_OBJECT ||
+                     JSON(the_stack)[JSON(the_top)] == MODE_ARRAY))
+                {
+                    zval *mval;
+                    smart_str_0(&buf);
+
+                    json_create_zval(&mval, &buf, type);
+                    add_next_index_zval(JSON(the_zstack)[JSON(the_top)], mval);
+                    buf.len = 0;
+                    JSON_RESET_TYPE();
+                }
+
+                if (!pop(&the_json, z, MODE_ARRAY)) {
+                    FREE_BUFFERS();
+                    return false;
+                }
+                the_state = 9;
+            }
+                break;
+/*
+    "
+*/
+            case -4:
+                switch (JSON(the_stack)[JSON(the_top)]) {
+                case MODE_KEY:
+                    the_state = 27;
+                    smart_str_0(&buf);
+                    SWAP_BUFFERS(buf, key);
+                    JSON_RESET_TYPE();
+                    break;
+                case MODE_ARRAY:
+                case MODE_OBJECT:
+                    the_state = 9;
+                    break;
+                default:
+                    FREE_BUFFERS();
+                    return false;
+                }
+                break;
+/*
+    ,
+*/
+            case -3:
+            {
+                zval *mval;
+
+                if (type != -1 &&
+                    (JSON(the_stack)[JSON(the_top)] == MODE_OBJECT ||
+                     JSON(the_stack[JSON(the_top)]) == MODE_ARRAY))
+                {
+                    smart_str_0(&buf);
+                    json_create_zval(&mval, &buf, type);
+                }
+
+                switch (JSON(the_stack)[JSON(the_top)]) {
+                    case MODE_OBJECT:
+                        if (pop(&the_json, z, MODE_OBJECT) && push(&the_json, z, MODE_KEY)) {
+                            if (type != -1)
+                            {
+                                if (!assoc)
+                                {
+                                    add_property_zval(JSON(the_zstack)[JSON(the_top)], (key.len ? key.c : "_empty_"), mval);
+#if PHP_MAJOR_VERSION >= 5
+                                    ZVAL_DELREF(mval);
+#endif
+                                }
+                                else
+                                {
+                                    add_assoc_zval(JSON(the_zstack)[JSON(the_top)], (key.len ? key.c : "_empty_"), mval);
+                                }
+                                key.len = 0;
+                            }
+                            the_state = 29;
+                        }
+                        break;
+                    case MODE_ARRAY:
+                        if (type != -1)
+                        {
+                            add_next_index_zval(JSON(the_zstack)[JSON(the_top)], mval);
+                        }
+                        the_state = 28;
+                        break;
+                    default:
+                        FREE_BUFFERS();
+                        return false;
+                }
+                buf.len = 0;
+                JSON_RESET_TYPE();
+            }
+            break;
+/*
+    :
+*/
+            case -2:
+                if (pop(&the_json, z, MODE_KEY) && push(&the_json, z, MODE_OBJECT)) {
+                    the_state = 28;
+                    break;
+                }
+/*
+    syntax error
+*/
+            case -1:
+                {
+                    FREE_BUFFERS();
+                    return false;
+                }
+            }
+        } else {
+/*
+    Change the state and iterate.
+*/
+            if (type == IS_STRING)
+            {
+                if (s == 3 && the_state != 8)
+                {
+                    if (the_state != 4)
+                    {
+                        utf16_to_utf8(&buf, b);
+                    }
+                    else
+                    {
+                        switch (b)
+                        {
+                            case 'b':
+                                smart_str_appendc(&buf, '\b');
+                                break;
+                            case 't':
+                                smart_str_appendc(&buf, '\t');
+                                break;
+                            case 'n':
+                                smart_str_appendc(&buf, '\n');
+                                break;
+                            case 'f':
+                                smart_str_appendc(&buf, '\f');
+                                break;
+                            case 'r':
+                                smart_str_appendc(&buf, '\r');
+                                break;
+                            default:
+                                utf16_to_utf8(&buf, b);
+                                break;
+                        }
+                    }
+                }
+                else if (s == 6)
+                {
+                    utf16 = dehexchar(b) << 12;
+                }
+                else if (s == 7)
+                {
+                    utf16 += dehexchar(b) << 8;
+                }
+                else if (s == 8)
+                {
+                    utf16 += dehexchar(b) << 4;
+                }
+                else if (s == 3 && the_state == 8)
+                {
+                    utf16 += dehexchar(b);
+                    utf16_to_utf8(&buf, utf16);
+                }
+            }
+            else if (type < IS_LONG && (c == S_DIG || c == S_ZER))
+            {
+                type = IS_LONG;
+                smart_str_appendc(&buf, b);
+            }
+            else if (type == IS_LONG && s == 24)
+            {
+                type = IS_DOUBLE;
+                smart_str_appendc(&buf, b);
+            }
+            else if (type < IS_DOUBLE && c == S_DOT)
+            {
+                type = IS_DOUBLE;
+                smart_str_appendc(&buf, b);
+            }
+            else if (type < IS_STRING && c == S_QUO)
+            {
+                type = IS_STRING;
+            }
+            else if (type < IS_BOOL && ((the_state == 12 && s == 9) || (the_state == 16 && s == 9)))
+            {
+                type = IS_BOOL;
+            }
+            else if (type < IS_NULL && the_state == 19 && s == 9)
+            {
+                type = IS_NULL;
+            }
+            else if (type != IS_STRING && c > S_WSP)
+            {
+                utf16_to_utf8(&buf, b);
+            }
+
+            the_state = s;
+        }
+    }
+
+    FREE_BUFFERS();
+
+    return the_state == 9 && pop(&the_json, z, MODE_DONE);
+}
+
+
+/*
+ * 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_parser.h b/ext/json/JSON_parser.h
new file mode 100644 (file)
index 0000000..085e776
--- /dev/null
@@ -0,0 +1,8 @@
+/* JSON_checker.h */
+
+#include "php.h"
+#include "ext/standard/php_smart_str.h"
+
+static char digits[] = "0123456789abcdef";
+
+extern int JSON_parser(zval *z, unsigned short p[], int length, int assoc TSRMLS_DC);
diff --git a/ext/json/README b/ext/json/README
new file mode 100644 (file)
index 0000000..d680b0c
--- /dev/null
@@ -0,0 +1,76 @@
+json 1.2.0
+==========
+
+This extension implements the JavaScript Object Notation (JSON)
+data-interchange format as specified in [0].
+
+Two functions are implemented: encoding and decoding. The decoding
+is handled by a parser based on JSON_checker[1] by Douglas Crockford.
+
+
+Function overview
+-----------------
+
+    string json_encode ( mixed value )
+
+json_encode returns a string containing the JSON representation of value.
+value can be any type except a resource.
+
+    mixed json_decode ( string json, [bool assoc] )
+
+json_decode takes a JSON string and converts it into a PHP variable.
+When assoc is given, and evaluates to TRUE, json_decode() will return
+any objects as associative arrays.
+
+
+Example usage
+-------------
+
+$arr = array("a"=>1,"b"=>2,"c"=>3,"d"=>4,"e"=>5);
+echo json_encode($arr);
+
+---> {"a":1,"b":2,"c":3,"d":4,"e":5}
+
+$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
+var_dump(json_decode($json));
+
+---> object(stdClass)#1 (5) {
+        ["a"]=>
+        int(1)
+        ["b"]=>
+        int(2)
+        ["c"]=>
+        int(3)
+        ["d"]=>
+        int(4)
+        ["e"]=>
+        int(5)
+     }
+
+$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
+var_dump(json_decode($json, true));
+
+---> array(5) {
+        ["a"]=>
+        int(1)
+        ["b"]=>
+        int(2)
+        ["c"]=>
+        int(3)
+        ["d"]=>
+        int(4)
+        ["e"]=>
+        int(5)
+     }
+
+
+Authors
+-------
+
+Omar Kilani <omar@php.net>
+
+
+---
+
+[0] http://www.crockford.com/JSON/draft-jsonorg-json-00.txt
+[1] http://www.crockford.com/JSON/JSON_checker/
diff --git a/ext/json/config.m4 b/ext/json/config.m4
new file mode 100644 (file)
index 0000000..a937b1f
--- /dev/null
@@ -0,0 +1,88 @@
+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_CHECKER], [
+  PHP_JSON_ADD_SOURCES([
+    utf8_to_utf16.c
+    utf8_decode.c
+    JSON_parser.c
+  ])
+])
+
+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
+
+  PHP_JSON_ADD_BASE_SOURCES([json.c])
+
+  dnl json_c is required
+  PHP_JSON_SETUP_JSON_CHECKER
+  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..fa001d3
--- /dev/null
@@ -0,0 +1,10 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_WITH("json", "JavaScript Object Serialization support", "no");
+
+if (PHP_JSON != "no") {
+       EXTENSION('json', 'json.c', PHP_JSON_SHARED, "");
+       ADD_SOURCES(configure_module_dirname, "JSON_parser.c utf8_decode.c utf8_to_utf16.c", "json");
+}
+
diff --git a/ext/json/json.c b/ext/json/json.c
new file mode 100644 (file)
index 0000000..d19eb2e
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+  +----------------------------------------------------------------------+
+  | PHP Version 5                                                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 1997-2006 The PHP Group                                |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt                                  |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Author: Omar Kilani <omar@php.net>                                   |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_smart_str.h"
+#include "utf8_to_utf16.h"
+#include "JSON_parser.h"
+#include "php_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,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    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_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_end();
+}
+/* }}} */
+
+static void json_encode_r(smart_str *buf, zval *val TSRMLS_DC);
+static void json_escape_string(smart_str *buf, char *s, int len TSRMLS_DC);
+
+static int json_determine_array_type(zval **val TSRMLS_DC) {
+    int i;
+    HashTable *myht;
+
+    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 void json_encode_array(smart_str *buf, zval **val TSRMLS_DC) {
+    int i, r;
+    HashTable *myht;
+
+    if (Z_TYPE_PP(val) == IS_ARRAY) {
+        myht = HASH_OF(*val);
+        r = json_determine_array_type(val TSRMLS_CC);
+    } else {
+        myht = Z_OBJPROP_PP(val);
+        r = 1;
+    }
+
+    if (r == 0)
+    {
+        smart_str_appendc(buf, '[');
+    }
+    else
+    {
+        smart_str_appendc(buf, '{');
+    }
+
+    i = myht ? zend_hash_num_elements(myht) : 0;
+    if (i > 0) {
+        char *key;
+        zval **data;
+        ulong index;
+        uint key_len;
+        HashPosition pos;
+        int need_comma = 0;
+
+        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) {
+                if (r == 0) {
+                    if (need_comma) {
+                        smart_str_appendc(buf, ',');
+                    } else {
+                        need_comma = 1;
+                    }
+                    json_encode_r(buf, *data TSRMLS_CC);
+                } else if (r == 1) {
+                    if (i == HASH_KEY_IS_STRING) {
+                        if (key[0] == '\0') {
+                            /* Skip protected and private members. */
+                            continue;
+                        }
+
+                        if (need_comma) {
+                            smart_str_appendc(buf, ',');
+                        } else {
+                            need_comma = 1;
+                        }
+
+                        json_escape_string(buf, key, key_len - 1 TSRMLS_CC);
+                        smart_str_appendc(buf, ':');
+
+                        json_encode_r(buf, *data TSRMLS_CC);
+                    } else {
+                        if (need_comma) {
+                            smart_str_appendc(buf, ',');
+                        } else {
+                            need_comma = 1;
+                        }
+                        
+                        smart_str_appendc(buf, '"');
+                        smart_str_append_long(buf, (long) index);
+                        smart_str_appendc(buf, '"');
+                        smart_str_appendc(buf, ':');
+
+                        json_encode_r(buf, *data TSRMLS_CC);
+                    }
+                }
+            }
+        }
+    }
+
+    if (r == 0)
+    {
+        smart_str_appendc(buf, ']');
+    }
+    else
+    {
+        smart_str_appendc(buf, '}');
+    }
+}
+
+#define REVERSE16(us) (((us & 0xf) << 12) | (((us >> 4) & 0xf) << 8) | (((us >> 8) & 0xf) << 4) | ((us >> 12) & 0xf))
+
+static void json_escape_string(smart_str *buf, char *s, int len TSRMLS_DC)
+{
+    int pos = 0;
+    unsigned short us;
+    unsigned short *utf16;
+
+    if (len == 0)
+    {
+        smart_str_appendl(buf, "\"\"", 2);
+        return;
+    }
+
+    utf16 = (unsigned short *) emalloc(len * sizeof(unsigned short));
+
+    len = utf8_to_utf16(utf16, s, len);
+    if (len <= 0)
+    {
+        if (utf16)
+        {
+            efree(utf16);
+        }
+
+        smart_str_appendl(buf, "\"\"", 2);
+        return;
+    }
+
+    smart_str_appendc(buf, '"');
+
+    while(pos < len)
+    {
+        us = utf16[pos++];
+
+        switch (us)
+        {
+            case '"':
+                {
+                    smart_str_appendl(buf, "\\\"", 2);
+                }
+                break;
+            case '\\':
+                {
+                    smart_str_appendl(buf, "\\\\", 2);
+                }
+                break;
+            case '/':
+                {
+                    smart_str_appendl(buf, "\\/", 2);
+                }
+                break;
+            case '\b':
+                {
+                    smart_str_appendl(buf, "\\b", 2);
+                }
+                break;
+            case '\f':
+                {
+                    smart_str_appendl(buf, "\\f", 2);
+                }
+                break;
+            case '\n':
+                {
+                    smart_str_appendl(buf, "\\n", 2);
+                }
+                break;
+            case '\r':
+                {
+                    smart_str_appendl(buf, "\\r", 2);
+                }
+                break;
+            case '\t':
+                {
+                    smart_str_appendl(buf, "\\t", 2);
+                }
+                break;
+            default:
+                {
+                    if (us < ' ' || (us & 127) == us)
+                    {
+                        smart_str_appendc(buf, (unsigned char) us);
+                    }
+                    else
+                    {
+                        smart_str_appendl(buf, "\\u", 2);
+                        us = REVERSE16(us);
+
+                        smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
+                        us >>= 4;
+                        smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
+                        us >>= 4;
+                        smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
+                        us >>= 4;
+                        smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
+                    }
+                }
+                break;
+        }
+    }
+
+    smart_str_appendc(buf, '"');
+    efree(utf16);
+}
+
+static void json_encode_r(smart_str *buf, zval *val TSRMLS_DC) {
+    switch (Z_TYPE_P(val)) {
+        case IS_NULL:
+            smart_str_appendl(buf, "null", 4);
+            break;
+        case IS_BOOL:
+            if (Z_BVAL_P(val))
+            {
+                smart_str_appendl(buf, "true", 4);
+            }
+            else
+            {
+                smart_str_appendl(buf, "false", 5);
+            }
+            break;
+        case IS_LONG:
+            smart_str_append_long(buf, Z_LVAL_P(val));
+            break;
+        case IS_DOUBLE:
+            {
+                char *d = NULL;
+                int len;
+                double dbl = Z_DVAL_P(val);
+
+                if (!zend_isinf(dbl) && !zend_isnan(dbl))
+                {
+                    len = spprintf(&d, 0, "%.9g", dbl);
+                    if (d)
+                    {
+                        smart_str_appendl(buf, d, len);
+                        efree(d);
+                    }
+                }
+                else
+                {
+                    zend_error(E_WARNING, "[json] (json_encode_r) double %.9g does not conform to the JSON spec, encoded as 0.", dbl);
+                    smart_str_appendc(buf, '0');
+                }
+            }
+            break;
+        case IS_STRING:
+            json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val) TSRMLS_CC);
+            break;
+        case IS_ARRAY:
+        case IS_OBJECT:
+            json_encode_array(buf, &val TSRMLS_CC);
+            break;
+        default:
+            zend_error(E_WARNING, "[json] (json_encode_r) type is unsupported, encoded as null.");
+            smart_str_appendl(buf, "null", 4);
+            break;
+    }
+
+    return;
+}
+
+PHP_FUNCTION(json_encode)
+{
+    zval *parameter;
+    smart_str buf = {0};
+
+    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &parameter) == FAILURE) {
+        return;
+    }
+
+    json_encode_r(&buf, parameter TSRMLS_CC);
+
+    ZVAL_STRINGL(return_value, buf.c, buf.len, 1);
+
+    smart_str_free(&buf);
+}
+
+PHP_FUNCTION(json_decode)
+{
+    char *parameter;
+    int parameter_len, utf16_len;
+    zend_bool assoc = 0; /* return JS objects as PHP objects by default */
+    zval *z;
+    unsigned short *utf16;
+
+    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &parameter, &parameter_len, &assoc) == FAILURE) {
+        return;
+    }
+
+    if (!parameter_len)
+    {
+        RETURN_NULL();
+    }
+
+    utf16 = (unsigned short *) emalloc((parameter_len+1) * sizeof(unsigned short));
+
+    utf16_len = utf8_to_utf16(utf16, parameter, parameter_len);
+    if (utf16_len <= 0)
+    {
+        if (utf16)
+        {
+            efree(utf16);
+        }
+
+        RETURN_NULL();
+    }
+
+    ALLOC_INIT_ZVAL(z);
+    if (JSON_parser(z, utf16, utf16_len, assoc TSRMLS_CC))
+    {
+        *return_value = *z;
+
+        FREE_ZVAL(z);
+        efree(utf16);
+    }
+    else
+    {
+        zval_dtor(z);
+        FREE_ZVAL(z);
+        efree(utf16);
+        RETURN_NULL();
+    }
+}
+
+/*
+ * 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..e5bb376
--- /dev/null
@@ -0,0 +1,135 @@
+# 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
+# Begin Source File\r
+\r
+SOURCE=.\JSON_parser.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\JSON_parser.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\utf8_decode.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\utf8_decode.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\utf8_to_utf16.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=.\utf8_to_utf16.h\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
+# End Target\r
+# End Project\r
diff --git a/ext/json/package.xml b/ext/json/package.xml
new file mode 100644 (file)
index 0000000..0651de7
--- /dev/null
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE package SYSTEM "../pear/package.dtd">
+<package>
+ <dep type="php" rel="ge" version="4.3.0" optional="no"/>
+ <name>json</name>
+ <summary>JavaScript Object Notation</summary>
+ <maintainers>
+  <maintainer>
+   <user>omar</user>
+   <name>Omar Kilani</name>
+   <email>omar@php.net</email>
+   <role>lead</role>
+  </maintainer>
+ </maintainers>
+ <description> 
+ Support for JSON (JavaScript Object Notation) serialization.
+ </description>
+ <license>PHP 3.01</license>
+ <release>
+  <state>stable</state>
+  <version>1.2.1</version>
+  <date>2006-03-18</date>
+  <notes>
+   Fix PECL bug #7147 - rework handling of comma insertion while encoding.
+   Add tests to package.xml
+  </notes>
+ </release>
+  <configureoptions>
+  </configureoptions>
+  <filelist>
+    <file role="doc" name="README" />
+    <file role="src" name="config.m4" />
+    <file role="src" name="config.w32" />
+    <file role="src" name="json.dsp" />
+    <file role="src" name="json.c" />
+    <file role="src" name="JSON_parser.c" />
+    <file role="src" name="JSON_parser.h" />
+    <file role="src" name="php_json.h" />
+    <file role="src" name="utf8_decode.c" />
+    <file role="src" name="utf8_decode.h" />
+    <file role="src" name="utf8_to_utf16.c" />
+    <file role="src" name="utf8_to_utf16.h" />
+    <dir role="test" name="tests">
+      <file role="test" name="fail001.phpt" />
+      <file role="test" name="pass001.phpt" />
+      <file role="test" name="pass001.1.phpt" />
+      <file role="test" name="pass002.phpt" />
+      <file role="test" name="pass003.phpt" />
+    </dir>
+  </filelist>
+  <changelog>
+     <release>
+      <state>stable</state>
+      <version>1.0.0</version>
+      <date>2005-04-01</date>
+      <notes>
+       Initial release.
+      </notes>
+     </release>
+     <release>
+      <state>stable</state>
+      <version>1.0.1</version>
+      <date>2005-06-10</date>
+      <notes>
+       Fixed non-linear and mixed type array index issues, fixed issues with escaping \\, forked json-c and added Unicode support.
+      </notes>
+     </release>
+   <release>
+    <state>stable</state>
+    <version>1.0.2</version>
+    <date>2005-06-11</date>
+    <notes>
+     Fixed issues with object reference counts under PHP4.
+    </notes>
+   </release>
+   <release>
+    <state>stable</state>
+    <version>1.0.3</version>
+    <date>2005-06-15</date>
+    <notes>
+     Fixed json-c string corruption issues under Mac OS X and FreeBSD.
+    </notes>
+   </release>
+   <release>
+    <state>stable</state>
+    <version>1.0.4</version>
+    <date>2005-06-15</date>
+    <notes>
+     Changes in 1.0.4 released with 1.0.5.
+    </notes>
+   </release>
+   <release>
+    <state>stable</state>
+    <version>1.0.5</version>
+    <date>2005-06-16</date>
+    <notes>
+     Changed spacing in json-c encoding, added optional assoc (boolean) parameter to json_decode to decode as associative array instead of object, fixed issues with escaping /.
+    </notes>
+   </release>
+ <release>
+  <state>stable</state>
+  <version>1.0.6</version>
+  <date>2005-08-05</date>
+  <notes>
+   Fixed issues with exporting private and protected class members.
+  </notes>
+ </release>
+ <release>
+  <state>stable</state>
+  <version>1.0.7</version>
+  <date>2005-09-07</date>
+  <notes>
+   Fixed issues with negative array keys, modified json-c to return an error on unquoted object key names instead of going into an infinite loop.
+  </notes>
+ </release>
+ <release>
+  <state>stable</state>
+  <version>1.0.8</version>
+  <date>2005-12-01</date>
+  <notes>
+   Changed license to LGPL, modified build system to allow static compilation into PHP, added strndup check for json-c.
+  </notes>
+ </release>
+ <release>
+  <state>stable</state>
+  <version>1.1.0</version>
+  <date>2005-12-04</date>
+  <notes>
+   Port to Win32.
+  </notes>
+ </release>
+ <release>
+  <state>stable</state>
+  <version>1.1.1</version>
+  <date>2006-01-12</date>
+  <notes>
+   Cleanup and TSRM performance fixes by rasmus.
+  </notes>
+ </release>
+ <release>
+  <state>stable</state>
+  <version>1.2.0</version>
+  <date>2006-03-15</date>
+  <notes>
+   Complete rewrite using JSON_checker as the base for the parser. Implements the JSON specification. 3-8x faster on encodes and 1.2x-4x faster on decodes.
+  </notes>
+ </release>
+ </changelog>
+</package>
+<!--
+vim:et:ts=1:sw=1
+-->
diff --git a/ext/json/php_json.h b/ext/json/php_json.h
new file mode 100644 (file)
index 0000000..48555ee
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+  +----------------------------------------------------------------------+
+  | PHP Version 5                                                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 1997-2006 The PHP Group                                |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE, and is        |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt                                  |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+  | Author: Omar Kilani <omar@php.net>                                   |
+  +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_JSON_H
+#define PHP_JSON_H
+
+#define PHP_JSON_VERSION "1.2.1"
+
+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_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
+ */
diff --git a/ext/json/tests/fail001.phpt b/ext/json/tests/fail001.phpt
new file mode 100644 (file)
index 0000000..4ee3780
--- /dev/null
@@ -0,0 +1,166 @@
+--TEST--
+JSON Test Pattern fail1 -> fail24
+http://www.crockford.com/JSON/JSON_checker/test/fail*.json
+--SKIPIF--
+<?php
+  if (!extension_loaded('json')) die('skip: json extension not available');
+?>
+--FILE--
+<?php
+    
+$tests = array('"A JSON payload should be an object or array, not a string."',
+               '["Unclosed array"',
+               '{unquoted_key: "keys must be quoted}',
+               '["extra comma",]',
+               '["double extra comma",,]',
+               '[   , "<-- missing value"]',
+               '["Comma after the close"],',
+               '["Extra close"]]',
+               '{"Extra comma": true,}',
+               '{"Extra value after close": true} "misplaced quoted value"',
+               '{"Illegal expression": 1 + 2}',
+               '{"Illegal invocation": alert()}',
+               '{"Numbers cannot have leading zeroes": 013}',
+               '{"Numbers cannot be hex": 0x14}',
+               '["Illegal backslash escape: \\x15"]',
+               '["Illegal backslash escape: \\\'"]',
+               '["Illegal backslash escape: \\017"]',
+               '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]',
+               '{"Missing colon" null}',
+               '{"Double colon":: null}',
+               '{"Comma instead of colon", null}',
+               '["Colon instead of comma": false]',
+               '["Bad value", truth]',
+               "['single quote']");
+
+foreach ($tests as $test)
+{
+    echo 'Testing: ' . $test . "\n";
+    echo "AS OBJECT\n";
+    var_dump(json_decode($test));
+    echo "AS ARRAY\n";
+    var_dump(json_decode($test, true));
+}
+
+?>
+--EXPECT--
+Testing: "A JSON payload should be an object or array, not a string."
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Unclosed array"
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {unquoted_key: "keys must be quoted}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["extra comma",]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["double extra comma",,]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: [   , "<-- missing value"]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Comma after the close"],
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Extra close"]]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Extra comma": true,}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Extra value after close": true} "misplaced quoted value"
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Illegal expression": 1 + 2}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Illegal invocation": alert()}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Numbers cannot have leading zeroes": 013}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Numbers cannot be hex": 0x14}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Illegal backslash escape: \x15"]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Illegal backslash escape: \'"]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Illegal backslash escape: \017"]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Missing colon" null}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Double colon":: null}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: {"Comma instead of colon", null}
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Colon instead of comma": false]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ["Bad value", truth]
+AS OBJECT
+NULL
+AS ARRAY
+NULL
+Testing: ['single quote']
+AS OBJECT
+NULL
+AS ARRAY
+NULL
diff --git a/ext/json/tests/pass001.1.phpt b/ext/json/tests/pass001.1.phpt
new file mode 100644 (file)
index 0000000..0cb0530
--- /dev/null
@@ -0,0 +1,895 @@
+--TEST--
+JSON Test Pattern pass1.1
+Modified to test unescaped UNICODE as keys and values.
+Modified to test numbers with exponents without a decimal point.
+Modified to test empty string values.
+Modified to test a mix of integers and strings as keys.
+http://www.crockford.com/JSON/JSON_checker/test/pass1.json
+--SKIPIF--
+<?php
+  if (!extension_loaded('json')) die('skip: json extension not available');
+?>
+--FILE--
+<?php
+// Expect warnings about INF.
+ini_set("error_reporting", E_ALL & ~E_WARNING);
+
+$test = "
+[
+    \"JSON Test Pattern pass1\",
+    {\"object with 1 member\":[\"array with 1 element\"]},
+    {},
+    [],
+    -42,
+    true,
+    false,
+    null,
+    {
+        \"integer\": 1234567890,
+        \"real\": -9876.543210,
+        \"e\": 0.123456789e-12,
+        \"E\": 1.234567890E+34,
+        \"\":  23456789012E666,
+        \"E no .\":  4E12,
+        \"zero\": 0,
+        \"one\": 1,
+        \"space\": \" \",
+        \"quote\": \"\\\"\",
+        \"backslash\": \"\\\\\",
+        \"controls\": \"\\b\\f\\n\\r\\t\",
+        \"slash\": \"/ & \\/\",
+        \"alpha\": \"abcdefghijklmnopqrstuvwyz\",
+        \"ALPHA\": \"ABCDEFGHIJKLMNOPQRSTUVWYZ\",
+        \"digit\": \"0123456789\",
+        \"special\": \"`1~!@#$%^&*()_+-={':[,]}|;.</>?\",
+        \"hex\": \"\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A\",
+        \"unicode\": \"\\u30d7\\u30ec\\u30b9\\u30ad\\u30c3\\u30c8\",
+        \"プレスキット\": \"プレスキット\",
+        \"empty_string\": \"\",
+        \"true\": true,
+        \"false\": false,
+        \"null\": null,
+        \"array\":[  ],
+        \"object\":{  },
+        \"123\":{\"456\":{\"abc\":{\"789\":\"def\",\"012\":[1,2,\"5\",500],\"ghi\":[1,2,\"five\",50,\"sixty\"]}}},
+        \"address\": \"50 St. James Street\",
+        \"url\": \"http://www.JSON.org/\",
+        \"comment\": \"// /* <!-- --\",
+        \"# -- --> */\": \" \",
+        \" s p a c e d \" :[1,2 , 3
+
+,
+
+4 , 5        ,          6           ,7        ],
+        \"compact\": [1,2,3,4,5,6,7],
+        \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",
+        \"quotes\": \"&#34; \\u0022 %22 0x22 034 &#x22;\",
+        \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?\"
+: \"A key can be any string\"
+    },
+    0.5 ,98.6
+,
+99.44
+,
+
+1066
+
+
+,\"rosebud\"]
+";
+
+echo 'Testing: ' . $test . "\n";
+echo "DECODE: AS OBJECT\n";
+$obj = json_decode($test);
+var_dump($obj);
+echo "DECODE: AS ARRAY\n";
+$arr = json_decode($test, true);
+var_dump($arr);
+
+echo "ENCODE: FROM OBJECT\n";
+$obj_enc = json_encode($obj);
+echo $obj_enc . "\n";
+echo "ENCODE: FROM ARRAY\n";
+$arr_enc = json_encode($arr);
+echo $arr_enc . "\n";
+
+echo "DECODE AGAIN: AS OBJECT\n";
+$obj = json_decode($obj_enc);
+var_dump($obj);
+echo "DECODE AGAIN: AS ARRAY\n";
+$arr = json_decode($arr_enc, true);
+var_dump($arr);
+
+?>
+--EXPECT--
+Testing: 
+[
+    "JSON Test Pattern pass1",
+    {"object with 1 member":["array with 1 element"]},
+    {},
+    [],
+    -42,
+    true,
+    false,
+    null,
+    {
+        "integer": 1234567890,
+        "real": -9876.543210,
+        "e": 0.123456789e-12,
+        "E": 1.234567890E+34,
+        "":  23456789012E666,
+        "E no .":  4E12,
+        "zero": 0,
+        "one": 1,
+        "space": " ",
+        "quote": "\"",
+        "backslash": "\\",
+        "controls": "\b\f\n\r\t",
+        "slash": "/ & \/",
+        "alpha": "abcdefghijklmnopqrstuvwyz",
+        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
+        "digit": "0123456789",
+        "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
+        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+        "unicode": "\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8",
+        "プレスキット": "プレスキット",
+        "empty_string": "",
+        "true": true,
+        "false": false,
+        "null": null,
+        "array":[  ],
+        "object":{  },
+        "123":{"456":{"abc":{"789":"def","012":[1,2,"5",500],"ghi":[1,2,"five",50,"sixty"]}}},
+        "address": "50 St. James Street",
+        "url": "http://www.JSON.org/",
+        "comment": "// /* <!-- --",
+        "# -- --> */": " ",
+        " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5        ,          6           ,7        ],
+        "compact": [1,2,3,4,5,6,7],
+        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+        "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
+: "A key can be any string"
+    },
+    0.5 ,98.6
+,
+99.44
+,
+
+1066
+
+
+,"rosebud"]
+
+DECODE: AS OBJECT
+array(14) {
+  [0]=>
+  string(23) "JSON Test Pattern pass1"
+  [1]=>
+  object(stdClass)#1 (1) {
+    ["object with 1 member"]=>
+    array(1) {
+      [0]=>
+      string(20) "array with 1 element"
+    }
+  }
+  [2]=>
+  object(stdClass)#2 (0) {
+  }
+  [3]=>
+  array(0) {
+  }
+  [4]=>
+  int(-42)
+  [5]=>
+  bool(true)
+  [6]=>
+  bool(false)
+  [7]=>
+  NULL
+  [8]=>
+  object(stdClass)#3 (36) {
+    ["integer"]=>
+    int(1234567890)
+    ["real"]=>
+    float(-9876.54321)
+    ["e"]=>
+    float(1.23456789E-13)
+    ["E"]=>
+    float(1.23456789E+34)
+    ["_empty_"]=>
+    float(INF)
+    ["E no ."]=>
+    float(4.0E+12)
+    ["zero"]=>
+    int(0)
+    ["one"]=>
+    int(1)
+    ["space"]=>
+    string(1) " "
+    ["quote"]=>
+    string(1) """
+    ["backslash"]=>
+    string(1) "\"
+    ["controls"]=>
+    string(5) "\b\f
+
+       "
+    ["slash"]=>
+    string(5) "/ & /"
+    ["alpha"]=>
+    string(25) "abcdefghijklmnopqrstuvwyz"
+    ["ALPHA"]=>
+    string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+    ["digit"]=>
+    string(10) "0123456789"
+    ["special"]=>
+    string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+    ["hex"]=>
+    string(17) "ģ䕧覫췯ꯍ"
+    ["unicode"]=>
+    string(18) "プレスキット"
+    ["プレスキット"]=>
+    string(18) "プレスキット"
+    ["empty_string"]=>
+    string(0) ""
+    ["true"]=>
+    bool(true)
+    ["false"]=>
+    bool(false)
+    ["null"]=>
+    NULL
+    ["array"]=>
+    array(0) {
+    }
+    ["object"]=>
+    object(stdClass)#4 (0) {
+    }
+    ["123"]=>
+    object(stdClass)#5 (1) {
+      ["456"]=>
+      object(stdClass)#6 (1) {
+        ["abc"]=>
+        object(stdClass)#7 (3) {
+          ["789"]=>
+          string(3) "def"
+          ["012"]=>
+          array(4) {
+            [0]=>
+            int(1)
+            [1]=>
+            int(2)
+            [2]=>
+            string(1) "5"
+            [3]=>
+            int(500)
+          }
+          ["ghi"]=>
+          array(5) {
+            [0]=>
+            int(1)
+            [1]=>
+            int(2)
+            [2]=>
+            string(4) "five"
+            [3]=>
+            int(50)
+            [4]=>
+            string(5) "sixty"
+          }
+        }
+      }
+    }
+    ["address"]=>
+    string(19) "50 St. James Street"
+    ["url"]=>
+    string(20) "http://www.JSON.org/"
+    ["comment"]=>
+    string(13) "// /* <!-- --"
+    ["# -- --> */"]=>
+    string(1) " "
+    [" s p a c e d "]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["compact"]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["jsontext"]=>
+    string(49) "{"object with 1 member":["array with 1 element"]}"
+    ["quotes"]=>
+    string(27) "&#34; " %22 0x22 034 &#x22;"
+    ["/\"쫾몾ꮘﳞ볚\b\f
+
+       `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+    string(23) "A key can be any string"
+  }
+  [9]=>
+  float(0.5)
+  [10]=>
+  float(98.6)
+  [11]=>
+  float(99.44)
+  [12]=>
+  int(1066)
+  [13]=>
+  string(7) "rosebud"
+}
+DECODE: AS ARRAY
+array(14) {
+  [0]=>
+  string(23) "JSON Test Pattern pass1"
+  [1]=>
+  array(1) {
+    ["object with 1 member"]=>
+    array(1) {
+      [0]=>
+      string(20) "array with 1 element"
+    }
+  }
+  [2]=>
+  array(0) {
+  }
+  [3]=>
+  array(0) {
+  }
+  [4]=>
+  int(-42)
+  [5]=>
+  bool(true)
+  [6]=>
+  bool(false)
+  [7]=>
+  NULL
+  [8]=>
+  array(36) {
+    ["integer"]=>
+    int(1234567890)
+    ["real"]=>
+    float(-9876.54321)
+    ["e"]=>
+    float(1.23456789E-13)
+    ["E"]=>
+    float(1.23456789E+34)
+    ["_empty_"]=>
+    float(INF)
+    ["E no ."]=>
+    float(4.0E+12)
+    ["zero"]=>
+    int(0)
+    ["one"]=>
+    int(1)
+    ["space"]=>
+    string(1) " "
+    ["quote"]=>
+    string(1) """
+    ["backslash"]=>
+    string(1) "\"
+    ["controls"]=>
+    string(5) "\b\f
+
+       "
+    ["slash"]=>
+    string(5) "/ & /"
+    ["alpha"]=>
+    string(25) "abcdefghijklmnopqrstuvwyz"
+    ["ALPHA"]=>
+    string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+    ["digit"]=>
+    string(10) "0123456789"
+    ["special"]=>
+    string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+    ["hex"]=>
+    string(17) "ģ䕧覫췯ꯍ"
+    ["unicode"]=>
+    string(18) "プレスキット"
+    ["プレスキット"]=>
+    string(18) "プレスキット"
+    ["empty_string"]=>
+    string(0) ""
+    ["true"]=>
+    bool(true)
+    ["false"]=>
+    bool(false)
+    ["null"]=>
+    NULL
+    ["array"]=>
+    array(0) {
+    }
+    ["object"]=>
+    array(0) {
+    }
+    [123]=>
+    array(1) {
+      [456]=>
+      array(1) {
+        ["abc"]=>
+        array(3) {
+          [789]=>
+          string(3) "def"
+          ["012"]=>
+          array(4) {
+            [0]=>
+            int(1)
+            [1]=>
+            int(2)
+            [2]=>
+            string(1) "5"
+            [3]=>
+            int(500)
+          }
+          ["ghi"]=>
+          array(5) {
+            [0]=>
+            int(1)
+            [1]=>
+            int(2)
+            [2]=>
+            string(4) "five"
+            [3]=>
+            int(50)
+            [4]=>
+            string(5) "sixty"
+          }
+        }
+      }
+    }
+    ["address"]=>
+    string(19) "50 St. James Street"
+    ["url"]=>
+    string(20) "http://www.JSON.org/"
+    ["comment"]=>
+    string(13) "// /* <!-- --"
+    ["# -- --> */"]=>
+    string(1) " "
+    [" s p a c e d "]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["compact"]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["jsontext"]=>
+    string(49) "{"object with 1 member":["array with 1 element"]}"
+    ["quotes"]=>
+    string(27) "&#34; " %22 0x22 034 &#x22;"
+    ["/\"쫾몾ꮘﳞ볚\b\f
+
+       `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+    string(23) "A key can be any string"
+  }
+  [9]=>
+  float(0.5)
+  [10]=>
+  float(98.6)
+  [11]=>
+  float(99.44)
+  [12]=>
+  int(1066)
+  [13]=>
+  string(7) "rosebud"
+}
+ENCODE: FROM OBJECT
+["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},{},[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":1.23456789e-13,"E":1.23456789e+34,"_empty_":0,"E no .":4.0e+12,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"\u0123\u4567\u89ab\ucdef\uabcd\uef4a","unicode":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","empty_string":"","true":true,"false":false,"null":null,"array":[],"object":{},"123":{"456":{"abc":{"789":"def","012":[1,2,"5",500],"ghi":[1,2,"five",50,"sixty"]}}},"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* <!-- --","# -- --> *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"]
+ENCODE: FROM ARRAY
+["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},[],[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":1.23456789e-13,"E":1.23456789e+34,"_empty_":0,"E no .":4.0e+12,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"\u0123\u4567\u89ab\ucdef\uabcd\uef4a","unicode":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8":"\u30d7\u30ec\u30b9\u30ad\u30c3\u30c8","empty_string":"","true":true,"false":false,"null":null,"array":[],"object":[],"123":{"456":{"abc":{"789":"def","012":[1,2,"5",500],"ghi":[1,2,"five",50,"sixty"]}}},"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* <!-- --","# -- --> *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"]
+DECODE AGAIN: AS OBJECT
+array(14) {
+  [0]=>
+  string(23) "JSON Test Pattern pass1"
+  [1]=>
+  object(stdClass)#8 (1) {
+    ["object with 1 member"]=>
+    array(1) {
+      [0]=>
+      string(20) "array with 1 element"
+    }
+  }
+  [2]=>
+  object(stdClass)#9 (0) {
+  }
+  [3]=>
+  array(0) {
+  }
+  [4]=>
+  int(-42)
+  [5]=>
+  bool(true)
+  [6]=>
+  bool(false)
+  [7]=>
+  NULL
+  [8]=>
+  object(stdClass)#10 (36) {
+    ["integer"]=>
+    int(1234567890)
+    ["real"]=>
+    float(-9876.54321)
+    ["e"]=>
+    float(1.23456789E-13)
+    ["E"]=>
+    float(1.23456789E+34)
+    ["_empty_"]=>
+    int(0)
+    ["E no ."]=>
+    float(4.0E+12)
+    ["zero"]=>
+    int(0)
+    ["one"]=>
+    int(1)
+    ["space"]=>
+    string(1) " "
+    ["quote"]=>
+    string(1) """
+    ["backslash"]=>
+    string(1) "\"
+    ["controls"]=>
+    string(5) "\b\f
+
+       "
+    ["slash"]=>
+    string(5) "/ & /"
+    ["alpha"]=>
+    string(25) "abcdefghijklmnopqrstuvwyz"
+    ["ALPHA"]=>
+    string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+    ["digit"]=>
+    string(10) "0123456789"
+    ["special"]=>
+    string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+    ["hex"]=>
+    string(17) "ģ䕧覫췯ꯍ"
+    ["unicode"]=>
+    string(18) "プレスキット"
+    ["プレスキット"]=>
+    string(18) "プレスキット"
+    ["empty_string"]=>
+    string(0) ""
+    ["true"]=>
+    bool(true)
+    ["false"]=>
+    bool(false)
+    ["null"]=>
+    NULL
+    ["array"]=>
+    array(0) {
+    }
+    ["object"]=>
+    object(stdClass)#11 (0) {
+    }
+    ["123"]=>
+    object(stdClass)#12 (1) {
+      ["456"]=>
+      object(stdClass)#13 (1) {
+        ["abc"]=>
+        object(stdClass)#14 (3) {
+          ["789"]=>
+          string(3) "def"
+          ["012"]=>
+          array(4) {
+            [0]=>
+            int(1)
+            [1]=>
+            int(2)
+            [2]=>
+            string(1) "5"
+            [3]=>
+            int(500)
+          }
+          ["ghi"]=>
+          array(5) {
+            [0]=>
+            int(1)
+            [1]=>
+            int(2)
+            [2]=>
+            string(4) "five"
+            [3]=>
+            int(50)
+            [4]=>
+            string(5) "sixty"
+          }
+        }
+      }
+    }
+    ["address"]=>
+    string(19) "50 St. James Street"
+    ["url"]=>
+    string(20) "http://www.JSON.org/"
+    ["comment"]=>
+    string(13) "// /* <!-- --"
+    ["# -- --> */"]=>
+    string(1) " "
+    [" s p a c e d "]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["compact"]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["jsontext"]=>
+    string(49) "{"object with 1 member":["array with 1 element"]}"
+    ["quotes"]=>
+    string(27) "&#34; " %22 0x22 034 &#x22;"
+    ["/\"쫾몾ꮘﳞ볚\b\f
+
+       `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+    string(23) "A key can be any string"
+  }
+  [9]=>
+  float(0.5)
+  [10]=>
+  float(98.6)
+  [11]=>
+  float(99.44)
+  [12]=>
+  int(1066)
+  [13]=>
+  string(7) "rosebud"
+}
+DECODE AGAIN: AS ARRAY
+array(14) {
+  [0]=>
+  string(23) "JSON Test Pattern pass1"
+  [1]=>
+  array(1) {
+    ["object with 1 member"]=>
+    array(1) {
+      [0]=>
+      string(20) "array with 1 element"
+    }
+  }
+  [2]=>
+  array(0) {
+  }
+  [3]=>
+  array(0) {
+  }
+  [4]=>
+  int(-42)
+  [5]=>
+  bool(true)
+  [6]=>
+  bool(false)
+  [7]=>
+  NULL
+  [8]=>
+  array(36) {
+    ["integer"]=>
+    int(1234567890)
+    ["real"]=>
+    float(-9876.54321)
+    ["e"]=>
+    float(1.23456789E-13)
+    ["E"]=>
+    float(1.23456789E+34)
+    ["_empty_"]=>
+    int(0)
+    ["E no ."]=>
+    float(4.0E+12)
+    ["zero"]=>
+    int(0)
+    ["one"]=>
+    int(1)
+    ["space"]=>
+    string(1) " "
+    ["quote"]=>
+    string(1) """
+    ["backslash"]=>
+    string(1) "\"
+    ["controls"]=>
+    string(5) "\b\f
+
+       "
+    ["slash"]=>
+    string(5) "/ & /"
+    ["alpha"]=>
+    string(25) "abcdefghijklmnopqrstuvwyz"
+    ["ALPHA"]=>
+    string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+    ["digit"]=>
+    string(10) "0123456789"
+    ["special"]=>
+    string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+    ["hex"]=>
+    string(17) "ģ䕧覫췯ꯍ"
+    ["unicode"]=>
+    string(18) "プレスキット"
+    ["プレスキット"]=>
+    string(18) "プレスキット"
+    ["empty_string"]=>
+    string(0) ""
+    ["true"]=>
+    bool(true)
+    ["false"]=>
+    bool(false)
+    ["null"]=>
+    NULL
+    ["array"]=>
+    array(0) {
+    }
+    ["object"]=>
+    array(0) {
+    }
+    [123]=>
+    array(1) {
+      [456]=>
+      array(1) {
+        ["abc"]=>
+        array(3) {
+          [789]=>
+          string(3) "def"
+          ["012"]=>
+          array(4) {
+            [0]=>
+            int(1)
+            [1]=>
+            int(2)
+            [2]=>
+            string(1) "5"
+            [3]=>
+            int(500)
+          }
+          ["ghi"]=>
+          array(5) {
+            [0]=>
+            int(1)
+            [1]=>
+            int(2)
+            [2]=>
+            string(4) "five"
+            [3]=>
+            int(50)
+            [4]=>
+            string(5) "sixty"
+          }
+        }
+      }
+    }
+    ["address"]=>
+    string(19) "50 St. James Street"
+    ["url"]=>
+    string(20) "http://www.JSON.org/"
+    ["comment"]=>
+    string(13) "// /* <!-- --"
+    ["# -- --> */"]=>
+    string(1) " "
+    [" s p a c e d "]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["compact"]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["jsontext"]=>
+    string(49) "{"object with 1 member":["array with 1 element"]}"
+    ["quotes"]=>
+    string(27) "&#34; " %22 0x22 034 &#x22;"
+    ["/\"쫾몾ꮘﳞ볚\b\f
+
+       `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+    string(23) "A key can be any string"
+  }
+  [9]=>
+  float(0.5)
+  [10]=>
+  float(98.6)
+  [11]=>
+  float(99.44)
+  [12]=>
+  int(1066)
+  [13]=>
+  string(7) "rosebud"
+}
diff --git a/ext/json/tests/pass001.phpt b/ext/json/tests/pass001.phpt
new file mode 100644 (file)
index 0000000..aff970b
--- /dev/null
@@ -0,0 +1,709 @@
+--TEST--
+JSON Test Pattern pass1
+http://www.crockford.com/JSON/JSON_checker/test/pass1.json
+--SKIPIF--
+<?php
+  if (!extension_loaded('json')) die('skip: json extension not available');
+?>
+--FILE--
+<?php
+// Expect warnings about INF.
+ini_set("error_reporting", E_ALL & ~E_WARNING);
+
+$test = "
+[
+    \"JSON Test Pattern pass1\",
+    {\"object with 1 member\":[\"array with 1 element\"]},
+    {},
+    [],
+    -42,
+    true,
+    false,
+    null,
+    {
+        \"integer\": 1234567890,
+        \"real\": -9876.543210,
+        \"e\": 0.123456789e-12,
+        \"E\": 1.234567890E+34,
+        \"\":  23456789012E666,
+        \"zero\": 0,
+        \"one\": 1,
+        \"space\": \" \",
+        \"quote\": \"\\\"\",
+        \"backslash\": \"\\\\\",
+        \"controls\": \"\\b\\f\\n\\r\\t\",
+        \"slash\": \"/ & \\/\",
+        \"alpha\": \"abcdefghijklmnopqrstuvwyz\",
+        \"ALPHA\": \"ABCDEFGHIJKLMNOPQRSTUVWYZ\",
+        \"digit\": \"0123456789\",
+        \"special\": \"`1~!@#$%^&*()_+-={':[,]}|;.</>?\",
+        \"hex\": \"\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A\",
+        \"true\": true,
+        \"false\": false,
+        \"null\": null,
+        \"array\":[  ],
+        \"object\":{  },
+        \"address\": \"50 St. James Street\",
+        \"url\": \"http://www.JSON.org/\",
+        \"comment\": \"// /* <!-- --\",
+        \"# -- --> */\": \" \",
+        \" s p a c e d \" :[1,2 , 3
+
+,
+
+4 , 5        ,          6           ,7        ],
+        \"compact\": [1,2,3,4,5,6,7],
+        \"jsontext\": \"{\\\"object with 1 member\\\":[\\\"array with 1 element\\\"]}\",
+        \"quotes\": \"&#34; \\u0022 %22 0x22 034 &#x22;\",
+        \"\\/\\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?\"
+: \"A key can be any string\"
+    },
+    0.5 ,98.6
+,
+99.44
+,
+
+1066
+
+
+,\"rosebud\"]
+";
+
+echo 'Testing: ' . $test . "\n";
+echo "DECODE: AS OBJECT\n";
+$obj = json_decode($test);
+var_dump($obj);
+echo "DECODE: AS ARRAY\n";
+$arr = json_decode($test, true);
+var_dump($arr);
+
+echo "ENCODE: FROM OBJECT\n";
+$obj_enc = json_encode($obj);
+echo $obj_enc . "\n";
+echo "ENCODE: FROM ARRAY\n";
+$arr_enc = json_encode($arr);
+echo $arr_enc . "\n";
+
+echo "DECODE AGAIN: AS OBJECT\n";
+$obj = json_decode($obj_enc);
+var_dump($obj);
+echo "DECODE AGAIN: AS ARRAY\n";
+$arr = json_decode($arr_enc, true);
+var_dump($arr);
+
+?>
+--EXPECT--
+Testing: 
+[
+    "JSON Test Pattern pass1",
+    {"object with 1 member":["array with 1 element"]},
+    {},
+    [],
+    -42,
+    true,
+    false,
+    null,
+    {
+        "integer": 1234567890,
+        "real": -9876.543210,
+        "e": 0.123456789e-12,
+        "E": 1.234567890E+34,
+        "":  23456789012E666,
+        "zero": 0,
+        "one": 1,
+        "space": " ",
+        "quote": "\"",
+        "backslash": "\\",
+        "controls": "\b\f\n\r\t",
+        "slash": "/ & \/",
+        "alpha": "abcdefghijklmnopqrstuvwyz",
+        "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
+        "digit": "0123456789",
+        "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
+        "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+        "true": true,
+        "false": false,
+        "null": null,
+        "array":[  ],
+        "object":{  },
+        "address": "50 St. James Street",
+        "url": "http://www.JSON.org/",
+        "comment": "// /* <!-- --",
+        "# -- --> */": " ",
+        " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5        ,          6           ,7        ],
+        "compact": [1,2,3,4,5,6,7],
+        "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+        "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+        "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
+: "A key can be any string"
+    },
+    0.5 ,98.6
+,
+99.44
+,
+
+1066
+
+
+,"rosebud"]
+
+DECODE: AS OBJECT
+array(14) {
+  [0]=>
+  string(23) "JSON Test Pattern pass1"
+  [1]=>
+  object(stdClass)#1 (1) {
+    ["object with 1 member"]=>
+    array(1) {
+      [0]=>
+      string(20) "array with 1 element"
+    }
+  }
+  [2]=>
+  object(stdClass)#2 (0) {
+  }
+  [3]=>
+  array(0) {
+  }
+  [4]=>
+  int(-42)
+  [5]=>
+  bool(true)
+  [6]=>
+  bool(false)
+  [7]=>
+  NULL
+  [8]=>
+  object(stdClass)#3 (31) {
+    ["integer"]=>
+    int(1234567890)
+    ["real"]=>
+    float(-9876.54321)
+    ["e"]=>
+    float(1.23456789E-13)
+    ["E"]=>
+    float(1.23456789E+34)
+    ["_empty_"]=>
+    float(INF)
+    ["zero"]=>
+    int(0)
+    ["one"]=>
+    int(1)
+    ["space"]=>
+    string(1) " "
+    ["quote"]=>
+    string(1) """
+    ["backslash"]=>
+    string(1) "\"
+    ["controls"]=>
+    string(5) "\b\f
+
+       "
+    ["slash"]=>
+    string(5) "/ & /"
+    ["alpha"]=>
+    string(25) "abcdefghijklmnopqrstuvwyz"
+    ["ALPHA"]=>
+    string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+    ["digit"]=>
+    string(10) "0123456789"
+    ["special"]=>
+    string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+    ["hex"]=>
+    string(17) "ģ䕧覫췯ꯍ"
+    ["true"]=>
+    bool(true)
+    ["false"]=>
+    bool(false)
+    ["null"]=>
+    NULL
+    ["array"]=>
+    array(0) {
+    }
+    ["object"]=>
+    object(stdClass)#4 (0) {
+    }
+    ["address"]=>
+    string(19) "50 St. James Street"
+    ["url"]=>
+    string(20) "http://www.JSON.org/"
+    ["comment"]=>
+    string(13) "// /* <!-- --"
+    ["# -- --> */"]=>
+    string(1) " "
+    [" s p a c e d "]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["compact"]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["jsontext"]=>
+    string(49) "{"object with 1 member":["array with 1 element"]}"
+    ["quotes"]=>
+    string(27) "&#34; " %22 0x22 034 &#x22;"
+    ["/\"쫾몾ꮘﳞ볚\b\f
+
+       `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+    string(23) "A key can be any string"
+  }
+  [9]=>
+  float(0.5)
+  [10]=>
+  float(98.6)
+  [11]=>
+  float(99.44)
+  [12]=>
+  int(1066)
+  [13]=>
+  string(7) "rosebud"
+}
+DECODE: AS ARRAY
+array(14) {
+  [0]=>
+  string(23) "JSON Test Pattern pass1"
+  [1]=>
+  array(1) {
+    ["object with 1 member"]=>
+    array(1) {
+      [0]=>
+      string(20) "array with 1 element"
+    }
+  }
+  [2]=>
+  array(0) {
+  }
+  [3]=>
+  array(0) {
+  }
+  [4]=>
+  int(-42)
+  [5]=>
+  bool(true)
+  [6]=>
+  bool(false)
+  [7]=>
+  NULL
+  [8]=>
+  array(31) {
+    ["integer"]=>
+    int(1234567890)
+    ["real"]=>
+    float(-9876.54321)
+    ["e"]=>
+    float(1.23456789E-13)
+    ["E"]=>
+    float(1.23456789E+34)
+    ["_empty_"]=>
+    float(INF)
+    ["zero"]=>
+    int(0)
+    ["one"]=>
+    int(1)
+    ["space"]=>
+    string(1) " "
+    ["quote"]=>
+    string(1) """
+    ["backslash"]=>
+    string(1) "\"
+    ["controls"]=>
+    string(5) "\b\f
+
+       "
+    ["slash"]=>
+    string(5) "/ & /"
+    ["alpha"]=>
+    string(25) "abcdefghijklmnopqrstuvwyz"
+    ["ALPHA"]=>
+    string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+    ["digit"]=>
+    string(10) "0123456789"
+    ["special"]=>
+    string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+    ["hex"]=>
+    string(17) "ģ䕧覫췯ꯍ"
+    ["true"]=>
+    bool(true)
+    ["false"]=>
+    bool(false)
+    ["null"]=>
+    NULL
+    ["array"]=>
+    array(0) {
+    }
+    ["object"]=>
+    array(0) {
+    }
+    ["address"]=>
+    string(19) "50 St. James Street"
+    ["url"]=>
+    string(20) "http://www.JSON.org/"
+    ["comment"]=>
+    string(13) "// /* <!-- --"
+    ["# -- --> */"]=>
+    string(1) " "
+    [" s p a c e d "]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["compact"]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["jsontext"]=>
+    string(49) "{"object with 1 member":["array with 1 element"]}"
+    ["quotes"]=>
+    string(27) "&#34; " %22 0x22 034 &#x22;"
+    ["/\"쫾몾ꮘﳞ볚\b\f
+
+       `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+    string(23) "A key can be any string"
+  }
+  [9]=>
+  float(0.5)
+  [10]=>
+  float(98.6)
+  [11]=>
+  float(99.44)
+  [12]=>
+  int(1066)
+  [13]=>
+  string(7) "rosebud"
+}
+ENCODE: FROM OBJECT
+["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},{},[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":1.23456789e-13,"E":1.23456789e+34,"_empty_":0,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"\u0123\u4567\u89ab\ucdef\uabcd\uef4a","true":true,"false":false,"null":null,"array":[],"object":{},"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* <!-- --","# -- --> *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"]
+ENCODE: FROM ARRAY
+["JSON Test Pattern pass1",{"object with 1 member":["array with 1 element"]},[],[],-42,true,false,null,{"integer":1234567890,"real":-9876.54321,"e":1.23456789e-13,"E":1.23456789e+34,"_empty_":0,"zero":0,"one":1,"space":" ","quote":"\"","backslash":"\\","controls":"\b\f\n\r\t","slash":"\/ & \/","alpha":"abcdefghijklmnopqrstuvwyz","ALPHA":"ABCDEFGHIJKLMNOPQRSTUVWYZ","digit":"0123456789","special":"`1~!@#$%^&*()_+-={':[,]}|;.<\/>?","hex":"\u0123\u4567\u89ab\ucdef\uabcd\uef4a","true":true,"false":false,"null":null,"array":[],"object":[],"address":"50 St. James Street","url":"http:\/\/www.JSON.org\/","comment":"\/\/ \/* <!-- --","# -- --> *\/":" "," s p a c e d ":[1,2,3,4,5,6,7],"compact":[1,2,3,4,5,6,7],"jsontext":"{\"object with 1 member\":[\"array with 1 element\"]}","quotes":"&#34; \" %22 0x22 034 &#x22;","\/\\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',.\/<>?":"A key can be any string"},0.5,98.6,99.44,1066,"rosebud"]
+DECODE AGAIN: AS OBJECT
+array(14) {
+  [0]=>
+  string(23) "JSON Test Pattern pass1"
+  [1]=>
+  object(stdClass)#5 (1) {
+    ["object with 1 member"]=>
+    array(1) {
+      [0]=>
+      string(20) "array with 1 element"
+    }
+  }
+  [2]=>
+  object(stdClass)#6 (0) {
+  }
+  [3]=>
+  array(0) {
+  }
+  [4]=>
+  int(-42)
+  [5]=>
+  bool(true)
+  [6]=>
+  bool(false)
+  [7]=>
+  NULL
+  [8]=>
+  object(stdClass)#7 (31) {
+    ["integer"]=>
+    int(1234567890)
+    ["real"]=>
+    float(-9876.54321)
+    ["e"]=>
+    float(1.23456789E-13)
+    ["E"]=>
+    float(1.23456789E+34)
+    ["_empty_"]=>
+    int(0)
+    ["zero"]=>
+    int(0)
+    ["one"]=>
+    int(1)
+    ["space"]=>
+    string(1) " "
+    ["quote"]=>
+    string(1) """
+    ["backslash"]=>
+    string(1) "\"
+    ["controls"]=>
+    string(5) "\b\f
+
+       "
+    ["slash"]=>
+    string(5) "/ & /"
+    ["alpha"]=>
+    string(25) "abcdefghijklmnopqrstuvwyz"
+    ["ALPHA"]=>
+    string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+    ["digit"]=>
+    string(10) "0123456789"
+    ["special"]=>
+    string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+    ["hex"]=>
+    string(17) "ģ䕧覫췯ꯍ"
+    ["true"]=>
+    bool(true)
+    ["false"]=>
+    bool(false)
+    ["null"]=>
+    NULL
+    ["array"]=>
+    array(0) {
+    }
+    ["object"]=>
+    object(stdClass)#8 (0) {
+    }
+    ["address"]=>
+    string(19) "50 St. James Street"
+    ["url"]=>
+    string(20) "http://www.JSON.org/"
+    ["comment"]=>
+    string(13) "// /* <!-- --"
+    ["# -- --> */"]=>
+    string(1) " "
+    [" s p a c e d "]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["compact"]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["jsontext"]=>
+    string(49) "{"object with 1 member":["array with 1 element"]}"
+    ["quotes"]=>
+    string(27) "&#34; " %22 0x22 034 &#x22;"
+    ["/\"쫾몾ꮘﳞ볚\b\f
+
+       `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+    string(23) "A key can be any string"
+  }
+  [9]=>
+  float(0.5)
+  [10]=>
+  float(98.6)
+  [11]=>
+  float(99.44)
+  [12]=>
+  int(1066)
+  [13]=>
+  string(7) "rosebud"
+}
+DECODE AGAIN: AS ARRAY
+array(14) {
+  [0]=>
+  string(23) "JSON Test Pattern pass1"
+  [1]=>
+  array(1) {
+    ["object with 1 member"]=>
+    array(1) {
+      [0]=>
+      string(20) "array with 1 element"
+    }
+  }
+  [2]=>
+  array(0) {
+  }
+  [3]=>
+  array(0) {
+  }
+  [4]=>
+  int(-42)
+  [5]=>
+  bool(true)
+  [6]=>
+  bool(false)
+  [7]=>
+  NULL
+  [8]=>
+  array(31) {
+    ["integer"]=>
+    int(1234567890)
+    ["real"]=>
+    float(-9876.54321)
+    ["e"]=>
+    float(1.23456789E-13)
+    ["E"]=>
+    float(1.23456789E+34)
+    ["_empty_"]=>
+    int(0)
+    ["zero"]=>
+    int(0)
+    ["one"]=>
+    int(1)
+    ["space"]=>
+    string(1) " "
+    ["quote"]=>
+    string(1) """
+    ["backslash"]=>
+    string(1) "\"
+    ["controls"]=>
+    string(5) "\b\f
+
+       "
+    ["slash"]=>
+    string(5) "/ & /"
+    ["alpha"]=>
+    string(25) "abcdefghijklmnopqrstuvwyz"
+    ["ALPHA"]=>
+    string(25) "ABCDEFGHIJKLMNOPQRSTUVWYZ"
+    ["digit"]=>
+    string(10) "0123456789"
+    ["special"]=>
+    string(31) "`1~!@#$%^&*()_+-={':[,]}|;.</>?"
+    ["hex"]=>
+    string(17) "ģ䕧覫췯ꯍ"
+    ["true"]=>
+    bool(true)
+    ["false"]=>
+    bool(false)
+    ["null"]=>
+    NULL
+    ["array"]=>
+    array(0) {
+    }
+    ["object"]=>
+    array(0) {
+    }
+    ["address"]=>
+    string(19) "50 St. James Street"
+    ["url"]=>
+    string(20) "http://www.JSON.org/"
+    ["comment"]=>
+    string(13) "// /* <!-- --"
+    ["# -- --> */"]=>
+    string(1) " "
+    [" s p a c e d "]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["compact"]=>
+    array(7) {
+      [0]=>
+      int(1)
+      [1]=>
+      int(2)
+      [2]=>
+      int(3)
+      [3]=>
+      int(4)
+      [4]=>
+      int(5)
+      [5]=>
+      int(6)
+      [6]=>
+      int(7)
+    }
+    ["jsontext"]=>
+    string(49) "{"object with 1 member":["array with 1 element"]}"
+    ["quotes"]=>
+    string(27) "&#34; " %22 0x22 034 &#x22;"
+    ["/\"쫾몾ꮘﳞ볚\b\f
+
+       `1~!@#$%^&*()_+-=[]{}|;:',./<>?"]=>
+    string(23) "A key can be any string"
+  }
+  [9]=>
+  float(0.5)
+  [10]=>
+  float(98.6)
+  [11]=>
+  float(99.44)
+  [12]=>
+  int(1066)
+  [13]=>
+  string(7) "rosebud"
+}
diff --git a/ext/json/tests/pass002.phpt b/ext/json/tests/pass002.phpt
new file mode 100644 (file)
index 0000000..a0e527a
--- /dev/null
@@ -0,0 +1,276 @@
+--TEST--
+JSON Test Pattern pass2
+http://www.crockford.com/JSON/JSON_checker/test/pass2.json
+--SKIPIF--
+<?php
+  if (!extension_loaded('json')) die('skip: json extension not available');
+?>
+--FILE--
+<?php
+    
+$test = '[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]';
+echo 'Testing: ' . $test . "\n";
+echo "DECODE: AS OBJECT\n";
+$obj = json_decode($test);
+var_dump($obj);
+echo "DECODE: AS ARRAY\n";
+$arr = json_decode($test, true);
+var_dump($arr);
+
+echo "ENCODE: FROM OBJECT\n";
+$obj_enc = json_encode($obj);
+echo $obj_enc . "\n";
+echo "ENCODE: FROM ARRAY\n";
+$arr_enc = json_encode($arr);
+echo $arr_enc . "\n";
+
+echo "DECODE AGAIN: AS OBJECT\n";
+$obj = json_decode($obj_enc);
+var_dump($obj);
+echo "DECODE AGAIN: AS ARRAY\n";
+$arr = json_decode($arr_enc, true);
+var_dump($arr);
+
+?>
+--EXPECT--
+Testing: [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
+DECODE: AS OBJECT
+array(1) {
+  [0]=>
+  array(1) {
+    [0]=>
+    array(1) {
+      [0]=>
+      array(1) {
+        [0]=>
+        array(1) {
+          [0]=>
+          array(1) {
+            [0]=>
+            array(1) {
+              [0]=>
+              array(1) {
+                [0]=>
+                array(1) {
+                  [0]=>
+                  array(1) {
+                    [0]=>
+                    array(1) {
+                      [0]=>
+                      array(1) {
+                        [0]=>
+                        array(1) {
+                          [0]=>
+                          array(1) {
+                            [0]=>
+                            array(1) {
+                              [0]=>
+                              array(1) {
+                                [0]=>
+                                array(1) {
+                                  [0]=>
+                                  array(1) {
+                                    [0]=>
+                                    array(1) {
+                                      [0]=>
+                                      string(12) "Not too deep"
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+DECODE: AS ARRAY
+array(1) {
+  [0]=>
+  array(1) {
+    [0]=>
+    array(1) {
+      [0]=>
+      array(1) {
+        [0]=>
+        array(1) {
+          [0]=>
+          array(1) {
+            [0]=>
+            array(1) {
+              [0]=>
+              array(1) {
+                [0]=>
+                array(1) {
+                  [0]=>
+                  array(1) {
+                    [0]=>
+                    array(1) {
+                      [0]=>
+                      array(1) {
+                        [0]=>
+                        array(1) {
+                          [0]=>
+                          array(1) {
+                            [0]=>
+                            array(1) {
+                              [0]=>
+                              array(1) {
+                                [0]=>
+                                array(1) {
+                                  [0]=>
+                                  array(1) {
+                                    [0]=>
+                                    array(1) {
+                                      [0]=>
+                                      string(12) "Not too deep"
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+ENCODE: FROM OBJECT
+[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
+ENCODE: FROM ARRAY
+[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
+DECODE AGAIN: AS OBJECT
+array(1) {
+  [0]=>
+  array(1) {
+    [0]=>
+    array(1) {
+      [0]=>
+      array(1) {
+        [0]=>
+        array(1) {
+          [0]=>
+          array(1) {
+            [0]=>
+            array(1) {
+              [0]=>
+              array(1) {
+                [0]=>
+                array(1) {
+                  [0]=>
+                  array(1) {
+                    [0]=>
+                    array(1) {
+                      [0]=>
+                      array(1) {
+                        [0]=>
+                        array(1) {
+                          [0]=>
+                          array(1) {
+                            [0]=>
+                            array(1) {
+                              [0]=>
+                              array(1) {
+                                [0]=>
+                                array(1) {
+                                  [0]=>
+                                  array(1) {
+                                    [0]=>
+                                    array(1) {
+                                      [0]=>
+                                      string(12) "Not too deep"
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+DECODE AGAIN: AS ARRAY
+array(1) {
+  [0]=>
+  array(1) {
+    [0]=>
+    array(1) {
+      [0]=>
+      array(1) {
+        [0]=>
+        array(1) {
+          [0]=>
+          array(1) {
+            [0]=>
+            array(1) {
+              [0]=>
+              array(1) {
+                [0]=>
+                array(1) {
+                  [0]=>
+                  array(1) {
+                    [0]=>
+                    array(1) {
+                      [0]=>
+                      array(1) {
+                        [0]=>
+                        array(1) {
+                          [0]=>
+                          array(1) {
+                            [0]=>
+                            array(1) {
+                              [0]=>
+                              array(1) {
+                                [0]=>
+                                array(1) {
+                                  [0]=>
+                                  array(1) {
+                                    [0]=>
+                                    array(1) {
+                                      [0]=>
+                                      string(12) "Not too deep"
+                                    }
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/ext/json/tests/pass003.phpt b/ext/json/tests/pass003.phpt
new file mode 100644 (file)
index 0000000..506ff05
--- /dev/null
@@ -0,0 +1,95 @@
+--TEST--
+JSON Test Pattern pass3
+http://www.crockford.com/JSON/JSON_checker/test/pass3.json
+--SKIPIF--
+<?php
+  if (!extension_loaded('json')) die('skip: json extension not available');
+?>
+--FILE--
+<?php
+    
+$test = '
+{
+    "JSON Test Pattern pass3": {
+        "The outermost value": "must be an object or array.",
+        "In this test": "It is an object."
+    }
+}
+';
+
+echo 'Testing: ' . $test . "\n";
+echo "DECODE: AS OBJECT\n";
+$obj = json_decode($test);
+var_dump($obj);
+echo "DECODE: AS ARRAY\n";
+$arr = json_decode($test, true);
+var_dump($arr);
+
+echo "ENCODE: FROM OBJECT\n";
+$obj_enc = json_encode($obj);
+echo $obj_enc . "\n";
+echo "ENCODE: FROM ARRAY\n";
+$arr_enc = json_encode($arr);
+echo $arr_enc . "\n";
+
+echo "DECODE AGAIN: AS OBJECT\n";
+$obj = json_decode($obj_enc);
+var_dump($obj);
+echo "DECODE AGAIN: AS ARRAY\n";
+$arr = json_decode($arr_enc, true);
+var_dump($arr);
+
+?>
+--EXPECT--
+Testing: 
+{
+    "JSON Test Pattern pass3": {
+        "The outermost value": "must be an object or array.",
+        "In this test": "It is an object."
+    }
+}
+
+DECODE: AS OBJECT
+object(stdClass)#1 (1) {
+  ["JSON Test Pattern pass3"]=>
+  object(stdClass)#2 (2) {
+    ["The outermost value"]=>
+    string(27) "must be an object or array."
+    ["In this test"]=>
+    string(16) "It is an object."
+  }
+}
+DECODE: AS ARRAY
+array(1) {
+  ["JSON Test Pattern pass3"]=>
+  array(2) {
+    ["The outermost value"]=>
+    string(27) "must be an object or array."
+    ["In this test"]=>
+    string(16) "It is an object."
+  }
+}
+ENCODE: FROM OBJECT
+{"JSON Test Pattern pass3":{"The outermost value":"must be an object or array.","In this test":"It is an object."}}
+ENCODE: FROM ARRAY
+{"JSON Test Pattern pass3":{"The outermost value":"must be an object or array.","In this test":"It is an object."}}
+DECODE AGAIN: AS OBJECT
+object(stdClass)#3 (1) {
+  ["JSON Test Pattern pass3"]=>
+  object(stdClass)#4 (2) {
+    ["The outermost value"]=>
+    string(27) "must be an object or array."
+    ["In this test"]=>
+    string(16) "It is an object."
+  }
+}
+DECODE AGAIN: AS ARRAY
+array(1) {
+  ["JSON Test Pattern pass3"]=>
+  array(2) {
+    ["The outermost value"]=>
+    string(27) "must be an object or array."
+    ["In this test"]=>
+    string(16) "It is an object."
+  }
+}
diff --git a/ext/json/utf8_decode.c b/ext/json/utf8_decode.c
new file mode 100644 (file)
index 0000000..cea1f8c
--- /dev/null
@@ -0,0 +1,179 @@
+/* utf8_decode.c */
+
+/* 2005-12-25 */
+
+/*
+Copyright (c) 2005 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include "utf8_decode.h"
+
+/*
+    Very Strict UTF-8 Decoder
+
+    UTF-8 is a multibyte character encoding of Unicode. A character can be
+    represented by 1-4 bytes. The bit pattern of the first byte indicates the
+    number of continuation bytes.
+
+    Most UTF-8 decoders tend to be lenient, attempting to recover as much
+    information as possible, even from badly encoded input. This UTF-8
+    decoder is not lenient. It will reject input which does not include
+    proper continuation bytes. It will reject aliases (or suboptimal
+    codings). It will reject surrogates. (Surrogate encoding should only be
+    used with UTF-16.)
+
+    Code     Contination Minimum Maximum
+    0xxxxxxx           0       0     127
+    10xxxxxx       error
+    110xxxxx           1     128    2047
+    1110xxxx           2    2048   65535 excluding 55296 - 57343
+    11110xxx           3   65536 1114111
+    11111xxx       error
+*/
+
+
+/*
+    Get the next byte. It returns UTF8_END if there are no more bytes.
+*/
+static int 
+get(json_utf8_decode *utf8)
+{
+    int c;
+    if (utf8->the_index >= utf8->the_length) {
+        return UTF8_END;
+    }
+    c = utf8->the_input[utf8->the_index] & 0xFF;
+    utf8->the_index += 1;
+    return c;
+}
+
+
+/*
+    Get the 6-bit payload of the next continuation byte.
+    Return UTF8_ERROR if it is not a contination byte.
+*/
+static int 
+cont(json_utf8_decode *utf8)
+{
+    int c = get(utf8);
+    return ((c & 0xC0) == 0x80) ? (c & 0x3F) : UTF8_ERROR;
+}
+
+
+/*
+    Initialize the UTF-8 decoder. The decoder is not reentrant,
+*/
+void 
+utf8_decode_init(json_utf8_decode *utf8, char p[], int length)
+{
+    utf8->the_index = 0;
+    utf8->the_input = p;
+    utf8->the_length = length;
+    utf8->the_char = 0;
+    utf8->the_byte = 0;
+}
+
+
+/*
+    Get the current byte offset. This is generally used in error reporting.
+*/
+int 
+utf8_decode_at_byte(json_utf8_decode *utf8)
+{
+    return utf8->the_byte;
+}
+
+
+/*
+    Get the current character offset. This is generally used in error reporting.
+    The character offset matches the byte offset if the text is strictly ASCII.
+*/
+int 
+utf8_decode_at_character(json_utf8_decode *utf8)
+{
+    return utf8->the_char > 0 ? utf8->the_char - 1 : 0;
+}
+
+
+/*
+    Extract the next character.
+    Returns: the character (between 0 and 1114111)
+         or  UTF8_END   (the end)
+         or  UTF8_ERROR (error)
+*/
+int 
+utf8_decode_next(json_utf8_decode *utf8)
+{
+    int c;  /* the first byte of the character */
+    int r;  /* the result */
+
+    if (utf8->the_index >= utf8->the_length) {
+        return utf8->the_index == utf8->the_length ? UTF8_END : UTF8_ERROR;
+    }
+    utf8->the_byte = utf8->the_index;
+    utf8->the_char += 1;
+    c = get(utf8);
+/*
+    Zero continuation (0 to 127)
+*/
+    if ((c & 0x80) == 0) {
+        return c;
+    }
+/*
+    One contination (128 to 2047)
+*/
+    if ((c & 0xE0) == 0xC0) {
+        int c1 = cont(utf8);
+        if (c1 < 0) {
+            return UTF8_ERROR;
+        }
+        r = ((c & 0x1F) << 6) | c1;
+        return r >= 128 ? r : UTF8_ERROR;
+    }
+/*
+    Two continuation (2048 to 55295 and 57344 to 65535) 
+*/
+    if ((c & 0xF0) == 0xE0) {
+        int c1 = cont(utf8);
+        int c2 = cont(utf8);
+        if (c1 < 0 || c2 < 0) {
+            return UTF8_ERROR;
+        }
+        r = ((c & 0x0F) << 12) | (c1 << 6) | c2;
+        return r >= 2048 && (r < 55296 || r > 57343) ? r : UTF8_ERROR;
+    }
+/*
+    Three continuation (65536 to 1114111)
+*/
+    if ((c & 0xF1) == 0xF0) {
+        int c1 = cont(utf8);
+        int c2 = cont(utf8);
+        int c3 = cont(utf8);
+        if (c1 < 0 || c2 < 0 || c3 < 0) {
+            return UTF8_ERROR;
+        }
+        r = ((c & 0x0F) << 18) | (c1 << 12) | (c2 << 6) | c3;
+        return r >= 65536 && r <= 1114111 ? r : UTF8_ERROR;
+    }
+    return UTF8_ERROR;
+}
diff --git a/ext/json/utf8_decode.h b/ext/json/utf8_decode.h
new file mode 100644 (file)
index 0000000..cc0fc79
--- /dev/null
@@ -0,0 +1,18 @@
+/* utf8_decode.h */
+
+#define UTF8_END   -1
+#define UTF8_ERROR -2
+
+typedef struct json_utf8_decode
+{
+    int the_index;
+    char *the_input;
+    int the_length;
+    int the_char;
+    int the_byte;
+} json_utf8_decode;
+
+extern int  utf8_decode_at_byte(json_utf8_decode *utf8);
+extern int  utf8_decode_at_character(json_utf8_decode *utf8);
+extern void utf8_decode_init(json_utf8_decode *utf8, char p[], int length);
+extern int  utf8_decode_next(json_utf8_decode *utf8);
diff --git a/ext/json/utf8_to_utf16.c b/ext/json/utf8_to_utf16.c
new file mode 100644 (file)
index 0000000..bc2d6f3
--- /dev/null
@@ -0,0 +1,56 @@
+/* utf8_to_utf16.c */
+
+/* 2005-12-25 */
+
+/*
+Copyright (c) 2005 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include "utf8_to_utf16.h"
+#include "utf8_decode.h"
+
+int 
+utf8_to_utf16(unsigned short w[], char p[], int length) 
+{
+    int c;
+    int the_index = 0;
+    json_utf8_decode utf8;
+    
+    utf8_decode_init(&utf8, p, length);
+    for (;;) {
+        c = utf8_decode_next(&utf8);
+        if (c < 0) {
+            return UTF8_END ? the_index : UTF8_ERROR;
+        }
+        if (c < 0x10000) {
+            w[the_index] = (unsigned short)c;
+            the_index += 1;
+        } else {
+            c &= 0xFFFF;
+            w[the_index] = (unsigned short)(0xD800 | (c >> 10));
+            the_index += 1;
+            w[the_index] = (unsigned short)(0xDC00 | (c & 0x3FF));
+            the_index += 1;
+        }
+    }
+}
diff --git a/ext/json/utf8_to_utf16.h b/ext/json/utf8_to_utf16.h
new file mode 100644 (file)
index 0000000..5aff026
--- /dev/null
@@ -0,0 +1,3 @@
+/* utf8_to_utf16.h */
+
+extern int utf8_to_utf16(unsigned short w[], char p[], int length);