summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/filter/CREDITS2
-rw-r--r--ext/filter/callback_filter.c68
-rw-r--r--ext/filter/config.m495
-rw-r--r--ext/filter/config.w328
-rw-r--r--ext/filter/sanitizing_filters.c340
-rw-r--r--ext/filter/tests/001.phpt8
-rw-r--r--ext/filter/tests/002.phpt11
-rw-r--r--ext/filter/tests/003.phpt22
-rw-r--r--ext/filter/tests/004.phpt24
-rw-r--r--ext/filter/tests/005.phpt21
-rw-r--r--ext/filter/tests/006.phpt10
-rw-r--r--ext/filter/tests/007.phpt68
-rw-r--r--ext/filter/tests/008.phpt88
-rw-r--r--ext/filter/tests/009.phpt30
-rw-r--r--ext/filter/tests/011.phpt49
-rw-r--r--ext/filter/tests/012.phpt16
-rw-r--r--ext/filter/tests/014.phpt41
-rw-r--r--ext/filter/tests/020.phpt18
-rw-r--r--ext/filter/tests/021.phpt44
-rw-r--r--ext/filter/tests/022.phpt20
-rw-r--r--ext/filter/tests/023.phpt20
-rw-r--r--ext/filter/tests/024.phpt18
-rw-r--r--ext/filter/tests/025.phpt24
-rw-r--r--ext/filter/tests/026.phpt30
-rw-r--r--ext/filter/tests/027.phpt30
-rw-r--r--ext/filter/tests/028.phpt35
-rw-r--r--ext/filter/tests/029.phpt103
-rw-r--r--ext/filter/tests/filter_data.phpt71
-rw-r--r--ext/json/JSON_parser.c757
-rw-r--r--ext/json/JSON_parser.h8
-rw-r--r--ext/json/README76
-rw-r--r--ext/json/config.m488
-rw-r--r--ext/json/config.w3210
-rw-r--r--ext/json/json.c449
-rw-r--r--ext/json/json.dsp135
-rw-r--r--ext/json/package.xml152
-rw-r--r--ext/json/php_json.h60
-rw-r--r--ext/json/tests/fail001.phpt166
-rw-r--r--ext/json/tests/pass001.1.phpt895
-rw-r--r--ext/json/tests/pass001.phpt709
-rw-r--r--ext/json/tests/pass002.phpt276
-rw-r--r--ext/json/tests/pass003.phpt95
-rw-r--r--ext/json/utf8_decode.c179
-rw-r--r--ext/json/utf8_decode.h18
-rw-r--r--ext/json/utf8_to_utf16.c56
-rw-r--r--ext/json/utf8_to_utf16.h3
46 files changed, 5446 insertions, 0 deletions
diff --git a/ext/filter/CREDITS b/ext/filter/CREDITS
new file mode 100644
index 0000000000..fade411d07
--- /dev/null
+++ b/ext/filter/CREDITS
@@ -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
index 0000000000..5ce17fe23f
--- /dev/null
+++ b/ext/filter/callback_filter.c
@@ -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
index 0000000000..0db0375e26
--- /dev/null
+++ b/ext/filter/config.m4
@@ -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
index 0000000000..083555a4c7
--- /dev/null
+++ b/ext/filter/config.w32
@@ -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
index 0000000000..50d17eb65c
--- /dev/null
+++ b/ext/filter/sanitizing_filters.c
@@ -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
index 0000000000..2755a57363
--- /dev/null
+++ b/ext/filter/tests/001.phpt
@@ -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
index 0000000000..7136b251a6
--- /dev/null
+++ b/ext/filter/tests/002.phpt
@@ -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
index 0000000000..43e6cd9b03
--- /dev/null
+++ b/ext/filter/tests/003.phpt
@@ -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
index 0000000000..05ea952145
--- /dev/null
+++ b/ext/filter/tests/004.phpt
@@ -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
index 0000000000..f44379153e
--- /dev/null
+++ b/ext/filter/tests/005.phpt
@@ -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
index 0000000000..189579acf1
--- /dev/null
+++ b/ext/filter/tests/006.phpt
@@ -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
index 0000000000..ffc727801d
--- /dev/null
+++ b/ext/filter/tests/007.phpt
@@ -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
index 0000000000..eb6963c099
--- /dev/null
+++ b/ext/filter/tests/008.phpt
@@ -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
index 0000000000..c33fe8ae36
--- /dev/null
+++ b/ext/filter/tests/009.phpt
@@ -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
index 0000000000..0d3fa42745
--- /dev/null
+++ b/ext/filter/tests/011.phpt
@@ -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
index 0000000000..77c1880137
--- /dev/null
+++ b/ext/filter/tests/012.phpt
@@ -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
index 0000000000..f31fe6e9f4
--- /dev/null
+++ b/ext/filter/tests/014.phpt
@@ -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
index 0000000000..914c199afb
--- /dev/null
+++ b/ext/filter/tests/020.phpt
@@ -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
index 0000000000..697fdd69d4
--- /dev/null
+++ b/ext/filter/tests/021.phpt
@@ -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
index 0000000000..28ad64e723
--- /dev/null
+++ b/ext/filter/tests/022.phpt
@@ -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
index 0000000000..21fdc49a9b
--- /dev/null
+++ b/ext/filter/tests/023.phpt
@@ -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
index 0000000000..d405af3f08
--- /dev/null
+++ b/ext/filter/tests/024.phpt
@@ -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
index 0000000000..c770fb80f7
--- /dev/null
+++ b/ext/filter/tests/025.phpt
@@ -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
index 0000000000..b53dcb1989
--- /dev/null
+++ b/ext/filter/tests/026.phpt
@@ -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
index 0000000000..048dc362ef
--- /dev/null
+++ b/ext/filter/tests/027.phpt
@@ -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
index 0000000000..1d0d2e2071
--- /dev/null
+++ b/ext/filter/tests/028.phpt
@@ -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
index 0000000000..f60c42ef3c
--- /dev/null
+++ b/ext/filter/tests/029.phpt
@@ -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
index 0000000000..e907d02093
--- /dev/null
+++ b/ext/filter/tests/filter_data.phpt
@@ -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
index 0000000000..adb974346e
--- /dev/null
+++ b/ext/json/JSON_parser.c
@@ -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
index 0000000000..085e776982
--- /dev/null
+++ b/ext/json/JSON_parser.h
@@ -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
index 0000000000..d680b0c592
--- /dev/null
+++ b/ext/json/README
@@ -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
index 0000000000..a937b1f91b
--- /dev/null
+++ b/ext/json/config.m4
@@ -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
index 0000000000..fa001d308c
--- /dev/null
+++ b/ext/json/config.w32
@@ -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
index 0000000000..d19eb2e9b5
--- /dev/null
+++ b/ext/json/json.c
@@ -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
index 0000000000..e5bb3767bf
--- /dev/null
+++ b/ext/json/json.dsp
@@ -0,0 +1,135 @@
+# Microsoft Developer Studio Project File - Name="json" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=json - Win32 Debug_TS
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "json.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "json.mak" CFG="json - Win32 Debug_TS"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "json - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "json - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "json - Win32 Debug_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug_TS"
+# PROP BASE Intermediate_Dir "Debug_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug_TS"
+# PROP Intermediate_Dir "Debug_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "json_c" /D HAVE_JSON=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D ZEND_DEBUG=1 /D ZTS=1 /D COMPILE_DL_JSON=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"
+# ADD RSC /l 0x1009 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 iconv.lib php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_json.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
+
+!ELSEIF "$(CFG)" == "json - Win32 Release_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release_TS"
+# PROP BASE Intermediate_Dir "Release_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release_TS"
+# PROP Intermediate_Dir "Release_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "json_c" /D HAVE_JSON=1 /D "ZEND_WIN32" /D ZEND_DEBUG=0 /D "PHP_WIN32" /D ZTS=1 /D COMPILE_DL_JSON=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /D "HAVE_FCNTL_H" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"
+# ADD RSC /l 0x1009 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 iconv.lib php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_json.dll" /libpath:"..\..\Release_TS"
+
+!ENDIF
+
+# Begin Target
+
+# Name "json - Win32 Debug_TS"
+# Name "json - Win32 Release_TS"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=".\json.c"
+# End Source File
+# Begin Source File
+
+SOURCE=.\JSON_parser.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\JSON_parser.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\utf8_decode.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\utf8_decode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\utf8_to_utf16.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\utf8_to_utf16.h
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\php_json.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/ext/json/package.xml b/ext/json/package.xml
new file mode 100644
index 0000000000..0651de736f
--- /dev/null
+++ b/ext/json/package.xml
@@ -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
index 0000000000..48555ee31f
--- /dev/null
+++ b/ext/json/php_json.h
@@ -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
index 0000000000..4ee3780cf3
--- /dev/null
+++ b/ext/json/tests/fail001.phpt
@@ -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
index 0000000000..0cb05308da
--- /dev/null
+++ b/ext/json/tests/pass001.1.phpt
@@ -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) "
+
+ "
+ ["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;"
+ ["/\"쫾몾ꮘﳞ볚
+
+ `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) "
+
+ "
+ ["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;"
+ ["/\"쫾몾ꮘﳞ볚
+
+ `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) "
+
+ "
+ ["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;"
+ ["/\"쫾몾ꮘﳞ볚
+
+ `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) "
+
+ "
+ ["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;"
+ ["/\"쫾몾ꮘﳞ볚
+
+ `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
index 0000000000..aff970b107
--- /dev/null
+++ b/ext/json/tests/pass001.phpt
@@ -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) "
+
+ "
+ ["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;"
+ ["/\"쫾몾ꮘﳞ볚
+
+ `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) "
+
+ "
+ ["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;"
+ ["/\"쫾몾ꮘﳞ볚
+
+ `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) "
+
+ "
+ ["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;"
+ ["/\"쫾몾ꮘﳞ볚
+
+ `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) "
+
+ "
+ ["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;"
+ ["/\"쫾몾ꮘﳞ볚
+
+ `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
index 0000000000..a0e527ac4f
--- /dev/null
+++ b/ext/json/tests/pass002.phpt
@@ -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
index 0000000000..506ff05b3e
--- /dev/null
+++ b/ext/json/tests/pass003.phpt
@@ -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
index 0000000000..cea1f8cec8
--- /dev/null
+++ b/ext/json/utf8_decode.c
@@ -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
index 0000000000..cc0fc79f6c
--- /dev/null
+++ b/ext/json/utf8_decode.h
@@ -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
index 0000000000..bc2d6f36d6
--- /dev/null
+++ b/ext/json/utf8_to_utf16.c
@@ -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
index 0000000000..5aff0268bf
--- /dev/null
+++ b/ext/json/utf8_to_utf16.h
@@ -0,0 +1,3 @@
+/* utf8_to_utf16.h */
+
+extern int utf8_to_utf16(unsigned short w[], char p[], int length);