php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
converter.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | This source file is subject to version 3.01 of the PHP license, |
4 | that is bundled with this package in the file LICENSE, and is |
5 | available through the world-wide-web at the following url: |
6 | https://www.php.net/license/3_01.txt |
7 | If you did not receive a copy of the PHP license and are unable to |
8 | obtain it through the world-wide-web, please send a note to |
9 | license@php.net so we can mail you a copy immediately. |
10 +----------------------------------------------------------------------+
11 | Authors: Sara Golemon <pollita@php.net> |
12 +----------------------------------------------------------------------+
13 */
14
15#include "converter.h"
16#include "zend_exceptions.h"
17
18#include <unicode/utypes.h>
19#include <unicode/utf8.h>
20#include <unicode/utf16.h>
21#include <unicode/ucnv.h>
22#include <unicode/ustring.h>
23
24#include "../intl_error.h"
25#include "../intl_common.h"
26#include "converter_arginfo.h"
27
35
36
37static inline php_converter_object *php_converter_fetch_object(zend_object *obj) {
38 return (php_converter_object *)((char*)(obj) - XtOffsetOf(php_converter_object, obj));
39}
40#define Z_INTL_CONVERTER_P(zv) php_converter_fetch_object(Z_OBJ_P(zv))
41
42static zend_class_entry *php_converter_ce;
43static zend_object_handlers php_converter_object_handlers;
44
45#define CONV_GET(pzv) (Z_INTL_CONVERTER_P((pzv)))
46#define THROW_UFAILURE(obj, fname, error) php_converter_throw_failure(obj, error, \
47 fname "() returned error " ZEND_LONG_FMT ": %s", (zend_long)error, u_errorName(error))
48
49/* {{{ php_converter_throw_failure */
50static inline void php_converter_throw_failure(php_converter_object *objval, UErrorCode error, const char *format, ...) {
51 intl_error *err = objval ? &(objval->error) : NULL;
52 char message[1024];
53 va_list vargs;
54
55 va_start(vargs, format);
56 vsnprintf(message, sizeof(message), format, vargs);
57 va_end(vargs);
58
59 intl_errors_set(err, error, message, 1);
60}
61/* }}} */
62
63/* {{{ php_converter_default_callback */
64static void php_converter_default_callback(zval *return_value, zval *zobj, zend_long reason, zval *error) {
65 /* Basic functionality so children can call parent::toUCallback() */
66 switch (reason) {
67 case UCNV_UNASSIGNED:
68 case UCNV_ILLEGAL:
69 case UCNV_IRREGULAR:
70 {
72 char chars[127];
73 int8_t chars_len = sizeof(chars);
74 UErrorCode uerror = U_ZERO_ERROR;
75 if(!objval->src) {
76 php_converter_throw_failure(objval, U_INVALID_STATE_ERROR, "Source Converter has not been initialized yet");
77 chars[0] = 0x1A;
78 chars[1] = 0;
79 chars_len = 1;
81 RETVAL_STRINGL(chars, chars_len);
82 return;
83 }
84
85 /* Yes, this is fairly wasteful at first glance,
86 * but considering that the alternative is to store
87 * what's sent into setSubstChars() and the fact
88 * that this is an extremely unlikely codepath
89 * I'd rather take the CPU hit here, than waste time
90 * storing a value I'm unlikely to use.
91 */
92 ucnv_getSubstChars(objval->src, chars, &chars_len, &uerror);
93 if (U_FAILURE(uerror)) {
94 THROW_UFAILURE(objval, "ucnv_getSubstChars", uerror);
95 chars[0] = 0x1A;
96 chars[1] = 0;
97 chars_len = 1;
98 }
100 RETVAL_STRINGL(chars, chars_len);
101 }
102 }
103}
104/* }}} */
105
106/* {{{ */
107PHP_METHOD(UConverter, toUCallback) {
108 zend_long reason;
109 zend_string *source, *codeUnits;
110 zval *error;
111
113 Z_PARAM_LONG(reason)
114 Z_PARAM_STR(source)
115 Z_PARAM_STR(codeUnits)
118
119 php_converter_default_callback(return_value, ZEND_THIS, reason, error);
120}
121/* }}} */
122
123/* {{{ */
124PHP_METHOD(UConverter, fromUCallback) {
125 zend_long reason;
126 zval *source, *error;
127 zend_long codePoint;
128
130 Z_PARAM_LONG(reason)
131 Z_PARAM_ARRAY(source)
132 Z_PARAM_LONG(codePoint)
135
136 php_converter_default_callback(return_value, ZEND_THIS, reason, error);
137}
138/* }}} */
139
140/* {{{ php_converter_check_limits */
141static inline bool php_converter_check_limits(php_converter_object *objval, zend_long available, zend_long needed) {
142 if (available < needed) {
143 php_converter_throw_failure(objval, U_BUFFER_OVERFLOW_ERROR, "Buffer overrun " ZEND_LONG_FMT " bytes needed, " ZEND_LONG_FMT " available", needed, available);
144 return 0;
145 }
146 return 1;
147}
148/* }}} */
149
150#define TARGET_CHECK(cnvargs, needed) php_converter_check_limits(objval, cnvargs->targetLimit - cnvargs->target, needed)
151
152/* {{{ php_converter_append_toUnicode_target */
153static void php_converter_append_toUnicode_target(zval *val, UConverterToUnicodeArgs *args, php_converter_object *objval) {
154 switch (Z_TYPE_P(val)) {
155 case IS_NULL:
156 /* Code unit is being skipped */
157 return;
158 case IS_LONG:
159 {
160 zend_long lval = Z_LVAL_P(val);
161 if ((lval < 0) || (lval > 0x10FFFF)) {
162 php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR, "Invalid codepoint U+%04lx", lval);
163 return;
164 }
165 if (lval > 0xFFFF) {
166 /* Supplemental planes U+010000 - U+10FFFF */
167 if (TARGET_CHECK(args, 2)) {
168 /* TODO: Find the ICU call which does this properly */
169 *(args->target++) = (UChar)(((lval - 0x10000) >> 10) | 0xD800);
170 *(args->target++) = (UChar)(((lval - 0x10000) & 0x3FF) | 0xDC00);
171 }
172 return;
173 }
174 /* Non-suggogate BMP codepoint */
175 if (TARGET_CHECK(args, 1)) {
176 *(args->target++) = (UChar)lval;
177 }
178 return;
179 }
180 case IS_STRING:
181 {
182 const char *strval = Z_STRVAL_P(val);
183 int i = 0, strlen = Z_STRLEN_P(val);
184
185 while((i != strlen) && TARGET_CHECK(args, 1)) {
186 UChar c;
187 U8_NEXT(strval, i, strlen, c);
188 *(args->target++) = c;
189 }
190 return;
191 }
192 case IS_ARRAY:
193 {
195 zval *tmpzval;
196
197 ZEND_HASH_FOREACH_VAL(ht, tmpzval) {
198 php_converter_append_toUnicode_target(tmpzval, args, objval);
200 return;
201 }
202 default:
203 php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR,
204 "toUCallback() specified illegal type for substitution character");
205 }
206}
207/* }}} */
208
209/* {{{ php_converter_to_u_callback */
210static void php_converter_to_u_callback(const void *context,
211 UConverterToUnicodeArgs *args,
212 const char *codeUnits, int32_t length,
213 UConverterCallbackReason reason,
214 UErrorCode *pErrorCode) {
216 zval retval;
217 zval zargs[4];
218
219 ZVAL_LONG(&zargs[0], reason);
220 if (args->source) {
221 ZVAL_STRINGL(&zargs[1], args->source, args->sourceLimit - args->source);
222 } else {
223 ZVAL_EMPTY_STRING(&zargs[1]);
224 }
225 if (codeUnits) {
226 ZVAL_STRINGL(&zargs[2], codeUnits, length);
227 } else {
228 ZVAL_EMPTY_STRING(&zargs[2]);
229 }
230 ZVAL_LONG(&zargs[3], *pErrorCode);
231 ZVAL_MAKE_REF(&zargs[3]);
232
233 objval->to_cb.param_count = 4;
234 objval->to_cb.params = zargs;
235 objval->to_cb.retval = &retval;
236 if (zend_call_function(&(objval->to_cb), &(objval->to_cache)) == FAILURE) {
237 /* Unlikely */
238 php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR, "Unexpected failure calling toUCallback()");
239 } else if (!Z_ISUNDEF(retval)) {
240 php_converter_append_toUnicode_target(&retval, args, objval);
242 }
243
244 if (Z_TYPE(zargs[3]) == IS_LONG) {
245 *pErrorCode = Z_LVAL(zargs[3]);
246 } else if (Z_ISREF(zargs[3]) && Z_TYPE_P(Z_REFVAL(zargs[3])) == IS_LONG) {
247 *pErrorCode = Z_LVAL_P(Z_REFVAL(zargs[3]));
248 }
249
250 zval_ptr_dtor(&zargs[0]);
251 zval_ptr_dtor(&zargs[1]);
252 zval_ptr_dtor(&zargs[2]);
253 zval_ptr_dtor(&zargs[3]);
254}
255/* }}} */
256
257/* {{{ php_converter_append_fromUnicode_target */
258static void php_converter_append_fromUnicode_target(zval *val, UConverterFromUnicodeArgs *args, php_converter_object *objval) {
259 switch (Z_TYPE_P(val)) {
260 case IS_NULL:
261 /* Ignore */
262 return;
263 case IS_LONG:
264 if (TARGET_CHECK(args, 1)) {
265 *(args->target++) = Z_LVAL_P(val);
266 }
267 return;
268 case IS_STRING:
269 {
270 size_t vallen = Z_STRLEN_P(val);
271 if (TARGET_CHECK(args, vallen)) {
272 args->target = zend_mempcpy(args->target, Z_STRVAL_P(val), vallen);
273 }
274 return;
275 }
276 case IS_ARRAY:
277 {
279 zval *tmpzval;
280 ZEND_HASH_FOREACH_VAL(ht, tmpzval) {
281 php_converter_append_fromUnicode_target(tmpzval, args, objval);
283 return;
284 }
285 default:
286 php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR, "fromUCallback() specified illegal type for substitution character");
287 }
288}
289/* }}} */
290
291/* {{{ php_converter_from_u_callback */
292static void php_converter_from_u_callback(const void *context,
293 UConverterFromUnicodeArgs *args,
294 const UChar *codeUnits, int32_t length, UChar32 codePoint,
295 UConverterCallbackReason reason,
296 UErrorCode *pErrorCode) {
298 zval retval;
299 zval zargs[4];
300 int i;
301
302 ZVAL_LONG(&zargs[0], reason);
303 array_init(&zargs[1]);
304 i = 0;
305 while (i < length) {
306 UChar32 c;
307 U16_NEXT(codeUnits, i, length, c);
308 add_next_index_long(&zargs[1], c);
309 }
310 ZVAL_LONG(&zargs[2], codePoint);
311 ZVAL_LONG(&zargs[3], *pErrorCode);
312 ZVAL_MAKE_REF(&zargs[3]);
313
314 objval->from_cb.param_count = 4;
315 objval->from_cb.params = zargs;
316 objval->from_cb.retval = &retval;
317 if (zend_call_function(&(objval->from_cb), &(objval->from_cache)) == FAILURE) {
318 /* Unlikely */
319 php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR, "Unexpected failure calling fromUCallback()");
320 } else if (!Z_ISUNDEF(retval)) {
321 php_converter_append_fromUnicode_target(&retval, args, objval);
323 }
324
325 if (Z_TYPE(zargs[3]) == IS_LONG) {
326 *pErrorCode = Z_LVAL(zargs[3]);
327 } else if (Z_ISREF(zargs[3]) && Z_TYPE_P(Z_REFVAL(zargs[3])) == IS_LONG) {
328 *pErrorCode = Z_LVAL_P(Z_REFVAL(zargs[3]));
329 }
330
331 zval_ptr_dtor(&zargs[0]);
332 zval_ptr_dtor(&zargs[1]);
333 zval_ptr_dtor(&zargs[2]);
334 zval_ptr_dtor(&zargs[3]);
335}
336/* }}} */
337
338/* {{{ php_converter_set_callbacks */
339static inline bool php_converter_set_callbacks(php_converter_object *objval, UConverter *cnv) {
340 bool ret = true;
341 UErrorCode error = U_ZERO_ERROR;
342
343 if (objval->obj.ce == php_converter_ce) {
344 /* Short-circuit having to go through method calls and data marshalling
345 * when we're using default behavior
346 */
347 return 1;
348 }
349
350 ucnv_setToUCallBack(cnv, (UConverterToUCallback)php_converter_to_u_callback, (const void*)objval,
351 NULL, NULL, &error);
352 if (U_FAILURE(error)) {
353 THROW_UFAILURE(objval, "ucnv_setToUCallBack", error);
354 ret = 0;
355 }
356
358 ucnv_setFromUCallBack(cnv, (UConverterFromUCallback)php_converter_from_u_callback, (const void*)objval,
359 NULL, NULL, &error);
360 if (U_FAILURE(error)) {
361 THROW_UFAILURE(objval, "ucnv_setFromUCallBack", error);
362 ret = 0;
363 }
364 return ret;
365}
366/* }}} */
367
368/* {{{ php_converter_set_encoding */
369static bool php_converter_set_encoding(php_converter_object *objval,
370 UConverter **pcnv,
371 const char *enc, size_t enc_len) {
372 UErrorCode error = U_ZERO_ERROR;
373 UConverter *cnv = ucnv_open(enc, &error);
374
376 UErrorCode getname_error = U_ZERO_ERROR;
377 const char *actual_encoding = ucnv_getName(cnv, &getname_error);
378 if (U_FAILURE(getname_error)) {
379 /* Should never happen */
380 actual_encoding = "(unknown)";
381 }
382 php_error_docref(NULL, E_WARNING, "Ambiguous encoding specified, using %s", actual_encoding);
383 } else if (U_FAILURE(error)) {
384 if (objval) {
385 THROW_UFAILURE(objval, "ucnv_open", error);
386 } else {
387 char *msg;
388 spprintf(&msg, 0, "Error setting encoding: %d - %s", (int)error, u_errorName(error));
390 efree(msg);
391 }
392 return false;
393 }
394
395 if (objval && !php_converter_set_callbacks(objval, cnv)) {
396 return false;
397 }
398
399 if (*pcnv) {
400 ucnv_close(*pcnv);
401 }
402 *pcnv = cnv;
403 return true;
404}
405/* }}} */
406
407/* {{{ php_converter_do_set_encoding */
408static void php_converter_do_set_encoding(UConverter **pcnv, INTERNAL_FUNCTION_PARAMETERS) {
410 char *enc;
411 size_t enc_len;
412
414 Z_PARAM_STRING(enc, enc_len)
416
417 intl_errors_reset(&objval->error);
418
419 RETURN_BOOL(php_converter_set_encoding(objval, pcnv, enc, enc_len));
420}
421/* }}} */
422
423/* {{{ */
424PHP_METHOD(UConverter, setSourceEncoding) {
426 php_converter_do_set_encoding(&(objval->src), INTERNAL_FUNCTION_PARAM_PASSTHRU);
427}
428/* }}} */
429
430/* {{{ */
431PHP_METHOD(UConverter, setDestinationEncoding) {
433 php_converter_do_set_encoding(&(objval->dest), INTERNAL_FUNCTION_PARAM_PASSTHRU);
434}
435/* }}} */
436
437/* {{{ php_converter_do_get_encoding */
438static void php_converter_do_get_encoding(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
439 const char *name;
440
442
443 intl_errors_reset(&objval->error);
444
445 if (!cnv) {
446 RETURN_NULL();
447 }
448
449 name = ucnv_getName(cnv, &objval->error.code);
450 if (U_FAILURE(objval->error.code)) {
451 THROW_UFAILURE(objval, "ucnv_getName()", objval->error.code);
453 }
454
456}
457/* }}} */
458
459/* {{{ */
460PHP_METHOD(UConverter, getSourceEncoding) {
462 php_converter_do_get_encoding(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
463}
464/* }}} */
465
466/* {{{ */
467PHP_METHOD(UConverter, getDestinationEncoding) {
469 php_converter_do_get_encoding(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
470}
471/* }}} */
472
473/* {{{ php_converter_do_get_type */
474static void php_converter_do_get_type(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
475 UConverterType t;
476
478 intl_errors_reset(&objval->error);
479
480 if (!cnv) {
481 RETURN_NULL();
482 }
483
484 t = ucnv_getType(cnv);
485 if (U_FAILURE(objval->error.code)) {
486 THROW_UFAILURE(objval, "ucnv_getType", objval->error.code);
488 }
489
490 RETURN_LONG(t);
491}
492/* }}} */
493
494/* {{{ */
495PHP_METHOD(UConverter, getSourceType) {
497 php_converter_do_get_type(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
498}
499/* }}} */
500
501/* {{{ */
502PHP_METHOD(UConverter, getDestinationType) {
504 php_converter_do_get_type(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
505}
506/* }}} */
507
508/* {{{ php_converter_resolve_callback */
509static void php_converter_resolve_callback(zval *zobj,
510 php_converter_object *objval,
511 const char *callback_name,
513 zend_fcall_info_cache *fcache) {
514 char *errstr = NULL;
515 zval caller;
516
517 array_init(&caller);
519 add_index_zval(&caller, 0, zobj);
520 add_index_string(&caller, 1, callback_name);
521 if (zend_fcall_info_init(&caller, 0, finfo, fcache, NULL, &errstr) == FAILURE) {
522 php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR, "Error setting converter callback: %s", errstr);
523 }
524 zend_array_destroy(Z_ARR(caller));
525 ZVAL_UNDEF(&finfo->function_name);
526 if (errstr) {
527 efree(errstr);
528 }
529}
530/* }}} */
531
532/* {{{ */
533PHP_METHOD(UConverter, __construct) {
535 char *src = "utf-8";
536 size_t src_len = sizeof("utf-8") - 1;
537 char *dest = src;
538 size_t dest_len = src_len;
539
541
544 Z_PARAM_STRING_OR_NULL(dest, dest_len)
545 Z_PARAM_STRING_OR_NULL(src, src_len)
547
548 php_converter_set_encoding(objval, &(objval->src), src, src_len );
549 php_converter_set_encoding(objval, &(objval->dest), dest, dest_len);
550 php_converter_resolve_callback(ZEND_THIS, objval, "toUCallback", &(objval->to_cb), &(objval->to_cache));
551 php_converter_resolve_callback(ZEND_THIS, objval, "fromUCallback", &(objval->from_cb), &(objval->from_cache));
552}
553/* }}} */
554
555/* {{{ */
556PHP_METHOD(UConverter, setSubstChars) {
558 char *chars;
559 size_t chars_len;
560 int ret = 1;
561
563 Z_PARAM_STRING(chars, chars_len)
565
566 intl_errors_reset(&objval->error);
567
568 if (objval->src) {
569 UErrorCode error = U_ZERO_ERROR;
570 ucnv_setSubstChars(objval->src, chars, chars_len, &error);
571 if (U_FAILURE(error)) {
572 THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
573 ret = 0;
574 }
575 } else {
576 php_converter_throw_failure(objval, U_INVALID_STATE_ERROR, "Source Converter has not been initialized yet");
577 ret = 0;
578 }
579
580 if (objval->dest) {
581 UErrorCode error = U_ZERO_ERROR;
582 ucnv_setSubstChars(objval->dest, chars, chars_len, &error);
583 if (U_FAILURE(error)) {
584 THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
585 ret = 0;
586 }
587 } else {
588 php_converter_throw_failure(objval, U_INVALID_STATE_ERROR, "Destination Converter has not been initialized yet");
589 ret = 0;
590 }
591
593}
594/* }}} */
595
596/* {{{ */
597PHP_METHOD(UConverter, getSubstChars) {
599 char chars[127];
600 int8_t chars_len = sizeof(chars);
601 UErrorCode error = U_ZERO_ERROR;
602
604 intl_errors_reset(&objval->error);
605
606 if (!objval->src) {
607 RETURN_NULL();
608 }
609
610 /* src and dest get the same subst chars set,
611 * so it doesn't really matter which one we read from
612 */
613 ucnv_getSubstChars(objval->src, chars, &chars_len, &error);
614 if (U_FAILURE(error)) {
615 THROW_UFAILURE(objval, "ucnv_getSubstChars", error);
617 }
618
619 RETURN_STRINGL(chars, chars_len);
620}
621/* }}} */
622
623/* {{{ php_converter_do_convert */
624static zend_string* php_converter_do_convert(UConverter *dest_cnv,
625 UConverter *src_cnv, const char *src, int32_t src_len,
627 ) {
628 UErrorCode error = U_ZERO_ERROR;
629 int32_t temp_len, ret_len;
631 UChar *temp;
632
633 if (!src_cnv || !dest_cnv) {
634 php_converter_throw_failure(objval, U_INVALID_STATE_ERROR,
635 "Internal converters not initialized");
636 return NULL;
637 }
638
639 /* Get necessary buffer size first */
640 temp_len = 1 + ucnv_toUChars(src_cnv, NULL, 0, src, src_len, &error);
641 if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
642 THROW_UFAILURE(objval, "ucnv_toUChars", error);
643 return NULL;
644 }
645 temp = safe_emalloc(sizeof(UChar), temp_len, sizeof(UChar));
646
647 /* Convert to intermediate UChar* array */
649 temp_len = ucnv_toUChars(src_cnv, temp, temp_len, src, src_len, &error);
650 if (U_FAILURE(error)) {
651 THROW_UFAILURE(objval, "ucnv_toUChars", error);
652 efree(temp);
653 return NULL;
654 }
655 temp[temp_len] = 0;
656
657 /* Get necessary output buffer size */
658 ret_len = ucnv_fromUChars(dest_cnv, NULL, 0, temp, temp_len, &error);
659 if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
660 THROW_UFAILURE(objval, "ucnv_fromUChars", error);
661 efree(temp);
662 return NULL;
663 }
664
665 ret = zend_string_alloc(ret_len, 0);
666
667 /* Convert to final encoding */
669 ZSTR_LEN(ret) = ucnv_fromUChars(dest_cnv, ZSTR_VAL(ret), ret_len+1, temp, temp_len, &error);
670 efree(temp);
671 if (U_FAILURE(error)) {
672 THROW_UFAILURE(objval, "ucnv_fromUChars", error);
673 zend_string_efree(ret);
674 return NULL;
675 }
676
677 return ret;
678}
679/* }}} */
680
681/* {{{ */
682#define UCNV_REASON_CASE(v) case (UCNV_ ## v) : RETURN_STRINGL( "REASON_" #v , sizeof( "REASON_" #v ) - 1);
683PHP_METHOD(UConverter, reasonText) {
684 zend_long reason;
685
687 Z_PARAM_LONG(reason)
690
691 switch (reason) {
692 UCNV_REASON_CASE(UNASSIGNED)
694 UCNV_REASON_CASE(IRREGULAR)
695 UCNV_REASON_CASE(RESET)
697 UCNV_REASON_CASE(CLONE)
698 default:
699 zend_argument_value_error(1, "must be a UConverter::REASON_* constant");
701 }
702}
703/* }}} */
704
705/* {{{ */
708 char *str;
709 size_t str_len;
711 bool reverse = false;
712
714 Z_PARAM_STRING(str, str_len)
716 Z_PARAM_BOOL(reverse)
718 intl_errors_reset(&objval->error);
719
720 ret = php_converter_do_convert(reverse ? objval->src : objval->dest,
721 reverse ? objval->dest : objval->src,
722 str, str_len,
723 objval);
724 if (ret) {
726 } else {
728 }
729}
730/* }}} */
731
732/* {{{ */
734 char *str, *src, *dest;
735 size_t str_len, src_len, dest_len;
736 zval *options = NULL;
737 UConverter *src_cnv = NULL, *dest_cnv = NULL;
738
740 Z_PARAM_STRING(str, str_len)
741 Z_PARAM_STRING(dest, dest_len)
742 Z_PARAM_STRING(src, src_len)
747
748 if (php_converter_set_encoding(NULL, &src_cnv, src, src_len) &&
749 php_converter_set_encoding(NULL, &dest_cnv, dest, dest_len)) {
751 UErrorCode error = U_ZERO_ERROR;
752
753 if (options && zend_hash_num_elements(Z_ARRVAL_P(options))) {
754 zval *tmpzval;
755
756 if (U_SUCCESS(error) &&
757 (tmpzval = zend_hash_str_find_deref(Z_ARRVAL_P(options), "from_subst", sizeof("from_subst") - 1)) != NULL &&
758 Z_TYPE_P(tmpzval) == IS_STRING) {
760 ucnv_setSubstChars(src_cnv, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval) & 0x7F, &error);
761 }
762 if (U_SUCCESS(error) &&
763 (tmpzval = zend_hash_str_find_deref(Z_ARRVAL_P(options), "to_subst", sizeof("to_subst") - 1)) != NULL &&
764 Z_TYPE_P(tmpzval) == IS_STRING) {
766 ucnv_setSubstChars(dest_cnv, Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval) & 0x7F, &error);
767 }
768 }
769
770 if (U_SUCCESS(error) &&
771 (ret = php_converter_do_convert(dest_cnv, src_cnv, str, str_len, NULL)) != NULL) {
773 }
774
775 if (U_FAILURE(error)) {
776 THROW_UFAILURE(NULL, "transcode", error);
778 }
779 } else {
781 }
782
783 if (src_cnv) {
784 ucnv_close(src_cnv);
785 }
786 if (dest_cnv) {
787 ucnv_close(dest_cnv);
788 }
789}
790/* }}} */
791
792/* {{{ */
800/* }}} */
801
802/* {{{ */
803PHP_METHOD(UConverter, getErrorMessage) {
805
807
808 zend_string *message = intl_error_get_message(&(objval->error));
809 if (message) {
810 RETURN_STR(message);
811 } else {
812 RETURN_NULL();
813 }
814}
815/* }}} */
816
817/* {{{ */
818PHP_METHOD(UConverter, getAvailable) {
819 int32_t i,
820 count = ucnv_countAvailable();
821
823
825
827 for(i = 0; i < count; i++) {
828 const char *name = ucnv_getAvailableName(i);
830 }
831}
832/* }}} */
833
834/* {{{ */
835PHP_METHOD(UConverter, getAliases) {
836 char *name;
837 size_t name_len;
838 UErrorCode error = U_ZERO_ERROR;
839 uint16_t i, count;
840
842 Z_PARAM_STRING(name, name_len)
845
846 count = ucnv_countAliases(name, &error);
847 if (U_FAILURE(error)) {
848 THROW_UFAILURE(NULL, "ucnv_countAliases", error);
850 }
851
853 for(i = 0; i < count; i++) {
854 const char *alias;
855
857 alias = ucnv_getAlias(name, i, &error);
858 if (U_FAILURE(error)) {
859 THROW_UFAILURE(NULL, "ucnv_getAlias", error);
861 RETURN_NULL();
862 }
864 }
865}
866/* }}} */
867
868/* {{{ */
869PHP_METHOD(UConverter, getStandards) {
870 uint16_t i, count;
871
874
876 count = ucnv_countStandards();
877 for(i = 0; i < count; i++) {
878 UErrorCode error = U_ZERO_ERROR;
879 const char *name = ucnv_getStandard(i, &error);
880 if (U_FAILURE(error)) {
881 THROW_UFAILURE(NULL, "ucnv_getStandard", error);
883 RETURN_NULL();
884 }
886 }
887}
888/* }}} */
889
890/* {{{ Converter create/clone/destroy */
891static void php_converter_free_object(zend_object *obj) {
892 php_converter_object *objval = php_converter_fetch_object(obj);
893
894 if (objval->src) {
895 ucnv_close(objval->src);
896 }
897
898 if (objval->dest) {
899 ucnv_close(objval->dest);
900 }
901
902 intl_error_reset(&objval->error);
904}
905
906static zend_object *php_converter_object_ctor(zend_class_entry *ce, php_converter_object **pobjval) {
907 php_converter_object *objval;
908
909 objval = zend_object_alloc(sizeof(php_converter_object), ce);
910
911 zend_object_std_init(&objval->obj, ce);
912 object_properties_init(&objval->obj, ce);
913 intl_error_init(&(objval->error));
914
915 *pobjval = objval;
916
917 return &objval->obj;
918}
919
920static zend_object *php_converter_create_object(zend_class_entry *ce) {
921 php_converter_object *objval = NULL;
922 zend_object *retval = php_converter_object_ctor(ce, &objval);
923
924 object_properties_init(&(objval->obj), ce);
925
926 return retval;
927}
928
929static zend_object *php_converter_clone_object(zend_object *object) {
930 php_converter_object *objval, *oldobj = php_converter_fetch_object(object);
931 zend_object *retval = php_converter_object_ctor(object->ce, &objval);
932 UErrorCode error = U_ZERO_ERROR;
933
934#if U_ICU_VERSION_MAJOR_NUM > 70
935 objval->src = ucnv_clone(oldobj->src, &error);
936#else
937 objval->src = ucnv_safeClone(oldobj->src, NULL, NULL, &error);
938#endif
939 if (U_SUCCESS(error)) {
941#if U_ICU_VERSION_MAJOR_NUM > 70
942 objval->dest = ucnv_clone(oldobj->dest, &error);
943#else
944 objval->dest = ucnv_safeClone(oldobj->dest, NULL, NULL, &error);
945#endif
946 }
947
948 if (U_FAILURE(error)) {
949 zend_throw_error(NULL, "Failed to clone UConverter");
950 return retval;
951 }
952
953 /* Update contexts for converter error handlers */
954 php_converter_set_callbacks(objval, objval->src );
955 php_converter_set_callbacks(objval, objval->dest);
956
957 zend_objects_clone_members(&(objval->obj), &(oldobj->obj));
958
959 /* Newly cloned object deliberately does not inherit error state from original object */
960
961 return retval;
962}
963/* }}} */
964
965/* {{{ php_converter_minit */
967 php_converter_ce = register_class_UConverter();
968 php_converter_ce->create_object = php_converter_create_object;
969 php_converter_ce->default_object_handlers = &php_converter_object_handlers;
970 memcpy(&php_converter_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
971 php_converter_object_handlers.offset = XtOffsetOf(php_converter_object, obj);
972 php_converter_object_handlers.clone_obj = php_converter_clone_object;
973 php_converter_object_handlers.free_obj = php_converter_free_object;
974
975 return SUCCESS;
976}
977/* }}} */
strval(mixed $value)
count(Countable|array $value, int $mode=COUNT_NORMAL)
const U_BUFFER_OVERFLOW_ERROR
const U_AMBIGUOUS_ALIAS_WARNING
const U_INTERNAL_PROGRAM_ERROR
const U_INVALID_STATE_ERROR
const U_ILLEGAL_ARGUMENT_ERROR
const U_ZERO_ERROR
struct _php_converter_object php_converter_object
#define UCNV_REASON_CASE(v)
Definition converter.c:682
#define THROW_UFAILURE(obj, fname, error)
Definition converter.c:46
#define CONV_GET(pzv)
Definition converter.c:45
#define TARGET_CHECK(cnvargs, needed)
Definition converter.c:150
int php_converter_minit(INIT_FUNC_ARGS)
Definition converter.c:966
error($message)
Definition ext_skel.php:22
memcpy(ptr1, ptr2, size)
char * err
Definition ffi.c:3029
zval * val
Definition ffi.c:4262
HashTable * ht
Definition ffi.c:4838
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
void intl_error_init(intl_error *err)
Definition intl_error.c:66
void intl_errors_set(intl_error *err, UErrorCode code, const char *msg, int copyMsg)
Definition intl_error.c:169
void intl_error_set(intl_error *err, UErrorCode code, const char *msg, int copyMsg)
Definition intl_error.c:161
void intl_error_reset(intl_error *err)
Definition intl_error.c:78
void intl_errors_reset(intl_error *err)
Definition intl_error.c:177
UErrorCode intl_error_get_code(intl_error *err)
Definition intl_error.c:151
zend_string * intl_error_get_message(intl_error *err)
Definition intl_error.c:116
struct _intl_error intl_error
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define PHP_METHOD
Definition php.h:365
#define CLOSE
PHP_JSON_API size_t int options
Definition php_json.h:102
char * msg
Definition phpdbg.h:289
#define vsnprintf
Definition snprintf.h:104
#define spprintf
Definition spprintf.h:29
UErrorCode code
Definition intl_error.h:27
zend_fcall_info to_cb
Definition converter.c:30
UConverter * dest
Definition converter.c:29
zend_fcall_info from_cb
Definition converter.c:30
zend_fcall_info_cache to_cache
Definition converter.c:31
UConverter * src
Definition converter.c:29
zend_fcall_info_cache from_cache
Definition converter.c:31
uint32_t param_count
Definition zend_API.h:51
zend_class_entry * ce
Definition zend_types.h:560
Definition dce.c:49
#define ILLEGAL
Definition utf7_helper.h:10
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
#define INTERNAL_FUNCTION_PARAMETERS
Definition zend.h:49
#define INTERNAL_FUNCTION_PARAM_PASSTHRU
Definition zend.h:50
ZEND_API zend_result add_next_index_long(zval *arg, zend_long n)
Definition zend_API.c:2132
ZEND_API zend_result zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error)
Definition zend_API.c:4310
ZEND_API void add_index_string(zval *arg, zend_ulong index, const char *str)
Definition zend_API.c:2087
ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type)
Definition zend_API.c:1688
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
ZEND_API zend_result add_next_index_string(zval *arg, const char *str)
Definition zend_API.c:2186
struct _zend_fcall_info_cache zend_fcall_info_cache
#define Z_PARAM_ARRAY_OR_NULL(dest)
Definition zend_API.h:1685
#define RETURN_STRING(s)
Definition zend_API.h:1043
#define RETURN_STRINGL(s, l)
Definition zend_API.h:1044
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define RETURN_FALSE
Definition zend_API.h:1058
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
#define RETURN_NULL()
Definition zend_API.h:1036
#define RETVAL_NEW_STR(s)
Definition zend_API.h:1015
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define Z_PARAM_STRING(dest, dest_len)
Definition zend_API.h:2071
#define Z_PARAM_STR(dest)
Definition zend_API.h:2086
#define Z_PARAM_STRING_OR_NULL(dest, dest_len)
Definition zend_API.h:2074
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define ZEND_TRY_ASSIGN_REF_LONG(zv, lval)
Definition zend_API.h:1205
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_BOOL(b)
Definition zend_API.h:1035
#define RETURN_NEW_STR(s)
Definition zend_API.h:1041
struct _zend_fcall_info zend_fcall_info
#define RETURN_THROWS()
Definition zend_API.h:1060
#define RETURN_STR(s)
Definition zend_API.h:1039
#define ZEND_THIS
Definition zend_API.h:523
#define Z_PARAM_BOOL(dest)
Definition zend_API.h:1726
#define Z_PARAM_ARRAY(dest)
Definition zend_API.h:1682
#define Z_PARAM_ZVAL(dest)
Definition zend_API.h:2100
#define ZVAL_STRINGL(z, s, l)
Definition zend_API.h:952
#define RETVAL_FALSE
Definition zend_API.h:1032
ZEND_API zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
#define RETVAL_STRINGL(s, l)
Definition zend_API.h:1018
#define array_init(arg)
Definition zend_API.h:537
#define ZVAL_EMPTY_STRING(z)
Definition zend_API.h:961
#define efree(ptr)
Definition zend_alloc.h:155
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
struct _zval_struct zval
strlen(string $string)
zval * args
#define E_WARNING
Definition zend_errors.h:24
ZEND_API void ZEND_FASTCALL zend_array_destroy(HashTable *ht)
Definition zend_hash.c:1808
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define ZEND_HASH_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1102
int32_t zend_long
Definition zend_long.h:42
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
#define INIT_FUNC_ARGS
ZEND_API const zend_object_handlers std_object_handlers
ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object)
ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce)
ZEND_API void zend_object_std_dtor(zend_object *object)
#define XtOffsetOf(s_type, field)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_UNDEF(z)
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_ARRAY
Definition zend_types.h:607
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
#define Z_REFVAL(zval)
#define Z_ADDREF_P(pz)
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define IS_NULL
Definition zend_types.h:601
@ FAILURE
Definition zend_types.h:61
#define IS_LONG
Definition zend_types.h:604
#define ZVAL_MAKE_REF(zv)
#define Z_ARR(zval)
Definition zend_types.h:983
#define Z_ISREF(zval)
Definition zend_types.h:953
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define Z_TYPE(zval)
Definition zend_types.h:659
#define Z_ARR_P(zval_p)
Definition zend_types.h:984
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define Z_LVAL(zval)
Definition zend_types.h:965
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval retval
zval * return_value
zend_string * name
object
zval * ret
zend_object * zobj