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

LTP GCOV extension - code coverage report
Current view: directory - json - json.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 195
Code covered: 97.4 % Executed lines: 190
Legend: not executed executed

       1                 : /*
       2                 :   +----------------------------------------------------------------------+
       3                 :   | PHP Version 5                                                        |
       4                 :   +----------------------------------------------------------------------+
       5                 :   | Copyright (c) 1997-2009 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: json.c 282593 2009-06-22 18:41:13Z stas $ */
      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/php_smart_str.h"
      29                 : #include "utf8_to_utf16.h"
      30                 : #include "JSON_parser.h"
      31                 : #include "php_json.h"
      32                 : 
      33                 : static PHP_MINFO_FUNCTION(json);
      34                 : 
      35                 : static PHP_FUNCTION(json_encode);
      36                 : static PHP_FUNCTION(json_decode);
      37                 : 
      38                 : static const char digits[] = "0123456789abcdef";
      39                 : 
      40                 : /* {{{ json_functions[]
      41                 :  *
      42                 :  * Every user visible function must have an entry in json_functions[].
      43                 :  */
      44                 : static function_entry json_functions[] = {
      45                 :     PHP_FE(json_encode, NULL)
      46                 :     PHP_FE(json_decode, NULL)
      47                 :     {NULL, NULL, NULL}  /* Must be the last line in json_functions[] */
      48                 : };
      49                 : /* }}} */
      50                 : 
      51                 : /* {{{ json_module_entry
      52                 :  */
      53                 : zend_module_entry json_module_entry = {
      54                 : #if ZEND_MODULE_API_NO >= 20010901
      55                 :     STANDARD_MODULE_HEADER,
      56                 : #endif
      57                 :     "json",
      58                 :     json_functions,
      59                 :     NULL,
      60                 :     NULL,
      61                 :     NULL,
      62                 :     NULL,
      63                 :     PHP_MINFO(json),
      64                 : #if ZEND_MODULE_API_NO >= 20010901
      65                 :     PHP_JSON_VERSION,
      66                 : #endif
      67                 :     STANDARD_MODULE_PROPERTIES
      68                 : };
      69                 : /* }}} */
      70                 : 
      71                 : #ifdef COMPILE_DL_JSON
      72                 : ZEND_GET_MODULE(json)
      73                 : #endif
      74                 : 
      75                 : /* {{{ PHP_MINFO_FUNCTION
      76                 :  */
      77                 : static PHP_MINFO_FUNCTION(json)
      78               6 : {
      79               6 :     php_info_print_table_start();
      80               6 :     php_info_print_table_row(2, "json support", "enabled");
      81               6 :     php_info_print_table_row(2, "json version", PHP_JSON_VERSION);
      82               6 :     php_info_print_table_end();
      83               6 : }
      84                 : /* }}} */
      85                 : 
      86                 : static void json_escape_string(smart_str *buf, char *s, int len TSRMLS_DC);
      87                 : 
      88                 : static int json_determine_array_type(zval **val TSRMLS_DC)  /* {{{ */
      89              95 : {
      90                 :     int i;
      91              95 :     HashTable *myht = HASH_OF(*val);
      92                 : 
      93              95 :     i = myht ? zend_hash_num_elements(myht) : 0;
      94              95 :     if (i > 0) {
      95                 :         char *key;
      96                 :         ulong index, idx;
      97                 :         uint key_len;
      98                 :         HashPosition pos;
      99                 : 
     100              81 :         zend_hash_internal_pointer_reset_ex(myht, &pos);
     101              81 :         idx = 0;
     102             190 :         for (;; zend_hash_move_forward_ex(myht, &pos)) {
     103             271 :             i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
     104             271 :             if (i == HASH_KEY_NON_EXISTANT)
     105              68 :                 break;
     106                 : 
     107             203 :             if (i == HASH_KEY_IS_STRING) {
     108              10 :                 return 1;
     109                 :             } else {
     110             193 :                 if (index != idx) {
     111               3 :                     return 1;
     112                 :                 }
     113                 :             }
     114             190 :             idx++;
     115             190 :         }
     116                 :     }
     117                 : 
     118              82 :     return 0;
     119                 : }
     120                 : /* }}} */
     121                 : 
     122             114 : static void json_encode_array(smart_str *buf, zval **val TSRMLS_DC) { /* {{{ */
     123                 :     int i, r;
     124                 :     HashTable *myht;
     125                 : 
     126             114 :     if (Z_TYPE_PP(val) == IS_ARRAY) {
     127              95 :         myht = HASH_OF(*val);
     128              95 :         r = json_determine_array_type(val TSRMLS_CC);
     129                 :     } else {
     130              19 :         myht = Z_OBJPROP_PP(val);
     131              19 :         r = 1;
     132                 :     }
     133                 : 
     134             114 :     if (myht && myht->nApplyCount > 1) {
     135               2 :         php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
     136               2 :         smart_str_appendl(buf, "null", 4);
     137               2 :         return;
     138                 :     }
     139                 : 
     140             112 :     if (r == 0)
     141                 :     {
     142              81 :         smart_str_appendc(buf, '[');
     143                 :     }
     144                 :     else
     145                 :     {
     146              31 :         smart_str_appendc(buf, '{');
     147                 :     }
     148                 : 
     149             112 :     i = myht ? zend_hash_num_elements(myht) : 0;
     150             112 :     if (i > 0) {
     151                 :         char *key;
     152                 :         zval **data;
     153                 :         ulong index;
     154                 :         uint key_len;
     155                 :         HashPosition pos;
     156                 :         HashTable *tmp_ht;
     157              94 :         int need_comma = 0;
     158                 : 
     159              94 :         zend_hash_internal_pointer_reset_ex(myht, &pos);
     160             369 :         for (;; zend_hash_move_forward_ex(myht, &pos)) {
     161             463 :             i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
     162             463 :             if (i == HASH_KEY_NON_EXISTANT)
     163              94 :                 break;
     164                 : 
     165             369 :             if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) {
     166             369 :                 tmp_ht = HASH_OF(*data);
     167             369 :                 if (tmp_ht) {
     168              91 :                     tmp_ht->nApplyCount++;
     169                 :                 }
     170                 : 
     171             369 :                 if (r == 0) {
     172             188 :                     if (need_comma) {
     173             121 :                         smart_str_appendc(buf, ',');
     174                 :                     } else {
     175              67 :                         need_comma = 1;
     176                 :                     }
     177                 :  
     178             188 :                     php_json_encode(buf, *data TSRMLS_CC);
     179             181 :                 } else if (r == 1) {
     180             181 :                     if (i == HASH_KEY_IS_STRING) {
     181             169 :                         if (key[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) {
     182                 :                             /* Skip protected and private members. */
     183               1 :                                                         if (tmp_ht) {
     184               1 :                                                                 tmp_ht->nApplyCount--;
     185                 :                                                         }
     186               1 :                             continue;
     187                 :                         }
     188                 : 
     189             168 :                         if (need_comma) {
     190             146 :                             smart_str_appendc(buf, ',');
     191                 :                         } else {
     192              22 :                             need_comma = 1;
     193                 :                         }
     194                 : 
     195             168 :                         json_escape_string(buf, key, key_len - 1 TSRMLS_CC);
     196             168 :                         smart_str_appendc(buf, ':');
     197                 : 
     198             168 :                         php_json_encode(buf, *data TSRMLS_CC);
     199                 :                     } else {
     200              12 :                         if (need_comma) {
     201               8 :                             smart_str_appendc(buf, ',');
     202                 :                         } else {
     203               4 :                             need_comma = 1;
     204                 :                         }
     205                 :                         
     206              12 :                         smart_str_appendc(buf, '"');
     207              12 :                         smart_str_append_long(buf, (long) index);
     208              12 :                         smart_str_appendc(buf, '"');
     209              12 :                         smart_str_appendc(buf, ':');
     210                 : 
     211              12 :                         php_json_encode(buf, *data TSRMLS_CC);
     212                 :                     }
     213                 :                 }
     214                 : 
     215             368 :                 if (tmp_ht) {
     216              90 :                     tmp_ht->nApplyCount--;
     217                 :                 }
     218                 :             }
     219             369 :         }
     220                 :     }
     221                 : 
     222             112 :     if (r == 0)
     223                 :     {
     224              81 :         smart_str_appendc(buf, ']');
     225                 :     }
     226                 :     else
     227                 :     {
     228              31 :         smart_str_appendc(buf, '}');
     229                 :     }
     230                 : }
     231                 : /* }}} */
     232                 : 
     233                 : #define REVERSE16(us) (((us & 0xf) << 12) | (((us >> 4) & 0xf) << 8) | (((us >> 8) & 0xf) << 4) | ((us >> 12) & 0xf))
     234                 : 
     235                 : static void json_escape_string(smart_str *buf, char *s, int len TSRMLS_DC) /* {{{ */
     236             314 : {
     237             314 :     int pos = 0;
     238                 :     unsigned short us;
     239                 :     unsigned short *utf16;
     240                 : 
     241             314 :     if (len == 0)
     242                 :     {
     243               9 :         smart_str_appendl(buf, "\"\"", 2);
     244               9 :         return;
     245                 :     }
     246                 : 
     247             305 :     utf16 = (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0);
     248                 : 
     249             305 :     len = utf8_to_utf16(utf16, s, len);
     250             305 :     if (len <= 0)
     251                 :     {
     252               4 :         if (utf16)
     253                 :         {
     254               4 :             efree(utf16);
     255                 :         }
     256               4 :         if(len < 0) {
     257               4 :                 if(!PG(display_errors)) {
     258               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid UTF-8 sequence in argument");
     259                 :                 }
     260               4 :                 smart_str_appendl(buf, "null", 4);
     261                 :         } else {
     262               0 :                 smart_str_appendl(buf, "\"\"", 2);
     263                 :         }
     264               4 :         return;
     265                 :     }
     266                 : 
     267             301 :     smart_str_appendc(buf, '"');
     268                 : 
     269            3412 :     while(pos < len)
     270                 :     {
     271            2810 :         us = utf16[pos++];
     272                 : 
     273            2810 :         switch (us)
     274                 :         {
     275                 :             case '"':
     276                 :                 {
     277              32 :                     smart_str_appendl(buf, "\\\"", 2);
     278                 :                 }
     279              32 :                 break;
     280                 :             case '\\':
     281                 :                 {
     282               8 :                     smart_str_appendl(buf, "\\\\", 2);
     283                 :                 }
     284               8 :                 break;
     285                 :             case '/':
     286                 :                 {
     287              48 :                     smart_str_appendl(buf, "\\/", 2);
     288                 :                 }
     289              48 :                 break;
     290                 :             case '\b':
     291                 :                 {
     292               8 :                     smart_str_appendl(buf, "\\b", 2);
     293                 :                 }
     294               8 :                 break;
     295                 :             case '\f':
     296                 :                 {
     297               8 :                     smart_str_appendl(buf, "\\f", 2);
     298                 :                 }
     299               8 :                 break;
     300                 :             case '\n':
     301                 :                 {
     302               9 :                     smart_str_appendl(buf, "\\n", 2);
     303                 :                 }
     304               9 :                 break;
     305                 :             case '\r':
     306                 :                 {
     307               8 :                     smart_str_appendl(buf, "\\r", 2);
     308                 :                 }
     309               8 :                 break;
     310                 :             case '\t':
     311                 :                 {
     312              10 :                     smart_str_appendl(buf, "\\t", 2);
     313                 :                 }
     314              10 :                 break;
     315                 :             default:
     316                 :                 {
     317            5216 :                     if (us >= ' ' && (us & 127) == us)
     318                 :                     {
     319            2537 :                         smart_str_appendc(buf, (unsigned char) us);
     320                 :                     }
     321                 :                     else
     322                 :                     {
     323             142 :                         smart_str_appendl(buf, "\\u", 2);
     324             142 :                         us = REVERSE16(us);
     325                 : 
     326             142 :                         smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
     327             142 :                         us >>= 4;
     328             142 :                         smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
     329             142 :                         us >>= 4;
     330             142 :                         smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
     331             142 :                         us >>= 4;
     332             142 :                         smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
     333                 :                     }
     334                 :                 }
     335                 :                 break;
     336                 :         }
     337                 :     }
     338                 : 
     339             301 :     smart_str_appendc(buf, '"');
     340             301 :     efree(utf16);
     341                 : }
     342                 : /* }}} */
     343                 : 
     344                 : PHP_JSON_API void php_json_encode(smart_str *buf, zval *val TSRMLS_DC) /* {{{ */
     345             445 : {
     346             445 :     switch (Z_TYPE_P(val)) {
     347                 :         case IS_NULL:
     348              14 :             smart_str_appendl(buf, "null", 4);
     349              14 :             break;
     350                 :         case IS_BOOL:
     351              22 :             if (Z_BVAL_P(val))
     352                 :             {
     353              12 :                 smart_str_appendl(buf, "true", 4);
     354                 :             }
     355                 :             else
     356                 :             {
     357              10 :                 smart_str_appendl(buf, "false", 5);
     358                 :             }
     359              22 :             break;
     360                 :         case IS_LONG:
     361             109 :             smart_str_append_long(buf, Z_LVAL_P(val));
     362             109 :             break;
     363                 :         case IS_DOUBLE:
     364                 :             {
     365              39 :                 char *d = NULL;
     366                 :                 int len;
     367              39 :                 double dbl = Z_DVAL_P(val);
     368                 : 
     369              74 :                 if (!zend_isinf(dbl) && !zend_isnan(dbl)) {
     370              35 :                         len = spprintf(&d, 0, "%.*k", (int) EG(precision), dbl);
     371              35 :                         smart_str_appendl(buf, d, len);
     372              35 :                         efree(d);
     373                 :                 } else {
     374               4 :                     zend_error(E_WARNING, "[json] (php_json_encode) double %.9g does not conform to the JSON spec, encoded as 0", dbl);
     375               4 :                     smart_str_appendc(buf, '0');
     376                 :                 }
     377                 :             }
     378              39 :             break;
     379                 :         case IS_STRING:
     380             146 :             json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val) TSRMLS_CC);
     381             146 :             break;
     382                 :         case IS_ARRAY:
     383                 :         case IS_OBJECT:
     384             114 :             json_encode_array(buf, &val TSRMLS_CC);
     385             114 :             break;
     386                 :         default:
     387               1 :             zend_error(E_WARNING, "[json] (php_json_encode) type is unsupported, encoded as null");
     388               1 :             smart_str_appendl(buf, "null", 4);
     389                 :             break;
     390                 :     }
     391                 : 
     392                 :     return;
     393                 : }
     394                 : /* }}} */
     395                 : 
     396                 : PHP_JSON_API void php_json_decode(zval *return_value, char *buf, int buf_len, zend_bool assoc TSRMLS_DC) /* {{{ */
     397             129 : {
     398                 :         unsigned short *utf16;
     399                 :         int utf16_len;
     400                 :         zval *z;
     401                 : 
     402             129 :         utf16 = (unsigned short *) safe_emalloc((buf_len+1), sizeof(unsigned short), 1);
     403                 : 
     404             129 :         utf16_len = utf8_to_utf16(utf16, buf, buf_len);
     405             129 :         if (utf16_len <= 0)
     406                 :         {
     407               0 :                 if (utf16)
     408                 :                 {
     409               0 :                         efree(utf16);
     410                 :                 }
     411                 : 
     412               0 :                 RETURN_NULL();
     413                 :         }
     414                 : 
     415             129 :         ALLOC_INIT_ZVAL(z);
     416             129 :         if (JSON_parser(z, utf16, utf16_len, assoc TSRMLS_CC))
     417                 :         {
     418              49 :                 *return_value = *z;
     419                 : 
     420              49 :                 FREE_ZVAL(z);
     421              49 :                 efree(utf16);
     422                 :         }
     423                 :         else
     424                 :         {
     425                 :                 double d;
     426                 :                 int type;
     427                 :                 long p;
     428                 : 
     429              80 :                 zval_dtor(z);
     430              80 :                 FREE_ZVAL(z);
     431              80 :                 efree(utf16);
     432                 : 
     433              80 :                 if (buf_len == 4) {
     434              10 :                         if (!strcasecmp(buf, "null")) {
     435               2 :                                 RETURN_NULL();
     436               8 :                         } else if (!strcasecmp(buf, "true")) {
     437               2 :                                 RETURN_BOOL(1);
     438                 :                         }
     439              70 :                 } else if (buf_len == 5 && !strcasecmp(buf, "false")) {
     440               2 :                         RETURN_BOOL(0);
     441                 :                 }
     442              74 :                 if ((type = is_numeric_string(buf, buf_len, &p, &d, 0)) != 0) {
     443              17 :                         if (type == IS_LONG) {
     444              14 :                                 RETURN_LONG(p);
     445               3 :                         } else if (type == IS_DOUBLE) {
     446               3 :                                 RETURN_DOUBLE(d);
     447                 :                         }
     448                 :                 }
     449              57 :                 RETURN_NULL();
     450                 :         }
     451                 : }
     452                 : /* }}} */
     453                 : 
     454                 : /* {{{ proto string json_encode(mixed data)
     455                 :    Returns the JSON representation of a value */
     456                 : static PHP_FUNCTION(json_encode)
     457              79 : {
     458                 :     zval *parameter;
     459              79 :     smart_str buf = {0};
     460                 : 
     461              79 :     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &parameter) == FAILURE) {
     462               2 :         return;
     463                 :     }
     464                 : 
     465              77 :     php_json_encode(&buf, parameter TSRMLS_CC);
     466                 : 
     467              77 :     ZVAL_STRINGL(return_value, buf.c, buf.len, 1);
     468                 : 
     469              77 :     smart_str_free(&buf);
     470                 : }
     471                 : /* }}} */
     472                 : 
     473                 : /* {{{ proto mixed json_decode(string json [, bool assoc])
     474                 :    Decodes the JSON representation into a PHP value */
     475                 : static PHP_FUNCTION(json_decode)
     476             136 : {
     477                 :     char *parameter;
     478                 :     int parameter_len;
     479             136 :     zend_bool assoc = 0; /* return JS objects as PHP objects by default */
     480                 : 
     481             136 :     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &parameter, &parameter_len, &assoc) == FAILURE) {
     482               3 :         return;
     483                 :     }
     484                 : 
     485             133 :     if (!parameter_len)
     486                 :     {
     487               4 :         RETURN_NULL();
     488                 :     }
     489                 : 
     490             129 :         php_json_decode(return_value, parameter, parameter_len, assoc TSRMLS_CC);
     491                 : }
     492                 : /* }}} */
     493                 : 
     494                 : /*
     495                 :  * Local variables:
     496                 :  * tab-width: 4
     497                 :  * c-basic-offset: 4
     498                 :  * End:
     499                 :  * vim600: noet sw=4 ts=4
     500                 :  * vim<600: noet sw=4 ts=4
     501                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:09 +0000 (5 days ago)

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