PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/json - json.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 339 358 94.7 %
Date: 2014-09-21 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sun, 21 Sep 2014 15:27:37 +0000 (2 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.