root/ext/json/json.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_MINIT_FUNCTION
  2. PHP_GINIT_FUNCTION
  3. ZEND_GET_MODULE
  4. json_determine_array_type
  5. json_pretty_print_char
  6. json_pretty_print_indent
  7. json_encode_array
  8. json_utf8_to_utf16
  9. json_escape_string
  10. json_encode_serializable_object
  11. php_json_encode
  12. php_json_decode_ex
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 5                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 The PHP Group                                |
   6   +----------------------------------------------------------------------+
   7   | This source file is subject to version 3.01 of the PHP license,      |
   8   | that is bundled with this package in the file LICENSE, and is        |
   9   | available through the world-wide-web at the following url:           |
  10   | http://www.php.net/license/3_01.txt                                  |
  11   | If you did not receive a copy of the PHP license and are unable to   |
  12   | obtain it through the world-wide-web, please send a note to          |
  13   | license@php.net so we can mail you a copy immediately.               |
  14   +----------------------------------------------------------------------+
  15   | Author: Omar Kilani <omar@php.net>                                   |
  16   +----------------------------------------------------------------------+
  17 */
  18 
  19 /* $Id$ */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include "config.h"
  23 #endif
  24 
  25 #include "php.h"
  26 #include "php_ini.h"
  27 #include "ext/standard/info.h"
  28 #include "ext/standard/html.h"
  29 #include "ext/standard/php_smart_str.h"
  30 #include "JSON_parser.h"
  31 #include "php_json.h"
  32 #include <zend_exceptions.h>
  33 
  34 #include <float.h>
  35 #if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP)
  36 #define NUM_BUF_SIZE (3 + DBL_MANT_DIG - DBL_MIN_EXP)
  37 #else
  38 #define NUM_BUF_SIZE 1080
  39 #endif
  40 
  41 
  42 static PHP_MINFO_FUNCTION(json);
  43 static PHP_FUNCTION(json_encode);
  44 static PHP_FUNCTION(json_decode);
  45 static PHP_FUNCTION(json_last_error);
  46 static PHP_FUNCTION(json_last_error_msg);
  47 
  48 static const char digits[] = "0123456789abcdef";
  49 
  50 PHP_JSON_API zend_class_entry *php_json_serializable_ce;
  51 
  52 ZEND_DECLARE_MODULE_GLOBALS(json)
  53 
  54 /* {{{ arginfo */
  55 ZEND_BEGIN_ARG_INFO_EX(arginfo_json_encode, 0, 0, 1)
  56         ZEND_ARG_INFO(0, value)
  57         ZEND_ARG_INFO(0, options)
  58         ZEND_ARG_INFO(0, depth)
  59 ZEND_END_ARG_INFO()
  60 
  61 ZEND_BEGIN_ARG_INFO_EX(arginfo_json_decode, 0, 0, 1)
  62         ZEND_ARG_INFO(0, json)
  63         ZEND_ARG_INFO(0, assoc)
  64         ZEND_ARG_INFO(0, depth)
  65         ZEND_ARG_INFO(0, options)
  66 ZEND_END_ARG_INFO()
  67 
  68 ZEND_BEGIN_ARG_INFO(arginfo_json_last_error, 0)
  69 ZEND_END_ARG_INFO()
  70 
  71 ZEND_BEGIN_ARG_INFO(arginfo_json_last_error_msg, 0)
  72 ZEND_END_ARG_INFO()
  73 /* }}} */
  74 
  75 /* {{{ json_functions[] */
  76 static const zend_function_entry json_functions[] = {
  77         PHP_FE(json_encode, arginfo_json_encode)
  78         PHP_FE(json_decode, arginfo_json_decode)
  79         PHP_FE(json_last_error, arginfo_json_last_error)
  80         PHP_FE(json_last_error_msg, arginfo_json_last_error_msg)
  81         PHP_FE_END
  82 };
  83 /* }}} */
  84 
  85 /* {{{ JsonSerializable methods */
  86 ZEND_BEGIN_ARG_INFO(json_serialize_arginfo, 0)
  87         /* No arguments */
  88 ZEND_END_ARG_INFO();
  89 
  90 static const zend_function_entry json_serializable_interface[] = {
  91         PHP_ABSTRACT_ME(JsonSerializable, jsonSerialize, json_serialize_arginfo)
  92         PHP_FE_END
  93 };
  94 /* }}} */
  95 
  96 /* {{{ MINIT */
  97 static PHP_MINIT_FUNCTION(json)
  98 {
  99         zend_class_entry ce;
 100 
 101         INIT_CLASS_ENTRY(ce, "JsonSerializable", json_serializable_interface);
 102         php_json_serializable_ce = zend_register_internal_interface(&ce TSRMLS_CC);
 103 
 104         REGISTER_LONG_CONSTANT("JSON_HEX_TAG",  PHP_JSON_HEX_TAG,  CONST_CS | CONST_PERSISTENT);
 105         REGISTER_LONG_CONSTANT("JSON_HEX_AMP",  PHP_JSON_HEX_AMP,  CONST_CS | CONST_PERSISTENT);
 106         REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT);
 107         REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT);
 108         REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT);
 109         REGISTER_LONG_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK, CONST_CS | CONST_PERSISTENT);
 110         REGISTER_LONG_CONSTANT("JSON_UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES, CONST_CS | CONST_PERSISTENT);
 111         REGISTER_LONG_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT, CONST_CS | CONST_PERSISTENT);
 112         REGISTER_LONG_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE, CONST_CS | CONST_PERSISTENT);
 113         REGISTER_LONG_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR, CONST_CS | CONST_PERSISTENT);
 114         REGISTER_LONG_CONSTANT("JSON_PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION, CONST_CS | CONST_PERSISTENT);
 115 
 116         REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
 117         REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
 118         REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
 119         REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
 120         REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
 121         REGISTER_LONG_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8, CONST_CS | CONST_PERSISTENT);
 122         REGISTER_LONG_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION, CONST_CS | CONST_PERSISTENT);
 123         REGISTER_LONG_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN, CONST_CS | CONST_PERSISTENT);
 124         REGISTER_LONG_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE, CONST_CS | CONST_PERSISTENT);
 125 
 126         REGISTER_LONG_CONSTANT("JSON_OBJECT_AS_ARRAY",          PHP_JSON_OBJECT_AS_ARRAY,               CONST_CS | CONST_PERSISTENT);
 127         REGISTER_LONG_CONSTANT("JSON_BIGINT_AS_STRING",         PHP_JSON_BIGINT_AS_STRING,              CONST_CS | CONST_PERSISTENT);
 128 
 129         return SUCCESS;
 130 }
 131 /* }}} */
 132 
 133 /* {{{ PHP_GINIT_FUNCTION
 134 */
 135 static PHP_GINIT_FUNCTION(json)
 136 {
 137         json_globals->encoder_depth = 0;
 138         json_globals->error_code = 0;
 139         json_globals->encode_max_depth = 0;
 140 }
 141 /* }}} */
 142 
 143 
 144 /* {{{ json_module_entry
 145  */
 146 zend_module_entry json_module_entry = {
 147         STANDARD_MODULE_HEADER,
 148         "json",
 149         json_functions,
 150         PHP_MINIT(json),
 151         NULL,
 152         NULL,
 153         NULL,
 154         PHP_MINFO(json),
 155         PHP_JSON_VERSION,
 156         PHP_MODULE_GLOBALS(json),
 157         PHP_GINIT(json),
 158         NULL,
 159         NULL,
 160         STANDARD_MODULE_PROPERTIES_EX
 161 };
 162 /* }}} */
 163 
 164 #ifdef COMPILE_DL_JSON
 165 ZEND_GET_MODULE(json)
 166 #endif
 167 
 168 /* {{{ PHP_MINFO_FUNCTION
 169  */
 170 static PHP_MINFO_FUNCTION(json)
 171 {
 172         php_info_print_table_start();
 173         php_info_print_table_row(2, "json support", "enabled");
 174         php_info_print_table_row(2, "json version", PHP_JSON_VERSION);
 175         php_info_print_table_end();
 176 }
 177 /* }}} */
 178 
 179 static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC);
 180 
 181 static int json_determine_array_type(zval **val TSRMLS_DC) /* {{{ */
 182 {
 183         int i;
 184         HashTable *myht = HASH_OF(*val);
 185 
 186         i = myht ? zend_hash_num_elements(myht) : 0;
 187         if (i > 0) {
 188                 char *key;
 189                 ulong index, idx;
 190                 uint key_len;
 191                 HashPosition pos;
 192 
 193                 zend_hash_internal_pointer_reset_ex(myht, &pos);
 194                 idx = 0;
 195                 for (;; zend_hash_move_forward_ex(myht, &pos)) {
 196                         i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
 197                         if (i == HASH_KEY_NON_EXISTENT) {
 198                                 break;
 199                         }
 200 
 201                         if (i == HASH_KEY_IS_STRING) {
 202                                 return 1;
 203                         } else {
 204                                 if (index != idx) {
 205                                         return 1;
 206                                 }
 207                         }
 208                         idx++;
 209                 }
 210         }
 211 
 212         return PHP_JSON_OUTPUT_ARRAY;
 213 }
 214 /* }}} */
 215 
 216 /* {{{ Pretty printing support functions */
 217 
 218 static inline void json_pretty_print_char(smart_str *buf, int options, char c TSRMLS_DC) /* {{{ */
 219 {
 220         if (options & PHP_JSON_PRETTY_PRINT) {
 221                 smart_str_appendc(buf, c);
 222         }
 223 }
 224 /* }}} */
 225 
 226 static inline void json_pretty_print_indent(smart_str *buf, int options TSRMLS_DC) /* {{{ */
 227 {
 228         int i;
 229 
 230         if (options & PHP_JSON_PRETTY_PRINT) {
 231                 for (i = 0; i < JSON_G(encoder_depth); ++i) {
 232                         smart_str_appendl(buf, "    ", 4);
 233                 }
 234         }
 235 }
 236 /* }}} */
 237 
 238 /* }}} */
 239 
 240 static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */
 241 {
 242         int i, r, need_comma = 0;
 243         HashTable *myht;
 244 
 245         if (Z_TYPE_PP(val) == IS_ARRAY) {
 246                 myht = HASH_OF(*val);
 247                 r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : json_determine_array_type(val TSRMLS_CC);
 248         } else {
 249                 myht = Z_OBJPROP_PP(val);
 250                 r = PHP_JSON_OUTPUT_OBJECT;
 251         }
 252 
 253         if (myht && myht->nApplyCount > 1) {
 254                 JSON_G(error_code) = PHP_JSON_ERROR_RECURSION;
 255                 smart_str_appendl(buf, "null", 4);
 256                 return;
 257         }
 258 
 259         if (r == PHP_JSON_OUTPUT_ARRAY) {
 260                 smart_str_appendc(buf, '[');
 261         } else {
 262                 smart_str_appendc(buf, '{');
 263         }
 264 
 265         ++JSON_G(encoder_depth);
 266 
 267         i = myht ? zend_hash_num_elements(myht) : 0;
 268 
 269         if (i > 0)
 270         {
 271                 char *key;
 272                 zval **data;
 273                 ulong index;
 274                 uint key_len;
 275                 HashPosition pos;
 276                 HashTable *tmp_ht;
 277 
 278                 zend_hash_internal_pointer_reset_ex(myht, &pos);
 279                 for (;; zend_hash_move_forward_ex(myht, &pos)) {
 280                         i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
 281                         if (i == HASH_KEY_NON_EXISTENT)
 282                                 break;
 283 
 284                         if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) {
 285                                 tmp_ht = HASH_OF(*data);
 286                                 if (tmp_ht) {
 287                                         tmp_ht->nApplyCount++;
 288                                 }
 289 
 290                                 if (r == PHP_JSON_OUTPUT_ARRAY) {
 291                                         if (need_comma) {
 292                                                 smart_str_appendc(buf, ',');
 293                                         } else {
 294                                                 need_comma = 1;
 295                                         }
 296 
 297                                         json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
 298                                         json_pretty_print_indent(buf, options TSRMLS_CC);
 299                                         php_json_encode(buf, *data, options TSRMLS_CC);
 300                                 } else if (r == PHP_JSON_OUTPUT_OBJECT) {
 301                                         if (i == HASH_KEY_IS_STRING) {
 302                                                 if (key[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) {
 303                                                         /* Skip protected and private members. */
 304                                                         if (tmp_ht) {
 305                                                                 tmp_ht->nApplyCount--;
 306                                                         }
 307                                                         continue;
 308                                                 }
 309 
 310                                                 if (need_comma) {
 311                                                         smart_str_appendc(buf, ',');
 312                                                 } else {
 313                                                         need_comma = 1;
 314                                                 }
 315 
 316                                                 json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
 317                                                 json_pretty_print_indent(buf, options TSRMLS_CC);
 318 
 319                                                 json_escape_string(buf, key, key_len - 1, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC);
 320                                                 smart_str_appendc(buf, ':');
 321 
 322                                                 json_pretty_print_char(buf, options, ' ' TSRMLS_CC);
 323 
 324                                                 php_json_encode(buf, *data, options TSRMLS_CC);
 325                                         } else {
 326                                                 if (need_comma) {
 327                                                         smart_str_appendc(buf, ',');
 328                                                 } else {
 329                                                         need_comma = 1;
 330                                                 }
 331 
 332                                                 json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
 333                                                 json_pretty_print_indent(buf, options TSRMLS_CC);
 334 
 335                                                 smart_str_appendc(buf, '"');
 336                                                 smart_str_append_long(buf, (long) index);
 337                                                 smart_str_appendc(buf, '"');
 338                                                 smart_str_appendc(buf, ':');
 339 
 340                                                 json_pretty_print_char(buf, options, ' ' TSRMLS_CC);
 341 
 342                                                 php_json_encode(buf, *data, options TSRMLS_CC);
 343                                         }
 344                                 }
 345 
 346                                 if (tmp_ht) {
 347                                         tmp_ht->nApplyCount--;
 348                                 }
 349                         }
 350                 }
 351         }
 352 
 353         if (JSON_G(encoder_depth) > JSON_G(encode_max_depth)) {
 354                 JSON_G(error_code) = PHP_JSON_ERROR_DEPTH;
 355         }
 356         --JSON_G(encoder_depth);
 357 
 358         /* Only keep closing bracket on same line for empty arrays/objects */
 359         if (need_comma) {
 360                 json_pretty_print_char(buf, options, '\n' TSRMLS_CC);
 361                 json_pretty_print_indent(buf, options TSRMLS_CC);
 362         }
 363 
 364         if (r == PHP_JSON_OUTPUT_ARRAY) {
 365                 smart_str_appendc(buf, ']');
 366         } else {
 367                 smart_str_appendc(buf, '}');
 368         }
 369 }
 370 /* }}} */
 371 
 372 static int json_utf8_to_utf16(unsigned short *utf16, char utf8[], int len) /* {{{ */
 373 {
 374         size_t pos = 0, us;
 375         int j, status;
 376 
 377         if (utf16) {
 378                 /* really convert the utf8 string */
 379                 for (j=0 ; pos < len ; j++) {
 380                         us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status);
 381                         if (status != SUCCESS) {
 382                                 return -1;
 383                         }
 384                         /* From http://en.wikipedia.org/wiki/UTF16 */
 385                         if (us >= 0x10000) {
 386                                 us -= 0x10000;
 387                                 utf16[j++] = (unsigned short)((us >> 10) | 0xd800);
 388                                 utf16[j] = (unsigned short)((us & 0x3ff) | 0xdc00);
 389                         } else {
 390                                 utf16[j] = (unsigned short)us;
 391                         }
 392                 }
 393         } else {
 394                 /* Only check if utf8 string is valid, and compute utf16 length */
 395                 for (j=0 ; pos < len ; j++) {
 396                         us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status);
 397                         if (status != SUCCESS) {
 398                                 return -1;
 399                         }
 400                         if (us >= 0x10000) {
 401                                 j++;
 402                         }
 403                 }
 404         }
 405         return j;
 406 }
 407 /* }}} */
 408 
 409 
 410 static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC) /* {{{ */
 411 {
 412         int pos = 0, ulen = 0;
 413         unsigned short us;
 414         unsigned short *utf16;
 415         size_t newlen;
 416 
 417         if (len == 0) {
 418                 smart_str_appendl(buf, "\"\"", 2);
 419                 return;
 420         }
 421 
 422         if (options & PHP_JSON_NUMERIC_CHECK) {
 423                 double d;
 424                 int type;
 425                 long p;
 426 
 427                 if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) {
 428                         if (type == IS_LONG) {
 429                                 smart_str_append_long(buf, p);
 430                                 return;
 431                         } else if (type == IS_DOUBLE && !zend_isinf(d) && !zend_isnan(d)) {
 432                                 char num[NUM_BUF_SIZE];
 433                                 int l;
 434 
 435                                 php_gcvt(d, EG(precision), '.', 'e', (char *)num);
 436                                 l = strlen(num);
 437                                 if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && l < NUM_BUF_SIZE - 2) {
 438                                         num[l++] = '.';
 439                                         num[l++] = '0';
 440                                         num[l] = '\0';
 441                                 }
 442                                 smart_str_appendl(buf, num, l);
 443                                 return;
 444                         }
 445                 }
 446 
 447         }
 448 
 449         utf16 = (options & PHP_JSON_UNESCAPED_UNICODE) ? NULL : (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0);
 450         ulen = json_utf8_to_utf16(utf16, s, len);
 451         if (ulen <= 0) {
 452                 if (utf16) {
 453                         efree(utf16);
 454                 }
 455                 if (ulen < 0) {
 456                         JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
 457                         smart_str_appendl(buf, "null", 4);
 458                 } else {
 459                         smart_str_appendl(buf, "\"\"", 2);
 460                 }
 461                 return;
 462         }
 463         if (!(options & PHP_JSON_UNESCAPED_UNICODE)) {
 464                 len = ulen;
 465         }
 466 
 467         /* pre-allocate for string length plus 2 quotes */
 468         smart_str_alloc(buf, len+2, 0);
 469         smart_str_appendc(buf, '"');
 470 
 471         while (pos < len)
 472         {
 473                 us = (options & PHP_JSON_UNESCAPED_UNICODE) ? s[pos++] : utf16[pos++];
 474 
 475                 switch (us)
 476                 {
 477                         case '"':
 478                                 if (options & PHP_JSON_HEX_QUOT) {
 479                                         smart_str_appendl(buf, "\\u0022", 6);
 480                                 } else {
 481                                         smart_str_appendl(buf, "\\\"", 2);
 482                                 }
 483                                 break;
 484 
 485                         case '\\':
 486                                 smart_str_appendl(buf, "\\\\", 2);
 487                                 break;
 488 
 489                         case '/':
 490                                 if (options & PHP_JSON_UNESCAPED_SLASHES) {
 491                                         smart_str_appendc(buf, '/');
 492                                 } else {
 493                                         smart_str_appendl(buf, "\\/", 2);
 494                                 }
 495                                 break;
 496 
 497                         case '\b':
 498                                 smart_str_appendl(buf, "\\b", 2);
 499                                 break;
 500 
 501                         case '\f':
 502                                 smart_str_appendl(buf, "\\f", 2);
 503                                 break;
 504 
 505                         case '\n':
 506                                 smart_str_appendl(buf, "\\n", 2);
 507                                 break;
 508 
 509                         case '\r':
 510                                 smart_str_appendl(buf, "\\r", 2);
 511                                 break;
 512 
 513                         case '\t':
 514                                 smart_str_appendl(buf, "\\t", 2);
 515                                 break;
 516 
 517                         case '<':
 518                                 if (options & PHP_JSON_HEX_TAG) {
 519                                         smart_str_appendl(buf, "\\u003C", 6);
 520                                 } else {
 521                                         smart_str_appendc(buf, '<');
 522                                 }
 523                                 break;
 524 
 525                         case '>':
 526                                 if (options & PHP_JSON_HEX_TAG) {
 527                                         smart_str_appendl(buf, "\\u003E", 6);
 528                                 } else {
 529                                         smart_str_appendc(buf, '>');
 530                                 }
 531                                 break;
 532 
 533                         case '&':
 534                                 if (options & PHP_JSON_HEX_AMP) {
 535                                         smart_str_appendl(buf, "\\u0026", 6);
 536                                 } else {
 537                                         smart_str_appendc(buf, '&');
 538                                 }
 539                                 break;
 540 
 541                         case '\'':
 542                                 if (options & PHP_JSON_HEX_APOS) {
 543                                         smart_str_appendl(buf, "\\u0027", 6);
 544                                 } else {
 545                                         smart_str_appendc(buf, '\'');
 546                                 }
 547                                 break;
 548 
 549                         default:
 550                                 if (us >= ' ' && ((options & PHP_JSON_UNESCAPED_UNICODE) || (us & 127) == us)) {
 551                                         smart_str_appendc(buf, (unsigned char) us);
 552                                 } else {
 553                                         smart_str_appendl(buf, "\\u", 2);
 554                                         smart_str_appendc(buf, digits[(us & 0xf000) >> 12]);
 555                                         smart_str_appendc(buf, digits[(us & 0xf00)  >> 8]);
 556                                         smart_str_appendc(buf, digits[(us & 0xf0)   >> 4]);
 557                                         smart_str_appendc(buf, digits[(us & 0xf)]);
 558                                 }
 559                                 break;
 560                 }
 561         }
 562 
 563         smart_str_appendc(buf, '"');
 564         if (utf16) {
 565                 efree(utf16);
 566         }
 567 }
 568 /* }}} */
 569 
 570 
 571 static void json_encode_serializable_object(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */
 572 {
 573         zend_class_entry *ce = Z_OBJCE_P(val);
 574         zval *retval = NULL, fname;
 575         HashTable* myht;
 576 
 577         if (Z_TYPE_P(val) == IS_ARRAY) {
 578                 myht = HASH_OF(val);
 579         } else {
 580                 myht = Z_OBJPROP_P(val);
 581         }
 582 
 583         if (myht && myht->nApplyCount > 1) {
 584                 JSON_G(error_code) = PHP_JSON_ERROR_RECURSION;
 585                 smart_str_appendl(buf, "null", 4);
 586                 return;
 587         }
 588 
 589         ZVAL_STRING(&fname, "jsonSerialize", 0);
 590 
 591         if (FAILURE == call_user_function_ex(EG(function_table), &val, &fname, &retval, 0, NULL, 1, NULL TSRMLS_CC) || !retval) {
 592                 zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Failed calling %s::jsonSerialize()", ce->name);
 593                 smart_str_appendl(buf, "null", sizeof("null") - 1);
 594                 return;
 595     }
 596 
 597         if (EG(exception)) {
 598                 /* Error already raised */
 599                 zval_ptr_dtor(&retval);
 600                 smart_str_appendl(buf, "null", sizeof("null") - 1);
 601                 return;
 602         }
 603 
 604         if ((Z_TYPE_P(retval) == IS_OBJECT) &&
 605                 (Z_OBJ_HANDLE_P(retval) == Z_OBJ_HANDLE_P(val))) {
 606                 /* Handle the case where jsonSerialize does: return $this; by going straight to encode array */
 607                 json_encode_array(buf, &retval, options TSRMLS_CC);
 608         } else {
 609                 /* All other types, encode as normal */
 610                 php_json_encode(buf, retval, options TSRMLS_CC);
 611         }
 612 
 613         zval_ptr_dtor(&retval);
 614 }
 615 /* }}} */
 616 
 617 PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */
 618 {
 619         switch (Z_TYPE_P(val))
 620         {
 621                 case IS_NULL:
 622                         smart_str_appendl(buf, "null", 4);
 623                         break;
 624 
 625                 case IS_BOOL:
 626                         if (Z_BVAL_P(val)) {
 627                                 smart_str_appendl(buf, "true", 4);
 628                         } else {
 629                                 smart_str_appendl(buf, "false", 5);
 630                         }
 631                         break;
 632 
 633                 case IS_LONG:
 634                         smart_str_append_long(buf, Z_LVAL_P(val));
 635                         break;
 636 
 637                 case IS_DOUBLE:
 638                         {
 639                                 char num[NUM_BUF_SIZE];
 640                                 int len;
 641                                 double dbl = Z_DVAL_P(val);
 642 
 643                                 if (!zend_isinf(dbl) && !zend_isnan(dbl)) {
 644                                         php_gcvt(dbl, EG(precision), '.', 'e', (char *)num);
 645                                         len = strlen(num);
 646                                         if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < NUM_BUF_SIZE - 2) {
 647                                                 num[len++] = '.';
 648                                                 num[len++] = '0';
 649                                                 num[len] = '\0';
 650                                         }
 651                                         smart_str_appendl(buf, num, len);
 652                                 } else {
 653                                         JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN;
 654                                         smart_str_appendc(buf, '0');
 655                                 }
 656                         }
 657                         break;
 658 
 659                 case IS_STRING:
 660                         json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options TSRMLS_CC);
 661                         break;
 662 
 663                 case IS_OBJECT:
 664                         if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce TSRMLS_CC)) {
 665                                 json_encode_serializable_object(buf, val, options TSRMLS_CC);
 666                                 break;
 667                         }
 668                         /* fallthrough -- Non-serializable object */
 669                 case IS_ARRAY:
 670                         json_encode_array(buf, &val, options TSRMLS_CC);
 671                         break;
 672 
 673                 default:
 674                         JSON_G(error_code) = PHP_JSON_ERROR_UNSUPPORTED_TYPE;
 675                         smart_str_appendl(buf, "null", 4);
 676                         break;
 677         }
 678 
 679         return;
 680 }
 681 /* }}} */
 682 
 683 PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC) /* {{{ */
 684 {
 685         int utf16_len;
 686         zval *z;
 687         unsigned short *utf16;
 688         JSON_parser jp;
 689 
 690         utf16 = (unsigned short *) safe_emalloc((str_len+1), sizeof(unsigned short), 1);
 691 
 692         utf16_len = json_utf8_to_utf16(utf16, str, str_len);
 693         if (utf16_len <= 0) {
 694                 if (utf16) {
 695                         efree(utf16);
 696                 }
 697                 JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
 698                 RETURN_NULL();
 699         }
 700 
 701         if (depth <= 0) {
 702                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Depth must be greater than zero");
 703                 efree(utf16);
 704                 RETURN_NULL();
 705         }
 706 
 707         ALLOC_INIT_ZVAL(z);
 708         jp = new_JSON_parser(depth);
 709         if (parse_JSON_ex(jp, z, utf16, utf16_len, options TSRMLS_CC)) {
 710                 *return_value = *z;
 711         }
 712         else
 713         {
 714                 double d;
 715                 int type, overflow_info;
 716                 long p;
 717                 char *trim = str;
 718                 int trim_len = str_len;
 719 
 720                 /* Increment trimmed string pointer to strip leading whitespace */
 721                 /* JSON RFC says to consider as whitespace: space, tab, LF or CR */
 722                 while (trim_len && (*trim == ' ' || *trim == '\t' || *trim == '\n' || *trim == '\r')) {
 723                         trim++;
 724                         trim_len--;
 725                 }
 726 
 727                 /* Decrement trimmed string length to strip trailing whitespace */
 728                 while (trim_len && (trim[trim_len - 1] == ' ' || trim[trim_len - 1] == '\t' || trim[trim_len - 1] == '\n' || trim[trim_len - 1] == '\r')) {
 729                         trim_len--;
 730                 }
 731 
 732                 RETVAL_NULL();
 733                 if (trim_len == 4) {
 734                         if (!strncmp(trim, "null", trim_len)) {
 735                                 /* We need to explicitly clear the error because its an actual NULL and not an error */
 736                                 jp->error_code = PHP_JSON_ERROR_NONE;
 737                                 RETVAL_NULL();
 738                         } else if (!strncmp(trim, "true", trim_len)) {
 739                                 RETVAL_BOOL(1);
 740                         }
 741                 } else if (trim_len == 5 && !strncmp(trim, "false", trim_len)) {
 742                         RETVAL_BOOL(0);
 743                 }
 744 
 745                 if ((type = is_numeric_string_ex(trim, trim_len, &p, &d, 0, &overflow_info)) != 0) {
 746                         if (type == IS_LONG) {
 747                                 RETVAL_LONG(p);
 748                         } else if (type == IS_DOUBLE) {
 749                                 if (options & PHP_JSON_BIGINT_AS_STRING && overflow_info) {
 750                                         /* Within an object or array, a numeric literal is assumed
 751                                          * to be an integer if and only if it's entirely made up of
 752                                          * digits (exponent notation will result in the number
 753                                          * being treated as a double). We'll match that behaviour
 754                                          * here. */
 755                                         int i;
 756                                         zend_bool is_float = 0;
 757 
 758                                         for (i = (trim[0] == '-' ? 1 : 0); i < trim_len; i++) {
 759                                                 /* Not using isdigit() because it's locale specific,
 760                                                  * but we expect JSON input to always be UTF-8. */
 761                                                 if (trim[i] < '0' || trim[i] > '9') {
 762                                                         is_float = 1;
 763                                                         break;
 764                                                 }
 765                                         }
 766 
 767                                         if (is_float) {
 768                                                 RETVAL_DOUBLE(d);
 769                                         } else {
 770                                                 RETVAL_STRINGL(trim, trim_len, 1);
 771                                         }
 772                                 } else {
 773                                         RETVAL_DOUBLE(d);
 774                                 }
 775                         }
 776                 }
 777 
 778                 if (Z_TYPE_P(return_value) != IS_NULL) {
 779                         jp->error_code = PHP_JSON_ERROR_NONE;
 780                 }
 781 
 782                 zval_dtor(z);
 783         }
 784         FREE_ZVAL(z);
 785         efree(utf16);
 786         JSON_G(error_code) = jp->error_code;
 787         free_JSON_parser(jp);
 788 }
 789 /* }}} */
 790 
 791 
 792 /* {{{ proto string json_encode(mixed data [, int options[, int depth]])
 793    Returns the JSON representation of a value */
 794 static PHP_FUNCTION(json_encode)
 795 {
 796         zval *parameter;
 797         smart_str buf = {0};
 798         long options = 0;
 799     long depth = JSON_PARSER_DEFAULT_DEPTH;
 800 
 801         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &parameter, &options, &depth) == FAILURE) {
 802                 return;
 803         }
 804 
 805         JSON_G(error_code) = PHP_JSON_ERROR_NONE;
 806 
 807         JSON_G(encode_max_depth) = depth;
 808 
 809         php_json_encode(&buf, parameter, options TSRMLS_CC);
 810 
 811         if (JSON_G(error_code) != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
 812                 ZVAL_FALSE(return_value);
 813         } else {
 814                 ZVAL_STRINGL(return_value, buf.c, buf.len, 1);
 815         }
 816 
 817         smart_str_free(&buf);
 818 }
 819 /* }}} */
 820 
 821 /* {{{ proto mixed json_decode(string json [, bool assoc [, long depth]])
 822    Decodes the JSON representation into a PHP value */
 823 static PHP_FUNCTION(json_decode)
 824 {
 825         char *str;
 826         int str_len;
 827         zend_bool assoc = 0; /* return JS objects as PHP objects by default */
 828         long depth = JSON_PARSER_DEFAULT_DEPTH;
 829         long options = 0;
 830 
 831         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) {
 832                 return;
 833         }
 834 
 835         JSON_G(error_code) = 0;
 836 
 837         if (!str_len) {
 838                 RETURN_NULL();
 839         }
 840 
 841         /* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
 842         if (assoc) {
 843                 options |=  PHP_JSON_OBJECT_AS_ARRAY;
 844         } else {
 845                 options &= ~PHP_JSON_OBJECT_AS_ARRAY;
 846         }
 847 
 848         php_json_decode_ex(return_value, str, str_len, options, depth TSRMLS_CC);
 849 }
 850 /* }}} */
 851 
 852 /* {{{ proto int json_last_error()
 853    Returns the error code of the last json_encode() or json_decode() call. */
 854 static PHP_FUNCTION(json_last_error)
 855 {
 856         if (zend_parse_parameters_none() == FAILURE) {
 857                 return;
 858         }
 859 
 860         RETURN_LONG(JSON_G(error_code));
 861 }
 862 /* }}} */
 863 
 864 /* {{{ proto string json_last_error_msg()
 865    Returns the error string of the last json_encode() or json_decode() call. */
 866 static PHP_FUNCTION(json_last_error_msg)
 867 {
 868         if (zend_parse_parameters_none() == FAILURE) {
 869                 return;
 870         }
 871 
 872         switch(JSON_G(error_code)) {
 873                 case PHP_JSON_ERROR_NONE:
 874                         RETURN_STRING("No error", 1);
 875                 case PHP_JSON_ERROR_DEPTH:
 876                         RETURN_STRING("Maximum stack depth exceeded", 1);
 877                 case PHP_JSON_ERROR_STATE_MISMATCH:
 878                         RETURN_STRING("State mismatch (invalid or malformed JSON)", 1);
 879                 case PHP_JSON_ERROR_CTRL_CHAR:
 880                         RETURN_STRING("Control character error, possibly incorrectly encoded", 1);
 881                 case PHP_JSON_ERROR_SYNTAX:
 882                         RETURN_STRING("Syntax error", 1);
 883                 case PHP_JSON_ERROR_UTF8:
 884                         RETURN_STRING("Malformed UTF-8 characters, possibly incorrectly encoded", 1);
 885                 case PHP_JSON_ERROR_RECURSION:
 886                         RETURN_STRING("Recursion detected", 1);
 887                 case PHP_JSON_ERROR_INF_OR_NAN:
 888                         RETURN_STRING("Inf and NaN cannot be JSON encoded", 1);
 889                 case PHP_JSON_ERROR_UNSUPPORTED_TYPE:
 890                         RETURN_STRING("Type is not supported", 1);
 891                 default:
 892                         RETURN_STRING("Unknown error", 1);
 893         }
 894 
 895 }
 896 /* }}} */
 897 
 898 /*
 899  * Local variables:
 900  * tab-width: 4
 901  * c-basic-offset: 4
 902  * End:
 903  * vim600: noet sw=4 ts=4 fdm=marker
 904  * vim<600: noet sw=4 ts=4
 905  */

/* [<][>][^][v][top][bottom][index][help] */