1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
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 )
31  * Initialize internals of Transliterator_object.
32  */
transliterator_object_construct(zval * object,UTransliterator * utrans,UErrorCode * status)33 int transliterator_object_construct( zval *object,
34 									 UTransliterator *utrans,
35 									 UErrorCode *status )
36 {
37 	const UChar           *ustr_id;
38 	int32_t               ustr_id_len;
39 	zend_string           *u8str;
40 	zval                  tmp;
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 	u8str = intl_convert_utf16_to_utf8(ustr_id, (int ) ustr_id_len, status );
53 	if( !u8str )
54 	{
55 		return FAILURE;
56 	}
57 
58 	ZVAL_NEW_STR(&tmp, u8str);
59 	zend_update_property(Transliterator_ce_ptr, object,
60 		"id", sizeof( "id" ) - 1, &tmp );
61 	GC_REFCOUNT(u8str)--;
62 	return SUCCESS;
63 }
64 /* }}} */
65 
66 /*
67  * Auxiliary functions needed by objects of 'Transliterator' class
68  */
69 
70 /* {{{ void transliterator_object_init( Transliterator_object* to )
71  * Initialize internals of Transliterator_object.
72  */
transliterator_object_init(Transliterator_object * to)73 static void transliterator_object_init( Transliterator_object* to )
74 {
75 	if( !to )
76 		return;
77 
78 	intl_error_init( TRANSLITERATOR_ERROR_P( to ) );
79 }
80 /* }}} */
81 
82 /* {{{ void transliterator_object_destroy( Transliterator_object* to )
83  * Clean up mem allocted by internals of Transliterator_object
84  */
transliterator_object_destroy(Transliterator_object * to)85 static void transliterator_object_destroy( Transliterator_object* to )
86 {
87 	if( !to )
88 		return;
89 
90 	if( to->utrans )
91 	{
92 		utrans_close( to->utrans );
93 		to->utrans = NULL;
94 	}
95 
96 	intl_error_reset( TRANSLITERATOR_ERROR_P( to ) );
97 }
98 /* }}} */
99 
100 /* {{{ Transliterator_objects_dtor */
Transliterator_objects_dtor(zend_object * object)101 static void Transliterator_objects_dtor(
102 	zend_object *object )
103 {
104 	zend_objects_destroy_object( object );
105 }
106 /* }}} */
107 
108 /* {{{ Transliterator_objects_free */
Transliterator_objects_free(zend_object * object)109 static void Transliterator_objects_free( zend_object *object )
110 {
111 	Transliterator_object* to = php_intl_transliterator_fetch_object(object);
112 
113 	zend_object_std_dtor( &to->zo );
114 
115 	transliterator_object_destroy( to );
116 }
117 /* }}} */
118 
119 /* {{{ Transliterator_object_create */
Transliterator_object_create(zend_class_entry * ce)120 static zend_object *Transliterator_object_create(
121 	zend_class_entry *ce )
122 {
123 	Transliterator_object* intern;
124 
125 	intern = ecalloc( 1, sizeof( Transliterator_object ) + zend_object_properties_size(ce));
126 
127 	zend_object_std_init( &intern->zo, ce );
128     object_properties_init( &intern->zo, ce );
129 	transliterator_object_init( intern );
130 
131 	intern->zo.handlers = &Transliterator_handlers;
132 
133 	return &intern->zo;
134 }
135 /* }}} */
136 
137 /*
138  * Object handlers for Transliterator class (and subclasses)
139  */
140 
141 /* {{{ clone handler for Transliterator */
Transliterator_clone_obj(zval * object)142 static zend_object *Transliterator_clone_obj( zval *object )
143 {
144 	Transliterator_object *to_orig,
145 	                      *to_new;
146 	zend_object 		  *ret_val;
147 	intl_error_reset( NULL );
148 
149 	to_orig = Z_INTL_TRANSLITERATOR_P( object );
150 	intl_error_reset( INTL_DATA_ERROR_P( to_orig ) );
151 	ret_val = Transliterator_ce_ptr->create_object( Z_OBJCE_P( object ) );
152 	to_new  = php_intl_transliterator_fetch_object( ret_val );
153 
154 	zend_objects_clone_members( &to_new->zo, &to_orig->zo );
155 
156 	if( to_orig->utrans != NULL )
157 	{
158 		UTransliterator *utrans = NULL;
159 		zval			tempz; /* dummy zval to pass to transliterator_object_construct */
160 
161 		/* guaranteed to return NULL if it fails */
162 		utrans = utrans_clone( to_orig->utrans, TRANSLITERATOR_ERROR_CODE_P( to_orig ) );
163 
164 		if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to_orig ) ) )
165 			goto err;
166 
167 		ZVAL_OBJ(&tempz, ret_val);
168 		transliterator_object_construct( &tempz, utrans,
169 			TRANSLITERATOR_ERROR_CODE_P( to_orig ) );
170 
171 		if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to_orig ) ) )
172 		{
173 			zend_string *err_msg;
174 err:
175 
176 			if( utrans != NULL )
177 				transliterator_object_destroy( to_new );
178 
179 			/* set the error anyway, in case in the future we decide not to
180 			 * throw an error. It also helps build the error message */
181 			intl_error_set_code( NULL, INTL_DATA_ERROR_CODE( to_orig ) );
182 			intl_errors_set_custom_msg( TRANSLITERATOR_ERROR_P( to_orig ),
183 				"Could not clone transliterator", 0 );
184 
185 			err_msg = intl_error_get_message( TRANSLITERATOR_ERROR_P( to_orig ) );
186 			php_error_docref( NULL, E_ERROR, "%s", ZSTR_VAL(err_msg) );
187 			zend_string_free( err_msg ); /* if it's changed into a warning */
188 			/* do not destroy tempz; we need to return something */
189 		}
190 	}
191 	else
192 	{
193 		/* We shouldn't have unconstructed objects in the first place */
194 		php_error_docref( NULL, E_WARNING,
195 			"Cloning unconstructed transliterator." );
196 	}
197 
198 	return ret_val;
199 }
200 /* }}} */
201 
202 #define TRANSLITERATOR_PROPERTY_HANDLER_PROLOG  \
203 	zval tmp_member;							\
204 	if( Z_TYPE_P( member ) != IS_STRING )		\
205 	{											\
206 		tmp_member = *member;					\
207 		zval_copy_ctor( &tmp_member );			\
208 		convert_to_string( &tmp_member );		\
209 		member = &tmp_member;					\
210 		cache_slot = NULL;						\
211     }
212 
213 #define TRANSLITERATOR_PROPERTY_HANDLER_EPILOG	\
214 	if( member == &tmp_member )					\
215 	{											\
216 		zval_dtor( &tmp_member );				\
217 	}
218 
219 /* {{{ get_property_ptr_ptr handler */
Transliterator_get_property_ptr_ptr(zval * object,zval * member,int type,void ** cache_slot)220 static zval *Transliterator_get_property_ptr_ptr( zval *object, zval *member, int type, void **cache_slot )
221 {
222 	zval *retval;
223 
224 	TRANSLITERATOR_PROPERTY_HANDLER_PROLOG;
225 
226 	if(zend_binary_strcmp( "id", sizeof( "id" ) - 1,
227 		Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 )
228 	{
229 		retval = NULL; /* fallback to read_property */
230 	}
231 	else
232 	{
233 		retval = std_object_handlers.get_property_ptr_ptr( object, member, type, cache_slot );
234 	}
235 
236 	TRANSLITERATOR_PROPERTY_HANDLER_EPILOG;
237 
238 	return retval;
239 }
240 /* }}} */
241 
242 /* {{{ read_property handler */
Transliterator_read_property(zval * object,zval * member,int type,void ** cache_slot,zval * rv)243 static zval *Transliterator_read_property( zval *object, zval *member, int type, void **cache_slot, zval *rv )
244 {
245 	zval *retval;
246 
247 	TRANSLITERATOR_PROPERTY_HANDLER_PROLOG;
248 
249 	if( ( type != BP_VAR_R && type != BP_VAR_IS ) &&
250 		( zend_binary_strcmp( "id", sizeof( "id" ) - 1,
251 		Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) )
252 	{
253 		php_error_docref0( NULL, E_WARNING, "The property \"id\" is read-only" );
254 		retval = &EG( uninitialized_zval );
255 	}
256 	else
257 	{
258 		retval = std_object_handlers.read_property( object, member, type, cache_slot, rv );
259 	}
260 
261 	TRANSLITERATOR_PROPERTY_HANDLER_EPILOG;
262 
263 	return retval;
264 }
265 
266 /* }}} */
267 
268 /* {{{ write_property handler */
Transliterator_write_property(zval * object,zval * member,zval * value,void ** cache_slot)269 static void Transliterator_write_property( zval *object, zval *member, zval *value,
270 	void **cache_slot )
271 {
272 	TRANSLITERATOR_PROPERTY_HANDLER_PROLOG;
273 
274 	if( ( EG( scope ) != Transliterator_ce_ptr ) &&
275 		( zend_binary_strcmp( "id", sizeof( "id" ) - 1,
276 		Z_STRVAL_P( member ), Z_STRLEN_P( member ) ) == 0 ) )
277 	{
278 		php_error_docref0( NULL, E_WARNING, "The property \"id\" is read-only" );
279 	}
280 	else
281 	{
282 		std_object_handlers.write_property( object, member, value, cache_slot );
283 	}
284 
285 	TRANSLITERATOR_PROPERTY_HANDLER_EPILOG;
286 }
287 /* }}} */
288 
289 /*
290  * 'Transliterator' class registration structures & functions
291  */
292 
293 /* {{{ Transliterator methods arguments info */
294 
295 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_void, 0, 0, 0 )
296 ZEND_END_ARG_INFO()
297 
298 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_create, 0, 0, 1 )
299 	ZEND_ARG_INFO( 0, id )
300 	ZEND_ARG_INFO( 0, direction )
301 ZEND_END_ARG_INFO()
302 
303 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_create_from_rules, 0, 0, 1 )
304 	ZEND_ARG_INFO( 0, rules )
305 	ZEND_ARG_INFO( 0, direction )
306 ZEND_END_ARG_INFO()
307 
308 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_create_inverse, 0, 0, 1 )
309 	ZEND_ARG_OBJ_INFO( 0, orig_trans, Transliterator, 0 )
310 ZEND_END_ARG_INFO()
311 
312 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_me_transliterate, 0, 0, 1 )
313 	ZEND_ARG_INFO( 0, subject )
314 	ZEND_ARG_INFO( 0, start )
315 	ZEND_ARG_INFO( 0, end )
316 ZEND_END_ARG_INFO()
317 
318 ZEND_BEGIN_ARG_INFO_EX( ainfo_trans_error, 0, 0, 1 )
319 	ZEND_ARG_OBJ_INFO( 0, trans, Transliterator, 0 )
320 ZEND_END_ARG_INFO()
321 
322 /* }}} */
323 
324 /* {{{ Transliterator_class_functions
325  * Every 'Transliterator' class method has an entry in this table
326  */
327 zend_function_entry Transliterator_class_functions[] = {
328 	PHP_ME( Transliterator,			__construct,						ainfo_trans_void,				ZEND_ACC_PRIVATE | ZEND_ACC_CTOR | ZEND_ACC_FINAL )
329 	PHP_ME_MAPPING( create,			transliterator_create,				ainfo_trans_create,				ZEND_ACC_STATIC |ZEND_ACC_PUBLIC )
330 	PHP_ME_MAPPING( createFromRules,transliterator_create_from_rules,	ainfo_trans_create_from_rules,	ZEND_ACC_STATIC | ZEND_ACC_PUBLIC )
331 	PHP_ME_MAPPING( createInverse,	transliterator_create_inverse,		ainfo_trans_void,				ZEND_ACC_PUBLIC )
332 	PHP_ME_MAPPING( listIDs,		transliterator_list_ids,			ainfo_trans_void,				ZEND_ACC_STATIC | ZEND_ACC_PUBLIC )
333 	PHP_ME_MAPPING( transliterate,	transliterator_transliterate,		ainfo_trans_me_transliterate,	ZEND_ACC_PUBLIC )
334 	PHP_ME_MAPPING( getErrorCode,	transliterator_get_error_code,		ainfo_trans_void,				ZEND_ACC_PUBLIC )
335 	PHP_ME_MAPPING( getErrorMessage,transliterator_get_error_message,	ainfo_trans_void,				ZEND_ACC_PUBLIC )
336 	PHP_FE_END
337 };
338 /* }}} */
339 
340 /* {{{ transliterator_register_Transliterator_class
341  * Initialize 'Transliterator' class
342  */
transliterator_register_Transliterator_class(void)343 void transliterator_register_Transliterator_class( void )
344 {
345 	zend_class_entry ce;
346 
347 	/* Create and register 'Transliterator' class. */
348 	INIT_CLASS_ENTRY( ce, "Transliterator", Transliterator_class_functions );
349 	ce.create_object = Transliterator_object_create;
350 	Transliterator_ce_ptr = zend_register_internal_class( &ce );
351 	memcpy( &Transliterator_handlers, zend_get_std_object_handlers(),
352 		sizeof Transliterator_handlers );
353 	Transliterator_handlers.offset = XtOffsetOf(Transliterator_object, zo);
354 	Transliterator_handlers.dtor_obj = Transliterator_objects_dtor;
355 	Transliterator_handlers.free_obj = Transliterator_objects_free;
356 	Transliterator_handlers.clone_obj = Transliterator_clone_obj;
357 	Transliterator_handlers.get_property_ptr_ptr = Transliterator_get_property_ptr_ptr;
358 	Transliterator_handlers.read_property = Transliterator_read_property;
359 	Transliterator_handlers.write_property = Transliterator_write_property;
360 
361 	/* Declare 'Transliterator' class properties */
362 	if( !Transliterator_ce_ptr )
363 	{
364 		zend_error( E_ERROR,
365 			"Transliterator: attempt to create properties "
366 			"on a non-registered class." );
367 		return;
368 	}
369 	zend_declare_property_null( Transliterator_ce_ptr,
370 		"id", sizeof( "id" ) - 1, ZEND_ACC_PUBLIC );
371 
372 	/* constants are declared in transliterator_register_constants, called from MINIT */
373 
374 }
375 /* }}} */
376 
377 /*
378  * Local variables:
379  * tab-width: 4
380  * c-basic-offset: 4
381  * End:
382  * vim600: noet sw=4 ts=4 fdm=marker
383  * vim<600: noet sw=4 ts=4
384  */
385