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