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

Generated by: LCOV version 1.10

Generated at Mon, 04 Aug 2014 15:49:06 +0000 (41 days ago)

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