1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
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 284625 2009-07-22 21:32:58Z rasmus $ */
20 :
21 : /*
22 : * UTODO
23 : * - take a look at json_decode, some weird IS_STRING checks there
24 : * - expose encode/decode API once that's done
25 : */
26 :
27 : #ifdef HAVE_CONFIG_H
28 : #include "config.h"
29 : #endif
30 :
31 : #include "php.h"
32 : #include "php_ini.h"
33 : #include "ext/standard/info.h"
34 : #include "ext/standard/php_smart_str.h"
35 : #include "utf8_to_utf16.h"
36 : #include "JSON_parser.h"
37 : #include "php_json.h"
38 :
39 : static PHP_MINFO_FUNCTION(json);
40 : static PHP_FUNCTION(json_encode);
41 : static PHP_FUNCTION(json_decode);
42 : static PHP_FUNCTION(json_last_error);
43 :
44 : static const char digits[] = "0123456789abcdef";
45 :
46 : #define PHP_JSON_HEX_TAG (1<<0)
47 : #define PHP_JSON_HEX_AMP (1<<1)
48 : #define PHP_JSON_HEX_APOS (1<<2)
49 : #define PHP_JSON_HEX_QUOT (1<<3)
50 : #define PHP_JSON_FORCE_OBJECT (1<<4)
51 :
52 : #define PHP_JSON_OUTPUT_ARRAY 0
53 : #define PHP_JSON_OUTPUT_OBJECT 1
54 :
55 : ZEND_DECLARE_MODULE_GLOBALS(json)
56 :
57 : /* {{{ arginfo */
58 : ZEND_BEGIN_ARG_INFO_EX(arginfo_json_encode, 0, 0, 1)
59 : ZEND_ARG_INFO(0, value)
60 : ZEND_ARG_INFO(0, options)
61 : ZEND_END_ARG_INFO()
62 :
63 : ZEND_BEGIN_ARG_INFO_EX(arginfo_json_decode, 0, 0, 1)
64 : ZEND_ARG_INFO(0, json)
65 : ZEND_ARG_INFO(0, assoc)
66 : ZEND_ARG_INFO(0, depth)
67 : ZEND_END_ARG_INFO()
68 :
69 : ZEND_BEGIN_ARG_INFO(arginfo_json_last_error, 0)
70 : ZEND_END_ARG_INFO()
71 : /* }}} */
72 :
73 : /* {{{ json_functions[] */
74 : static const function_entry json_functions[] = {
75 : PHP_FE(json_encode, arginfo_json_encode)
76 : PHP_FE(json_decode, arginfo_json_decode)
77 : PHP_FE(json_last_error, arginfo_json_last_error)
78 : {NULL, NULL, NULL}
79 : };
80 : /* }}} */
81 :
82 : /* {{{ MINIT */
83 : static PHP_MINIT_FUNCTION(json)
84 17007 : {
85 17007 : REGISTER_LONG_CONSTANT("JSON_HEX_TAG", PHP_JSON_HEX_TAG, CONST_CS | CONST_PERSISTENT);
86 17007 : REGISTER_LONG_CONSTANT("JSON_HEX_AMP", PHP_JSON_HEX_AMP, CONST_CS | CONST_PERSISTENT);
87 17007 : REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT);
88 17007 : REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT);
89 17007 : REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT);
90 :
91 17007 : REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
92 17007 : REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
93 17007 : REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
94 17007 : REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
95 17007 : REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
96 17007 : REGISTER_LONG_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8, CONST_CS | CONST_PERSISTENT);
97 :
98 17007 : return SUCCESS;
99 : }
100 : /* }}} */
101 :
102 : /* {{{ PHP_GINIT_FUNCTION
103 : */
104 : static PHP_GINIT_FUNCTION(json)
105 17007 : {
106 17007 : json_globals->error_code = 0;
107 17007 : }
108 : /* }}} */
109 :
110 :
111 : /* {{{ json_module_entry
112 : */
113 : zend_module_entry json_module_entry = {
114 : STANDARD_MODULE_HEADER,
115 : "json",
116 : json_functions,
117 : PHP_MINIT(json),
118 : NULL,
119 : NULL,
120 : NULL,
121 : PHP_MINFO(json),
122 : PHP_JSON_VERSION,
123 : PHP_MODULE_GLOBALS(json),
124 : PHP_GINIT(json),
125 : NULL,
126 : NULL,
127 : STANDARD_MODULE_PROPERTIES_EX
128 : };
129 : /* }}} */
130 :
131 : #ifdef COMPILE_DL_JSON
132 : ZEND_GET_MODULE(json)
133 : #endif
134 :
135 : /* {{{ PHP_MINFO_FUNCTION
136 : */
137 : static PHP_MINFO_FUNCTION(json)
138 43 : {
139 43 : php_info_print_table_start();
140 43 : php_info_print_table_row(2, "json support", "enabled");
141 43 : php_info_print_table_row(2, "json version", PHP_JSON_VERSION);
142 43 : php_info_print_table_end();
143 43 : }
144 : /* }}} */
145 :
146 : static void json_encode_r(smart_str *buf, zval *val, int options TSRMLS_DC);
147 : static void json_escape_string(smart_str *buf, zstr s, int len, zend_uchar type, int options TSRMLS_DC);
148 :
149 : static int json_determine_array_type(zval **val TSRMLS_DC) /* {{{ */
150 102 : {
151 : int i;
152 102 : HashTable *myht = HASH_OF(*val);
153 :
154 102 : i = myht ? zend_hash_num_elements(myht) : 0;
155 102 : if (i > 0) {
156 : zstr key;
157 : ulong index, idx;
158 : uint key_len;
159 : HashPosition pos;
160 :
161 87 : zend_hash_internal_pointer_reset_ex(myht, &pos);
162 87 : idx = 0;
163 214 : for (;; zend_hash_move_forward_ex(myht, &pos)) {
164 301 : i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
165 301 : if (i == HASH_KEY_NON_EXISTANT)
166 74 : break;
167 :
168 227 : if (i == HASH_KEY_IS_STRING || i == HASH_KEY_IS_UNICODE) {
169 10 : return 1;
170 : } else {
171 217 : if (index != idx) {
172 3 : return 1;
173 : }
174 : }
175 214 : idx++;
176 214 : }
177 : }
178 :
179 89 : return PHP_JSON_OUTPUT_ARRAY;
180 : }
181 : /* }}} */
182 :
183 : static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */
184 125 : {
185 : int i, r;
186 : HashTable *myht;
187 :
188 125 : if (Z_TYPE_PP(val) == IS_ARRAY) {
189 106 : myht = HASH_OF(*val);
190 106 : r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : json_determine_array_type(val TSRMLS_CC);
191 : } else {
192 19 : myht = Z_OBJPROP_PP(val);
193 19 : r = PHP_JSON_OUTPUT_OBJECT;
194 : }
195 :
196 125 : if (myht && myht->nApplyCount > 1) {
197 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
198 2 : smart_str_appendl(buf, "null", 4);
199 2 : return;
200 : }
201 :
202 123 : if (r == PHP_JSON_OUTPUT_ARRAY) {
203 88 : smart_str_appendc(buf, '[');
204 : } else {
205 35 : smart_str_appendc(buf, '{');
206 : }
207 :
208 123 : i = myht ? zend_hash_num_elements(myht) : 0;
209 :
210 123 : if (i > 0)
211 : {
212 : zstr key;
213 : zval **data;
214 : ulong index;
215 : uint key_len;
216 : HashPosition pos;
217 : HashTable *tmp_ht;
218 103 : int need_comma = 0;
219 :
220 103 : zend_hash_internal_pointer_reset_ex(myht, &pos);
221 396 : for (;; zend_hash_move_forward_ex(myht, &pos)) {
222 499 : i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
223 499 : if (i == HASH_KEY_NON_EXISTANT)
224 103 : break;
225 :
226 396 : if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) {
227 396 : tmp_ht = HASH_OF(*data);
228 396 : if (tmp_ht) {
229 92 : tmp_ht->nApplyCount++;
230 : }
231 :
232 396 : if (r == PHP_JSON_OUTPUT_ARRAY) {
233 212 : if (need_comma) {
234 139 : smart_str_appendc(buf, ',');
235 : } else {
236 73 : need_comma = 1;
237 : }
238 :
239 212 : json_encode_r(buf, *data, options TSRMLS_CC);
240 184 : } else if (r == PHP_JSON_OUTPUT_OBJECT) {
241 353 : if (i == HASH_KEY_IS_STRING || i == HASH_KEY_IS_UNICODE) {
242 170 : if (key.s[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) {
243 : /* Skip protected and private members. */
244 1 : if (tmp_ht) {
245 1 : tmp_ht->nApplyCount--;
246 : }
247 1 : continue;
248 : }
249 :
250 169 : if (need_comma) {
251 146 : smart_str_appendc(buf, ',');
252 : } else {
253 23 : need_comma = 1;
254 : }
255 :
256 169 : json_escape_string(buf, key, key_len - 1, (i == HASH_KEY_IS_UNICODE) ? IS_UNICODE : IS_STRING, options TSRMLS_CC);
257 169 : smart_str_appendc(buf, ':');
258 :
259 169 : json_encode_r(buf, *data, options TSRMLS_CC);
260 : } else {
261 14 : if (need_comma) {
262 8 : smart_str_appendc(buf, ',');
263 : } else {
264 6 : need_comma = 1;
265 : }
266 :
267 14 : smart_str_appendc(buf, '"');
268 14 : smart_str_append_long(buf, (long) index);
269 14 : smart_str_appendc(buf, '"');
270 14 : smart_str_appendc(buf, ':');
271 :
272 14 : json_encode_r(buf, *data, options TSRMLS_CC);
273 : }
274 : }
275 :
276 395 : if (tmp_ht) {
277 91 : tmp_ht->nApplyCount--;
278 : }
279 : }
280 396 : }
281 : }
282 :
283 123 : if (r == PHP_JSON_OUTPUT_ARRAY) {
284 88 : smart_str_appendc(buf, ']');
285 : } else {
286 35 : smart_str_appendc(buf, '}');
287 : }
288 : }
289 : /* }}} */
290 :
291 : #define REVERSE16(us) (((us & 0xf) << 12) | (((us >> 4) & 0xf) << 8) | (((us >> 8) & 0xf) << 4) | ((us >> 12) & 0xf))
292 :
293 : static void json_escape_string(smart_str *buf, zstr s, int len, zend_uchar type, int options TSRMLS_DC) /* {{{ */
294 324 : {
295 324 : int pos = 0;
296 : unsigned short us;
297 : unsigned short *utf16;
298 :
299 324 : if (len == 0) {
300 11 : smart_str_appendl(buf, "\"\"", 2);
301 11 : return;
302 : }
303 :
304 313 : if (type == IS_UNICODE) {
305 306 : utf16 = (unsigned short *) s.u;
306 : } else {
307 7 : utf16 = (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0);
308 :
309 7 : len = utf8_to_utf16(utf16, s.s, len);
310 7 : if (len <= 0) {
311 4 : if (utf16) {
312 4 : efree(utf16);
313 : }
314 4 : if (len < 0) {
315 4 : JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
316 4 : if (!PG(display_errors)) {
317 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid UTF-8 sequence in argument");
318 : }
319 4 : smart_str_appendl(buf, "null", 4);
320 : } else {
321 0 : smart_str_appendl(buf, "\"\"", 2);
322 : }
323 4 : return;
324 : }
325 : }
326 :
327 309 : smart_str_appendc(buf, '"');
328 :
329 3466 : while (pos < len)
330 : {
331 2848 : us = utf16[pos++];
332 :
333 2848 : switch (us)
334 : {
335 : case '"':
336 44 : if (options & PHP_JSON_HEX_QUOT) {
337 4 : smart_str_appendl(buf, "\\u0022", 6);
338 : } else {
339 40 : smart_str_appendl(buf, "\\\"", 2);
340 : }
341 44 : break;
342 :
343 : case '\\':
344 8 : smart_str_appendl(buf, "\\\\", 2);
345 8 : break;
346 :
347 : case '/':
348 48 : smart_str_appendl(buf, "\\/", 2);
349 48 : break;
350 :
351 : case '\b':
352 8 : smart_str_appendl(buf, "\\b", 2);
353 8 : break;
354 :
355 : case '\f':
356 8 : smart_str_appendl(buf, "\\f", 2);
357 8 : break;
358 :
359 : case '\n':
360 9 : smart_str_appendl(buf, "\\n", 2);
361 9 : break;
362 :
363 : case '\r':
364 8 : smart_str_appendl(buf, "\\r", 2);
365 8 : break;
366 :
367 : case '\t':
368 10 : smart_str_appendl(buf, "\\t", 2);
369 10 : break;
370 :
371 : case '<':
372 18 : if (options & PHP_JSON_HEX_TAG) {
373 2 : smart_str_appendl(buf, "\\u003C", 6);
374 : } else {
375 16 : smart_str_appendc(buf, '<');
376 : }
377 18 : break;
378 :
379 : case '>':
380 18 : if (options & PHP_JSON_HEX_TAG) {
381 2 : smart_str_appendl(buf, "\\u003E", 6);
382 : } else {
383 16 : smart_str_appendc(buf, '>');
384 : }
385 18 : break;
386 :
387 : case '&':
388 32 : if (options & PHP_JSON_HEX_AMP) {
389 4 : smart_str_appendl(buf, "\\u0026", 6);
390 : } else {
391 28 : smart_str_appendc(buf, '&');
392 : }
393 32 : break;
394 :
395 : case '\'':
396 20 : if (options & PHP_JSON_HEX_APOS) {
397 4 : smart_str_appendl(buf, "\\u0027", 6);
398 : } else {
399 16 : smart_str_appendc(buf, '\'');
400 : }
401 20 : break;
402 :
403 : default:
404 5122 : if (us >= ' ' && (us & 127) == us) {
405 2505 : smart_str_appendc(buf, (unsigned char) us);
406 : } else {
407 112 : smart_str_appendl(buf, "\\u", 2);
408 112 : us = REVERSE16(us);
409 :
410 112 : smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
411 112 : us >>= 4;
412 112 : smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
413 112 : us >>= 4;
414 112 : smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
415 112 : us >>= 4;
416 112 : smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
417 : }
418 : break;
419 : }
420 : }
421 :
422 309 : smart_str_appendc(buf, '"');
423 :
424 309 : if (type == IS_STRING) {
425 3 : efree(utf16);
426 : }
427 : }
428 : /* }}} */
429 :
430 : static void json_encode_r(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */
431 466 : {
432 466 : switch (Z_TYPE_P(val))
433 : {
434 : case IS_NULL:
435 14 : smart_str_appendl(buf, "null", 4);
436 14 : break;
437 :
438 : case IS_BOOL:
439 22 : if (Z_BVAL_P(val)) {
440 12 : smart_str_appendl(buf, "true", 4);
441 : } else {
442 10 : smart_str_appendl(buf, "false", 5);
443 : }
444 22 : break;
445 :
446 : case IS_LONG:
447 110 : smart_str_append_long(buf, Z_LVAL_P(val));
448 110 : break;
449 :
450 : case IS_DOUBLE:
451 : {
452 39 : char *d = NULL;
453 : int len;
454 39 : double dbl = Z_DVAL_P(val);
455 :
456 74 : if (!zend_isinf(dbl) && !zend_isnan(dbl)) {
457 35 : len = spprintf(&d, 0, "%.*k", (int) EG(precision), dbl);
458 35 : smart_str_appendl(buf, d, len);
459 35 : efree(d);
460 : } else {
461 4 : zend_error(E_WARNING, "[json] (json_encode_r) double %.9g does not conform to the JSON spec, encoded as 0", dbl);
462 4 : smart_str_appendc(buf, '0');
463 : }
464 : }
465 39 : break;
466 :
467 : case IS_STRING:
468 : case IS_UNICODE:
469 155 : json_escape_string(buf, Z_UNIVAL_P(val), Z_UNILEN_P(val), Z_TYPE_P(val), options TSRMLS_CC);
470 155 : break;
471 :
472 : case IS_ARRAY:
473 : case IS_OBJECT:
474 125 : json_encode_array(buf, &val, options TSRMLS_CC);
475 125 : break;
476 :
477 : default:
478 1 : zend_error(E_WARNING, "[json] (json_encode_r) type is unsupported, encoded as null");
479 1 : smart_str_appendl(buf, "null", 4);
480 : break;
481 : }
482 :
483 : return;
484 : }
485 : /* }}} */
486 :
487 : /* {{{ proto string json_encode(mixed data [, long options]) U
488 : Returns the JSON representation of a value */
489 : static PHP_FUNCTION(json_encode)
490 73 : {
491 : zval *parameter;
492 73 : smart_str buf = {0};
493 73 : long options = 0;
494 :
495 73 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", ¶meter, &options) == FAILURE) {
496 2 : return;
497 : }
498 :
499 71 : json_encode_r(&buf, parameter, options TSRMLS_CC);
500 :
501 : /*
502 : * Return as binary string, since the result is 99% likely to be just
503 : * echo'ed out and we want to avoid overhead of double conversion.
504 : */
505 71 : ZVAL_STRINGL(return_value, buf.c, buf.len, 1);
506 :
507 71 : smart_str_free(&buf);
508 : }
509 : /* }}} */
510 :
511 : /* {{{ proto mixed json_decode(string json [, bool assoc [, long depth]]) U
512 : Decodes the JSON representation into a PHP value */
513 : static PHP_FUNCTION(json_decode)
514 142 : {
515 : zstr str;
516 : int str_len, utf16_len;
517 : zend_uchar str_type;
518 142 : zend_bool assoc = 0; /* return JS objects as PHP objects by default */
519 142 : long depth = JSON_PARSER_DEFAULT_DEPTH;
520 : zval *z;
521 : unsigned short *utf16;
522 : JSON_parser jp;
523 :
524 142 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t|bl", &str, &str_len, &str_type, &assoc, &depth) == FAILURE) {
525 3 : return;
526 : }
527 :
528 139 : if (!str_len) {
529 4 : RETURN_NULL();
530 : }
531 :
532 135 : if (str_type == IS_UNICODE) {
533 123 : utf16 = str.u;
534 123 : utf16_len = str_len;
535 : } else {
536 12 : utf16 = (unsigned short *) safe_emalloc((str_len+1), sizeof(unsigned short), 0);
537 :
538 12 : utf16_len = utf8_to_utf16(utf16, str.s, str_len);
539 12 : if (utf16_len <= 0) {
540 0 : if (utf16) {
541 0 : efree(utf16);
542 : }
543 0 : JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
544 0 : RETURN_NULL();
545 : }
546 : }
547 :
548 135 : if (depth <= 0) {
549 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Depth must greater than zero");
550 0 : efree(utf16);
551 0 : RETURN_NULL();
552 : }
553 :
554 135 : ALLOC_INIT_ZVAL(z);
555 135 : jp = new_JSON_parser(depth);
556 135 : if (parse_JSON(jp, z, utf16, utf16_len, assoc TSRMLS_CC)) {
557 51 : *return_value = *z;
558 : }
559 84 : else if (str_type == IS_STRING)
560 : {
561 : double d;
562 : int type;
563 : long p;
564 :
565 1 : zval_dtor(z);
566 1 : RETVAL_NULL();
567 :
568 1 : if (str_len == 4) {
569 0 : if (!strcasecmp(str.s, "null")) {
570 : /* We need to explicitly clear the error because its an actual NULL and not an error */
571 0 : jp->error_code = PHP_JSON_ERROR_NONE;
572 0 : RETVAL_NULL();
573 0 : } else if (!strcasecmp(str.s, "true")) {
574 0 : RETVAL_BOOL(1);
575 : }
576 1 : } else if (str_len == 5 && !strcasecmp(str.s, "false")) {
577 0 : RETVAL_BOOL(0);
578 : }
579 :
580 1 : if ((type = is_numeric_string(str.s, str_len, &p, &d, 0)) != 0) {
581 1 : if (type == IS_LONG) {
582 0 : RETVAL_LONG(p);
583 1 : } else if (type == IS_DOUBLE) {
584 1 : RETVAL_DOUBLE(d);
585 : }
586 : }
587 :
588 1 : if (Z_TYPE_P(return_value) != IS_NULL) {
589 1 : jp->error_code = PHP_JSON_ERROR_NONE;
590 : }
591 : }
592 : else
593 : {
594 : double d;
595 : int type;
596 : long p;
597 :
598 83 : zval_dtor(z);
599 83 : RETVAL_NULL();
600 :
601 83 : if (str_len == 4) {
602 10 : if (ZEND_U_CASE_EQUAL(IS_UNICODE, str, str_len, "null", sizeof("null")-1)) {
603 : /* We need to explicitly clear the error because its an actual NULL and not an error */
604 2 : jp->error_code = PHP_JSON_ERROR_NONE;
605 2 : RETVAL_NULL();
606 8 : } else if (ZEND_U_CASE_EQUAL(IS_UNICODE, str, str_len, "true", sizeof("true")-1)) {
607 2 : RETVAL_BOOL(1);
608 : }
609 73 : } else if (str_len == 5 && ZEND_U_CASE_EQUAL(IS_UNICODE, str, str_len, "false", sizeof("false")-1)) {
610 2 : RETVAL_BOOL(0);
611 : }
612 :
613 83 : if ((type = is_numeric_unicode(str.u, str_len, &p, &d, 0)) != 0) {
614 16 : if (type == IS_LONG) {
615 14 : RETVAL_LONG(p);
616 2 : } else if (type == IS_DOUBLE) {
617 2 : RETVAL_DOUBLE(d);
618 : }
619 : }
620 :
621 83 : if (Z_TYPE_P(return_value) != IS_NULL) {
622 20 : jp->error_code = PHP_JSON_ERROR_NONE;
623 : }
624 : }
625 :
626 135 : FREE_ZVAL(z);
627 135 : if (str_type == IS_STRING) {
628 12 : efree(utf16);
629 : }
630 135 : JSON_G(error_code) = jp->error_code;
631 135 : free_JSON_parser(jp);
632 : }
633 : /* }}} */
634 :
635 : /* {{{ proto int json_last_error() U
636 : Returns the error code of the last json_decode(). */
637 : static PHP_FUNCTION(json_last_error)
638 5 : {
639 5 : if (zend_parse_parameters_none() == FAILURE) {
640 0 : return;
641 : }
642 :
643 5 : RETURN_LONG(JSON_G(error_code));
644 : }
645 : /* }}} */
646 :
647 : /*
648 : * Local variables:
649 : * tab-width: 4
650 : * c-basic-offset: 4
651 : * End:
652 : * vim600: noet sw=4 ts=4
653 : * vim<600: noet sw=4 ts=4
654 : */
|