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: Gustavo Lopes <cataphract@php.net> |
12 +----------------------------------------------------------------------+
13 */
14
15 #include "transliterator_class.h"
16 #include "php_intl.h"
17 #include "transliterator_arginfo.h"
18 #include "intl_error.h"
19 #include "intl_convert.h"
20 #include "intl_data.h"
21
22 #include <unicode/utrans.h>
23
24 zend_class_entry *Transliterator_ce_ptr = NULL;
25
26 zend_object_handlers Transliterator_handlers;
27
28 /* {{{ int transliterator_object_construct( zval *object, UTransliterator *utrans, UErrorCode *status )
29 * Initialize internals of Transliterator_object.
30 */
transliterator_object_construct(zval * object,UTransliterator * utrans,UErrorCode * status)31 int transliterator_object_construct( zval *object,
32 UTransliterator *utrans,
33 UErrorCode *status )
34 {
35 const UChar *ustr_id;
36 int32_t ustr_id_len;
37 zend_string *u8str;
38 zval tmp;
39 Transliterator_object *to;
40
41 TRANSLITERATOR_METHOD_FETCH_OBJECT_NO_CHECK;
42
43 assert( to->utrans == NULL );
44 /* this assignment must happen before any return with failure because the
45 * caller relies on it always being made (so it can just destroy the object
46 * to close the transliterator) */
47 to->utrans = utrans;
48
49 ustr_id = utrans_getUnicodeID( utrans, &ustr_id_len );
50 u8str = intl_convert_utf16_to_utf8(ustr_id, (int ) ustr_id_len, status );
51 if( !u8str )
52 {
53 return FAILURE;
54 }
55
56 ZVAL_NEW_STR(&tmp, u8str);
57 zend_update_property(Transliterator_ce_ptr, Z_OBJ_P(object),
58 "id", sizeof( "id" ) - 1, &tmp );
59 GC_DELREF(u8str);
60 return SUCCESS;
61 }
62 /* }}} */
63
64 /*
65 * Auxiliary functions needed by objects of 'Transliterator' class
66 */
67
68 /* {{{ void transliterator_object_init( Transliterator_object* to )
69 * Initialize internals of Transliterator_object.
70 */
transliterator_object_init(Transliterator_object * to)71 static void transliterator_object_init( Transliterator_object* to )
72 {
73 if( !to )
74 return;
75
76 intl_error_init( TRANSLITERATOR_ERROR_P( to ) );
77 }
78 /* }}} */
79
80 /* {{{ void transliterator_object_destroy( Transliterator_object* to )
81 * Clean up mem allocted by internals of Transliterator_object
82 */
transliterator_object_destroy(Transliterator_object * to)83 static void transliterator_object_destroy( Transliterator_object* to )
84 {
85 if( !to )
86 return;
87
88 if( to->utrans )
89 {
90 utrans_close( to->utrans );
91 to->utrans = NULL;
92 }
93
94 intl_error_reset( TRANSLITERATOR_ERROR_P( to ) );
95 }
96 /* }}} */
97
98 /* {{{ Transliterator_objects_free */
Transliterator_objects_free(zend_object * object)99 static void Transliterator_objects_free( zend_object *object )
100 {
101 Transliterator_object* to = php_intl_transliterator_fetch_object(object);
102
103 zend_object_std_dtor( &to->zo );
104
105 transliterator_object_destroy( to );
106 }
107 /* }}} */
108
109 /* {{{ Transliterator_object_create */
Transliterator_object_create(zend_class_entry * ce)110 static zend_object *Transliterator_object_create( zend_class_entry *ce )
111 {
112 Transliterator_object* intern;
113
114 intern = zend_object_alloc(sizeof(Transliterator_object), ce);
115
116 zend_object_std_init( &intern->zo, ce );
117 object_properties_init( &intern->zo, ce );
118 transliterator_object_init( intern );
119
120 intern->zo.handlers = &Transliterator_handlers;
121
122 return &intern->zo;
123 }
124 /* }}} */
125
126 /*
127 * Object handlers for Transliterator class (and subclasses)
128 */
129
130 /* {{{ clone handler for Transliterator */
Transliterator_clone_obj(zend_object * object)131 static zend_object *Transliterator_clone_obj( zend_object *object )
132 {
133 Transliterator_object *to_orig,
134 *to_new;
135 zend_object *ret_val;
136 intl_error_reset( NULL );
137
138 to_orig = php_intl_transliterator_fetch_object( object );
139 intl_error_reset( INTL_DATA_ERROR_P( to_orig ) );
140 ret_val = Transliterator_ce_ptr->create_object( object->ce );
141 to_new = php_intl_transliterator_fetch_object( ret_val );
142
143 zend_objects_clone_members( &to_new->zo, &to_orig->zo );
144
145 if( to_orig->utrans != NULL )
146 {
147 zval tempz; /* dummy zval to pass to transliterator_object_construct */
148
149 /* guaranteed to return NULL if it fails */
150 UTransliterator *utrans = utrans_clone( to_orig->utrans, TRANSLITERATOR_ERROR_CODE_P( to_orig ) );
151
152 if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to_orig ) ) )
153 goto err;
154
155 ZVAL_OBJ(&tempz, ret_val);
156 transliterator_object_construct( &tempz, utrans,
157 TRANSLITERATOR_ERROR_CODE_P( to_orig ) );
158
159 if( U_FAILURE( TRANSLITERATOR_ERROR_CODE( to_orig ) ) )
160 {
161 zend_string *err_msg;
162 err:
163
164 if( utrans != NULL )
165 transliterator_object_destroy( to_new );
166
167 /* set the error anyway, in case in the future we decide not to
168 * throw an error. It also helps build the error message */
169 intl_error_set_code( NULL, INTL_DATA_ERROR_CODE( to_orig ) );
170 intl_errors_set_custom_msg( TRANSLITERATOR_ERROR_P( to_orig ),
171 "Could not clone transliterator", 0 );
172
173 err_msg = intl_error_get_message( TRANSLITERATOR_ERROR_P( to_orig ) );
174 zend_throw_error( NULL, "%s", ZSTR_VAL(err_msg) );
175 zend_string_free( err_msg ); /* if it's changed into a warning */
176 /* do not destroy tempz; we need to return something */
177 }
178 }
179 else
180 {
181 /* We shouldn't have unconstructed objects in the first place */
182 zend_throw_error(NULL, "Unconstructed Transliterator object cannot be cloned");
183 }
184
185 return ret_val;
186 }
187 /* }}} */
188
189 /* {{{ get_property_ptr_ptr handler */
Transliterator_get_property_ptr_ptr(zend_object * object,zend_string * name,int type,void ** cache_slot)190 static zval *Transliterator_get_property_ptr_ptr( zend_object *object, zend_string *name, int type, void **cache_slot )
191 {
192 if (zend_string_equals_literal(name, "id")) {
193 return NULL; /* fallback to read_property */
194 }
195 return zend_std_get_property_ptr_ptr( object, name, type, cache_slot );
196 }
197 /* }}} */
198
199 /* {{{ read_property handler */
Transliterator_read_property(zend_object * object,zend_string * name,int type,void ** cache_slot,zval * rv)200 static zval *Transliterator_read_property( zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv )
201 {
202 zval *retval;
203
204 if ((type != BP_VAR_R && type != BP_VAR_IS) && zend_string_equals_literal(name, "id")) {
205 zend_throw_error(NULL, "Transliterator::$id is read-only");
206 retval = &EG( uninitialized_zval );
207 } else {
208 retval = zend_std_read_property( object, name, type, cache_slot, rv );
209 }
210
211 return retval;
212 }
213
214 /* }}} */
215
216 /* {{{ write_property handler */
Transliterator_write_property(zend_object * object,zend_string * name,zval * value,void ** cache_slot)217 static zval *Transliterator_write_property( zend_object *object, zend_string *name, zval *value,
218 void **cache_slot )
219 {
220 zend_class_entry *scope;
221
222 if (EG(fake_scope)) {
223 scope = EG(fake_scope);
224 } else {
225 scope = zend_get_executed_scope();
226 }
227 if ((scope != Transliterator_ce_ptr) && zend_string_equals_literal(name, "id")) {
228 zend_throw_error(NULL, "Transliterator::$id is read-only");
229 } else {
230 value = zend_std_write_property( object, name, value, cache_slot );
231 }
232
233 return value;
234 }
235 /* }}} */
236
237 /* {{{ transliterator_register_Transliterator_class
238 * Initialize 'Transliterator' class
239 */
transliterator_register_Transliterator_class(void)240 void transliterator_register_Transliterator_class( void )
241 {
242 /* Create and register 'Transliterator' class. */
243 Transliterator_ce_ptr = register_class_Transliterator();
244 Transliterator_ce_ptr->create_object = Transliterator_object_create;
245 memcpy( &Transliterator_handlers, &std_object_handlers, sizeof Transliterator_handlers );
246 Transliterator_handlers.offset = XtOffsetOf(Transliterator_object, zo);
247 Transliterator_handlers.free_obj = Transliterator_objects_free;
248 Transliterator_handlers.clone_obj = Transliterator_clone_obj;
249 Transliterator_handlers.get_property_ptr_ptr = Transliterator_get_property_ptr_ptr;
250 Transliterator_handlers.read_property = Transliterator_read_property;
251 Transliterator_handlers.write_property = Transliterator_write_property;
252
253 /* constants are declared in transliterator_register_constants, called from MINIT */
254
255 }
256 /* }}} */
257