1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2007 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is SplSubject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Marcus Boerger <helly@php.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: spl_observer.c,v 1.2.2.6.2.3 2007/02/08 22:14:25 helly Exp $ */
20 :
21 : #ifdef HAVE_CONFIG_H
22 : # include "config.h"
23 : #endif
24 :
25 : #include "php.h"
26 : #include "php_ini.h"
27 : #include "ext/standard/info.h"
28 : #include "ext/standard/php_var.h"
29 : #include "ext/standard/php_smart_str.h"
30 : #include "zend_interfaces.h"
31 : #include "zend_exceptions.h"
32 :
33 : #include "php_spl.h"
34 : #include "spl_functions.h"
35 : #include "spl_engine.h"
36 : #include "spl_observer.h"
37 : #include "spl_iterators.h"
38 : #include "spl_array.h"
39 : #include "spl_exceptions.h"
40 :
41 : SPL_METHOD(SplObserver, update);
42 : SPL_METHOD(SplSubject, attach);
43 : SPL_METHOD(SplSubject, detach);
44 : SPL_METHOD(SplSubject, notify);
45 :
46 : static
47 : ZEND_BEGIN_ARG_INFO(arginfo_SplObserver_update, 0)
48 : ZEND_ARG_OBJ_INFO(0, SplSubject, SplSubject, 0)
49 : ZEND_END_ARG_INFO();
50 :
51 : static zend_function_entry spl_funcs_SplObserver[] = {
52 : SPL_ABSTRACT_ME(SplObserver, update, arginfo_SplObserver_update)
53 : {NULL, NULL, NULL}
54 : };
55 :
56 : static
57 : ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_attach, 0)
58 : ZEND_ARG_OBJ_INFO(0, SplObserver, SplObserver, 0)
59 : ZEND_END_ARG_INFO();
60 :
61 : /*static
62 : ZEND_BEGIN_ARG_INFO_EX(arginfo_SplSubject_notify, 0, 0, 1)
63 : ZEND_ARG_OBJ_INFO(0, ignore, SplObserver, 1)
64 : ZEND_END_ARG_INFO();*/
65 :
66 : static zend_function_entry spl_funcs_SplSubject[] = {
67 : SPL_ABSTRACT_ME(SplSubject, attach, arginfo_SplSubject_attach)
68 : SPL_ABSTRACT_ME(SplSubject, detach, arginfo_SplSubject_attach)
69 : SPL_ABSTRACT_ME(SplSubject, notify, NULL)
70 : {NULL, NULL, NULL}
71 : };
72 :
73 : PHPAPI zend_class_entry *spl_ce_SplObserver;
74 : PHPAPI zend_class_entry *spl_ce_SplSubject;
75 : PHPAPI zend_class_entry *spl_ce_SplObjectStorage;
76 : PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
77 :
78 : typedef struct _spl_SplObjectStorage {
79 : zend_object std;
80 : HashTable storage;
81 : long index;
82 : HashPosition pos;
83 : } spl_SplObjectStorage;
84 :
85 : /* storage is an assoc aray of [zend_object_value]=>[zval*] */
86 :
87 : void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */
88 0 : {
89 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage *)object;
90 :
91 0 : zend_object_std_dtor(&intern->std TSRMLS_CC);
92 :
93 0 : zend_hash_destroy(&intern->storage);
94 :
95 0 : efree(object);
96 0 : } /* }}} */
97 :
98 : static zend_object_value spl_object_storage_new_ex(zend_class_entry *class_type, spl_SplObjectStorage **obj, zval *orig TSRMLS_DC) /* {{{ */
99 0 : {
100 : zend_object_value retval;
101 : spl_SplObjectStorage *intern;
102 : zval *tmp;
103 :
104 0 : intern = emalloc(sizeof(spl_SplObjectStorage));
105 0 : memset(intern, 0, sizeof(spl_SplObjectStorage));
106 0 : *obj = intern;
107 :
108 0 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
109 0 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
110 :
111 0 : zend_hash_init(&intern->storage, 0, NULL, ZVAL_PTR_DTOR, 0);
112 :
113 0 : retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_SplOjectStorage_free_storage, NULL TSRMLS_CC);
114 0 : retval.handlers = &spl_handler_SplObjectStorage;
115 0 : return retval;
116 : }
117 : /* }}} */
118 :
119 : /* {{{ spl_array_object_new */
120 : static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type TSRMLS_DC)
121 0 : {
122 : spl_SplObjectStorage *tmp;
123 0 : return spl_object_storage_new_ex(class_type, &tmp, NULL TSRMLS_CC);
124 : }
125 : /* }}} */
126 :
127 : void spl_object_storage_attach(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
128 0 : {
129 : #if HAVE_PACKED_OBJECT_VALUE
130 0 : zend_hash_update(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value), &obj, sizeof(zval*), NULL);
131 : #else
132 : {
133 : zend_object_value zvalue;
134 : memset(&zvalue, 0, sizeof(zend_object_value));
135 : zvalue.handle = Z_OBJ_HANDLE_P(obj);
136 : zvalue.handlers = Z_OBJ_HT_P(obj);
137 : zend_hash_update(&intern->storage, (char*)&zvalue, sizeof(zend_object_value), &obj, sizeof(zval*), NULL);
138 : }
139 : #endif
140 :
141 0 : obj->refcount++;
142 0 : } /* }}} */
143 :
144 : /* {{{ proto void SplObjectStorage::attach($obj)
145 : Attaches an object to the storage if not yet contained */
146 : SPL_METHOD(SplObjectStorage, attach)
147 0 : {
148 : zval *obj;
149 :
150 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
151 :
152 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
153 0 : return;
154 : }
155 0 : spl_object_storage_attach(intern, obj TSRMLS_CC);
156 : } /* }}} */
157 :
158 : /* {{{ proto void SplObjectStorage::detach($obj)
159 : Detaches an object from the storage */
160 : SPL_METHOD(SplObjectStorage, detach)
161 0 : {
162 : zval *obj;
163 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
164 :
165 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
166 0 : return;
167 : }
168 :
169 : #if HAVE_PACKED_OBJECT_VALUE
170 0 : zend_hash_del(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value));
171 : #else
172 : {
173 : zend_object_value zvalue;
174 : memset(&zvalue, 0, sizeof(zend_object_value));
175 : zvalue.handle = Z_OBJ_HANDLE_P(obj);
176 : zvalue.handlers = Z_OBJ_HT_P(obj);
177 : zend_hash_del(&intern->storage, (char*)&zvalue, sizeof(zend_object_value));
178 : }
179 : #endif
180 :
181 0 : zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
182 0 : intern->index = 0;
183 : } /* }}} */
184 :
185 : /* {{{ proto bool SplObjectStorage::contains($obj)
186 : Determine whethe an object is contained in the storage */
187 : SPL_METHOD(SplObjectStorage, contains)
188 0 : {
189 : zval *obj;
190 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
191 :
192 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
193 0 : return;
194 : }
195 :
196 : #if HAVE_PACKED_OBJECT_VALUE
197 0 : RETURN_BOOL(zend_hash_exists(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value)));
198 : #else
199 : {
200 : zend_object_value zvalue;
201 : memset(&zvalue, 0, sizeof(zend_object_value));
202 : zvalue.handle = Z_OBJ_HANDLE_P(obj);
203 : zvalue.handlers = Z_OBJ_HT_P(obj);
204 : RETURN_BOOL(zend_hash_exists(&intern->storage, (char*)&zvalue, sizeof(zend_object_value)));
205 : }
206 : #endif
207 : } /* }}} */
208 :
209 : /* {{{ proto int SplObjectStorage::count()
210 : Determine number of objects in storage */
211 : SPL_METHOD(SplObjectStorage, count)
212 0 : {
213 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
214 :
215 0 : RETURN_LONG(zend_hash_num_elements(&intern->storage));
216 : } /* }}} */
217 :
218 : /* {{{ proto void SplObjectStorage::rewind()
219 : */
220 : SPL_METHOD(SplObjectStorage, rewind)
221 0 : {
222 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
223 :
224 0 : zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
225 0 : intern->index = 0;
226 0 : } /* }}} */
227 :
228 : /* {{{ proto bool SplObjectStorage::valid()
229 : */
230 : SPL_METHOD(SplObjectStorage, valid)
231 0 : {
232 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
233 :
234 0 : RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS);
235 : } /* }}} */
236 :
237 : /* {{{ proto mixed SplObjectStorage::key()
238 : */
239 : SPL_METHOD(SplObjectStorage, key)
240 0 : {
241 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
242 :
243 0 : RETURN_LONG(intern->index);
244 : } /* }}} */
245 :
246 : /* {{{ proto mixed SplObjectStorage::current()
247 : */
248 : SPL_METHOD(SplObjectStorage, current)
249 0 : {
250 : zval **entry;
251 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
252 :
253 0 : if (zend_hash_get_current_data_ex(&intern->storage, (void**)&entry, &intern->pos) == FAILURE) {
254 0 : return;
255 : }
256 0 : RETVAL_ZVAL(*entry, 1, 0);
257 : } /* }}} */
258 :
259 : /* {{{ proto void SplObjectStorage::next()
260 : */
261 : SPL_METHOD(SplObjectStorage, next)
262 0 : {
263 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
264 :
265 0 : zend_hash_move_forward_ex(&intern->storage, &intern->pos);
266 0 : intern->index++;
267 0 : } /* }}} */
268 :
269 : /* {{{ proto string SplObjectStorage::serialize()
270 : */
271 : SPL_METHOD(SplObjectStorage, serialize)
272 0 : {
273 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
274 :
275 : zval **entry, members, *pmembers;
276 : HashPosition pos;
277 : php_serialize_data_t var_hash;
278 0 : smart_str buf = {0};
279 :
280 0 : PHP_VAR_SERIALIZE_INIT(var_hash);
281 :
282 : /* storage */
283 0 : smart_str_appendl(&buf, "x:i:", 4);
284 0 : smart_str_append_long(&buf, zend_hash_num_elements(&intern->storage));
285 0 : smart_str_appendc(&buf, ';');
286 :
287 0 : zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
288 :
289 0 : while(zend_hash_has_more_elements_ex(&intern->storage, &pos) == SUCCESS) {
290 0 : if (zend_hash_get_current_data_ex(&intern->storage, (void**)&entry, &pos) == FAILURE) {
291 0 : smart_str_free(&buf);
292 0 : PHP_VAR_SERIALIZE_DESTROY(var_hash);
293 0 : RETURN_NULL();
294 : }
295 0 : php_var_serialize(&buf, entry, &var_hash TSRMLS_CC);
296 0 : smart_str_appendc(&buf, ';');
297 0 : zend_hash_move_forward_ex(&intern->storage, &pos);
298 : }
299 :
300 : /* members */
301 0 : smart_str_appendl(&buf, "m:", 2);
302 0 : INIT_PZVAL(&members);
303 0 : Z_ARRVAL(members) = intern->std.properties;
304 0 : Z_TYPE(members) = IS_ARRAY;
305 0 : pmembers = &members;
306 0 : php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
307 :
308 : /* done */
309 0 : PHP_VAR_SERIALIZE_DESTROY(var_hash);
310 :
311 0 : if (buf.c) {
312 0 : RETURN_STRINGL(buf.c, buf.len, 0);
313 : } else {
314 0 : RETURN_NULL();
315 : }
316 :
317 : } /* }}} */
318 :
319 : /* {{{ proto void SplObjectStorage::unserialize(string serialized)
320 : */
321 : SPL_METHOD(SplObjectStorage, unserialize)
322 0 : {
323 0 : spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
324 :
325 : char *buf;
326 : int buf_len;
327 : const unsigned char *p, *s;
328 : php_unserialize_data_t var_hash;
329 0 : zval *pentry, *pmembers, *pcount = NULL;
330 : long count;
331 :
332 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
333 0 : return;
334 : }
335 :
336 0 : if (buf_len == 0) {
337 0 : zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
338 0 : return;
339 : }
340 :
341 : /* storage */
342 0 : s = p = (const unsigned char*)buf;
343 0 : PHP_VAR_UNSERIALIZE_INIT(var_hash);
344 :
345 0 : if (*p!= 'x' || *++p != ':') {
346 : goto outexcept;
347 : }
348 0 : ++p;
349 :
350 0 : ALLOC_INIT_ZVAL(pcount);
351 0 : if (!php_var_unserialize(&pcount, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
352 0 : zval_ptr_dtor(&pcount);
353 0 : goto outexcept;
354 : }
355 :
356 0 : --p; /* for ';' */
357 0 : count = Z_LVAL_P(pcount);
358 0 : zval_ptr_dtor(&pcount);
359 :
360 0 : while(count-- > 0) {
361 0 : if (*p != ';') {
362 0 : goto outexcept;
363 : }
364 0 : ++p;
365 0 : ALLOC_INIT_ZVAL(pentry);
366 0 : if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) {
367 0 : zval_ptr_dtor(&pentry);
368 0 : goto outexcept;
369 : }
370 0 : spl_object_storage_attach(intern, pentry TSRMLS_CC);
371 0 : zval_ptr_dtor(&pentry);
372 : }
373 :
374 0 : if (*p != ';') {
375 0 : goto outexcept;
376 : }
377 0 : ++p;
378 :
379 : /* members */
380 0 : if (*p!= 'm' || *++p != ':') {
381 : goto outexcept;
382 : }
383 0 : ++p;
384 :
385 0 : ALLOC_INIT_ZVAL(pmembers);
386 0 : if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
387 0 : zval_ptr_dtor(&pmembers);
388 0 : goto outexcept;
389 : }
390 :
391 : /* copy members */
392 0 : zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
393 0 : zval_ptr_dtor(&pmembers);
394 :
395 : /* done reading $serialized */
396 :
397 0 : PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
398 0 : return;
399 :
400 0 : outexcept:
401 0 : PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
402 0 : zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
403 0 : return;
404 :
405 : } /* }}} */
406 :
407 : static
408 : ZEND_BEGIN_ARG_INFO(arginfo_Object, 0)
409 : ZEND_ARG_INFO(0, object)
410 : ZEND_END_ARG_INFO();
411 :
412 : static
413 : ZEND_BEGIN_ARG_INFO(arginfo_Serialized, 0)
414 : ZEND_ARG_INFO(0, serialized)
415 : ZEND_END_ARG_INFO();
416 :
417 : static zend_function_entry spl_funcs_SplObjectStorage[] = {
418 : SPL_ME(SplObjectStorage, attach, arginfo_Object, 0)
419 : SPL_ME(SplObjectStorage, detach, arginfo_Object, 0)
420 : SPL_ME(SplObjectStorage, contains, arginfo_Object, 0)
421 : SPL_ME(SplObjectStorage, count, NULL, 0)
422 : SPL_ME(SplObjectStorage, rewind, NULL, 0)
423 : SPL_ME(SplObjectStorage, valid, NULL, 0)
424 : SPL_ME(SplObjectStorage, key, NULL, 0)
425 : SPL_ME(SplObjectStorage, current, NULL, 0)
426 : SPL_ME(SplObjectStorage, next, NULL, 0)
427 : SPL_ME(SplObjectStorage, unserialize, arginfo_Serialized, 0)
428 : SPL_ME(SplObjectStorage, serialize, NULL, 0)
429 : {NULL, NULL, NULL}
430 : };
431 :
432 : /* {{{ PHP_MINIT_FUNCTION(spl_observer) */
433 : PHP_MINIT_FUNCTION(spl_observer)
434 220 : {
435 220 : REGISTER_SPL_INTERFACE(SplObserver);
436 220 : REGISTER_SPL_INTERFACE(SplSubject);
437 :
438 220 : REGISTER_SPL_STD_CLASS_EX(SplObjectStorage, spl_SplObjectStorage_new, spl_funcs_SplObjectStorage);
439 220 : memcpy(&spl_handler_SplObjectStorage, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
440 :
441 220 : REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Countable);
442 220 : REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Iterator);
443 220 : REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable);
444 :
445 220 : return SUCCESS;
446 : }
447 : /* }}} */
448 :
449 : /*
450 : * Local variables:
451 : * tab-width: 4
452 : * c-basic-offset: 4
453 : * End:
454 : * vim600: fdm=marker
455 : * vim: noet sw=4 ts=4
456 : */
|