1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | http://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Sara Golemon <pollita@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17 #include "converter.h"
18 #include "zend_exceptions.h"
19
20 #include <unicode/utypes.h>
21 #include <unicode/ucnv.h>
22 #include <unicode/ustring.h>
23
24 #include "../intl_error.h"
25
26 typedef struct _php_converter_object {
27 zend_object obj;
28 #ifdef ZTS
29 void ***tsrm_ls;
30 #endif
31 UConverter *src, *dest;
32 zend_fcall_info to_cb, from_cb;
33 zend_fcall_info_cache to_cache, from_cache;
34 intl_error error;
35 } php_converter_object;
36
37 static zend_class_entry *php_converter_ce;
38 static zend_object_handlers php_converter_object_handlers;
39
40 #define CONV_GET(pzv) ((php_converter_object*)zend_objects_get_address((pzv) TSRMLS_CC))
41 #define THROW_UFAILURE(obj, fname, error) php_converter_throw_failure(obj, error TSRMLS_CC, \
42 fname "() returned error %ld: %s", (long)error, u_errorName(error))
43
44 /* {{{ php_converter_throw_failure */
php_converter_throw_failure(php_converter_object * objval,UErrorCode error TSRMLS_DC,const char * format,...)45 static inline void php_converter_throw_failure(php_converter_object *objval, UErrorCode error TSRMLS_DC, const char *format, ...) {
46 intl_error *err = objval ? &(objval->error) : NULL;
47 char message[1024];
48 va_list vargs;
49
50 va_start(vargs, format);
51 vsnprintf(message, sizeof(message), format, vargs);
52 va_end(vargs);
53
54 intl_errors_set(err, error, message, 1 TSRMLS_CC);
55 }
56 /* }}} */
57
58 /* {{{ php_converter_default_callback */
php_converter_default_callback(zval * return_value,zval * zobj,long reason,zval * error TSRMLS_DC)59 static void php_converter_default_callback(zval *return_value, zval *zobj, long reason, zval *error TSRMLS_DC) {
60 zval_dtor(error);
61 ZVAL_LONG(error, U_ZERO_ERROR);
62 /* Basic functionality so children can call parent::toUCallback() */
63 switch (reason) {
64 case UCNV_UNASSIGNED:
65 case UCNV_ILLEGAL:
66 case UCNV_IRREGULAR:
67 {
68 php_converter_object *objval = (php_converter_object*)CONV_GET(zobj);
69 char chars[127];
70 int8_t chars_len = sizeof(chars);
71 UErrorCode uerror = U_ZERO_ERROR;
72 if(!objval->src) {
73 php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, "Source Converter has not been initialized yet");
74 chars[0] = 0x1A;
75 chars[1] = 0;
76 chars_len = 1;
77 ZVAL_LONG(error, U_INVALID_STATE_ERROR);
78 RETVAL_STRINGL(chars, chars_len, 1);
79 return;
80 }
81
82 /* Yes, this is fairly wasteful at first glance,
83 * but considering that the alternative is to store
84 * what's sent into setSubstChars() and the fact
85 * that this is an extremely unlikely codepath
86 * I'd rather take the CPU hit here, than waste time
87 * storing a value I'm unlikely to use.
88 */
89 ucnv_getSubstChars(objval->src, chars, &chars_len, &uerror);
90 if (U_FAILURE(uerror)) {
91 THROW_UFAILURE(objval, "ucnv_getSubstChars", uerror);
92 chars[0] = 0x1A;
93 chars[1] = 0;
94 chars_len = 1;
95 ZVAL_LONG(error, uerror);
96 }
97 RETVAL_STRINGL(chars, chars_len, 1);
98 }
99 }
100 }
101 /* }}} */
102
103 /* {{{ proto void UConverter::toUCallback(long $reason,
104 string $source, string $codeUnits,
105 long &$error) */
106 ZEND_BEGIN_ARG_INFO_EX(php_converter_toUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4)
107 ZEND_ARG_INFO(0, reason)
108 ZEND_ARG_INFO(0, source)
109 ZEND_ARG_INFO(0, codeUnits)
110 ZEND_ARG_INFO(1, error)
111 ZEND_END_ARG_INFO();
PHP_METHOD(UConverter,toUCallback)112 static PHP_METHOD(UConverter, toUCallback) {
113 long reason;
114 zval *source, *codeUnits, *error;
115
116 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lzzz",
117 &reason, &source, &codeUnits, &error) == FAILURE) {
118 return;
119 }
120
121 php_converter_default_callback(return_value, getThis(), reason, error TSRMLS_CC);
122 }
123 /* }}} */
124
125 /* {{{ proto void UConverter::fromUCallback(long $reason,
126 Array $source, long $codePoint,
127 long &$error) */
128 ZEND_BEGIN_ARG_INFO_EX(php_converter_fromUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4)
129 ZEND_ARG_INFO(0, reason)
130 ZEND_ARG_INFO(0, source)
131 ZEND_ARG_INFO(0, codePoint)
132 ZEND_ARG_INFO(1, error)
133 ZEND_END_ARG_INFO();
PHP_METHOD(UConverter,fromUCallback)134 static PHP_METHOD(UConverter, fromUCallback) {
135 long reason;
136 zval *source, *codePoint, *error;
137
138 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lzzz",
139 &reason, &source, &codePoint, &error) == FAILURE) {
140 return;
141 }
142
143 php_converter_default_callback(return_value, getThis(), reason, error TSRMLS_CC);
144 }
145 /* }}} */
146
147 /* {{{ php_converter_check_limits */
php_converter_check_limits(php_converter_object * objval,long available,long needed TSRMLS_DC)148 static inline zend_bool php_converter_check_limits(php_converter_object *objval, long available, long needed TSRMLS_DC) {
149 if (available < needed) {
150 php_converter_throw_failure(objval, U_BUFFER_OVERFLOW_ERROR TSRMLS_CC, "Buffer overrun %ld bytes needed, %ld available", needed, available);
151 return 0;
152 }
153 return 1;
154 }
155 /* }}} */
156
157 #define TARGET_CHECK(cnvargs, needed) php_converter_check_limits(objval, cnvargs->targetLimit - cnvargs->target, needed TSRMLS_CC)
158
159 /* {{{ php_converter_append_toUnicode_target */
php_converter_append_toUnicode_target(zval * val,UConverterToUnicodeArgs * args,php_converter_object * objval TSRMLS_DC)160 static void php_converter_append_toUnicode_target(zval *val, UConverterToUnicodeArgs *args, php_converter_object *objval TSRMLS_DC) {
161 switch (Z_TYPE_P(val)) {
162 case IS_NULL:
163 /* Code unit is being skipped */
164 return;
165 case IS_LONG:
166 {
167 long lval = Z_LVAL_P(val);
168 if ((lval < 0) || (lval > 0x10FFFF)) {
169 php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC, "Invalid codepoint U+%04lx", lval);
170 return;
171 }
172 if (lval > 0xFFFF) {
173 /* Supplemental planes U+010000 - U+10FFFF */
174 if (TARGET_CHECK(args, 2)) {
175 /* TODO: Find the ICU call which does this properly */
176 *(args->target++) = (UChar)(((lval - 0x10000) >> 10) | 0xD800);
177 *(args->target++) = (UChar)(((lval - 0x10000) & 0x3FF) | 0xDC00);
178 }
179 return;
180 }
181 /* Non-suggogate BMP codepoint */
182 if (TARGET_CHECK(args, 1)) {
183 *(args->target++) = (UChar)lval;
184 }
185 return;
186 }
187 case IS_STRING:
188 {
189 const char *strval = Z_STRVAL_P(val);
190 int i = 0, strlen = Z_STRLEN_P(val);
191
192 while((i != strlen) && TARGET_CHECK(args, 1)) {
193 UChar c;
194 U8_NEXT(strval, i, strlen, c);
195 *(args->target++) = c;
196 }
197 return;
198 }
199 case IS_ARRAY:
200 {
201 HashTable *ht = Z_ARRVAL_P(val);
202 HashPosition pos;
203 zval **tmpzval;
204
205 for(zend_hash_internal_pointer_reset_ex(ht, &pos);
206 zend_hash_get_current_data_ex(ht, (void**)&tmpzval, &pos) == SUCCESS;
207 zend_hash_move_forward_ex(ht, &pos)) {
208 php_converter_append_toUnicode_target(*tmpzval, args, objval TSRMLS_CC);
209 }
210 return;
211 }
212 default:
213 php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC,
214 "toUCallback() specified illegal type for substitution character");
215 }
216 }
217 /* }}} */
218
219 /* {{{ php_converter_to_u_callback */
php_converter_to_u_callback(const void * context,UConverterToUnicodeArgs * args,const char * codeUnits,int32_t length,UConverterCallbackReason reason,UErrorCode * pErrorCode)220 static void php_converter_to_u_callback(const void *context,
221 UConverterToUnicodeArgs *args,
222 const char *codeUnits, int32_t length,
223 UConverterCallbackReason reason,
224 UErrorCode *pErrorCode) {
225 php_converter_object *objval = (php_converter_object*)context;
226 zval *zreason, *zsource, *zcodeunits, *zerror, *retval = NULL;
227 zval **zargs[4];
228 #ifdef ZTS
229 TSRMLS_D = objval->tsrm_ls;
230 #endif
231
232 MAKE_STD_ZVAL(zreason);
233 ZVAL_LONG(zreason, reason);
234 zargs[0] = &zreason;
235
236 MAKE_STD_ZVAL(zsource);
237 ZVAL_STRINGL(zsource, args->source, args->sourceLimit - args->source, 1);
238 zargs[1] = &zsource;
239
240 MAKE_STD_ZVAL(zcodeunits);
241 ZVAL_STRINGL(zcodeunits, codeUnits, length, 1);
242 zargs[2] = &zcodeunits;
243
244 MAKE_STD_ZVAL(zerror);
245 ZVAL_LONG(zerror, *pErrorCode);
246 zargs[3] = &zerror;
247
248 objval->to_cb.param_count = 4;
249 objval->to_cb.params = zargs;
250 objval->to_cb.retval_ptr_ptr = &retval;
251 objval->to_cb.no_separation = 0;
252 if (zend_call_function(&(objval->to_cb), &(objval->to_cache) TSRMLS_CC) == FAILURE) {
253 /* Unlikely */
254 php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Unexpected failure calling toUCallback()");
255 } else if (retval) {
256 php_converter_append_toUnicode_target(retval, args, objval TSRMLS_CC);
257 zval_ptr_dtor(&retval);
258 }
259
260 if (Z_TYPE_P(zerror) == IS_LONG) {
261 *pErrorCode = Z_LVAL_P(zerror);
262 }
263
264 zval_ptr_dtor(&zreason);
265 zval_ptr_dtor(&zsource);
266 zval_ptr_dtor(&zcodeunits);
267 zval_ptr_dtor(&zerror);
268 }
269 /* }}} */
270
271 /* {{{ php_converter_append_fromUnicode_target */
php_converter_append_fromUnicode_target(zval * val,UConverterFromUnicodeArgs * args,php_converter_object * objval TSRMLS_DC)272 static void php_converter_append_fromUnicode_target(zval *val, UConverterFromUnicodeArgs *args, php_converter_object *objval TSRMLS_DC) {
273 switch (Z_TYPE_P(val)) {
274 case IS_NULL:
275 /* Ignore */
276 return;
277 case IS_LONG:
278 if (TARGET_CHECK(args, 1)) {
279 *(args->target++) = Z_LVAL_P(val);
280 }
281 return;
282 case IS_STRING:
283 {
284 int vallen = Z_STRLEN_P(val);
285 if (TARGET_CHECK(args, vallen)) {
286 memcpy(args->target, Z_STRVAL_P(val), vallen);
287 args->target += vallen;
288 }
289 return;
290 }
291 case IS_ARRAY:
292 {
293 HashTable *ht = Z_ARRVAL_P(val);
294 HashPosition pos;
295 zval **tmpzval;
296 for(zend_hash_internal_pointer_reset_ex(ht, &pos);
297 zend_hash_get_current_data_ex(ht, (void**)&tmpzval, &pos) == SUCCESS;
298 zend_hash_move_forward_ex(ht, &pos)) {
299 php_converter_append_fromUnicode_target(*tmpzval, args, objval TSRMLS_CC);
300 }
301 return;
302 }
303 default:
304 php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC, "fromUCallback() specified illegal type for substitution character");
305 }
306 }
307 /* }}} */
308
309 /* {{{ php_converter_from_u_callback */
php_converter_from_u_callback(const void * context,UConverterFromUnicodeArgs * args,const UChar * codeUnits,int32_t length,UChar32 codePoint,UConverterCallbackReason reason,UErrorCode * pErrorCode)310 static void php_converter_from_u_callback(const void *context,
311 UConverterFromUnicodeArgs *args,
312 const UChar *codeUnits, int32_t length, UChar32 codePoint,
313 UConverterCallbackReason reason,
314 UErrorCode *pErrorCode) {
315 php_converter_object *objval = (php_converter_object*)context;
316 zval *zreason, *zsource, *zcodepoint, *zerror, *retval = NULL;
317 zval **zargs[4];
318 int i;
319 #ifdef ZTS
320 TSRMLS_D = objval->tsrm_ls;
321 #endif
322
323 MAKE_STD_ZVAL(zreason);
324 ZVAL_LONG(zreason, reason);
325 zargs[0] = &zreason;
326
327 MAKE_STD_ZVAL(zsource);
328 array_init(zsource);
329 i = 0;
330 while (i < length) {
331 UChar32 c;
332 U16_NEXT(codeUnits, i, length, c);
333 add_next_index_long(zsource, c);
334 }
335 zargs[1] = &zsource;
336
337 MAKE_STD_ZVAL(zcodepoint);
338 ZVAL_LONG(zcodepoint, codePoint);
339 zargs[2] = &zcodepoint;
340
341 MAKE_STD_ZVAL(zerror);
342 ZVAL_LONG(zerror, *pErrorCode);
343 zargs[3] = &zerror;
344
345 objval->from_cb.param_count = 4;
346 objval->from_cb.params = zargs;
347 objval->from_cb.retval_ptr_ptr = &retval;
348 objval->from_cb.no_separation = 0;
349 if (zend_call_function(&(objval->from_cb), &(objval->from_cache) TSRMLS_CC) == FAILURE) {
350 /* Unlikely */
351 php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Unexpected failure calling fromUCallback()");
352 } else if (retval) {
353 php_converter_append_fromUnicode_target(retval, args, objval TSRMLS_CC);
354 zval_ptr_dtor(&retval);
355 }
356
357 if (Z_TYPE_P(zerror) == IS_LONG) {
358 *pErrorCode = Z_LVAL_P(zerror);
359 }
360
361 zval_ptr_dtor(&zreason);
362 zval_ptr_dtor(&zsource);
363 zval_ptr_dtor(&zcodepoint);
364 zval_ptr_dtor(&zerror);
365 }
366 /* }}} */
367
368 /* {{{ php_converter_set_callbacks */
php_converter_set_callbacks(php_converter_object * objval,UConverter * cnv TSRMLS_DC)369 static inline zend_bool php_converter_set_callbacks(php_converter_object *objval, UConverter *cnv TSRMLS_DC) {
370 zend_bool ret = 1;
371 UErrorCode error = U_ZERO_ERROR;
372
373 if (objval->obj.ce == php_converter_ce) {
374 /* Short-circuit having to go through method calls and data marshalling
375 * when we're using default behavior
376 */
377 return 1;
378 }
379
380 ucnv_setToUCallBack(cnv, (UConverterToUCallback)php_converter_to_u_callback, (const void*)objval,
381 NULL, NULL, &error);
382 if (U_FAILURE(error)) {
383 THROW_UFAILURE(objval, "ucnv_setToUCallBack", error);
384 ret = 0;
385 }
386
387 error = U_ZERO_ERROR;
388 ucnv_setFromUCallBack(cnv, (UConverterFromUCallback)php_converter_from_u_callback, (const void*)objval,
389 NULL, NULL, &error);
390 if (U_FAILURE(error)) {
391 THROW_UFAILURE(objval, "ucnv_setFromUCallBack", error);
392 ret = 0;
393 }
394 return ret;
395 }
396 /* }}} */
397
398 /* {{{ php_converter_set_encoding */
php_converter_set_encoding(php_converter_object * objval,UConverter ** pcnv,const char * enc,int enc_len TSRMLS_DC)399 static zend_bool php_converter_set_encoding(php_converter_object *objval,
400 UConverter **pcnv,
401 const char *enc, int enc_len
402 TSRMLS_DC) {
403 UErrorCode error = U_ZERO_ERROR;
404 UConverter *cnv = ucnv_open(enc, &error);
405
406 if (error == U_AMBIGUOUS_ALIAS_WARNING) {
407 UErrorCode getname_error = U_ZERO_ERROR;
408 const char *actual_encoding = ucnv_getName(cnv, &getname_error);
409 if (U_FAILURE(getname_error)) {
410 /* Should never happen */
411 actual_encoding = "(unknown)";
412 }
413 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ambiguous encoding specified, using %s", actual_encoding);
414 } else if (U_FAILURE(error)) {
415 if (objval) {
416 THROW_UFAILURE(objval, "ucnv_open", error);
417 } else {
418 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error setting encoding: %d - %s", (int)error, u_errorName(error));
419 }
420 return 0;
421 }
422
423 if (objval && !php_converter_set_callbacks(objval, cnv TSRMLS_CC)) {
424 return 0;
425 }
426
427 if (*pcnv) {
428 ucnv_close(*pcnv);
429 }
430 *pcnv = cnv;
431 return 1;
432 }
433 /* }}} */
434
435 /* {{{ php_converter_do_set_encoding */
436 ZEND_BEGIN_ARG_INFO_EX(php_converter_set_encoding_arginfo, 0, ZEND_RETURN_VALUE, 1)
437 ZEND_ARG_INFO(0, encoding)
438 ZEND_END_ARG_INFO();
php_converter_do_set_encoding(UConverter * cnv,INTERNAL_FUNCTION_PARAMETERS)439 static void php_converter_do_set_encoding(UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
440 php_converter_object *objval = CONV_GET(getThis());
441 char *enc;
442 int enc_len;
443
444 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &enc, &enc_len) == FAILURE) {
445 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Bad arguments, "
446 "expected one string argument", 0 TSRMLS_CC);
447 RETURN_FALSE;
448 }
449 intl_errors_reset(&objval->error TSRMLS_CC);
450
451 RETURN_BOOL(php_converter_set_encoding(objval, &(objval->src), enc, enc_len TSRMLS_CC));
452 }
453 /* }}} */
454
455 /* {{{ proto bool UConverter::setSourceEncoding(string encoding) */
PHP_METHOD(UConverter,setSourceEncoding)456 static PHP_METHOD(UConverter, setSourceEncoding) {
457 php_converter_object *objval = CONV_GET(getThis());
458 php_converter_do_set_encoding(objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
459 }
460 /* }}} */
461
462 /* {{{ proto bool UConverter::setDestinationEncoding(string encoding) */
PHP_METHOD(UConverter,setDestinationEncoding)463 static PHP_METHOD(UConverter, setDestinationEncoding) {
464 php_converter_object *objval = CONV_GET(getThis());
465 php_converter_do_set_encoding(objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
466 }
467 /* }}} */
468
469 /* {{{ php_converter_do_get_encoding */
470 ZEND_BEGIN_ARG_INFO_EX(php_converter_get_encoding_arginfo, 0, ZEND_RETURN_VALUE, 0)
471 ZEND_END_ARG_INFO();
php_converter_do_get_encoding(php_converter_object * objval,UConverter * cnv,INTERNAL_FUNCTION_PARAMETERS)472 static void php_converter_do_get_encoding(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
473 const char *name;
474
475 if (zend_parse_parameters_none() == FAILURE) {
476 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0 TSRMLS_CC);
477 RETURN_FALSE;
478 }
479
480 intl_errors_reset(&objval->error TSRMLS_CC);
481
482 if (!cnv) {
483 RETURN_NULL();
484 }
485
486 name = ucnv_getName(cnv, &objval->error.code);
487 if (U_FAILURE(objval->error.code)) {
488 THROW_UFAILURE(objval, "ucnv_getName()", objval->error.code);
489 RETURN_FALSE;
490 }
491
492 RETURN_STRING(name, 1);
493 }
494 /* }}} */
495
496 /* {{{ proto string UConverter::getSourceEncoding() */
PHP_METHOD(UConverter,getSourceEncoding)497 static PHP_METHOD(UConverter, getSourceEncoding) {
498 php_converter_object *objval = CONV_GET(getThis());
499 php_converter_do_get_encoding(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
500 }
501 /* }}} */
502
503 /* {{{ proto string UConverter::getDestinationEncoding() */
PHP_METHOD(UConverter,getDestinationEncoding)504 static PHP_METHOD(UConverter, getDestinationEncoding) {
505 php_converter_object *objval = CONV_GET(getThis());
506 php_converter_do_get_encoding(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
507 }
508 /* }}} */
509
510 /* {{{ php_converter_do_get_type */
511 ZEND_BEGIN_ARG_INFO_EX(php_converter_get_type_arginfo, 0, ZEND_RETURN_VALUE, 0)
512 ZEND_END_ARG_INFO();
php_converter_do_get_type(php_converter_object * objval,UConverter * cnv,INTERNAL_FUNCTION_PARAMETERS)513 static void php_converter_do_get_type(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
514 UConverterType t;
515
516 if (zend_parse_parameters_none() == FAILURE) {
517 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0 TSRMLS_CC);
518 RETURN_FALSE;
519 }
520 intl_errors_reset(&objval->error TSRMLS_CC);
521
522 if (!cnv) {
523 RETURN_NULL();
524 }
525
526 t = ucnv_getType(cnv);
527 if (U_FAILURE(objval->error.code)) {
528 THROW_UFAILURE(objval, "ucnv_getType", objval->error.code);
529 RETURN_FALSE;
530 }
531
532 RETURN_LONG(t);
533 }
534 /* }}} */
535
536 /* {{{ proto long UConverter::getSourceType() */
PHP_METHOD(UConverter,getSourceType)537 static PHP_METHOD(UConverter, getSourceType) {
538 php_converter_object *objval = CONV_GET(getThis());
539 php_converter_do_get_type(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
540 }
541 /* }}} */
542
543 /* {{{ proto long UConverter::getDestinationType() */
PHP_METHOD(UConverter,getDestinationType)544 static PHP_METHOD(UConverter, getDestinationType) {
545 php_converter_object *objval = CONV_GET(getThis());
546 php_converter_do_get_type(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
547 }
548 /* }}} */
549
550 /* {{{ php_converter_resolve_callback */
php_converter_resolve_callback(zval * zobj,php_converter_object * objval,const char * callback_name,zend_fcall_info * finfo,zend_fcall_info_cache * fcache TSRMLS_DC)551 static void php_converter_resolve_callback(zval *zobj,
552 php_converter_object *objval,
553 const char *callback_name,
554 zend_fcall_info *finfo,
555 zend_fcall_info_cache *fcache TSRMLS_DC) {
556 char *errstr = NULL;
557 zval caller;
558
559 array_init(&caller);
560 Z_ADDREF_P(zobj);
561 add_index_zval(&caller, 0, zobj);
562 add_index_string(&caller, 1, callback_name, 1);
563 if (zend_fcall_info_init(&caller, 0, finfo, fcache, NULL, &errstr TSRMLS_CC) == FAILURE) {
564 php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Error setting converter callback: %s", errstr);
565 }
566 zval_dtor(&caller);
567 if (errstr) {
568 efree(errstr);
569 }
570 }
571 /* }}} */
572
573 /* {{{ proto void UConverter::__construct([string dest = 'utf-8',[string src = 'utf-8']]) */
574 ZEND_BEGIN_ARG_INFO_EX(php_converter_arginfo, 0, ZEND_RETURN_VALUE, 0)
575 ZEND_ARG_INFO(0, destination_encoding)
576 ZEND_ARG_INFO(0, source_encoding)
577 ZEND_END_ARG_INFO();
578
PHP_METHOD(UConverter,__construct)579 static PHP_METHOD(UConverter, __construct) {
580 php_converter_object *objval = CONV_GET(getThis());
581 char *src = "utf-8";
582 int src_len = sizeof("utf-8") - 1;
583 char *dest = src;
584 int dest_len = src_len;
585
586 intl_error_reset(NULL TSRMLS_CC);
587
588 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!",
589 &dest, &dest_len, &src, &src_len) == FAILURE) {
590 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
591 "UConverter::__construct(): bad arguments", 0 TSRMLS_CC);
592 return;
593 }
594
595 php_converter_set_encoding(objval, &(objval->src), src, src_len TSRMLS_CC);
596 php_converter_set_encoding(objval, &(objval->dest), dest, dest_len TSRMLS_CC);
597 php_converter_resolve_callback(getThis(), objval, "toUCallback", &(objval->to_cb), &(objval->to_cache) TSRMLS_CC);
598 php_converter_resolve_callback(getThis(), objval, "fromUCallback", &(objval->from_cb), &(objval->from_cache) TSRMLS_CC);
599 }
600 /* }}} */
601
602 /* {{{ proto bool UConverter::setSubstChars(string $chars) */
603 ZEND_BEGIN_ARG_INFO_EX(php_converter_setSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 1)
604 ZEND_ARG_INFO(0, chars)
605 ZEND_END_ARG_INFO();
606
PHP_METHOD(UConverter,setSubstChars)607 static PHP_METHOD(UConverter, setSubstChars) {
608 php_converter_object *objval = CONV_GET(getThis());
609 char *chars;
610 int chars_len, ret = 1;
611
612 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &chars, &chars_len) == FAILURE) {
613 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
614 "UConverter::setSubstChars(): bad arguments", 0 TSRMLS_CC);
615 RETURN_FALSE;
616 }
617 intl_errors_reset(&objval->error TSRMLS_CC);
618
619 if (objval->src) {
620 UErrorCode error = U_ZERO_ERROR;
621 ucnv_setSubstChars(objval->src, chars, chars_len, &error);
622 if (U_FAILURE(error)) {
623 THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
624 ret = 0;
625 }
626 } else {
627 php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, "Source Converter has not been initialized yet");
628 ret = 0;
629 }
630
631 if (objval->dest) {
632 UErrorCode error = U_ZERO_ERROR;
633 ucnv_setSubstChars(objval->dest, chars, chars_len, &error);
634 if (U_FAILURE(error)) {
635 THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
636 ret = 0;
637 }
638 } else {
639 php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, "Destination Converter has not been initialized yet");
640 ret = 0;
641 }
642
643 RETURN_BOOL(ret);
644 }
645 /* }}} */
646
647 /* {{{ proto string UConverter::getSubstChars() */
648 ZEND_BEGIN_ARG_INFO_EX(php_converter_getSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 0)
649 ZEND_END_ARG_INFO();
650
PHP_METHOD(UConverter,getSubstChars)651 static PHP_METHOD(UConverter, getSubstChars) {
652 php_converter_object *objval = CONV_GET(getThis());
653 char chars[127];
654 int8_t chars_len = sizeof(chars);
655 UErrorCode error = U_ZERO_ERROR;
656
657 if (zend_parse_parameters_none() == FAILURE) {
658 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
659 "UConverter::getSubstChars(): expected no arguments", 0 TSRMLS_CC);
660 RETURN_FALSE;
661 }
662 intl_errors_reset(&objval->error TSRMLS_CC);
663
664 if (!objval->src) {
665 RETURN_NULL();
666 }
667
668 /* src and dest get the same subst chars set,
669 * so it doesn't really matter which one we read from
670 */
671 ucnv_getSubstChars(objval->src, chars, &chars_len, &error);
672 if (U_FAILURE(error)) {
673 THROW_UFAILURE(objval, "ucnv_getSubstChars", error);
674 RETURN_FALSE;
675 }
676
677 RETURN_STRINGL(chars, chars_len, 1);
678 }
679 /* }}} */
680
681 /* {{{ php_converter_do_convert */
php_converter_do_convert(UConverter * dest_cnv,char ** pdest,int32_t * pdest_len,UConverter * src_cnv,const char * src,int32_t src_len,php_converter_object * objval TSRMLS_DC)682 static zend_bool php_converter_do_convert(UConverter *dest_cnv, char **pdest, int32_t *pdest_len,
683 UConverter *src_cnv, const char *src, int32_t src_len,
684 php_converter_object *objval
685 TSRMLS_DC) {
686 UErrorCode error = U_ZERO_ERROR;
687 int32_t dest_len,
688 temp_len;
689 char *dest;
690 UChar *temp;
691
692 if (!src_cnv || !dest_cnv) {
693 php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC,
694 "Internal converters not initialized");
695 return 0;
696 }
697
698 /* Get necessary buffer size first */
699 temp_len = 1 + ucnv_toUChars(src_cnv, NULL, 0, src, src_len, &error);
700 if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
701 THROW_UFAILURE(objval, "ucnv_toUChars", error);
702 return 0;
703 }
704 temp = safe_emalloc(sizeof(UChar), temp_len, sizeof(UChar));
705
706 /* Convert to intermediate UChar* array */
707 error = U_ZERO_ERROR;
708 temp_len = ucnv_toUChars(src_cnv, temp, temp_len, src, src_len, &error);
709 if (U_FAILURE(error)) {
710 THROW_UFAILURE(objval, "ucnv_toUChars", error);
711 efree(temp);
712 return 0;
713 }
714 temp[temp_len] = 0;
715
716 /* Get necessary output buffer size */
717 dest_len = 1 + ucnv_fromUChars(dest_cnv, NULL, 0, temp, temp_len, &error);
718 if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
719 THROW_UFAILURE(objval, "ucnv_fromUChars", error);
720 efree(temp);
721 return 0;
722 }
723 dest = safe_emalloc(sizeof(char), dest_len, sizeof(char));
724
725 /* Convert to final encoding */
726 error = U_ZERO_ERROR;
727 dest_len = ucnv_fromUChars(dest_cnv, dest, dest_len, temp, temp_len, &error);
728 efree(temp);
729 if (U_FAILURE(error)) {
730 THROW_UFAILURE(objval, "ucnv_fromUChars", error);
731 efree(dest);
732 return 0;
733 }
734
735 *pdest = dest;
736 if (pdest_len) {
737 *pdest_len = dest_len;
738 }
739
740 return 1;
741 }
742 /* }}} */
743
744 /* {{{ proto string UConverter::reasonText(long reason) */
745 #define UCNV_REASON_CASE(v) case (UCNV_ ## v) : RETURN_STRINGL( "REASON_" #v , sizeof( "REASON_" #v ) - 1, 1);
746 ZEND_BEGIN_ARG_INFO_EX(php_converter_reasontext_arginfo, 0, ZEND_RETURN_VALUE, 0)
747 ZEND_ARG_INFO(0, reason)
748 ZEND_END_ARG_INFO();
PHP_METHOD(UConverter,reasonText)749 static PHP_METHOD(UConverter, reasonText) {
750 long reason;
751
752 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &reason) == FAILURE) {
753 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
754 "UConverter::reasonText(): bad arguments", 0 TSRMLS_CC);
755 RETURN_FALSE;
756 }
757 intl_error_reset(NULL TSRMLS_CC);
758
759 switch (reason) {
760 UCNV_REASON_CASE(UNASSIGNED)
761 UCNV_REASON_CASE(ILLEGAL)
762 UCNV_REASON_CASE(IRREGULAR)
763 UCNV_REASON_CASE(RESET)
764 UCNV_REASON_CASE(CLOSE)
765 UCNV_REASON_CASE(CLONE)
766 default:
767 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown UConverterCallbackReason: %ld", reason);
768 RETURN_FALSE;
769 }
770 }
771 /* }}} */
772
773 /* {{{ proto string UConverter::convert(string str[, bool reverse]) */
774 ZEND_BEGIN_ARG_INFO_EX(php_converter_convert_arginfo, 0, ZEND_RETURN_VALUE, 1)
775 ZEND_ARG_INFO(0, str)
776 ZEND_ARG_INFO(0, reverse)
777 ZEND_END_ARG_INFO();
778
PHP_METHOD(UConverter,convert)779 static PHP_METHOD(UConverter, convert) {
780 php_converter_object *objval = CONV_GET(getThis());
781 char *str, *dest;
782 int str_len, dest_len;
783 zend_bool reverse = 0;
784
785 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b",
786 &str, &str_len, &reverse) == FAILURE) {
787 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
788 "UConverter::convert(): bad arguments", 0 TSRMLS_CC);
789 RETURN_FALSE;
790 }
791 intl_errors_reset(&objval->error TSRMLS_CC);
792
793 if (php_converter_do_convert(reverse ? objval->src : objval->dest,
794 &dest, &dest_len,
795 reverse ? objval->dest : objval->src,
796 str, str_len,
797 objval TSRMLS_CC)) {
798 RETURN_STRINGL(dest, dest_len, 0);
799 } else {
800 RETURN_FALSE;
801 }
802 }
803 /* }}} */
804
805 /* {{{ proto string UConverter::transcode(string $str, string $toEncoding, string $fromEncoding[, Array $options = array()]) */
806 ZEND_BEGIN_ARG_INFO_EX(php_converter_transcode_arginfo, 0, ZEND_RETURN_VALUE, 3)
807 ZEND_ARG_INFO(0, str)
808 ZEND_ARG_INFO(0, toEncoding)
809 ZEND_ARG_INFO(0, fromEncoding)
810 ZEND_ARG_ARRAY_INFO(0, options, 1)
811 ZEND_END_ARG_INFO();
812
PHP_METHOD(UConverter,transcode)813 static PHP_METHOD(UConverter, transcode) {
814 char *str, *src, *dest;
815 int str_len, src_len, dest_len;
816 zval *options = NULL;
817 UConverter *src_cnv = NULL, *dest_cnv = NULL;
818
819 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|a!",
820 &str, &str_len, &dest, &dest_len, &src, &src_len, &options) == FAILURE) {
821 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
822 "UConverter::transcode(): bad arguments", 0 TSRMLS_CC);
823 RETURN_FALSE;
824 }
825 intl_error_reset(NULL TSRMLS_CC);
826
827 if (php_converter_set_encoding(NULL, &src_cnv, src, src_len TSRMLS_CC) &&
828 php_converter_set_encoding(NULL, &dest_cnv, dest, dest_len TSRMLS_CC)) {
829 char *out = NULL;
830 int out_len = 0;
831 UErrorCode error = U_ZERO_ERROR;
832
833 if (options && zend_hash_num_elements(Z_ARRVAL_P(options))) {
834 zval **tmpzval;
835
836 if (U_SUCCESS(error) &&
837 zend_hash_find(Z_ARRVAL_P(options), "from_subst", sizeof("from_subst"), (void**)&tmpzval) == SUCCESS &&
838 Z_TYPE_PP(tmpzval) == IS_STRING) {
839 error = U_ZERO_ERROR;
840 ucnv_setSubstChars(src_cnv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) & 0x7F, &error);
841 }
842 if (U_SUCCESS(error) &&
843 zend_hash_find(Z_ARRVAL_P(options), "to_subst", sizeof("to_subst"), (void**)&tmpzval) == SUCCESS &&
844 Z_TYPE_PP(tmpzval) == IS_STRING) {
845 error = U_ZERO_ERROR;
846 ucnv_setSubstChars(dest_cnv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) & 0x7F, &error);
847 }
848 }
849
850 if (U_SUCCESS(error) &&
851 php_converter_do_convert(dest_cnv, &out, &out_len, src_cnv, str, str_len, NULL TSRMLS_CC)) {
852 RETVAL_STRINGL(out, out_len, 0);
853 }
854
855 if (U_FAILURE(error)) {
856 THROW_UFAILURE(NULL, "transcode", error);
857 RETVAL_FALSE;
858 }
859 } else {
860 RETVAL_FALSE;
861 }
862
863 if (src_cnv) {
864 ucnv_close(src_cnv);
865 }
866 if (dest_cnv) {
867 ucnv_close(dest_cnv);
868 }
869 }
870 /* }}} */
871
872 /* {{{ proto int UConverter::getErrorCode() */
873 ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrorcode_arginfo, 0, ZEND_RETURN_VALUE, 0)
874 ZEND_END_ARG_INFO();
PHP_METHOD(UConverter,getErrorCode)875 static PHP_METHOD(UConverter, getErrorCode) {
876 php_converter_object *objval = CONV_GET(getThis());
877
878 if (zend_parse_parameters_none() == FAILURE) {
879 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
880 "UConverter::getErrorCode(): expected no arguments", 0 TSRMLS_CC);
881 RETURN_FALSE;
882 }
883
884 RETURN_LONG(intl_error_get_code(&(objval->error) TSRMLS_CC));
885 }
886 /* }}} */
887
888 /* {{{ proto string UConverter::getErrorMessage() */
889 ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrormsg_arginfo, 0, ZEND_RETURN_VALUE, 0)
890 ZEND_END_ARG_INFO();
PHP_METHOD(UConverter,getErrorMessage)891 static PHP_METHOD(UConverter, getErrorMessage) {
892 php_converter_object *objval = CONV_GET(getThis());
893 char *message = intl_error_get_message(&(objval->error) TSRMLS_CC);
894
895 if (zend_parse_parameters_none() == FAILURE) {
896 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
897 "UConverter::getErrorMessage(): expected no arguments", 0 TSRMLS_CC);
898 RETURN_FALSE;
899 }
900
901 if (message) {
902 RETURN_STRING(message, 1);
903 } else {
904 RETURN_NULL();
905 }
906 }
907 /* }}} */
908
909 /* {{{ proto array UConverter::getAvailable() */
910 ZEND_BEGIN_ARG_INFO_EX(php_converter_getavailable_arginfo, 0, ZEND_RETURN_VALUE, 0)
911 ZEND_END_ARG_INFO();
PHP_METHOD(UConverter,getAvailable)912 static PHP_METHOD(UConverter, getAvailable) {
913 int32_t i,
914 count = ucnv_countAvailable();
915
916 if (zend_parse_parameters_none() == FAILURE) {
917 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
918 "UConverter::getErrorMessage(): expected no arguments", 0 TSRMLS_CC);
919 RETURN_FALSE;
920 }
921 intl_error_reset(NULL TSRMLS_CC);
922
923 array_init(return_value);
924 for(i = 0; i < count; i++) {
925 const char *name = ucnv_getAvailableName(i);
926 add_next_index_string(return_value, name, 1);
927 }
928 }
929 /* }}} */
930
931 /* {{{ proto array UConverter::getAliases(string name) */
932 ZEND_BEGIN_ARG_INFO_EX(php_converter_getaliases_arginfo, 0, ZEND_RETURN_VALUE, 0)
933 ZEND_ARG_INFO(0, name)
934 ZEND_END_ARG_INFO();
PHP_METHOD(UConverter,getAliases)935 static PHP_METHOD(UConverter, getAliases) {
936 char *name;
937 int name_len;
938 UErrorCode error = U_ZERO_ERROR;
939 uint16_t i, count;
940
941 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
942 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
943 "UConverter::getAliases(): bad arguments", 0 TSRMLS_CC);
944 RETURN_FALSE;
945 }
946 intl_error_reset(NULL TSRMLS_CC);
947
948 count = ucnv_countAliases(name, &error);
949 if (U_FAILURE(error)) {
950 THROW_UFAILURE(NULL, "ucnv_countAliases", error);
951 RETURN_FALSE;
952 }
953
954 array_init(return_value);
955 for(i = 0; i < count; i++) {
956 const char *alias;
957
958 error = U_ZERO_ERROR;
959 alias = ucnv_getAlias(name, i, &error);
960 if (U_FAILURE(error)) {
961 THROW_UFAILURE(NULL, "ucnv_getAlias", error);
962 zval_dtor(return_value);
963 RETURN_NULL();
964 }
965 add_next_index_string(return_value, alias, 1);
966 }
967 }
968 /* }}} */
969
970 /* {{{ proto array UConverter::getStandards() */
971 ZEND_BEGIN_ARG_INFO_EX(php_converter_getstandards_arginfo, 0, ZEND_RETURN_VALUE, 0)
972 ZEND_END_ARG_INFO();
PHP_METHOD(UConverter,getStandards)973 static PHP_METHOD(UConverter, getStandards) {
974 uint16_t i, count;
975
976 if (zend_parse_parameters_none() == FAILURE) {
977 intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
978 "UConverter::getStandards(): expected no arguments", 0 TSRMLS_CC);
979 RETURN_FALSE;
980 }
981 intl_error_reset(NULL TSRMLS_CC);
982
983 array_init(return_value);
984 count = ucnv_countStandards();
985 for(i = 0; i < count; i++) {
986 UErrorCode error = U_ZERO_ERROR;
987 const char *name = ucnv_getStandard(i, &error);
988 if (U_FAILURE(error)) {
989 THROW_UFAILURE(NULL, "ucnv_getStandard", error);
990 zval_dtor(return_value);
991 RETURN_NULL();
992 }
993 add_next_index_string(return_value, name, 1);
994 }
995 }
996 /* }}} */
997
998 static zend_function_entry php_converter_methods[] = {
999 PHP_ME(UConverter, __construct, php_converter_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
1000
1001 /* Encoding selection */
1002 PHP_ME(UConverter, setSourceEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC)
1003 PHP_ME(UConverter, setDestinationEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC)
1004 PHP_ME(UConverter, getSourceEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC)
1005 PHP_ME(UConverter, getDestinationEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC)
1006
1007 /* Introspection for algorithmic converters */
1008 PHP_ME(UConverter, getSourceType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC)
1009 PHP_ME(UConverter, getDestinationType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC)
1010
1011 /* Basic codeunit error handling */
1012 PHP_ME(UConverter, getSubstChars, php_converter_getSubstChars_arginfo, ZEND_ACC_PUBLIC)
1013 PHP_ME(UConverter, setSubstChars, php_converter_setSubstChars_arginfo, ZEND_ACC_PUBLIC)
1014
1015 /* Default callback handlers */
1016 PHP_ME(UConverter, toUCallback, php_converter_toUCallback_arginfo, ZEND_ACC_PUBLIC)
1017 PHP_ME(UConverter, fromUCallback, php_converter_fromUCallback_arginfo, ZEND_ACC_PUBLIC)
1018
1019 /* Core conversion workhorses */
1020 PHP_ME(UConverter, convert, php_converter_convert_arginfo, ZEND_ACC_PUBLIC)
1021 PHP_ME(UConverter, transcode, php_converter_transcode_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1022
1023 /* Error inspection */
1024 PHP_ME(UConverter, getErrorCode, php_converter_geterrorcode_arginfo, ZEND_ACC_PUBLIC)
1025 PHP_ME(UConverter, getErrorMessage, php_converter_geterrormsg_arginfo, ZEND_ACC_PUBLIC)
1026
1027 /* Ennumeration and lookup */
1028 PHP_ME(UConverter, reasonText, php_converter_reasontext_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1029 PHP_ME(UConverter, getAvailable, php_converter_getavailable_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1030 PHP_ME(UConverter, getAliases, php_converter_getaliases_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1031 PHP_ME(UConverter, getStandards, php_converter_getstandards_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
1032 { NULL, NULL, NULL }
1033 };
1034
1035 /* {{{ Converter create/clone/destroy */
php_converter_free_object(php_converter_object * objval TSRMLS_DC)1036 static void php_converter_free_object(php_converter_object *objval TSRMLS_DC) {
1037 if (objval->src) {
1038 ucnv_close(objval->src);
1039 }
1040
1041 if (objval->dest) {
1042 ucnv_close(objval->dest);
1043 }
1044
1045 intl_error_reset(&(objval->error) TSRMLS_CC);
1046 zend_object_std_dtor(&(objval->obj) TSRMLS_CC);
1047
1048 efree(objval);
1049 }
1050
php_converter_object_ctor(zend_class_entry * ce,php_converter_object ** pobjval TSRMLS_DC)1051 static zend_object_value php_converter_object_ctor(zend_class_entry *ce, php_converter_object **pobjval TSRMLS_DC) {
1052 php_converter_object *objval;
1053 zend_object_value retval;
1054
1055 objval = ecalloc(1, sizeof(php_converter_object));
1056 objval->obj.ce = ce;
1057
1058 #ifdef ZTS
1059 objval->tsrm_ls = TSRMLS_C;
1060 #endif
1061 intl_error_init(&(objval->error) TSRMLS_CC);
1062
1063 retval.handle = zend_objects_store_put(objval, NULL, (zend_objects_free_object_storage_t)php_converter_free_object, NULL TSRMLS_CC);
1064 retval.handlers = &php_converter_object_handlers;
1065 *pobjval = objval;
1066
1067 return retval;
1068 }
1069
php_converter_create_object(zend_class_entry * ce TSRMLS_DC)1070 static zend_object_value php_converter_create_object(zend_class_entry *ce TSRMLS_DC) {
1071 php_converter_object *objval = NULL;
1072 zend_object_value retval = php_converter_object_ctor(ce, &objval TSRMLS_CC);
1073
1074 object_properties_init(&(objval->obj), ce);
1075
1076 return retval;
1077 }
1078
php_converter_clone_object(zval * object TSRMLS_DC)1079 static zend_object_value php_converter_clone_object(zval *object TSRMLS_DC) {
1080 php_converter_object *objval, *oldobj = (php_converter_object*)zend_objects_get_address(object TSRMLS_CC);
1081 zend_object_value retval = php_converter_object_ctor(Z_OBJCE_P(object), &objval TSRMLS_CC);
1082 UErrorCode error = U_ZERO_ERROR;
1083
1084 intl_errors_reset(&oldobj->error TSRMLS_CC);
1085
1086 objval->src = ucnv_safeClone(oldobj->src, NULL, NULL, &error);
1087 if (U_SUCCESS(error)) {
1088 error = U_ZERO_ERROR;
1089 objval->dest = ucnv_safeClone(oldobj->dest, NULL, NULL, &error);
1090 }
1091 if (U_FAILURE(error)) {
1092 char *err_msg;
1093 THROW_UFAILURE(oldobj, "ucnv_safeClone", error);
1094
1095 err_msg = intl_error_get_message(&oldobj->error TSRMLS_CC);
1096 zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC);
1097 efree(err_msg);
1098
1099 return retval;
1100 }
1101
1102 /* Update contexts for converter error handlers */
1103 php_converter_set_callbacks(objval, objval->src TSRMLS_CC);
1104 php_converter_set_callbacks(objval, objval->dest TSRMLS_CC);
1105
1106 zend_objects_clone_members(&(objval->obj), retval, &(oldobj->obj), Z_OBJ_HANDLE_P(object) TSRMLS_CC);
1107
1108 /* Newly cloned object deliberately does not inherit error state from original object */
1109
1110 return retval;
1111 }
1112 /* }}} */
1113
1114 #define CONV_REASON_CONST(v) zend_declare_class_constant_long(php_converter_ce, "REASON_" #v, sizeof("REASON_" #v) - 1, UCNV_ ## v TSRMLS_CC)
1115 #define CONV_TYPE_CONST(v) zend_declare_class_constant_long(php_converter_ce, #v , sizeof(#v) - 1, UCNV_ ## v TSRMLS_CC)
1116
1117 /* {{{ php_converter_minit */
php_converter_minit(INIT_FUNC_ARGS)1118 int php_converter_minit(INIT_FUNC_ARGS) {
1119 zend_class_entry ce;
1120
1121 INIT_CLASS_ENTRY(ce, "UConverter", php_converter_methods);
1122 php_converter_ce = zend_register_internal_class(&ce TSRMLS_CC);
1123 php_converter_ce->create_object = php_converter_create_object;
1124 memcpy(&php_converter_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1125 php_converter_object_handlers.clone_obj = php_converter_clone_object;
1126
1127 /* enum UConverterCallbackReason */
1128 CONV_REASON_CONST(UNASSIGNED);
1129 CONV_REASON_CONST(ILLEGAL);
1130 CONV_REASON_CONST(IRREGULAR);
1131 CONV_REASON_CONST(RESET);
1132 CONV_REASON_CONST(CLOSE);
1133 CONV_REASON_CONST(CLONE);
1134
1135 /* enum UConverterType */
1136 CONV_TYPE_CONST(UNSUPPORTED_CONVERTER);
1137 CONV_TYPE_CONST(SBCS);
1138 CONV_TYPE_CONST(DBCS);
1139 CONV_TYPE_CONST(MBCS);
1140 CONV_TYPE_CONST(LATIN_1);
1141 CONV_TYPE_CONST(UTF8);
1142 CONV_TYPE_CONST(UTF16_BigEndian);
1143 CONV_TYPE_CONST(UTF16_LittleEndian);
1144 CONV_TYPE_CONST(UTF32_BigEndian);
1145 CONV_TYPE_CONST(UTF32_LittleEndian);
1146 CONV_TYPE_CONST(EBCDIC_STATEFUL);
1147 CONV_TYPE_CONST(ISO_2022);
1148 CONV_TYPE_CONST(LMBCS_1);
1149 CONV_TYPE_CONST(LMBCS_2);
1150 CONV_TYPE_CONST(LMBCS_3);
1151 CONV_TYPE_CONST(LMBCS_4);
1152 CONV_TYPE_CONST(LMBCS_5);
1153 CONV_TYPE_CONST(LMBCS_6);
1154 CONV_TYPE_CONST(LMBCS_8);
1155 CONV_TYPE_CONST(LMBCS_11);
1156 CONV_TYPE_CONST(LMBCS_16);
1157 CONV_TYPE_CONST(LMBCS_17);
1158 CONV_TYPE_CONST(LMBCS_18);
1159 CONV_TYPE_CONST(LMBCS_19);
1160 CONV_TYPE_CONST(LMBCS_LAST);
1161 CONV_TYPE_CONST(HZ);
1162 CONV_TYPE_CONST(SCSU);
1163 CONV_TYPE_CONST(ISCII);
1164 CONV_TYPE_CONST(US_ASCII);
1165 CONV_TYPE_CONST(UTF7);
1166 CONV_TYPE_CONST(BOCU1);
1167 CONV_TYPE_CONST(UTF16);
1168 CONV_TYPE_CONST(UTF32);
1169 CONV_TYPE_CONST(CESU8);
1170 CONV_TYPE_CONST(IMAP_MAILBOX);
1171
1172 return SUCCESS;
1173 }
1174 /* }}} */
1175
1176 /*
1177 * Local variables:
1178 * tab-width: 4
1179 * c-basic-offset: 4
1180 * End:
1181 * vim600: noet sw=4 ts=4 fdm=marker
1182 * vim<600: noet sw=4 ts=4
1183 */
1184