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    | http://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 	zval *retval;
193 
194 	if(zend_binary_strcmp( "id", sizeof( "id" ) - 1,
195 		ZSTR_VAL( name ), ZSTR_LEN( name ) ) == 0 )
196 	{
197 		retval = NULL; /* fallback to read_property */
198 	}
199 	else
200 	{
201 		retval = zend_std_get_property_ptr_ptr( object, name, type, cache_slot );
202 	}
203 
204 	return retval;
205 }
206 /* }}} */
207 
208 /* {{{ read_property handler */
Transliterator_read_property(zend_object * object,zend_string * name,int type,void ** cache_slot,zval * rv)209 static zval *Transliterator_read_property( zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv )
210 {
211 	zval *retval;
212 
213 	if( ( type != BP_VAR_R && type != BP_VAR_IS ) &&
214 		( zend_binary_strcmp( "id", sizeof( "id" ) - 1,
215 		ZSTR_VAL( name ), ZSTR_LEN( name ) ) == 0 ) )
216 	{
217 		zend_throw_error(NULL, "Transliterator::$id is read-only");
218 		retval = &EG( uninitialized_zval );
219 	}
220 	else
221 	{
222 		retval = zend_std_read_property( object, name, type, cache_slot, rv );
223 	}
224 
225 	return retval;
226 }
227 
228 /* }}} */
229 
230 /* {{{ write_property handler */
Transliterator_write_property(zend_object * object,zend_string * name,zval * value,void ** cache_slot)231 static zval *Transliterator_write_property( zend_object *object, zend_string *name, zval *value,
232 	void **cache_slot )
233 {
234 	zend_class_entry *scope;
235 
236 	if (EG(fake_scope)) {
237 		scope = EG(fake_scope);
238 	} else {
239 		scope = zend_get_executed_scope();
240 	}
241 	if( ( scope != Transliterator_ce_ptr ) &&
242 		( zend_binary_strcmp( "id", sizeof( "id" ) - 1,
243 		ZSTR_VAL( name ), ZSTR_LEN( name ) ) == 0 ) )
244 	{
245 		zend_throw_error(NULL, "Transliterator::$id is read-only");
246 	}
247 	else
248 	{
249 		value = zend_std_write_property( object, name, value, cache_slot );
250 	}
251 
252 	return value;
253 }
254 /* }}} */
255 
256 /* {{{ transliterator_register_Transliterator_class
257  * Initialize 'Transliterator' class
258  */
transliterator_register_Transliterator_class(void)259 void transliterator_register_Transliterator_class( void )
260 {
261 	zend_class_entry ce;
262 
263 	/* Create and register 'Transliterator' class. */
264 	INIT_CLASS_ENTRY( ce, "Transliterator", class_Transliterator_methods );
265 	ce.create_object = Transliterator_object_create;
266 	Transliterator_ce_ptr = zend_register_internal_class( &ce );
267 	memcpy( &Transliterator_handlers, &std_object_handlers,
268 		sizeof Transliterator_handlers );
269 	Transliterator_handlers.offset = XtOffsetOf(Transliterator_object, zo);
270 	Transliterator_handlers.free_obj = Transliterator_objects_free;
271 	Transliterator_handlers.clone_obj = Transliterator_clone_obj;
272 	Transliterator_handlers.get_property_ptr_ptr = Transliterator_get_property_ptr_ptr;
273 	Transliterator_handlers.read_property = Transliterator_read_property;
274 	Transliterator_handlers.write_property = Transliterator_write_property;
275 
276 	/* Declare 'Transliterator' class properties */
277 	if( !Transliterator_ce_ptr )
278 	{
279 		zend_error( E_ERROR,
280 			"Transliterator: attempt to create properties "
281 			"on a non-registered class." );
282 		return;
283 	}
284 	zend_declare_property_null( Transliterator_ce_ptr,
285 		"id", sizeof( "id" ) - 1, ZEND_ACC_PUBLIC );
286 
287 	/* constants are declared in transliterator_register_constants, called from MINIT */
288 
289 }
290 /* }}} */
291