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: Hans-Peter Oeri (University of St.Gallen) <hp@oeri.ch>      |
14    +----------------------------------------------------------------------+
15  */
16 
17 #include <php.h>
18 #include <zend.h>
19 #include <zend_API.h>
20 
21 #include "resourcebundle/resourcebundle.h"
22 #include "resourcebundle/resourcebundle_class.h"
23 #include "resourcebundle/resourcebundle_iterator.h"
24 
25 /*
26  * Although libicu offers iterator functions, they are not used here: libicu does iterate
27  * irrespective of array indices. Those cannot be recreated afterwards. Arrays as well as tables
28  * can however be accessed by numerical index, with table keys readable ex post.
29  */
30 
31 /* {{{ resourcebundle_iterator_read */
resourcebundle_iterator_read(ResourceBundle_iterator * iterator TSRMLS_DC)32 static void resourcebundle_iterator_read( ResourceBundle_iterator *iterator TSRMLS_DC )
33 {
34 	UErrorCode icuerror = U_ZERO_ERROR;
35 	ResourceBundle_object *rb = iterator->subject;
36 
37 	rb->child = ures_getByIndex( rb->me, iterator->i, rb->child, &icuerror );
38 
39 	if (U_SUCCESS(icuerror)) {
40 		/* ATTN: key extraction must be the first thing to do... rb->child might be reset in read! */
41 		if (iterator->is_table) {
42 			iterator->currentkey = estrdup( ures_getKey( rb->child ) );
43 		}
44 		MAKE_STD_ZVAL( iterator->current );
45 		resourcebundle_extract_value( iterator->current, rb TSRMLS_CC );
46 	}
47 	else {
48 		// zend_throw_exception( spl_ce_OutOfRangeException, "Running past end of ResourceBundle", 0 TSRMLS_CC);
49 		iterator->current = NULL;
50 	}
51 }
52 /* }}} */
53 
54 /* {{{ resourcebundle_iterator_invalidate */
resourcebundle_iterator_invalidate(zend_object_iterator * iter TSRMLS_DC)55 static void resourcebundle_iterator_invalidate( zend_object_iterator *iter TSRMLS_DC )
56 {
57 	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
58 
59 	if (iterator->current) {
60 		zval_ptr_dtor( &iterator->current );
61 		iterator->current = NULL;
62 	}
63 	if (iterator->currentkey) {
64 		efree( iterator->currentkey );
65 		iterator->currentkey = NULL;
66 	}
67 }
68 /* }}} */
69 
70 /* {{{ resourcebundle_iterator_dtor */
resourcebundle_iterator_dtor(zend_object_iterator * iter TSRMLS_DC)71 static void resourcebundle_iterator_dtor( zend_object_iterator *iter TSRMLS_DC )
72 {
73 	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
74 	zval                    *object = (zval *)iterator->intern.data;
75 
76 	resourcebundle_iterator_invalidate( iter TSRMLS_CC );
77 
78 	Z_DELREF_P(object);
79 
80 	efree(iterator);
81 }
82 /* }}} */
83 
84 /* {{{ resourcebundle_iterator_has_more */
resourcebundle_iterator_has_more(zend_object_iterator * iter TSRMLS_DC)85 static int resourcebundle_iterator_has_more( zend_object_iterator *iter TSRMLS_DC )
86 {
87 	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
88 	return (iterator->i < iterator->length) ? SUCCESS : FAILURE;
89 }
90 /* }}} */
91 
92 /* {{{ resourcebundle_iterator_current */
resourcebundle_iterator_current(zend_object_iterator * iter,zval *** data TSRMLS_DC)93 static void resourcebundle_iterator_current( zend_object_iterator *iter, zval ***data TSRMLS_DC )
94 {
95 	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
96 	if (!iterator->current) {
97 		resourcebundle_iterator_read( iterator TSRMLS_CC);
98 	}
99 	*data = &iterator->current;
100 }
101 /* }}} */
102 
103 /* {{{ resourcebundle_iterator_key */
resourcebundle_iterator_key(zend_object_iterator * iter,char ** str_key,uint * str_key_len,ulong * int_key TSRMLS_DC)104 static int resourcebundle_iterator_key( zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC )
105 {
106 	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
107 
108 	if (!iterator->current) {
109 		resourcebundle_iterator_read( iterator TSRMLS_CC);
110 	}
111 	if (iterator->is_table) {
112 		*str_key = estrdup( iterator->currentkey );
113 		*str_key_len = strlen( iterator->currentkey ) + 1;
114 		return HASH_KEY_IS_STRING;
115 	}
116 	else {
117 		*int_key = iterator->i;
118 		return HASH_KEY_IS_LONG;
119 	}
120 }
121 /* }}} */
122 
123 /* {{{ resourcebundle_iterator_has_more */
resourcebundle_iterator_step(zend_object_iterator * iter TSRMLS_DC)124 static void resourcebundle_iterator_step( zend_object_iterator *iter TSRMLS_DC )
125 {
126 	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
127 
128 	iterator->i++;
129 	resourcebundle_iterator_invalidate( iter TSRMLS_CC );
130 }
131 /* }}} */
132 
133 /* {{{ resourcebundle_iterator_has_reset */
resourcebundle_iterator_reset(zend_object_iterator * iter TSRMLS_DC)134 static void resourcebundle_iterator_reset( zend_object_iterator *iter TSRMLS_DC )
135 {
136 	ResourceBundle_iterator *iterator = (ResourceBundle_iterator *) iter;
137 
138 	iterator->i = 0;
139 	resourcebundle_iterator_invalidate( iter TSRMLS_CC );
140 }
141 /* }}} */
142 
143 /* {{{ resourcebundle_iterator_funcs */
144 static zend_object_iterator_funcs resourcebundle_iterator_funcs = {
145 	resourcebundle_iterator_dtor,
146 	resourcebundle_iterator_has_more,
147 	resourcebundle_iterator_current,
148 	resourcebundle_iterator_key,
149 	resourcebundle_iterator_step,
150 	resourcebundle_iterator_reset,
151 	resourcebundle_iterator_invalidate
152 };
153 /* }}} */
154 
155 /* {{{ resourcebundle_get_iterator */
resourcebundle_get_iterator(zend_class_entry * ce,zval * object,int byref TSRMLS_DC)156 zend_object_iterator *resourcebundle_get_iterator( zend_class_entry *ce, zval *object, int byref TSRMLS_DC )
157 {
158 	ResourceBundle_object   *rb = (ResourceBundle_object *) zend_object_store_get_object( object TSRMLS_CC );
159 	ResourceBundle_iterator *iterator = emalloc( sizeof( ResourceBundle_iterator ) );
160 
161 	if (byref) {
162 	     php_error( E_ERROR, "ResourceBundle does not support writable iterators" );
163 	}
164 
165 	Z_ADDREF_P(object);
166 	iterator->intern.data = (void *) object;
167 	iterator->intern.funcs = &resourcebundle_iterator_funcs;
168 
169 	iterator->subject = rb;
170 
171 	/* The iterated rb can only be either URES_TABLE or URES_ARRAY
172 	 * All other types are returned as php primitives!
173 	 */
174 	iterator->is_table = (ures_getType( rb->me ) == URES_TABLE);
175 	iterator->length = ures_getSize( rb->me );
176 
177 	iterator->current = NULL;
178 	iterator->currentkey = NULL;
179 	iterator->i = 0;
180 
181 	return (zend_object_iterator *) iterator;
182 }
183 /* }}} */
184 
185 /*
186  * Local variables:
187  * tab-width: 4
188  * c-basic-offset: 4
189  * End:
190  * vim600: noet sw=4 ts=4 fdm=marker
191  * vim<600: noet sw=4 ts=4
192  */
193