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: Gustavo Lopes <cataphract@php.net>                          |
14    +----------------------------------------------------------------------+
15  */
16 
17 #include "transliterator_class.h"
18 #include "php_intl.h"
19 #include "transliterator_methods.h"
20 #include "intl_error.h"
21 #include "intl_convert.h"
22 #include "intl_data.h"
23 
24 #include <unicode/utrans.h>
25 
26 zend_class_entry *Transliterator_ce_ptr = NULL;
27 
28 zend_object_handlers Transliterator_handlers;
29 
30 /* {{{ int transliterator_object_construct( zval *object, UTransliterator *utrans, UErrorCode *status TSRMLS_DC )
31  * Initialize internals of Transliterator_object.
32  */
transliterator_object_construct(zval * object,UTransliterator * utrans,UErrorCode * status TSRMLS_DC)33 int transliterator_object_construct( zval *object,
34 									 UTransliterator *utrans,
35 									 UErrorCode *status TSRMLS_DC )
36 {
37 	const UChar           *ustr_id;
38 	int32_t               ustr_id_len;
39 	char                  *str_id;
40 	int                   str_id_len;
41 	Transliterator_object *to;
42 
43 	TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
44 
45 	assert( to->utrans == NULL );
46 	/* this assignment must happen before any return with failure because the
47 	 * caller relies on it always being made (so it can just destroy the object
48 	 * to close the transliterator) */
49 	to->utrans = utrans;
50 
51 	ustr_id = utrans_getUnicodeID( utrans, &ustr_id_len );
52 	intl_convert_utf16_to_utf8( &str_id, &str_id_len, ustr_id, (int ) ustr_id_len, status );
53 	if( U_FAILURE( *status ) )
54 	{
55 		return FAILURE;
56 	}
57 
58 	zend_update_property_stringl( Transliterator_ce_ptr, object,
59 		"id", sizeof( "id" ) - 1, str_id, str_id_len TSRMLS_CC );
60 	efree( str_id );
61 	return SUCCESS;
62 }
63 /* }}} */
64 
65 /*
66  * Auxiliary functions needed by objects of 'Transliterator' class
67  */
68 
69 /* {{{ void transliterator_object_init( Transliterator_object* to )
70  * Initialize internals of Transliterator_object.
71  */
transliterator_object_init(Transliterator_object * to TSRMLS_DC)72 static void transliterator_object_init( Transliterator_object* to TSRMLS_DC )
73 {
74 	if( !to )
75 		return;
76 
77 	intl_error_init( TRANSLITERATOR_ERROR_P( to ) TSRMLS_CC );
78 }
79 /* }}} */
80 
81 /* {{{ void transliterator_object_destroy( Transliterator_object* to )
82  * Clean up mem allocted by internals of Transliterator_object
83  */
transliterator_object_destroy(Transliterator_object * to TSRMLS_DC)84 static void transliterator_object_destroy( Transliterator_object* to TSRMLS_DC )
85 {
86 	if( !to )
87 		return;
88 
89 	if( to->utrans )
90 	{
91 		utrans_close( to->utrans );
92 		to->utrans = NULL;
93 	}
94 
95 	intl_error_reset( TRANSLITERATOR_ERROR_P( to ) TSRMLS_CC );
96 }
97 /* }}} */
98 
99 /* {{{ Transliterator_objects_dtor */
Transliterator_objects_dtor(void * object,zend_object_handle handle TSRMLS_DC)100 static void Transliterator_objects_dtor(
101 	void *object,
102 	zend_object_handle handle TSRMLS_DC )
103 {
104 	zend_objects_destroy_object( object, handle TSRMLS_CC );
105 }
106 /* }}} */
107 
108 /* {{{ Transliterator_objects_free */
Transliterator_objects_free(zend_object * object TSRMLS_DC)109 static void Transliterator_objects_free( zend_object *object TSRMLS_DC )
110 {
111 	Transliterator_object* to = (Transliterator_object*) object;
112 
113 	zend_object_std_dtor( &to->zo TSRMLS_CC );
114 
115 	transliterator_object_destroy( to TSRMLS_CC );
116 
117 	efree( to );
118 }
119 /* }}} */
120 
121 /* {{{ Transliterator_object_create */
Transliterator_object_create(zend_class_entry * ce TSRMLS_DC)122 static zend_object_value Transliterator_object_create(
123 	zend_class_entry *ce TSRMLS_DC )
124 {
125 	zend_object_value      retval;
126 	Transliterator_object* intern;
127 
128 	intern = ecalloc( 1, sizeof( Transliterator_object ) );
129 
130 	zend_object_std_init( &intern->zo, ce TSRMLS_CC );
131 #if PHP_VERSION_ID < 50399
132     zend_hash_copy( intern->zo.properties, &(ce->default_properties ),
133         (copy_ctor_func_t) zval_add_ref, NULL, sizeof( zval* ) );
134 #else
135     object_properties_init( (zend_object*) intern, ce );
136 #endif
137 	transliterator_object_init( intern TSRMLS_CC );
138 
139 	retval.handle = zend_objects_store_put(
140 		intern,
141 		Transliterator_objects_dtor,
142 		(zend_objects_free_object_storage_t) Transliterator_objects_free,
143 		NULL TSRMLS_CC );
144 
145 	retval.handlers = &Transliterator_handlers;
146 
147 	return retval;
148 }
149 /* }}} */
150 
151 /*
152  * Object handlers for Transliterator class (and subclasses)
153  */
154 
155 /* {{{ clone handler for Transliterator */
Transliterator_clone_obj(zval * object TSRMLS_DC)156 static zend_object_value Transliterator_clone_obj( zval *object TSRMLS_DC )
157 {
158 	Transliterator_object *to_orig,
159 	                      *to_new;
160 	zend_object_value     ret_val;
161 	intl_error_reset( NULL TSRMLS_CC );
162 
163 	to_orig = zend_object_store_get_object( object TSRMLS_CC );
164 	intl_error_reset( INTL_DATA_ERROR_P( to_orig ) TSRMLS_CC );
165 	ret_val = Transliterator_ce_ptr->create_object( Z_OBJCE_P( object ) TSRMLS_CC );
166 	to_new  = zend_object_store_get_object_by_handle( ret_val.handle TSRMLS_CC );
167 
168 	zend_objects_clone_members( &to_new->zo, ret_val,
169 		&to_orig->zo, Z_OBJ_HANDLE_P( object ) TSRMLS_CC );
170 
171 	if( to_orig->utrans != NULL )
172 	{
173 		UTransliterator *utrans = NULL;
174 		zval			tempz; /* dummy zval to pass to transliterator_object_construct */
175 
176 		/* guaranteed to return NULL if it fails */
177 		utrans = utrans_clone( to_orig->utrans, TRANSLITERATOR_ERROR_CODE_P( to_orig ) );
178 
179 		if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to_orig ) ) )
180 			goto err;
181 
182 		Z_OBJVAL( tempz ) = ret_val;
183 		transliterator_object_construct( &tempz, utrans,
184 			TRANSLITERATOR_ERROR_CODE_P( to_orig ) TSRMLS_CC );
185 
186 		if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to_orig ) ) )
187 		{
188 			char *err_msg;
189 err:
190 
191 			if( utrans != NULL )
192 				transliterator_object_destroy( to_new TSRMLS_CC );
193 
194 			/* set the error anyway, in case in the future we decide not to
195 			 * throw an error. It also helps build the error message */
196 			intl_error_set_code( NULL, INTL_DATA_ERROR_CODE( to_orig ) TSRMLS_CC );
197 			intl_errors_set_custom_msg( TRANSLITERATOR_ERROR_P( to_orig ),
198 				"Could not clone transliterator", 0 TSRMLS_CC );
199 
200 			err_msg = intl_error_get_message( TRANSLITERATOR_ERROR_P( to_orig ) TSRMLS_CC );
201 			php_error_docref( NULL TSRMLS_CC, E_ERROR, "%s", err_msg );
202 			efree( err_msg ); /* if it's changed into a warning */
203 			/* do not destroy tempz; we need to return something */
204 		}
205 	}
206 	else
207 	{
208 		/* We shouldn't have unconstructed objects in the first place */
209 		php_error_docref( NULL TSRMLS_CC, E_WARNING,
210 			"Cloning unconstructed transliterator." );
211 	}
212 
213 	return ret_val;
214 }
215 /* }}} */
216 
217 #if PHP_VERSION_ID >= 50399
218 # define TRANSLITERATOR_PROPERTY_HANDLER_PROLOG \
219 	zval tmp_member;							\
220 	if( Z_TYPE_P( member ) != IS_STRING )		\
221 	{											\
222 		tmp_member = *member;					\
223 		zval_copy_ctor( &tmp_member );			\
224 		convert_to_string( &tmp_member );		\
225 		member = &tmp_member;					\
226 		key = NULL;								\
227     }
228 #else
229 # define TRANSLITERATOR_PROPERTY_HANDLER_PROLOG \
230 	zval tmp_member;							\
231 	if( Z_TYPE_P( member ) != IS_STRING )		\
232 	{											\
233 		tmp_member = *member;					\
234 		zval_copy_ctor( &tmp_member );			\
235 		convert_to_string( &tmp_member );		\
236 		member = &tmp_member;					\
237     }
238 #endif
239 
240 #define TRANSLITERATOR_PROPERTY_HANDLER_EPILOG	\
241 	if( member == &tmp_member )				\
242 	{											\
243 		zval_dtor( &tmp_member );				\
244 	}
245 
246 /* {{{ get_property_ptr_ptr handler */
247 #if PHP_VERSION_ID < 50399
Transliterator_get_property_ptr_ptr(zval * object,zval * member TSRMLS_DC)248 static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member TSRMLS_DC )
249 #else
250 static zval **Transliterator_get_property_ptr_ptr( zval *object, zval *member,
251 	const struct _zend_literal *key TSRMLS_DC )
252 #endif
253 {
254 	zval **retval;
255 
256 	TRANSLITERATOR_PROPERTY_HANDLER_PROLOG;
257 
258 	if(zend_binary_strcmp( "id", sizeof( "id" ) - 1,
259 		Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 )
260 	{
261 		retval = NULL; /* fallback to read_property */
262 	}
263 	else
264 	{
265 #if PHP_VERSION_ID < 50399
266 		retval = std_object_handlers.get_property_ptr_ptr( object, member TSRMLS_CC );
267 #else
268 		retval = std_object_handlers.get_property_ptr_ptr( object, member, key TSRMLS_CC );
269 #endif
270 	}
271 
272 	TRANSLITERATOR_PROPERTY_HANDLER_EPILOG;
273 
274 	return retval;
275 }
276 /* }}} */
277 
278 /* {{{ read_property handler */
279 #if PHP_VERSION_ID < 50399
Transliterator_read_property(zval * object,zval * member,int type TSRMLS_DC)280 static zval *Transliterator_read_property( zval *object, zval *member, int type TSRMLS_DC ) /* {{{ */
281 #else
282 static zval *Transliterator_read_property( zval *object, zval *member, int type,
283 	const struct _zend_literal *key TSRMLS_DC ) /* {{{ */
284 #endif
285 {
286 	zval *retval;
287 
288 	TRANSLITERATOR_PROPERTY_HANDLER_PROLOG;
289 
290 	if( ( type != BP_VAR_R && type != BP_VAR_IS ) &&
291 		( zend_binary_strcmp( "id", sizeof( "id" ) - 1,
292 		Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) )
293 	{
294 		php_error_docref0( NULL TSRMLS_CC, E_WARNING, "The property \"id\" is read-only" );
295 		retval = &EG( uninitialized_zval );
296 	}
297 	else
298 	{
299 #if PHP_VERSION_ID < 50399
300 		retval = std_object_handlers.read_property( object, member, type TSRMLS_CC );
301 #else
302 		retval = std_object_handlers.read_property( object, member, type, key TSRMLS_CC );
303 #endif
304 	}
305 
306 	TRANSLITERATOR_PROPERTY_HANDLER_EPILOG;
307 
308 	return retval;
309 }
310 
311 /* }}} */
312 
313 /* {{{ write_property handler */
314 #if PHP_VERSION_ID < 50399
Transliterator_write_property(zval * object,zval * member,zval * value TSRMLS_DC)315 static void Transliterator_write_property( zval *object, zval *member, zval *value TSRMLS_DC )
316 #else
317 static void Transliterator_write_property( zval *object, zval *member, zval *value,
318 	const struct _zend_literal *key TSRMLS_DC )
319 #endif
320 {
321 	TRANSLITERATOR_PROPERTY_HANDLER_PROLOG;
322 
323 	if( ( EG( scope ) != Transliterator_ce_ptr ) &&
324 		( zend_binary_strcmp( "id", sizeof( "id" ) - 1,
325 		Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) )
326 	{
327 		php_error_docref0( NULL TSRMLS_CC, E_WARNING, "The property \"id\" is read-only" );
328 	}
329 	else
330 	{
331 #if PHP_VERSION_ID < 50399
332 		std_object_handlers.write_property( object, member, value TSRMLS_CC );
333 #else
334 		std_object_handlers.write_property( object, member, value, key TSRMLS_CC );
335 #endif
336 	}
337 
338 	TRANSLITERATOR_PROPERTY_HANDLER_EPILOG;
339 }
340 /* }}} */
341 
342 /*
343  * 'Transliterator' class registration structures & functions
344  */
345 
346 /* {{{ Transliterator methods arguments info */
347 
348 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_void, 0, 0, 0 )
349 ZEND_END_ARG_INFO()
350 
351 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_create, 0, 0, 1 )
352 	ZEND_ARG_INFO( 0, id )
353 	ZEND_ARG_INFO( 0, direction )
354 ZEND_END_ARG_INFO()
355 
356 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_create_from_rules, 0, 0, 1 )
357 	ZEND_ARG_INFO( 0, rules )
358 	ZEND_ARG_INFO( 0, direction )
359 ZEND_END_ARG_INFO()
360 
361 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_create_inverse, 0, 0, 1 )
362 	ZEND_ARG_OBJ_INFO( 0, orig_trans, Transliterator, 0 )
363 ZEND_END_ARG_INFO()
364 
365 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_me_transliterate, 0, 0, 1 )
366 	ZEND_ARG_INFO( 0, subject )
367 	ZEND_ARG_INFO( 0, start )
368 	ZEND_ARG_INFO( 0, end )
369 ZEND_END_ARG_INFO()
370 
371 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_error, 0, 0, 1 )
372 	ZEND_ARG_OBJ_INFO( 0, trans, Transliterator, 0 )
373 ZEND_END_ARG_INFO()
374 
375 /* }}} */
376 
377 /* {{{ Transliterator_class_functions
378  * Every 'Transliterator' class method has an entry in this table
379  */
380 zend_function_entry Transliterator_class_functions[] = {
381 	PHP_ME( Transliterator,			__construct,						ainfo_trans_void,				ZEND_ACC_PRIVATE | ZEND_ACC_CTOR | ZEND_ACC_FINAL )
382 	PHP_ME_MAPPING( create,			transliterator_create,				ainfo_trans_create,				ZEND_ACC_STATIC |ZEND_ACC_PUBLIC )
383 	PHP_ME_MAPPING( createFromRules,transliterator_create_from_rules,	ainfo_trans_create_from_rules,	ZEND_ACC_STATIC | ZEND_ACC_PUBLIC )
384 	PHP_ME_MAPPING( createInverse,	transliterator_create_inverse,		ainfo_trans_void,				ZEND_ACC_PUBLIC )
385 	PHP_ME_MAPPING( listIDs,		transliterator_list_ids,			ainfo_trans_void,				ZEND_ACC_STATIC | ZEND_ACC_PUBLIC )
386 	PHP_ME_MAPPING( transliterate,	transliterator_transliterate,		ainfo_trans_me_transliterate,	ZEND_ACC_PUBLIC )
387 	PHP_ME_MAPPING( getErrorCode,	transliterator_get_error_code,		ainfo_trans_void,				ZEND_ACC_PUBLIC )
388 	PHP_ME_MAPPING( getErrorMessage,transliterator_get_error_message,	ainfo_trans_void,				ZEND_ACC_PUBLIC )
389 	PHP_FE_END
390 };
391 /* }}} */
392 
393 /* {{{ transliterator_register_Transliterator_class
394  * Initialize 'Transliterator' class
395  */
transliterator_register_Transliterator_class(TSRMLS_D)396 void transliterator_register_Transliterator_class( TSRMLS_D )
397 {
398 	zend_class_entry ce;
399 
400 	/* Create and register 'Transliterator' class. */
401 	INIT_CLASS_ENTRY( ce, "Transliterator", Transliterator_class_functions );
402 	ce.create_object = Transliterator_object_create;
403 	Transliterator_ce_ptr = zend_register_internal_class( &ce TSRMLS_CC );
404 	memcpy( &Transliterator_handlers, zend_get_std_object_handlers(),
405 		sizeof Transliterator_handlers );
406 	Transliterator_handlers.clone_obj = Transliterator_clone_obj;
407 	Transliterator_handlers.get_property_ptr_ptr = Transliterator_get_property_ptr_ptr;
408 	Transliterator_handlers.read_property = Transliterator_read_property;
409 	Transliterator_handlers.write_property = Transliterator_write_property;
410 
411 	/* Declare 'Transliterator' class properties */
412 	if( !Transliterator_ce_ptr )
413 	{
414 		zend_error( E_ERROR,
415 			"Transliterator: attempt to create properties "
416 			"on a non-registered class." );
417 		return;
418 	}
419 	zend_declare_property_null( Transliterator_ce_ptr,
420 		"id", sizeof( "id" ) - 1, ZEND_ACC_PUBLIC TSRMLS_CC );
421 
422 	/* constants are declared in transliterator_register_constants, called from MINIT */
423 
424 }
425 /* }}} */
426 
427 /*
428  * Local variables:
429  * tab-width: 4
430  * c-basic-offset: 4
431  * End:
432  * vim600: noet sw=4 ts=4 fdm=marker
433  * vim<600: noet sw=4 ts=4
434  */
435