~ufirst/phpredis/igbinary

« back to all changes in this revision

Viewing changes to igbinary-1.2.1/igbinary.c

  • Committer: Michael Ruoss
  • Date: 2015-03-18 14:12:19 UTC
  • Revision ID: git-v1:c591bdc61de714458440ff13454bc51d94ab5f3d
new build info structure

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  +----------------------------------------------------------------------+
 
3
  | See COPYING file for further copyright information                   |
 
4
  +----------------------------------------------------------------------+
 
5
  | Author: Oleg Grenrus <oleg.grenrus@dynamoid.com>                     |
 
6
  | See CREDITS for contributors                                         |
 
7
  +----------------------------------------------------------------------+
 
8
*/
 
9
 
 
10
#ifdef HAVE_CONFIG_H
 
11
#include "config.h"
 
12
#endif
 
13
 
 
14
#ifdef PHP_WIN32
 
15
# include "ig_win32.h"
 
16
#endif
 
17
 
 
18
#include "php.h"
 
19
#include "php_ini.h"
 
20
#include "zend_dynamic_array.h"
 
21
#include "zend_alloc.h"
 
22
#include "ext/standard/info.h"
 
23
#include "ext/standard/php_var.h"
 
24
 
 
25
#if HAVE_PHP_SESSION
 
26
# include "ext/session/php_session.h"
 
27
#endif /* HAVE_PHP_SESSION */
 
28
 
 
29
#include "ext/standard/php_incomplete_class.h"
 
30
 
 
31
#if defined(HAVE_APCU_SUPPORT)
 
32
# include "ext/apcu/apc_serializer.h"
 
33
#elif defined(HAVE_APC_SUPPORT)
 
34
# if USE_BUNDLED_APC
 
35
#  include "apc_serializer.h"
 
36
# else
 
37
#  include "ext/apc/apc_serializer.h"
 
38
# endif
 
39
#endif /* HAVE_APCU_SUPPORT || HAVE_APC_SUPPORT */
 
40
 
 
41
#include "php_igbinary.h"
 
42
 
 
43
#include "igbinary.h"
 
44
 
 
45
#include <assert.h>
 
46
 
 
47
#ifndef PHP_WIN32
 
48
# include <inttypes.h>
 
49
# include <stdbool.h>
 
50
# include <stdint.h>
 
51
#endif
 
52
 
 
53
 
 
54
#include <stddef.h>
 
55
#include "hash.h"
 
56
 
 
57
#if HAVE_PHP_SESSION
 
58
/** Session serializer function prototypes. */
 
59
PS_SERIALIZER_FUNCS(igbinary);
 
60
#endif /* HAVE_PHP_SESSION */
 
61
 
 
62
#if defined(HAVE_APC_SUPPORT) || defined(HAVE_APCU_SUPPORT)
 
63
/** Apc serializer function prototypes */
 
64
static int APC_SERIALIZER_NAME(igbinary) (APC_SERIALIZER_ARGS);
 
65
static int APC_UNSERIALIZER_NAME(igbinary) (APC_UNSERIALIZER_ARGS);
 
66
#endif
 
67
 
 
68
/* {{{ Types */
 
69
enum igbinary_type {
 
70
        /* 00 */ igbinary_type_null,                    /**< Null. */
 
71
 
 
72
        /* 01 */ igbinary_type_ref8,                    /**< Array reference. */
 
73
        /* 02 */ igbinary_type_ref16,                   /**< Array reference. */
 
74
        /* 03 */ igbinary_type_ref32,                   /**< Array reference. */
 
75
 
 
76
        /* 04 */ igbinary_type_bool_false,              /**< Boolean true. */
 
77
        /* 05 */ igbinary_type_bool_true,               /**< Boolean false. */
 
78
 
 
79
        /* 06 */ igbinary_type_long8p,                  /**< Long 8bit positive. */
 
80
        /* 07 */ igbinary_type_long8n,                  /**< Long 8bit negative. */
 
81
        /* 08 */ igbinary_type_long16p,                 /**< Long 16bit positive. */
 
82
        /* 09 */ igbinary_type_long16n,                 /**< Long 16bit negative. */
 
83
        /* 0a */ igbinary_type_long32p,                 /**< Long 32bit positive. */
 
84
        /* 0b */ igbinary_type_long32n,                 /**< Long 32bit negative. */
 
85
 
 
86
        /* 0c */ igbinary_type_double,                  /**< Double. */
 
87
 
 
88
        /* 0d */ igbinary_type_string_empty,    /**< Empty string. */
 
89
 
 
90
        /* 0e */ igbinary_type_string_id8,              /**< String id. */
 
91
        /* 0f */ igbinary_type_string_id16,             /**< String id. */
 
92
        /* 10 */ igbinary_type_string_id32,             /**< String id. */
 
93
 
 
94
        /* 11 */ igbinary_type_string8,                 /**< String. */
 
95
        /* 12 */ igbinary_type_string16,                /**< String. */
 
96
        /* 13 */ igbinary_type_string32,                /**< String. */
 
97
 
 
98
        /* 14 */ igbinary_type_array8,                  /**< Array. */
 
99
        /* 15 */ igbinary_type_array16,                 /**< Array. */
 
100
        /* 16 */ igbinary_type_array32,                 /**< Array. */
 
101
 
 
102
        /* 17 */ igbinary_type_object8,                 /**< Object. */
 
103
        /* 18 */ igbinary_type_object16,                /**< Object. */
 
104
        /* 19 */ igbinary_type_object32,                /**< Object. */
 
105
 
 
106
        /* 1a */ igbinary_type_object_id8,              /**< Object string id. */
 
107
        /* 1b */ igbinary_type_object_id16,             /**< Object string id. */
 
108
        /* 1c */ igbinary_type_object_id32,             /**< Object string id. */
 
109
 
 
110
        /* 1d */ igbinary_type_object_ser8,             /**< Object serialized data. */
 
111
        /* 1e */ igbinary_type_object_ser16,    /**< Object serialized data. */
 
112
        /* 1f */ igbinary_type_object_ser32,    /**< Object serialized data. */
 
113
 
 
114
        /* 20 */ igbinary_type_long64p,                 /**< Long 64bit positive. */
 
115
        /* 21 */ igbinary_type_long64n,                 /**< Long 64bit negative. */
 
116
 
 
117
        /* 22 */ igbinary_type_objref8,                 /**< Object reference. */
 
118
        /* 23 */ igbinary_type_objref16,                /**< Object reference. */
 
119
        /* 24 */ igbinary_type_objref32,                /**< Object reference. */
 
120
 
 
121
        /* 25 */ igbinary_type_ref,                             /**< Simple reference */
 
122
};
 
123
 
 
124
/** Serializer data.
 
125
 * @author Oleg Grenrus <oleg.grenrus@dynamoid.com>
 
126
 */
 
127
struct igbinary_serialize_data {
 
128
        uint8_t *buffer;                        /**< Buffer. */
 
129
        size_t buffer_size;                     /**< Buffer size. */
 
130
        size_t buffer_capacity;         /**< Buffer capacity. */
 
131
        bool scalar;                            /**< Serializing scalar. */
 
132
        bool compact_strings;           /**< Check for duplicate strings. */
 
133
        struct hash_si strings;         /**< Hash of already serialized strings. */
 
134
        struct hash_si objects;         /**< Hash of already serialized objects. */
 
135
        int string_count;                       /**< Serialized string count, used for back referencing */
 
136
        int error;                                      /**< Error number. Not used. */
 
137
        struct igbinary_memory_manager  mm; /**< Memory management functions. */
 
138
};
 
139
 
 
140
/** String/len pair for the igbinary_unserializer_data.
 
141
 * @author Oleg Grenrus <oleg.grenrus@dynamoid.com>
 
142
 * @see igbinary_unserialize_data.
 
143
 */
 
144
struct igbinary_unserialize_string_pair {
 
145
        char *data;             /**< Data. */
 
146
        size_t len;             /**< Data length. */
 
147
};
 
148
 
 
149
/** Unserializer data.
 
150
 * @author Oleg Grenrus <oleg.grenrus@dynamoid.com>
 
151
 */
 
152
struct igbinary_unserialize_data {
 
153
        uint8_t *buffer;                                /**< Buffer. */
 
154
        size_t buffer_size;                             /**< Buffer size. */
 
155
        size_t buffer_offset;                   /**< Current read offset. */
 
156
 
 
157
        struct igbinary_unserialize_string_pair *strings; /**< Unserialized strings. */
 
158
        size_t strings_count;                   /**< Unserialized string count. */
 
159
        size_t strings_capacity;                /**< Unserialized string array capacity. */
 
160
 
 
161
        void **references;                              /**< Unserialized Arrays/Objects. */
 
162
        size_t references_count;                /**< Unserialized array/objects count. */
 
163
        size_t references_capacity;             /**< Unserialized array/object array capacity. */
 
164
 
 
165
        int error;                                              /**< Error number. Not used. */
 
166
        smart_str string0_buf;                  /**< Temporary buffer for strings */
 
167
};
 
168
/* }}} */
 
169
/* {{{ Memory allocator wrapper prototypes */
 
170
static inline void *igbinary_mm_wrapper_malloc(size_t size, void *context);
 
171
static inline void *igbinary_mm_wrapper_realloc(void *ptr, size_t size, void *context);
 
172
static inline void igbinary_mm_wrapper_free(void *ptr, void *context);
 
173
/* }}} */
 
174
/* {{{ Serializing functions prototypes */
 
175
inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar, struct igbinary_memory_manager *memory_manager TSRMLS_DC);
 
176
inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd, int free_buffer TSRMLS_DC);
 
177
 
 
178
inline static int igbinary_serialize_header(struct igbinary_serialize_data *igsd TSRMLS_DC);
 
179
 
 
180
inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i TSRMLS_DC);
 
181
inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i TSRMLS_DC);
 
182
inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i TSRMLS_DC);
 
183
inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i TSRMLS_DC);
 
184
 
 
185
inline static int igbinary_serialize_null(struct igbinary_serialize_data *igsd TSRMLS_DC);
 
186
inline static int igbinary_serialize_bool(struct igbinary_serialize_data *igsd, int b TSRMLS_DC);
 
187
inline static int igbinary_serialize_long(struct igbinary_serialize_data *igsd, long l TSRMLS_DC);
 
188
inline static int igbinary_serialize_double(struct igbinary_serialize_data *igsd, double d TSRMLS_DC);
 
189
inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, char *s, size_t len TSRMLS_DC);
 
190
inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len TSRMLS_DC);
 
191
 
 
192
inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class TSRMLS_DC);
 
193
inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval *z, bool object TSRMLS_DC);
 
194
inline static int igbinary_serialize_array_sleep(struct igbinary_serialize_data *igsd, zval *z, HashTable *ht, zend_class_entry *ce, bool incomplete_class TSRMLS_DC);
 
195
inline static int igbinary_serialize_object_name(struct igbinary_serialize_data *igsd, const char *name, size_t name_len TSRMLS_DC);
 
196
inline static int igbinary_serialize_object(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC);
 
197
 
 
198
static int igbinary_serialize_zval(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC);
 
199
/* }}} */
 
200
/* {{{ Unserializing functions prototypes */
 
201
inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd TSRMLS_DC);
 
202
inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd TSRMLS_DC);
 
203
 
 
204
inline static int igbinary_unserialize_header(struct igbinary_unserialize_data *igsd TSRMLS_DC);
 
205
 
 
206
inline static uint8_t igbinary_unserialize8(struct igbinary_unserialize_data *igsd TSRMLS_DC);
 
207
inline static uint16_t igbinary_unserialize16(struct igbinary_unserialize_data *igsd TSRMLS_DC);
 
208
inline static uint32_t igbinary_unserialize32(struct igbinary_unserialize_data *igsd TSRMLS_DC);
 
209
inline static uint64_t igbinary_unserialize64(struct igbinary_unserialize_data *igsd TSRMLS_DC);
 
210
 
 
211
inline static int igbinary_unserialize_long(struct igbinary_unserialize_data *igsd, enum igbinary_type t, long *ret TSRMLS_DC);
 
212
inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, enum igbinary_type t, double *ret TSRMLS_DC);
 
213
inline static int igbinary_unserialize_string(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC);
 
214
inline static int igbinary_unserialize_chararray(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC);
 
215
 
 
216
inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, int object TSRMLS_DC);
 
217
inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC);
 
218
inline static int igbinary_unserialize_object_ser(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, zend_class_entry *ce TSRMLS_DC);
 
219
inline static int igbinary_unserialize_ref(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC);
 
220
 
 
221
static int igbinary_unserialize_zval(struct igbinary_unserialize_data *igsd, zval **z TSRMLS_DC);
 
222
/* }}} */
 
223
/* {{{ arginfo */
 
224
ZEND_BEGIN_ARG_INFO_EX(arginfo_igbinary_serialize, 0, 0, 1)
 
225
        ZEND_ARG_INFO(0, value)
 
226
ZEND_END_ARG_INFO()
 
227
 
 
228
ZEND_BEGIN_ARG_INFO_EX(arginfo_igbinary_unserialize, 0, 0, 1)
 
229
        ZEND_ARG_INFO(0, str)
 
230
ZEND_END_ARG_INFO()
 
231
/* }}} */
 
232
/* {{{ igbinary_functions[] */
 
233
/** Exported php functions. */
 
234
zend_function_entry igbinary_functions[] = {
 
235
        PHP_FE(igbinary_serialize,                arginfo_igbinary_serialize)
 
236
        PHP_FE(igbinary_unserialize,              arginfo_igbinary_unserialize)
 
237
        {NULL, NULL, NULL}
 
238
};
 
239
/* }}} */
 
240
 
 
241
/* {{{ igbinary dependencies */
 
242
#if ZEND_MODULE_API_NO >= 20050922
 
243
static const zend_module_dep igbinary_module_deps[] = {
 
244
        ZEND_MOD_REQUIRED("standard")
 
245
#ifdef HAVE_PHP_SESSION
 
246
        ZEND_MOD_REQUIRED("session")
 
247
#endif
 
248
#if defined(HAVE_APCU_SUPPORT)
 
249
        ZEND_MOD_OPTIONAL("apcu")
 
250
#elif defined(HAVE_APC_SUPPORT)
 
251
        ZEND_MOD_OPTIONAL("apc")
 
252
#endif
 
253
        {NULL, NULL, NULL}
 
254
};
 
255
#endif
 
256
/* }}} */
 
257
 
 
258
/* {{{ igbinary_module_entry */
 
259
zend_module_entry igbinary_module_entry = {
 
260
#if ZEND_MODULE_API_NO >= 20050922
 
261
        STANDARD_MODULE_HEADER_EX, NULL,
 
262
        igbinary_module_deps,
 
263
#elif ZEND_MODULE_API_NO >= 20010901
 
264
        STANDARD_MODULE_HEADER,
 
265
#endif
 
266
        "igbinary",
 
267
        igbinary_functions,
 
268
        PHP_MINIT(igbinary),
 
269
        PHP_MSHUTDOWN(igbinary),
 
270
        NULL,
 
271
        NULL,
 
272
        PHP_MINFO(igbinary),
 
273
#if ZEND_MODULE_API_NO >= 20010901
 
274
        PHP_IGBINARY_VERSION, /* Replace with version number for your extension */
 
275
#endif
 
276
        STANDARD_MODULE_PROPERTIES
 
277
};
 
278
/* }}} */
 
279
 
 
280
ZEND_DECLARE_MODULE_GLOBALS(igbinary)
 
281
 
 
282
/* {{{ ZEND_GET_MODULE */
 
283
#ifdef COMPILE_DL_IGBINARY
 
284
ZEND_GET_MODULE(igbinary)
 
285
#endif
 
286
/* }}} */
 
287
 
 
288
/* {{{ INI entries */
 
289
PHP_INI_BEGIN()
 
290
        STD_PHP_INI_BOOLEAN("igbinary.compact_strings", "1", PHP_INI_ALL, OnUpdateBool, compact_strings, zend_igbinary_globals, igbinary_globals)
 
291
PHP_INI_END()
 
292
/* }}} */
 
293
 
 
294
/* {{{ php_igbinary_init_globals */
 
295
static void php_igbinary_init_globals(zend_igbinary_globals *igbinary_globals) {
 
296
        igbinary_globals->compact_strings = 1;
 
297
}
 
298
/* }}} */
 
299
 
 
300
/* {{{ PHP_MINIT_FUNCTION */
 
301
PHP_MINIT_FUNCTION(igbinary) {
 
302
        (void) type;
 
303
        (void) module_number;
 
304
        ZEND_INIT_MODULE_GLOBALS(igbinary, php_igbinary_init_globals, NULL);
 
305
 
 
306
#if HAVE_PHP_SESSION
 
307
        php_session_register_serializer("igbinary",
 
308
                PS_SERIALIZER_ENCODE_NAME(igbinary),
 
309
                PS_SERIALIZER_DECODE_NAME(igbinary));
 
310
#endif
 
311
 
 
312
#if defined(HAVE_APC_SUPPORT) || defined(HAVE_APCU_SUPPORT)
 
313
        apc_register_serializer("igbinary",
 
314
                APC_SERIALIZER_NAME(igbinary),
 
315
                APC_UNSERIALIZER_NAME(igbinary),
 
316
                NULL TSRMLS_CC);
 
317
#endif
 
318
 
 
319
        REGISTER_INI_ENTRIES();
 
320
 
 
321
        return SUCCESS;
 
322
}
 
323
/* }}} */
 
324
/* {{{ PHP_MSHUTDOWN_FUNCTION */
 
325
PHP_MSHUTDOWN_FUNCTION(igbinary) {
 
326
        (void) type;
 
327
        (void) module_number;
 
328
 
 
329
#ifdef ZTS
 
330
        ts_free_id(igbinary_globals_id);
 
331
#endif
 
332
 
 
333
        /*
 
334
         * unregister serializer?
 
335
         */
 
336
        UNREGISTER_INI_ENTRIES();
 
337
 
 
338
        return SUCCESS;
 
339
}
 
340
/* }}} */
 
341
/* {{{ PHP_MINFO_FUNCTION */
 
342
PHP_MINFO_FUNCTION(igbinary) {
 
343
        (void) zend_module;
 
344
        php_info_print_table_start();
 
345
        php_info_print_table_row(2, "igbinary support", "enabled");
 
346
        php_info_print_table_row(2, "igbinary version", PHP_IGBINARY_VERSION);
 
347
#if defined(HAVE_APCU_SUPPORT)
 
348
        php_info_print_table_row(2, "igbinary APCU serializer ABI", APC_SERIALIZER_ABI);
 
349
#elif defined(HAVE_APC_SUPPORT)
 
350
        php_info_print_table_row(2, "igbinary APC serializer ABI", APC_SERIALIZER_ABI);
 
351
#else
 
352
        php_info_print_table_row(2, "igbinary APC serializer ABI", "no");
 
353
#endif
 
354
#if HAVE_PHP_SESSION
 
355
        php_info_print_table_row(2, "igbinary session support", "yes");
 
356
#else
 
357
        php_info_print_table_row(2, "igbinary session support", "no");
 
358
#endif
 
359
        php_info_print_table_end();
 
360
 
 
361
        DISPLAY_INI_ENTRIES();
 
362
}
 
363
/* }}} */
 
364
/* {{{ Memory allocator wrappers */
 
365
static inline void *igbinary_mm_wrapper_malloc(size_t size, void *context)
 
366
{
 
367
    return emalloc(size);
 
368
}
 
369
 
 
370
static inline void *igbinary_mm_wrapper_realloc(void *ptr, size_t size, void *context)
 
371
{
 
372
    return erealloc(ptr, size);
 
373
}
 
374
 
 
375
static inline void igbinary_mm_wrapper_free(void *ptr, void *context)
 
376
{
 
377
    return efree(ptr);
 
378
}
 
379
/* }}} */
 
380
/* {{{ int igbinary_serialize(uint8_t**, size_t*, zval*) */
 
381
IGBINARY_API int igbinary_serialize(uint8_t **ret, size_t *ret_len, zval *z TSRMLS_DC) {
 
382
        return igbinary_serialize_ex(ret, ret_len, z, NULL TSRMLS_CC);
 
383
}
 
384
/* }}} */
 
385
/* {{{ int igbinary_serialize_ex(uint8_t**, size_t*, zval*, igbinary_memory_manager*) */
 
386
IGBINARY_API int igbinary_serialize_ex(uint8_t **ret, size_t *ret_len, zval *z, struct igbinary_memory_manager *memory_manager TSRMLS_DC) {
 
387
        struct igbinary_serialize_data igsd;
 
388
        uint8_t *tmpbuf;
 
389
 
 
390
        if (igbinary_serialize_data_init(&igsd, Z_TYPE_P(z) != IS_OBJECT && Z_TYPE_P(z) != IS_ARRAY, memory_manager TSRMLS_CC)) {
 
391
                zend_error(E_WARNING, "igbinary_serialize: cannot init igsd");
 
392
                return 1;
 
393
        }
 
394
 
 
395
        if (igbinary_serialize_header(&igsd TSRMLS_CC) != 0) {
 
396
                zend_error(E_WARNING, "igbinary_serialize: cannot write header");
 
397
                igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
 
398
                return 1;
 
399
        }
 
400
 
 
401
        if (igbinary_serialize_zval(&igsd, z TSRMLS_CC) != 0) {
 
402
                igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
 
403
                return 1;
 
404
        }
 
405
 
 
406
        /* Explicit nul termination */
 
407
        if (igbinary_serialize8(&igsd, 0 TSRMLS_CC) != 0) {
 
408
                igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
 
409
                return 1;
 
410
        }
 
411
 
 
412
        /* shrink buffer to the real length, ignore errors */
 
413
        tmpbuf = (uint8_t *) igsd.mm.realloc(igsd.buffer, igsd.buffer_size, igsd.mm.context);
 
414
        if (tmpbuf != NULL) {
 
415
                igsd.buffer = tmpbuf;
 
416
        }
 
417
 
 
418
        /* Set return values */
 
419
        *ret_len = igsd.buffer_size - 1;
 
420
        *ret = igsd.buffer;
 
421
 
 
422
        igbinary_serialize_data_deinit(&igsd, 0 TSRMLS_CC);
 
423
 
 
424
        return 0;
 
425
}
 
426
/* }}} */
 
427
/* {{{ int igbinary_unserialize(const uint8_t *, size_t, zval **) */
 
428
IGBINARY_API int igbinary_unserialize(const uint8_t *buf, size_t buf_len, zval **z TSRMLS_DC) {
 
429
        struct igbinary_unserialize_data igsd;
 
430
 
 
431
        igbinary_unserialize_data_init(&igsd TSRMLS_CC);
 
432
 
 
433
        igsd.buffer = (uint8_t *) buf;
 
434
        igsd.buffer_size = buf_len;
 
435
 
 
436
        if (igbinary_unserialize_header(&igsd TSRMLS_CC)) {
 
437
                igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
 
438
                return 1;
 
439
        }
 
440
 
 
441
        if (igbinary_unserialize_zval(&igsd, z TSRMLS_CC)) {
 
442
                igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
 
443
                return 1;
 
444
        }
 
445
 
 
446
        igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
 
447
 
 
448
        return 0;
 
449
}
 
450
/* }}} */
 
451
/* {{{ proto string igbinary_unserialize(mixed value) */
 
452
PHP_FUNCTION(igbinary_unserialize) {
 
453
        char *string;
 
454
        int string_len;
 
455
 
 
456
        (void) return_value_ptr;
 
457
        (void) this_ptr;
 
458
        (void) return_value_used;
 
459
 
 
460
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &string_len) == FAILURE) {
 
461
                RETURN_NULL();
 
462
        }
 
463
 
 
464
        if (string_len <= 0) {
 
465
                RETURN_FALSE;
 
466
        }
 
467
 
 
468
        if (igbinary_unserialize((uint8_t *) string, string_len, &return_value TSRMLS_CC) != 0) {
 
469
                RETURN_NULL();
 
470
        }
 
471
}
 
472
/* }}} */
 
473
/* {{{ proto mixed igbinary_serialize(string value) */
 
474
PHP_FUNCTION(igbinary_serialize) {
 
475
        zval *z;
 
476
        uint8_t *string;
 
477
        size_t string_len;
 
478
 
 
479
        (void) return_value_ptr;
 
480
        (void) this_ptr;
 
481
        (void) return_value_used;
 
482
 
 
483
 
 
484
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &z) == FAILURE) {
 
485
                RETURN_NULL();
 
486
        }
 
487
 
 
488
        if (igbinary_serialize(&string, &string_len, z TSRMLS_CC) != 0) {
 
489
                RETURN_NULL();
 
490
        }
 
491
 
 
492
        RETVAL_STRINGL((char *)string, string_len, 0);
 
493
}
 
494
/* }}} */
 
495
#ifdef HAVE_PHP_SESSION
 
496
/* {{{ Serializer encode function */
 
497
PS_SERIALIZER_ENCODE_FUNC(igbinary)
 
498
{
 
499
        struct igbinary_serialize_data igsd;
 
500
        uint8_t *tmpbuf;
 
501
 
 
502
        if (igbinary_serialize_data_init(&igsd, false, NULL TSRMLS_CC)) {
 
503
                zend_error(E_WARNING, "igbinary_serialize: cannot init igsd");
 
504
                return FAILURE;
 
505
        }
 
506
 
 
507
        if (igbinary_serialize_header(&igsd TSRMLS_CC) != 0) {
 
508
                zend_error(E_WARNING, "igbinary_serialize: cannot write header");
 
509
                igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
 
510
                return FAILURE;
 
511
        }
 
512
 
 
513
        if (igbinary_serialize_array(&igsd, PS(http_session_vars), false, false TSRMLS_CC) != 0) {
 
514
                igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
 
515
                return FAILURE;
 
516
        }
 
517
 
 
518
        if (igbinary_serialize8(&igsd, 0 TSRMLS_CC) != 0) {
 
519
                igbinary_serialize_data_deinit(&igsd, 1 TSRMLS_CC);
 
520
                return FAILURE;
 
521
        }
 
522
 
 
523
        /* shrink buffer to the real length, ignore errors */
 
524
        tmpbuf = (uint8_t *)igsd.mm.realloc(igsd.buffer, igsd.buffer_size, igsd.mm.context);
 
525
        if (tmpbuf != NULL) {
 
526
                igsd.buffer = tmpbuf;
 
527
        }
 
528
 
 
529
        *newstr = (char *)igsd.buffer;
 
530
        if (newlen) {
 
531
                *newlen = igsd.buffer_size - 1;
 
532
        }
 
533
 
 
534
        igbinary_serialize_data_deinit(&igsd, 0 TSRMLS_CC);
 
535
 
 
536
        return SUCCESS;
 
537
}
 
538
/* }}} */
 
539
/* {{{ Serializer decode function */
 
540
PS_SERIALIZER_DECODE_FUNC(igbinary) {
 
541
        HashPosition tmp_hash_pos;
 
542
        HashTable *tmp_hash;
 
543
        char *key_str;
 
544
        ulong key_long;
 
545
        int tmp_int;
 
546
        uint key_len;
 
547
        zval *z;
 
548
        zval **d;
 
549
 
 
550
        struct igbinary_unserialize_data igsd;
 
551
 
 
552
        if (!val || vallen==0)
 
553
                return SUCCESS;
 
554
 
 
555
        if (igbinary_unserialize_data_init(&igsd TSRMLS_CC) != 0) {
 
556
                return FAILURE;
 
557
        }
 
558
 
 
559
        igsd.buffer = (uint8_t *)val;
 
560
        igsd.buffer_size = vallen;
 
561
 
 
562
        if (igbinary_unserialize_header(&igsd TSRMLS_CC)) {
 
563
                igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
 
564
                return FAILURE;
 
565
        }
 
566
 
 
567
        ALLOC_INIT_ZVAL(z);
 
568
        if (igbinary_unserialize_zval(&igsd, &z TSRMLS_CC)) {
 
569
                igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
 
570
                zval_dtor(z);
 
571
                FREE_ZVAL(z);
 
572
                return FAILURE;
 
573
        }
 
574
 
 
575
        igbinary_unserialize_data_deinit(&igsd TSRMLS_CC);
 
576
 
 
577
        tmp_hash = HASH_OF(z);
 
578
 
 
579
        zend_hash_internal_pointer_reset_ex(tmp_hash, &tmp_hash_pos);
 
580
        while (zend_hash_get_current_data_ex(tmp_hash, (void *) &d, &tmp_hash_pos) == SUCCESS) {
 
581
                tmp_int = zend_hash_get_current_key_ex(tmp_hash, &key_str, &key_len, &key_long, 0, &tmp_hash_pos);
 
582
 
 
583
                switch (tmp_int) {
 
584
                        case HASH_KEY_IS_LONG:
 
585
                                /* ??? */
 
586
                                break;
 
587
                        case HASH_KEY_IS_STRING:
 
588
                                php_set_session_var(key_str, key_len-1, *d, NULL TSRMLS_CC);
 
589
                                php_add_session_var(key_str, key_len-1 TSRMLS_CC);
 
590
                                break;
 
591
                }
 
592
                zend_hash_move_forward_ex(tmp_hash, &tmp_hash_pos);
 
593
        }
 
594
        zval_dtor(z);
 
595
        FREE_ZVAL(z);
 
596
 
 
597
        return SUCCESS;
 
598
}
 
599
/* }}} */
 
600
#endif /* HAVE_PHP_SESSION */
 
601
 
 
602
#if defined(HAVE_APC_SUPPORT) || defined(HAVE_APCU_SUPPORT)
 
603
/* {{{ apc_serialize function */
 
604
static int APC_SERIALIZER_NAME(igbinary) ( APC_SERIALIZER_ARGS ) {
 
605
        (void)config;
 
606
 
 
607
        if (igbinary_serialize(buf, buf_len, (zval *)value TSRMLS_CC) == 0) {
 
608
                /* flipped semantics */
 
609
                return 1;
 
610
        }
 
611
        return 0;
 
612
}
 
613
/* }}} */
 
614
/* {{{ apc_unserialize function */
 
615
static int APC_UNSERIALIZER_NAME(igbinary) ( APC_UNSERIALIZER_ARGS ) {
 
616
        (void)config;
 
617
 
 
618
        if (igbinary_unserialize(buf, buf_len, value TSRMLS_CC) == 0) {
 
619
                /* flipped semantics */
 
620
                return 1;
 
621
        }
 
622
        zval_dtor(*value);
 
623
        (*value)->type = IS_NULL;
 
624
        return 0;
 
625
}
 
626
/* }}} */
 
627
#endif
 
628
 
 
629
/* {{{ igbinary_serialize_data_init */
 
630
/** Inits igbinary_serialize_data. */
 
631
inline static int igbinary_serialize_data_init(struct igbinary_serialize_data *igsd, bool scalar, struct igbinary_memory_manager *memory_manager TSRMLS_DC) {
 
632
        int r = 0;
 
633
 
 
634
        if (memory_manager == NULL) {
 
635
                igsd->mm.alloc = igbinary_mm_wrapper_malloc;
 
636
                igsd->mm.realloc = igbinary_mm_wrapper_realloc;
 
637
                igsd->mm.free = igbinary_mm_wrapper_free;
 
638
                igsd->mm.context = NULL;
 
639
        } else {
 
640
                igsd->mm = *memory_manager;
 
641
        }
 
642
 
 
643
        igsd->buffer = NULL;
 
644
        igsd->buffer_size = 0;
 
645
        igsd->buffer_capacity = 32;
 
646
        igsd->string_count = 0;
 
647
        igsd->error = 0;
 
648
 
 
649
        igsd->buffer = (uint8_t *) igsd->mm.alloc(igsd->buffer_capacity, igsd->mm.context);
 
650
        if (igsd->buffer == NULL) {
 
651
                return 1;
 
652
        }
 
653
 
 
654
        igsd->scalar = scalar;
 
655
        if (!igsd->scalar) {
 
656
                hash_si_init(&igsd->strings, 16);
 
657
                hash_si_init(&igsd->objects, 16);
 
658
        }
 
659
 
 
660
        igsd->compact_strings = (bool)IGBINARY_G(compact_strings);
 
661
 
 
662
        return r;
 
663
}
 
664
/* }}} */
 
665
/* {{{ igbinary_serialize_data_deinit */
 
666
/** Deinits igbinary_serialize_data. */
 
667
inline static void igbinary_serialize_data_deinit(struct igbinary_serialize_data *igsd, int free_buffer TSRMLS_DC) {
 
668
        if (free_buffer && igsd->buffer) {
 
669
                igsd->mm.free(igsd->buffer, igsd->mm.context);
 
670
        }
 
671
 
 
672
        if (!igsd->scalar) {
 
673
                hash_si_deinit(&igsd->strings);
 
674
                hash_si_deinit(&igsd->objects);
 
675
        }
 
676
}
 
677
/* }}} */
 
678
/* {{{ igbinary_serialize_header */
 
679
/** Serializes header. */
 
680
inline static int igbinary_serialize_header(struct igbinary_serialize_data *igsd TSRMLS_DC) {
 
681
        return igbinary_serialize32(igsd, IGBINARY_FORMAT_VERSION TSRMLS_CC); /* version */
 
682
}
 
683
/* }}} */
 
684
/* {{{ igbinary_serialize_resize */
 
685
/** Expands igbinary_serialize_data. */
 
686
inline static int igbinary_serialize_resize(struct igbinary_serialize_data *igsd, size_t size TSRMLS_DC) {
 
687
        if (igsd->buffer_size + size < igsd->buffer_capacity) {
 
688
                return 0;
 
689
        }
 
690
 
 
691
        while (igsd->buffer_size + size >= igsd->buffer_capacity) {
 
692
                igsd->buffer_capacity *= 2;
 
693
        }
 
694
 
 
695
        igsd->buffer = (uint8_t *) igsd->mm.realloc(igsd->buffer, igsd->buffer_capacity, igsd->mm.context);
 
696
        if (igsd->buffer == NULL)
 
697
                return 1;
 
698
 
 
699
        return 0;
 
700
}
 
701
/* }}} */
 
702
/* {{{ igbinary_serialize8 */
 
703
/** Serialize 8bit value. */
 
704
inline static int igbinary_serialize8(struct igbinary_serialize_data *igsd, uint8_t i TSRMLS_DC) {
 
705
        if (igbinary_serialize_resize(igsd, 1 TSRMLS_CC)) {
 
706
                return 1;
 
707
        }
 
708
 
 
709
        igsd->buffer[igsd->buffer_size++] = i;
 
710
        return 0;
 
711
}
 
712
/* }}} */
 
713
/* {{{ igbinary_serialize16 */
 
714
/** Serialize 16bit value. */
 
715
inline static int igbinary_serialize16(struct igbinary_serialize_data *igsd, uint16_t i TSRMLS_DC) {
 
716
        if (igbinary_serialize_resize(igsd, 2 TSRMLS_CC)) {
 
717
                return 1;
 
718
        }
 
719
 
 
720
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 8 & 0xff);
 
721
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i & 0xff);
 
722
 
 
723
        return 0;
 
724
}
 
725
/* }}} */
 
726
/* {{{ igbinary_serialize32 */
 
727
/** Serialize 32bit value. */
 
728
inline static int igbinary_serialize32(struct igbinary_serialize_data *igsd, uint32_t i TSRMLS_DC) {
 
729
        if (igbinary_serialize_resize(igsd, 4 TSRMLS_CC)) {
 
730
                return 1;
 
731
        }
 
732
 
 
733
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 24 & 0xff);
 
734
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 16 & 0xff);
 
735
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 8 & 0xff);
 
736
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i & 0xff);
 
737
 
 
738
        return 0;
 
739
}
 
740
/* }}} */
 
741
/* {{{ igbinary_serialize64 */
 
742
/** Serialize 64bit value. */
 
743
inline static int igbinary_serialize64(struct igbinary_serialize_data *igsd, uint64_t i TSRMLS_DC) {
 
744
        if (igbinary_serialize_resize(igsd, 8 TSRMLS_CC)) {
 
745
                return 1;
 
746
        }
 
747
 
 
748
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 56 & 0xff);
 
749
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 48 & 0xff);
 
750
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 40 & 0xff);
 
751
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 32 & 0xff);
 
752
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 24 & 0xff);
 
753
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 16 & 0xff);
 
754
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i >> 8 & 0xff);
 
755
        igsd->buffer[igsd->buffer_size++] = (uint8_t) (i & 0xff);
 
756
 
 
757
        return 0;
 
758
}
 
759
/* }}} */
 
760
/* {{{ igbinary_serialize_null */
 
761
/** Serializes null. */
 
762
inline static int igbinary_serialize_null(struct igbinary_serialize_data *igsd TSRMLS_DC) {
 
763
        return igbinary_serialize8(igsd, igbinary_type_null TSRMLS_CC);
 
764
}
 
765
/* }}} */
 
766
/* {{{ igbinary_serialize_bool */
 
767
/** Serializes bool. */
 
768
inline static int igbinary_serialize_bool(struct igbinary_serialize_data *igsd, int b TSRMLS_DC) {
 
769
        return igbinary_serialize8(igsd, (uint8_t) (b ? igbinary_type_bool_true : igbinary_type_bool_false) TSRMLS_CC);
 
770
}
 
771
/* }}} */
 
772
/* {{{ igbinary_serialize_long */
 
773
/** Serializes long. */
 
774
inline static int igbinary_serialize_long(struct igbinary_serialize_data *igsd, long l TSRMLS_DC) {
 
775
        long k = l >= 0 ? l : -l;
 
776
        bool p = l >= 0 ? true : false;
 
777
 
 
778
        /* -LONG_MIN is 0 otherwise. */
 
779
        if (l == LONG_MIN) {
 
780
#if SIZEOF_LONG == 8
 
781
                if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_long64n TSRMLS_CC) != 0) {
 
782
                        return 1;
 
783
                }
 
784
 
 
785
                if (igbinary_serialize64(igsd, (uint64_t) 0x8000000000000000 TSRMLS_CC) != 0) {
 
786
                        return 1;
 
787
                }
 
788
#elif SIZEOF_LONG == 4
 
789
                if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_long32n TSRMLS_CC) != 0) {
 
790
                        return 1;
 
791
                }
 
792
                if (igbinary_serialize32(igsd, (uint32_t) 0x80000000 TSRMLS_CC) != 0) {
 
793
                        return 1;
 
794
                }
 
795
#else
 
796
#error "Strange sizeof(long)."
 
797
#endif
 
798
                return 0;
 
799
        }
 
800
 
 
801
        if (k <= 0xff) {
 
802
                if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long8p : igbinary_type_long8n) TSRMLS_CC) != 0) {
 
803
                        return 1;
 
804
                }
 
805
 
 
806
                if (igbinary_serialize8(igsd, (uint8_t) k TSRMLS_CC) != 0) {
 
807
                        return 1;
 
808
                }
 
809
        } else if (k <= 0xffff) {
 
810
                if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long16p : igbinary_type_long16n) TSRMLS_CC) != 0) {
 
811
                        return 1;
 
812
                }
 
813
 
 
814
                if (igbinary_serialize16(igsd, (uint16_t) k TSRMLS_CC) != 0) {
 
815
                        return 1;
 
816
                }
 
817
#if SIZEOF_LONG == 8
 
818
        } else if (k <= 0xffffffff) {
 
819
                if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long32p : igbinary_type_long32n) TSRMLS_CC) != 0) {
 
820
                        return 1;
 
821
                }
 
822
 
 
823
                if (igbinary_serialize32(igsd, (uint32_t) k TSRMLS_CC) != 0) {
 
824
                        return 1;
 
825
                }
 
826
        } else {
 
827
                if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long64p : igbinary_type_long64n) TSRMLS_CC) != 0) {
 
828
                        return 1;
 
829
                }
 
830
                if (igbinary_serialize64(igsd, (uint64_t) k TSRMLS_CC) != 0) {
 
831
                        return 1;
 
832
                }
 
833
        }
 
834
#elif SIZEOF_LONG == 4
 
835
        } else {
 
836
                if (igbinary_serialize8(igsd, (uint8_t) (p ? igbinary_type_long32p : igbinary_type_long32n) TSRMLS_CC) != 0) {
 
837
                        return 1;
 
838
                }
 
839
                if (igbinary_serialize32(igsd, (uint32_t) k TSRMLS_CC) != 0) {
 
840
                        return 1;
 
841
                }
 
842
        }
 
843
#else
 
844
#error "Strange sizeof(long)."
 
845
#endif
 
846
 
 
847
        return 0;
 
848
}
 
849
/* }}} */
 
850
/* {{{ igbinary_serialize_double */
 
851
/** Serializes double. */
 
852
inline static int igbinary_serialize_double(struct igbinary_serialize_data *igsd, double d TSRMLS_DC) {
 
853
        union {
 
854
                double d;
 
855
                uint64_t u;
 
856
        } u;
 
857
 
 
858
        if (igbinary_serialize8(igsd, igbinary_type_double TSRMLS_CC) != 0) {
 
859
                return 1;
 
860
        }
 
861
 
 
862
        u.d = d;
 
863
 
 
864
        return igbinary_serialize64(igsd, u.u TSRMLS_CC);
 
865
}
 
866
/* }}} */
 
867
/* {{{ igbinary_serialize_string */
 
868
/** Serializes string.
 
869
 * Serializes each string once, after first time uses pointers.
 
870
 */
 
871
inline static int igbinary_serialize_string(struct igbinary_serialize_data *igsd, char *s, size_t len TSRMLS_DC) {
 
872
        uint32_t t;
 
873
        uint32_t *i = &t;
 
874
 
 
875
        if (len == 0) {
 
876
                if (igbinary_serialize8(igsd, igbinary_type_string_empty TSRMLS_CC) != 0) {
 
877
                        return 1;
 
878
                }
 
879
 
 
880
                return 0;
 
881
        }
 
882
 
 
883
        if (igsd->scalar || !igsd->compact_strings || hash_si_find(&igsd->strings, s, len, i) == 1) {
 
884
                if (!igsd->scalar && igsd->compact_strings) {
 
885
                        hash_si_insert(&igsd->strings, s, len, igsd->string_count);
 
886
                }
 
887
 
 
888
                igsd->string_count += 1;
 
889
 
 
890
                if (igbinary_serialize_chararray(igsd, s, len TSRMLS_CC) != 0) {
 
891
                        return 1;
 
892
                }
 
893
        } else {
 
894
                if (*i <= 0xff) {
 
895
                        if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id8 TSRMLS_CC) != 0) {
 
896
                                return 1;
 
897
                        }
 
898
 
 
899
                        if (igbinary_serialize8(igsd, (uint8_t) *i TSRMLS_CC) != 0) {
 
900
                                return 1;
 
901
                        }
 
902
                } else if (*i <= 0xffff) {
 
903
                        if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id16 TSRMLS_CC) != 0) {
 
904
                                return 1;
 
905
                        }
 
906
 
 
907
                        if (igbinary_serialize16(igsd, (uint16_t) *i TSRMLS_CC) != 0) {
 
908
                                return 1;
 
909
                        }
 
910
                } else {
 
911
                        if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_string_id32 TSRMLS_CC) != 0) {
 
912
                                return 1;
 
913
                        }
 
914
 
 
915
                        if (igbinary_serialize32(igsd, (uint32_t) *i TSRMLS_CC) != 0) {
 
916
                                return 1;
 
917
                        }
 
918
                }
 
919
        }
 
920
 
 
921
        return 0;
 
922
}
 
923
/* }}} */
 
924
/* {{{ igbinary_serialize_chararray */
 
925
/** Serializes string data. */
 
926
inline static int igbinary_serialize_chararray(struct igbinary_serialize_data *igsd, const char *s, size_t len TSRMLS_DC) {
 
927
        if (len <= 0xff) {
 
928
                if (igbinary_serialize8(igsd, igbinary_type_string8 TSRMLS_CC) != 0) {
 
929
                        return 1;
 
930
                }
 
931
 
 
932
                if (igbinary_serialize8(igsd, len TSRMLS_CC) != 0) {
 
933
                        return 1;
 
934
                }
 
935
        } else if (len <= 0xffff) {
 
936
                if (igbinary_serialize8(igsd, igbinary_type_string16 TSRMLS_CC) != 0) {
 
937
                        return 1;
 
938
                }
 
939
 
 
940
                if (igbinary_serialize16(igsd, len TSRMLS_CC) != 0) {
 
941
                        return 1;
 
942
                }
 
943
        } else {
 
944
                if (igbinary_serialize8(igsd, igbinary_type_string32 TSRMLS_CC) != 0) {
 
945
                        return 1;
 
946
                }
 
947
 
 
948
                if (igbinary_serialize32(igsd, len TSRMLS_CC) != 0) {
 
949
                        return 1;
 
950
                }
 
951
        }
 
952
 
 
953
        if (igbinary_serialize_resize(igsd, len TSRMLS_CC)) {
 
954
                return 1;
 
955
        }
 
956
 
 
957
        memcpy(igsd->buffer+igsd->buffer_size, s, len);
 
958
        igsd->buffer_size += len;
 
959
 
 
960
        return 0;
 
961
}
 
962
/* }}} */
 
963
/* {{{ igbinay_serialize_array */
 
964
/** Serializes array or objects inner properties. */
 
965
inline static int igbinary_serialize_array(struct igbinary_serialize_data *igsd, zval *z, bool object, bool incomplete_class TSRMLS_DC) {
 
966
        HashTable *h;
 
967
        HashPosition pos;
 
968
        size_t n;
 
969
        zval **d;
 
970
 
 
971
        char *key;
 
972
        uint key_len;
 
973
        int key_type;
 
974
        ulong key_index;
 
975
 
 
976
        /* hash */
 
977
        h = object ? Z_OBJPROP_P(z) : HASH_OF(z);
 
978
 
 
979
        /* hash size */
 
980
        n = h ? zend_hash_num_elements(h) : 0;
 
981
 
 
982
        /* incomplete class magic member */
 
983
        if (n > 0 && incomplete_class) {
 
984
                --n;
 
985
        }
 
986
 
 
987
        if (!object && igbinary_serialize_array_ref(igsd, z, object TSRMLS_CC) == 0) {
 
988
                return 0;
 
989
        }
 
990
 
 
991
        if (n <= 0xff) {
 
992
                if (igbinary_serialize8(igsd, igbinary_type_array8 TSRMLS_CC) != 0) {
 
993
                        return 1;
 
994
                }
 
995
 
 
996
                if (igbinary_serialize8(igsd, n TSRMLS_CC) != 0) {
 
997
                        return 1;
 
998
                }
 
999
        } else if (n <= 0xffff) {
 
1000
                if (igbinary_serialize8(igsd, igbinary_type_array16 TSRMLS_CC) != 0) {
 
1001
                        return 1;
 
1002
                }
 
1003
 
 
1004
                if (igbinary_serialize16(igsd, n TSRMLS_CC) != 0) {
 
1005
                        return 1;
 
1006
                }
 
1007
        } else {
 
1008
                if (igbinary_serialize8(igsd, igbinary_type_array32 TSRMLS_CC) != 0) {
 
1009
                        return 1;
 
1010
                }
 
1011
 
 
1012
                if (igbinary_serialize32(igsd, n TSRMLS_CC) != 0) {
 
1013
                        return 1;
 
1014
                }
 
1015
        }
 
1016
 
 
1017
        if (n == 0) {
 
1018
                return 0;
 
1019
        }
 
1020
 
 
1021
        /* serialize properties. */
 
1022
        zend_hash_internal_pointer_reset_ex(h, &pos);
 
1023
        for (;; zend_hash_move_forward_ex(h, &pos)) {
 
1024
                key_type = zend_hash_get_current_key_ex(h, &key, &key_len, &key_index, 0, &pos);
 
1025
 
 
1026
                /* last */
 
1027
                if (key_type == HASH_KEY_NON_EXISTANT) {
 
1028
                        break;
 
1029
                }
 
1030
 
 
1031
                /* skip magic member in incomplete classes */
 
1032
                if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) {
 
1033
                        continue;
 
1034
                }
 
1035
 
 
1036
                switch (key_type) {
 
1037
                        case HASH_KEY_IS_LONG:
 
1038
                                if (igbinary_serialize_long(igsd, key_index TSRMLS_CC) != 0) {
 
1039
                                        return 1;
 
1040
                                }
 
1041
                                break;
 
1042
 
 
1043
                        case HASH_KEY_IS_STRING:
 
1044
                                if (igbinary_serialize_string(igsd, key, key_len-1 TSRMLS_CC) != 0) {
 
1045
                                        return 1;
 
1046
                                }
 
1047
                                break;
 
1048
 
 
1049
                        default:
 
1050
                                zend_error(E_ERROR, "igbinary_serialize_array: key is not string nor array");
 
1051
                                /* not reached */
 
1052
                                return 1;
 
1053
                }
 
1054
 
 
1055
                /* we should still add element even if it's not OK,
 
1056
                 * since we already wrote the length of the array before */
 
1057
                if (zend_hash_get_current_data_ex(h, (void *) &d, &pos) != SUCCESS || d == NULL) {
 
1058
                        if (igbinary_serialize_null(igsd TSRMLS_CC)) {
 
1059
                                return 1;
 
1060
                        }
 
1061
                } else {
 
1062
                        if (igbinary_serialize_zval(igsd, *d TSRMLS_CC)) {
 
1063
                                return 1;
 
1064
                        }
 
1065
                }
 
1066
        }
 
1067
 
 
1068
        return 0;
 
1069
}
 
1070
/* }}} */
 
1071
/* {{{ igbinary_serialize_array_ref */
 
1072
/** Serializes array reference. */
 
1073
inline static int igbinary_serialize_array_ref(struct igbinary_serialize_data *igsd, zval *z, bool object TSRMLS_DC) {
 
1074
        uint32_t t = 0;
 
1075
        uint32_t *i = &t;
 
1076
        union {
 
1077
                zval *z;
 
1078
                struct {
 
1079
                        zend_class_entry *ce;
 
1080
                        zend_object_handle handle;
 
1081
                } obj;
 
1082
        } key = { 0 };
 
1083
 
 
1084
        if (object && Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_class_entry) {
 
1085
                key.obj.ce = Z_OBJCE_P(z);
 
1086
                key.obj.handle = Z_OBJ_HANDLE_P(z);
 
1087
        } else {
 
1088
                key.z = z;
 
1089
        }
 
1090
 
 
1091
        if (hash_si_find(&igsd->objects, (char *)&key, sizeof(key), i) == 1) {
 
1092
                t = hash_si_size(&igsd->objects);
 
1093
                hash_si_insert(&igsd->objects, (char *)&key, sizeof(key), t);
 
1094
                return 1;
 
1095
        } else {
 
1096
                enum igbinary_type type;
 
1097
                if (*i <= 0xff) {
 
1098
                        type = object ? igbinary_type_objref8 : igbinary_type_ref8;
 
1099
                        if (igbinary_serialize8(igsd, (uint8_t) type TSRMLS_CC) != 0) {
 
1100
                                return 1;
 
1101
                        }
 
1102
 
 
1103
                        if (igbinary_serialize8(igsd, (uint8_t) *i TSRMLS_CC) != 0) {
 
1104
                                return 1;
 
1105
                        }
 
1106
                } else if (*i <= 0xffff) {
 
1107
                        type = object ? igbinary_type_objref16 : igbinary_type_ref16;
 
1108
                        if (igbinary_serialize8(igsd, (uint8_t) type TSRMLS_CC) != 0) {
 
1109
                                return 1;
 
1110
                        }
 
1111
 
 
1112
                        if (igbinary_serialize16(igsd, (uint16_t) *i TSRMLS_CC) != 0) {
 
1113
                                return 1;
 
1114
                        }
 
1115
                } else {
 
1116
                        type = object ? igbinary_type_objref32 : igbinary_type_ref32;
 
1117
                        if (igbinary_serialize8(igsd, (uint8_t) type TSRMLS_CC) != 0) {
 
1118
                                return 1;
 
1119
                        }
 
1120
 
 
1121
                        if (igbinary_serialize32(igsd, (uint32_t) *i TSRMLS_CC) != 0) {
 
1122
                                return 1;
 
1123
                        }
 
1124
                }
 
1125
 
 
1126
                return 0;
 
1127
        }
 
1128
 
 
1129
        return 1;
 
1130
}
 
1131
/* }}} */
 
1132
/* {{{ igbinary_serialize_array_sleep */
 
1133
/** Serializes object's properties array with __sleep -function. */
 
1134
inline static int igbinary_serialize_array_sleep(struct igbinary_serialize_data *igsd, zval *z, HashTable *h, zend_class_entry *ce, bool incomplete_class TSRMLS_DC) {
 
1135
        HashPosition pos;
 
1136
        size_t n = zend_hash_num_elements(h);
 
1137
        zval **d;
 
1138
        zval **v;
 
1139
 
 
1140
        char *key;
 
1141
        uint key_len;
 
1142
        int key_type;
 
1143
        ulong key_index;
 
1144
 
 
1145
        /* Decrease array size by one, because of magic member (with class name) */
 
1146
        if (n > 0 && incomplete_class) {
 
1147
                --n;
 
1148
        }
 
1149
 
 
1150
        /* Serialize array id. */
 
1151
        if (n <= 0xff) {
 
1152
                if (igbinary_serialize8(igsd, igbinary_type_array8 TSRMLS_CC) != 0) {
 
1153
                        return 1;
 
1154
                }
 
1155
 
 
1156
                if (igbinary_serialize8(igsd, n TSRMLS_CC) != 0) {
 
1157
                        return 1;
 
1158
                }
 
1159
        } else if (n <= 0xffff) {
 
1160
                if (igbinary_serialize8(igsd, igbinary_type_array16 TSRMLS_CC) != 0) {
 
1161
                        return 1;
 
1162
                }
 
1163
 
 
1164
                if (igbinary_serialize16(igsd, n TSRMLS_CC) != 0) {
 
1165
                        return 1;
 
1166
                }
 
1167
        } else {
 
1168
                if (igbinary_serialize8(igsd, igbinary_type_array32 TSRMLS_CC) != 0) {
 
1169
                        return 1;
 
1170
                }
 
1171
 
 
1172
                if (igbinary_serialize32(igsd, n TSRMLS_CC) != 0) {
 
1173
                        return 1;
 
1174
                }
 
1175
        }
 
1176
 
 
1177
        if (n == 0) {
 
1178
                return 0;
 
1179
        }
 
1180
 
 
1181
        zend_hash_internal_pointer_reset_ex(h, &pos);
 
1182
 
 
1183
        for (;; zend_hash_move_forward_ex(h, &pos)) {
 
1184
                key_type = zend_hash_get_current_key_ex(h, &key, &key_len, &key_index, 0, &pos);
 
1185
 
 
1186
                /* last */
 
1187
                if (key_type == HASH_KEY_NON_EXISTANT) {
 
1188
                        break;
 
1189
                }
 
1190
 
 
1191
                /* skip magic member in incomplete classes */
 
1192
                if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) {
 
1193
                        continue;
 
1194
                }
 
1195
 
 
1196
                if (zend_hash_get_current_data_ex(h, (void *) &d, &pos) != SUCCESS || d == NULL || Z_TYPE_PP(d) != IS_STRING) {
 
1197
                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only "
 
1198
                                        "containing the names of instance-variables to "
 
1199
                                        "serialize");
 
1200
 
 
1201
                        /* we should still add element even if it's not OK,
 
1202
                         * since we already wrote the length of the array before
 
1203
                         * serialize null as key-value pair */
 
1204
                        if (igbinary_serialize_null(igsd TSRMLS_CC) != 0) {
 
1205
                                return 1;
 
1206
                        }
 
1207
                } else {
 
1208
 
 
1209
                        if (zend_hash_find(Z_OBJPROP_P(z), Z_STRVAL_PP(d), Z_STRLEN_PP(d) + 1, (void *) &v) == SUCCESS) {
 
1210
                                if (igbinary_serialize_string(igsd, Z_STRVAL_PP(d), Z_STRLEN_PP(d) TSRMLS_CC) != 0) {
 
1211
                                        return 1;
 
1212
                                }
 
1213
 
 
1214
                                if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) {
 
1215
                                        return 1;
 
1216
                                }
 
1217
                        } else if (ce) {
 
1218
                                char *prot_name = NULL;
 
1219
                                char *priv_name = NULL;
 
1220
                                int prop_name_length;
 
1221
 
 
1222
                                do {
 
1223
                                        /* try private */
 
1224
                                        zend_mangle_property_name(&priv_name, &prop_name_length, ce->name, ce->name_length,
 
1225
                                                                Z_STRVAL_PP(d), Z_STRLEN_PP(d), ce->type & ZEND_INTERNAL_CLASS);
 
1226
                                        if (zend_hash_find(Z_OBJPROP_P(z), priv_name, prop_name_length+1, (void *) &v) == SUCCESS) {
 
1227
                                                if (igbinary_serialize_string(igsd, priv_name, prop_name_length TSRMLS_CC) != 0) {
 
1228
                                                        efree(priv_name);
 
1229
                                                        return 1;
 
1230
                                                }
 
1231
 
 
1232
                                                efree(priv_name);
 
1233
                                                if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) {
 
1234
                                                        return 1;
 
1235
                                                }
 
1236
                                                break;
 
1237
                                        }
 
1238
                                        efree(priv_name);
 
1239
 
 
1240
                                        /* try protected */
 
1241
                                        zend_mangle_property_name(&prot_name, &prop_name_length, "*", 1,
 
1242
                                                                Z_STRVAL_PP(d), Z_STRLEN_PP(d), ce->type & ZEND_INTERNAL_CLASS);
 
1243
                                        if (zend_hash_find(Z_OBJPROP_P(z), prot_name, prop_name_length+1, (void *) &v) == SUCCESS) {
 
1244
                                                if (igbinary_serialize_string(igsd, prot_name, prop_name_length TSRMLS_CC) != 0) {
 
1245
                                                        efree(prot_name);
 
1246
                                                        return 1;
 
1247
                                                }
 
1248
 
 
1249
                                                efree(prot_name);
 
1250
                                                if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) {
 
1251
                                                        return 1;
 
1252
                                                }
 
1253
                                                break;
 
1254
                                        }
 
1255
                                        efree(prot_name);
 
1256
 
 
1257
                                        /* no win */
 
1258
                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "\"%s\" returned as member variable from __sleep() but does not exist", Z_STRVAL_PP(d));
 
1259
                                        if (igbinary_serialize_string(igsd, Z_STRVAL_PP(d), Z_STRLEN_PP(d) TSRMLS_CC) != 0) {
 
1260
                                                return 1;
 
1261
                                        }
 
1262
 
 
1263
                                        if (igbinary_serialize_null(igsd TSRMLS_CC) != 0) {
 
1264
                                                return 1;
 
1265
                                        }
 
1266
                                } while (0);
 
1267
 
 
1268
                        } else {
 
1269
                                // if all else fails, just serialize the value in anyway.
 
1270
                                if (igbinary_serialize_string(igsd, Z_STRVAL_PP(d), Z_STRLEN_PP(d) TSRMLS_CC) != 0) {
 
1271
                                        return 1;
 
1272
                                }
 
1273
 
 
1274
                                if (igbinary_serialize_zval(igsd, *v TSRMLS_CC) != 0) {
 
1275
                                        return 1;
 
1276
                                }
 
1277
                        }
 
1278
                }
 
1279
        }
 
1280
 
 
1281
        return 0;
 
1282
}
 
1283
/* }}} */
 
1284
/* {{{ igbinary_serialize_object_name */
 
1285
/** Serialize object name. */
 
1286
inline static int igbinary_serialize_object_name(struct igbinary_serialize_data *igsd, const char *class_name, size_t name_len TSRMLS_DC) {
 
1287
        uint32_t t;
 
1288
        uint32_t *i = &t;
 
1289
 
 
1290
        if (hash_si_find(&igsd->strings, class_name, name_len, i) == 1) {
 
1291
                hash_si_insert(&igsd->strings, class_name, name_len, igsd->string_count);
 
1292
                igsd->string_count += 1;
 
1293
 
 
1294
                if (name_len <= 0xff) {
 
1295
                        if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object8 TSRMLS_CC) != 0) {
 
1296
                                return 1;
 
1297
                        }
 
1298
 
 
1299
                        if (igbinary_serialize8(igsd, (uint8_t) name_len TSRMLS_CC) != 0) {
 
1300
                                return 1;
 
1301
                        }
 
1302
                } else if (name_len <= 0xffff) {
 
1303
                        if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object16 TSRMLS_CC) != 0) {
 
1304
                                return 1;
 
1305
                        }
 
1306
 
 
1307
                        if (igbinary_serialize16(igsd, (uint16_t) name_len TSRMLS_CC) != 0) {
 
1308
                                return 1;
 
1309
                        }
 
1310
                } else {
 
1311
                        if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object32 TSRMLS_CC) != 0) {
 
1312
                                return 1;
 
1313
                        }
 
1314
 
 
1315
                        if (igbinary_serialize32(igsd, (uint32_t) name_len TSRMLS_CC) != 0) {
 
1316
                                return 1;
 
1317
                        }
 
1318
                }
 
1319
 
 
1320
                if (igbinary_serialize_resize(igsd, name_len TSRMLS_CC)) {
 
1321
                        return 1;
 
1322
                }
 
1323
 
 
1324
                memcpy(igsd->buffer+igsd->buffer_size, class_name, name_len);
 
1325
                igsd->buffer_size += name_len;
 
1326
        } else {
 
1327
                /* already serialized string */
 
1328
                if (*i <= 0xff) {
 
1329
                        if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id8 TSRMLS_CC) != 0) {
 
1330
                                return 1;
 
1331
                        }
 
1332
 
 
1333
                        if (igbinary_serialize8(igsd, (uint8_t) *i TSRMLS_CC) != 0) {
 
1334
                                return 1;
 
1335
                        }
 
1336
                } else if (*i <= 0xffff) {
 
1337
                        if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id16 TSRMLS_CC) != 0) {
 
1338
                                return 1;
 
1339
                        }
 
1340
 
 
1341
                        if (igbinary_serialize16(igsd, (uint16_t) *i TSRMLS_CC) != 0) {
 
1342
                                return 1;
 
1343
                        }
 
1344
                } else {
 
1345
                        if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_id32 TSRMLS_CC) != 0) {
 
1346
                                return 1;
 
1347
                        }
 
1348
 
 
1349
                        if (igbinary_serialize32(igsd, (uint32_t) *i TSRMLS_CC) != 0) {
 
1350
                                return 1;
 
1351
                        }
 
1352
                }
 
1353
        }
 
1354
 
 
1355
        return 0;
 
1356
}
 
1357
/* }}} */
 
1358
/* {{{ igbinary_serialize_object */
 
1359
/** Serialize object.
 
1360
 * @see ext/standard/var.c
 
1361
 * */
 
1362
inline static int igbinary_serialize_object(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC) {
 
1363
        zend_class_entry *ce;
 
1364
 
 
1365
        zval f;
 
1366
        zval *h = NULL;
 
1367
 
 
1368
        int r = 0;
 
1369
 
 
1370
        unsigned char *serialized_data = NULL;
 
1371
        zend_uint serialized_len;
 
1372
 
 
1373
        PHP_CLASS_ATTRIBUTES;
 
1374
 
 
1375
        if (igbinary_serialize_array_ref(igsd, z, true TSRMLS_CC) == 0) {
 
1376
                return r;
 
1377
        }
 
1378
 
 
1379
        ce = Z_OBJCE_P(z);
 
1380
 
 
1381
        /* custom serializer */
 
1382
        if (ce && ce->serialize != NULL) {
 
1383
                if (ce->serialize(z, &serialized_data, &serialized_len, (zend_serialize_data *)NULL TSRMLS_CC) == SUCCESS && !EG(exception)) {
 
1384
                        if (igbinary_serialize_object_name(igsd, ce->name, ce->name_length TSRMLS_CC) != 0) {
 
1385
                                if (serialized_data) {
 
1386
                                        efree(serialized_data);
 
1387
                                }
 
1388
                                return 1;
 
1389
                        }
 
1390
 
 
1391
 
 
1392
                        if (serialized_len <= 0xff) {
 
1393
                                if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser8 TSRMLS_CC) != 0) {
 
1394
                                        if (serialized_data) {
 
1395
                                                efree(serialized_data);
 
1396
                                        }
 
1397
                                        return 1;
 
1398
                                }
 
1399
 
 
1400
                                if (igbinary_serialize8(igsd, (uint8_t) serialized_len TSRMLS_CC) != 0) {
 
1401
                                        if (serialized_data) {
 
1402
                                                efree(serialized_data);
 
1403
                                        }
 
1404
                                        return 1;
 
1405
                                }
 
1406
                        } else if (serialized_len <= 0xffff) {
 
1407
                                if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser16 TSRMLS_CC) != 0) {
 
1408
                                        if (serialized_data) {
 
1409
                                                efree(serialized_data);
 
1410
                                        }
 
1411
                                        return 1;
 
1412
                                }
 
1413
 
 
1414
                                if (igbinary_serialize16(igsd, (uint16_t) serialized_len TSRMLS_CC) != 0) {
 
1415
                                        if (serialized_data) {
 
1416
                                                efree(serialized_data);
 
1417
                                        }
 
1418
                                        return 1;
 
1419
                                }
 
1420
                        } else {
 
1421
                                if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_object_ser32 TSRMLS_CC) != 0) {
 
1422
                                        if (serialized_data) {
 
1423
                                                efree(serialized_data);
 
1424
                                        }
 
1425
                                        return 1;
 
1426
                                }
 
1427
 
 
1428
                                if (igbinary_serialize32(igsd, (uint32_t) serialized_len TSRMLS_CC) != 0) {
 
1429
                                        if (serialized_data) {
 
1430
                                                efree(serialized_data);
 
1431
                                        }
 
1432
                                        return 1;
 
1433
                                }
 
1434
                        }
 
1435
 
 
1436
                        if (igbinary_serialize_resize(igsd, serialized_len TSRMLS_CC)) {
 
1437
                                if (serialized_data) {
 
1438
                                        efree(serialized_data);
 
1439
                                }
 
1440
 
 
1441
                                return 1;
 
1442
                        }
 
1443
 
 
1444
                        memcpy(igsd->buffer+igsd->buffer_size, serialized_data, serialized_len);
 
1445
                        igsd->buffer_size += serialized_len;
 
1446
                } else if (EG(exception)) {
 
1447
                        /* exception, return failure */
 
1448
                        r = 1;
 
1449
                } else {
 
1450
                        /* Serialization callback failed, assume null output */
 
1451
                        r = igbinary_serialize_null(igsd TSRMLS_CC);
 
1452
                }
 
1453
 
 
1454
                if (serialized_data) {
 
1455
                        efree(serialized_data);
 
1456
                }
 
1457
 
 
1458
                return r;
 
1459
        }
 
1460
 
 
1461
        /* serialize class name */
 
1462
        PHP_SET_CLASS_ATTRIBUTES(z);
 
1463
        if (igbinary_serialize_object_name(igsd, class_name, name_len TSRMLS_CC) != 0) {
 
1464
                PHP_CLEANUP_CLASS_ATTRIBUTES();
 
1465
                return 1;
 
1466
        }
 
1467
        PHP_CLEANUP_CLASS_ATTRIBUTES();
 
1468
 
 
1469
        if (ce && ce != PHP_IC_ENTRY && zend_hash_exists(&ce->function_table, "__sleep", sizeof("__sleep"))) {
 
1470
                /* function name string */
 
1471
                INIT_PZVAL(&f);
 
1472
                ZVAL_STRINGL(&f, "__sleep", sizeof("__sleep") - 1, 0);
 
1473
 
 
1474
                /* calling z->__sleep */
 
1475
                r = call_user_function_ex(CG(function_table), &z, &f, &h, 0, 0, 1, NULL TSRMLS_CC);
 
1476
 
 
1477
                if (r == SUCCESS && !EG(exception)) {
 
1478
                        r = 0;
 
1479
 
 
1480
                        if (h) {
 
1481
                                if (Z_TYPE_P(h) == IS_ARRAY) {
 
1482
                                        r = igbinary_serialize_array_sleep(igsd, z, HASH_OF(h), ce, incomplete_class TSRMLS_CC);
 
1483
                                } else {
 
1484
                                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "__sleep should return an array only "
 
1485
                                                        "containing the names of instance-variables to "
 
1486
                                                        "serialize");
 
1487
 
 
1488
                                        /* empty array */
 
1489
                                        r = igbinary_serialize8(igsd, igbinary_type_array8 TSRMLS_CC);
 
1490
                                        if (r == 0) {
 
1491
                                                r = igbinary_serialize8(igsd, 0 TSRMLS_CC);
 
1492
                                        }
 
1493
                                }
 
1494
                        }
 
1495
                } else {
 
1496
                        r = 1;
 
1497
                }
 
1498
 
 
1499
                /* cleanup */
 
1500
                if (h) {
 
1501
                        zval_ptr_dtor(&h);
 
1502
                }
 
1503
 
 
1504
                return r;
 
1505
        } else {
 
1506
                return igbinary_serialize_array(igsd, z, true, incomplete_class TSRMLS_CC);
 
1507
        }
 
1508
}
 
1509
/* }}} */
 
1510
/* {{{ igbinary_serialize_zval */
 
1511
/** Serialize zval. */
 
1512
static int igbinary_serialize_zval(struct igbinary_serialize_data *igsd, zval *z TSRMLS_DC) {
 
1513
        if (Z_ISREF_P(z)) {
 
1514
                if (igbinary_serialize8(igsd, (uint8_t) igbinary_type_ref TSRMLS_CC) != 0) {
 
1515
                        return 1;
 
1516
                }
 
1517
 
 
1518
                /* Complex types serialize a reference, scalars do not... */
 
1519
                /* FIXME: Absolutely wrong level to check this. */
 
1520
                switch (Z_TYPE_P(z)) {
 
1521
                        case IS_RESOURCE:
 
1522
                        case IS_STRING:
 
1523
                        case IS_LONG:
 
1524
                        case IS_NULL:
 
1525
                        case IS_BOOL:
 
1526
                        case IS_DOUBLE:
 
1527
                                /* Serialize a reference if zval already added */
 
1528
                                if (igbinary_serialize_array_ref(igsd, z, false TSRMLS_CC) == 0) {
 
1529
                                        return 0;
 
1530
                                }
 
1531
                                /* otherwise fall through */
 
1532
                }
 
1533
        }
 
1534
        switch (Z_TYPE_P(z)) {
 
1535
                case IS_RESOURCE:
 
1536
                        return igbinary_serialize_null(igsd TSRMLS_CC);
 
1537
                case IS_OBJECT:
 
1538
                        return igbinary_serialize_object(igsd, z TSRMLS_CC);
 
1539
                case IS_ARRAY:
 
1540
                        return igbinary_serialize_array(igsd, z, false, false TSRMLS_CC);
 
1541
                case IS_STRING:
 
1542
                        return igbinary_serialize_string(igsd, Z_STRVAL_P(z), Z_STRLEN_P(z) TSRMLS_CC);
 
1543
                case IS_LONG:
 
1544
                        return igbinary_serialize_long(igsd, Z_LVAL_P(z) TSRMLS_CC);
 
1545
                case IS_NULL:
 
1546
                        return igbinary_serialize_null(igsd TSRMLS_CC);
 
1547
                case IS_BOOL:
 
1548
                        return igbinary_serialize_bool(igsd, Z_LVAL_P(z) ? 1 : 0 TSRMLS_CC);
 
1549
                case IS_DOUBLE:
 
1550
                        return igbinary_serialize_double(igsd, Z_DVAL_P(z) TSRMLS_CC);
 
1551
                default:
 
1552
                        zend_error(E_ERROR, "igbinary_serialize_zval: zval has unknown type %d", (int)Z_TYPE_P(z));
 
1553
                        /* not reached */
 
1554
                        return 1;
 
1555
        }
 
1556
 
 
1557
        return 0;
 
1558
}
 
1559
/* }}} */
 
1560
/* {{{ igbinary_unserialize_data_init */
 
1561
/** Inits igbinary_unserialize_data_init. */
 
1562
inline static int igbinary_unserialize_data_init(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
 
1563
        smart_str empty_str = { 0 };
 
1564
 
 
1565
        igsd->buffer = NULL;
 
1566
        igsd->buffer_size = 0;
 
1567
        igsd->buffer_offset = 0;
 
1568
 
 
1569
        igsd->strings = NULL;
 
1570
        igsd->strings_count = 0;
 
1571
        igsd->strings_capacity = 4;
 
1572
        igsd->string0_buf = empty_str;
 
1573
 
 
1574
        igsd->error = 0;
 
1575
        igsd->references = NULL;
 
1576
        igsd->references_count = 0;
 
1577
        igsd->references_capacity = 4;
 
1578
 
 
1579
        igsd->references = (void **) emalloc(sizeof(void *) * igsd->references_capacity);
 
1580
        if (igsd->references == NULL) {
 
1581
                return 1;
 
1582
        }
 
1583
 
 
1584
        igsd->strings = (struct igbinary_unserialize_string_pair *) emalloc(sizeof(struct igbinary_unserialize_string_pair) * igsd->strings_capacity);
 
1585
        if (igsd->strings == NULL) {
 
1586
                efree(igsd->references);
 
1587
                return 1;
 
1588
        }
 
1589
 
 
1590
        return 0;
 
1591
}
 
1592
/* }}} */
 
1593
/* {{{ igbinary_unserialize_data_deinit */
 
1594
/** Deinits igbinary_unserialize_data_init. */
 
1595
inline static void igbinary_unserialize_data_deinit(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
 
1596
        if (igsd->strings) {
 
1597
                efree(igsd->strings);
 
1598
        }
 
1599
 
 
1600
        if (igsd->references) {
 
1601
                efree(igsd->references);
 
1602
        }
 
1603
 
 
1604
        smart_str_free(&igsd->string0_buf);
 
1605
 
 
1606
        return;
 
1607
}
 
1608
/* }}} */
 
1609
/* {{{ igbinary_unserialize_header */
 
1610
/** Unserialize header. Check for version. */
 
1611
inline static int igbinary_unserialize_header(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
 
1612
        uint32_t version;
 
1613
 
 
1614
        if (igsd->buffer_offset + 4 >= igsd->buffer_size) {
 
1615
                return 1;
 
1616
        }
 
1617
 
 
1618
        version = igbinary_unserialize32(igsd TSRMLS_CC);
 
1619
 
 
1620
        /* Support older version 1 and the current format 2 */
 
1621
        if (version == IGBINARY_FORMAT_VERSION || version == 0x00000001) {
 
1622
                return 0;
 
1623
        } else {
 
1624
                zend_error(E_WARNING, "igbinary_unserialize_header: unsupported version: %u, should be %u or %u", (unsigned int) version, 0x00000001, (unsigned int) IGBINARY_FORMAT_VERSION);
 
1625
                return 1;
 
1626
        }
 
1627
}
 
1628
/* }}} */
 
1629
/* {{{ igbinary_unserialize8 */
 
1630
/** Unserialize 8bit value. */
 
1631
inline static uint8_t igbinary_unserialize8(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
 
1632
        uint8_t ret = 0;
 
1633
        ret = igsd->buffer[igsd->buffer_offset++];
 
1634
        return ret;
 
1635
}
 
1636
/* }}} */
 
1637
/* {{{ igbinary_unserialize16 */
 
1638
/** Unserialize 16bit value. */
 
1639
inline static uint16_t igbinary_unserialize16(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
 
1640
        uint16_t ret = 0;
 
1641
        ret |= ((uint16_t) igsd->buffer[igsd->buffer_offset++] << 8);
 
1642
        ret |= ((uint16_t) igsd->buffer[igsd->buffer_offset++] << 0);
 
1643
        return ret;
 
1644
}
 
1645
/* }}} */
 
1646
/* {{{ igbinary_unserialize32 */
 
1647
/** Unserialize 32bit value. */
 
1648
inline static uint32_t igbinary_unserialize32(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
 
1649
        uint32_t ret = 0;
 
1650
        ret |= ((uint32_t) igsd->buffer[igsd->buffer_offset++] << 24);
 
1651
        ret |= ((uint32_t) igsd->buffer[igsd->buffer_offset++] << 16);
 
1652
        ret |= ((uint32_t) igsd->buffer[igsd->buffer_offset++] << 8);
 
1653
        ret |= ((uint32_t) igsd->buffer[igsd->buffer_offset++] << 0);
 
1654
        return ret;
 
1655
}
 
1656
/* }}} */
 
1657
/* {{{ igbinary_unserialize64 */
 
1658
/** Unserialize 64bit value. */
 
1659
inline static uint64_t igbinary_unserialize64(struct igbinary_unserialize_data *igsd TSRMLS_DC) {
 
1660
        uint64_t ret = 0;
 
1661
        ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 56);
 
1662
        ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 48);
 
1663
        ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 40);
 
1664
        ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 32);
 
1665
        ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 24);
 
1666
        ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 16);
 
1667
        ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 8);
 
1668
        ret |= ((uint64_t) igsd->buffer[igsd->buffer_offset++] << 0);
 
1669
        return ret;
 
1670
}
 
1671
/* }}} */
 
1672
/* {{{ igbinary_unserialize_long */
 
1673
/** Unserializes long */
 
1674
inline static int igbinary_unserialize_long(struct igbinary_unserialize_data *igsd, enum igbinary_type t, long *ret TSRMLS_DC) {
 
1675
        uint32_t tmp32;
 
1676
#if SIZEOF_LONG == 8
 
1677
        uint64_t tmp64;
 
1678
#endif
 
1679
 
 
1680
        if (t == igbinary_type_long8p || t == igbinary_type_long8n) {
 
1681
                if (igsd->buffer_offset + 1 > igsd->buffer_size) {
 
1682
                        zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
 
1683
                        return 1;
 
1684
                }
 
1685
 
 
1686
                *ret = (long) (t == igbinary_type_long8n ? -1 : 1) * igbinary_unserialize8(igsd TSRMLS_CC);
 
1687
        } else if (t == igbinary_type_long16p || t == igbinary_type_long16n) {
 
1688
                if (igsd->buffer_offset + 2 > igsd->buffer_size) {
 
1689
                        zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
 
1690
                        return 1;
 
1691
                }
 
1692
 
 
1693
                *ret = (long) (t == igbinary_type_long16n ? -1 : 1) * igbinary_unserialize16(igsd TSRMLS_CC);
 
1694
        } else if (t == igbinary_type_long32p || t == igbinary_type_long32n) {
 
1695
                if (igsd->buffer_offset + 4 > igsd->buffer_size) {
 
1696
                        zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
 
1697
                        return 1;
 
1698
                }
 
1699
 
 
1700
                /* check for boundaries */
 
1701
                tmp32 = igbinary_unserialize32(igsd TSRMLS_CC);
 
1702
#if SIZEOF_LONG == 4
 
1703
                if (tmp32 > 0x80000000 || (tmp32 == 0x80000000 && t == igbinary_type_long32p)) {
 
1704
                        zend_error(E_WARNING, "igbinary_unserialize_long: 64bit long on 32bit platform?");
 
1705
                        tmp32 = 0; /* t == igbinary_type_long32p ? LONG_MAX : LONG_MIN; */
 
1706
                }
 
1707
#endif
 
1708
                *ret = (long) (t == igbinary_type_long32n ? -1 : 1) * tmp32;
 
1709
        } else if (t == igbinary_type_long64p || t == igbinary_type_long64n) {
 
1710
#if SIZEOF_LONG == 8
 
1711
                if (igsd->buffer_offset + 8 > igsd->buffer_size) {
 
1712
                        zend_error(E_WARNING, "igbinary_unserialize_long: end-of-data");
 
1713
                        return 1;
 
1714
                }
 
1715
 
 
1716
                /* check for boundaries */
 
1717
                tmp64 = igbinary_unserialize64(igsd TSRMLS_CC);
 
1718
                if (tmp64 > 0x8000000000000000 || (tmp64 == 0x8000000000000000 && t == igbinary_type_long64p)) {
 
1719
                        zend_error(E_WARNING, "igbinary_unserialize_long: too big 64bit long.");
 
1720
                        tmp64 = 0; /* t == igbinary_type_long64p ? LONG_MAX : LONG_MIN */;
 
1721
                }
 
1722
 
 
1723
                *ret = (long) (t == igbinary_type_long64n ? -1 : 1) * tmp64;
 
1724
#elif SIZEOF_LONG == 4
 
1725
                /* can't put 64bit long into 32bit one, placeholder zero */
 
1726
                *ret = 0;
 
1727
                igbinary_unserialize64(igsd TSRMLS_CC);
 
1728
                zend_error(E_WARNING, "igbinary_unserialize_long: 64bit long on 32bit platform");
 
1729
#else
 
1730
#error "Strange sizeof(long)."
 
1731
#endif
 
1732
        } else {
 
1733
                *ret = 0;
 
1734
                zend_error(E_WARNING, "igbinary_unserialize_long: unknown type '%02x', position %zu", t, igsd->buffer_offset);
 
1735
                return 1;
 
1736
        }
 
1737
 
 
1738
        return 0;
 
1739
}
 
1740
/* }}} */
 
1741
/* {{{ igbinary_unserialize_double */
 
1742
/** Unserializes double. */
 
1743
inline static int igbinary_unserialize_double(struct igbinary_unserialize_data *igsd, enum igbinary_type t, double *ret TSRMLS_DC) {
 
1744
        union {
 
1745
                double d;
 
1746
                uint64_t u;
 
1747
        } u;
 
1748
 
 
1749
        (void) t;
 
1750
 
 
1751
        if (igsd->buffer_offset + 8 > igsd->buffer_size) {
 
1752
                zend_error(E_WARNING, "igbinary_unserialize_double: end-of-data");
 
1753
                return 1;
 
1754
        }
 
1755
 
 
1756
 
 
1757
        u.u = igbinary_unserialize64(igsd TSRMLS_CC);
 
1758
 
 
1759
        *ret = u.d;
 
1760
 
 
1761
        return 0;
 
1762
}
 
1763
/* }}} */
 
1764
/* {{{ igbinary_unserialize_string */
 
1765
/** Unserializes string. Unserializes both actual string or by string id. */
 
1766
inline static int igbinary_unserialize_string(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC) {
 
1767
        size_t i;
 
1768
        if (t == igbinary_type_string_id8 || t == igbinary_type_object_id8) {
 
1769
                if (igsd->buffer_offset + 1 > igsd->buffer_size) {
 
1770
                        zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data");
 
1771
                        return 1;
 
1772
                }
 
1773
                i = igbinary_unserialize8(igsd TSRMLS_CC);
 
1774
        } else if (t == igbinary_type_string_id16 || t == igbinary_type_object_id16) {
 
1775
                if (igsd->buffer_offset + 2 > igsd->buffer_size) {
 
1776
                        zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data");
 
1777
                        return 1;
 
1778
                }
 
1779
                i = igbinary_unserialize16(igsd TSRMLS_CC);
 
1780
        } else if (t == igbinary_type_string_id32 || t == igbinary_type_object_id32) {
 
1781
                if (igsd->buffer_offset + 4 > igsd->buffer_size) {
 
1782
                        zend_error(E_WARNING, "igbinary_unserialize_string: end-of-data");
 
1783
                        return 1;
 
1784
                }
 
1785
                i = igbinary_unserialize32(igsd TSRMLS_CC);
 
1786
        } else {
 
1787
                zend_error(E_WARNING, "igbinary_unserialize_string: unknown type '%02x', position %zu", t, igsd->buffer_offset);
 
1788
                return 1;
 
1789
        }
 
1790
 
 
1791
        if (i >= igsd->strings_count) {
 
1792
                zend_error(E_WARNING, "igbinary_unserialize_string: string index is out-of-bounds");
 
1793
                return 1;
 
1794
        }
 
1795
 
 
1796
        *s = igsd->strings[i].data;
 
1797
        *len = igsd->strings[i].len;
 
1798
 
 
1799
        return 0;
 
1800
}
 
1801
/* }}} */
 
1802
/* {{{ igbinary_unserialize_chararray */
 
1803
/** Unserializes chararray of string. */
 
1804
inline static int igbinary_unserialize_chararray(struct igbinary_unserialize_data *igsd, enum igbinary_type t, char **s, size_t *len TSRMLS_DC) {
 
1805
        size_t l;
 
1806
 
 
1807
        if (t == igbinary_type_string8 || t == igbinary_type_object8) {
 
1808
                if (igsd->buffer_offset + 1 > igsd->buffer_size) {
 
1809
                        zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
 
1810
                        return 1;
 
1811
                }
 
1812
                l = igbinary_unserialize8(igsd TSRMLS_CC);
 
1813
                if (igsd->buffer_offset + l > igsd->buffer_size) {
 
1814
                        zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
 
1815
                        return 1;
 
1816
                }
 
1817
        } else if (t == igbinary_type_string16 || t == igbinary_type_object16) {
 
1818
                if (igsd->buffer_offset + 2 > igsd->buffer_size) {
 
1819
                        zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
 
1820
                        return 1;
 
1821
                }
 
1822
                l = igbinary_unserialize16(igsd TSRMLS_CC);
 
1823
                if (igsd->buffer_offset + l > igsd->buffer_size) {
 
1824
                        zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
 
1825
                        return 1;
 
1826
                }
 
1827
        } else if (t == igbinary_type_string32 || t == igbinary_type_object32) {
 
1828
                if (igsd->buffer_offset + 4 > igsd->buffer_size) {
 
1829
                        zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
 
1830
                        return 1;
 
1831
                }
 
1832
                l = igbinary_unserialize32(igsd TSRMLS_CC);
 
1833
                if (igsd->buffer_offset + l > igsd->buffer_size) {
 
1834
                        zend_error(E_WARNING, "igbinary_unserialize_chararray: end-of-data");
 
1835
                        return 1;
 
1836
                }
 
1837
        } else {
 
1838
                zend_error(E_WARNING, "igbinary_unserialize_chararray: unknown type '%02x', position %zu", t, igsd->buffer_offset);
 
1839
                return 1;
 
1840
        }
 
1841
 
 
1842
        if (igsd->strings_count + 1 > igsd->strings_capacity) {
 
1843
                while (igsd->strings_count + 1 > igsd->strings_capacity) {
 
1844
                        igsd->strings_capacity *= 2;
 
1845
                }
 
1846
 
 
1847
                igsd->strings = (struct igbinary_unserialize_string_pair *) erealloc(igsd->strings, sizeof(struct igbinary_unserialize_string_pair) * igsd->strings_capacity);
 
1848
                if (igsd->strings == NULL) {
 
1849
                        return 1;
 
1850
                }
 
1851
        }
 
1852
 
 
1853
        igsd->strings[igsd->strings_count].data = (char *) (igsd->buffer + igsd->buffer_offset);
 
1854
        igsd->strings[igsd->strings_count].len = l;
 
1855
 
 
1856
        igsd->buffer_offset += l;
 
1857
 
 
1858
        if (igsd->strings[igsd->strings_count].data == NULL) {
 
1859
                return 1;
 
1860
        }
 
1861
 
 
1862
        *len = igsd->strings[igsd->strings_count].len;
 
1863
        *s = igsd->strings[igsd->strings_count].data;
 
1864
 
 
1865
        igsd->strings_count += 1;
 
1866
 
 
1867
        return 0;
 
1868
}
 
1869
/* }}} */
 
1870
/* {{{ igbinary_unserialize_array */
 
1871
/** Unserializes array. */
 
1872
inline static int igbinary_unserialize_array(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, int object TSRMLS_DC) {
 
1873
        size_t n;
 
1874
        size_t i;
 
1875
 
 
1876
        zval *v = NULL;
 
1877
        /*      zval *old_v; */
 
1878
 
 
1879
        char *key;
 
1880
        size_t key_len = 0;
 
1881
        long key_index = 0;
 
1882
 
 
1883
        enum igbinary_type key_type;
 
1884
 
 
1885
        HashTable *h;
 
1886
 
 
1887
        if (t == igbinary_type_array8) {
 
1888
                if (igsd->buffer_offset + 1 > igsd->buffer_size) {
 
1889
                        zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
 
1890
                        return 1;
 
1891
                }
 
1892
                n = igbinary_unserialize8(igsd TSRMLS_CC);
 
1893
        } else if (t == igbinary_type_array16) {
 
1894
                if (igsd->buffer_offset + 2 > igsd->buffer_size) {
 
1895
                        zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
 
1896
                        return 1;
 
1897
                }
 
1898
                n = igbinary_unserialize16(igsd TSRMLS_CC);
 
1899
        } else if (t == igbinary_type_array32) {
 
1900
                if (igsd->buffer_offset + 4 > igsd->buffer_size) {
 
1901
                        zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
 
1902
                        return 1;
 
1903
                }
 
1904
                n = igbinary_unserialize32(igsd TSRMLS_CC);
 
1905
        } else {
 
1906
                zend_error(E_WARNING, "igbinary_unserialize_array: unknown type '%02x', position %zu", t, igsd->buffer_offset);
 
1907
                return 1;
 
1908
        }
 
1909
 
 
1910
        // n cannot be larger than the number of minimum "objects" in the array
 
1911
        if (n > igsd->buffer_size - igsd->buffer_offset) {
 
1912
                zend_error(E_WARNING, "%s: data size %zu smaller that requested array length %zu.", "igbinary_unserialize_array", igsd->buffer_size - igsd->buffer_offset, n);
 
1913
                return 1;
 
1914
        }
 
1915
 
 
1916
        if (!object) {
 
1917
                Z_TYPE_PP(z) = IS_ARRAY;
 
1918
                ALLOC_HASHTABLE(Z_ARRVAL_PP(z));
 
1919
                zend_hash_init(Z_ARRVAL_PP(z), n + 1, NULL, ZVAL_PTR_DTOR, 0);
 
1920
 
 
1921
                /* references */
 
1922
                if (igsd->references_count + 1 >= igsd->references_capacity) {
 
1923
                        while (igsd->references_count + 1 >= igsd->references_capacity) {
 
1924
                                igsd->references_capacity *= 2;
 
1925
                        }
 
1926
 
 
1927
                        igsd->references = (void **) erealloc(igsd->references, sizeof(void *) * igsd->references_capacity);
 
1928
                        if (igsd->references == NULL)
 
1929
                                return 1;
 
1930
                }
 
1931
 
 
1932
                igsd->references[igsd->references_count++] = (void *) *z;
 
1933
        }
 
1934
 
 
1935
        /* empty array */
 
1936
        if (n == 0) {
 
1937
                return 0;
 
1938
        }
 
1939
 
 
1940
        h = HASH_OF(*z);
 
1941
 
 
1942
        for (i = 0; i < n; i++) {
 
1943
                key = NULL;
 
1944
 
 
1945
                if (igsd->buffer_offset + 1 > igsd->buffer_size) {
 
1946
                        zend_error(E_WARNING, "igbinary_unserialize_array: end-of-data");
 
1947
                        zval_dtor(*z);
 
1948
                        ZVAL_NULL(*z);
 
1949
                        return 1;
 
1950
                }
 
1951
 
 
1952
                key_type = (enum igbinary_type) igbinary_unserialize8(igsd TSRMLS_CC);
 
1953
 
 
1954
                switch (key_type) {
 
1955
                        case igbinary_type_long8p:
 
1956
                        case igbinary_type_long8n:
 
1957
                        case igbinary_type_long16p:
 
1958
                        case igbinary_type_long16n:
 
1959
                        case igbinary_type_long32p:
 
1960
                        case igbinary_type_long32n:
 
1961
                        case igbinary_type_long64p:
 
1962
                        case igbinary_type_long64n:
 
1963
                                if (igbinary_unserialize_long(igsd, key_type, &key_index TSRMLS_CC)) {
 
1964
                                        zval_dtor(*z);
 
1965
                                        ZVAL_NULL(*z);
 
1966
                                        return 1;
 
1967
                                }
 
1968
                                break;
 
1969
                        case igbinary_type_string_id8:
 
1970
                        case igbinary_type_string_id16:
 
1971
                        case igbinary_type_string_id32:
 
1972
                                if (igbinary_unserialize_string(igsd, key_type, &key, &key_len TSRMLS_CC)) {
 
1973
                                        zval_dtor(*z);
 
1974
                                        ZVAL_NULL(*z);
 
1975
                                        return 1;
 
1976
                                }
 
1977
                                break;
 
1978
                        case igbinary_type_string8:
 
1979
                        case igbinary_type_string16:
 
1980
                        case igbinary_type_string32:
 
1981
                                if (igbinary_unserialize_chararray(igsd, key_type, &key, &key_len TSRMLS_CC)) {
 
1982
                                        zval_dtor(*z);
 
1983
                                        ZVAL_NULL(*z);
 
1984
                                        return 1;
 
1985
                                }
 
1986
                                break;
 
1987
                        case igbinary_type_string_empty:
 
1988
                                key = "";
 
1989
                                key_len = 0;
 
1990
                                break;
 
1991
                        case igbinary_type_null:
 
1992
                                continue;
 
1993
                        default:
 
1994
                                zend_error(E_WARNING, "igbinary_unserialize_array: unknown key type '%02x', position %zu", key_type, igsd->buffer_offset);
 
1995
                                zval_dtor(*z);
 
1996
                                ZVAL_NULL(*z);
 
1997
                                return 1;
 
1998
                }
 
1999
 
 
2000
 
 
2001
                ALLOC_INIT_ZVAL(v);
 
2002
                if (igbinary_unserialize_zval(igsd, &v TSRMLS_CC)) {
 
2003
                        zval_dtor(*z);
 
2004
                        ZVAL_NULL(*z);
 
2005
                        zval_ptr_dtor(&v);
 
2006
                        return 1;
 
2007
                }
 
2008
 
 
2009
                if (key) {
 
2010
                        /* Keys must include a terminating null. */
 
2011
                        /* Ensure buffer starts at the beginning. */
 
2012
                        igsd->string0_buf.len = 0;
 
2013
                        smart_str_appendl(&igsd->string0_buf, key, key_len);
 
2014
                        smart_str_0(&igsd->string0_buf);
 
2015
/*
 
2016
                        if (zend_symtable_find(h, key, key_len + 1, (void **)&old_v) == SUCCESS) {
 
2017
                                var_push_dtor(var_hash, old_v);
 
2018
                        }
 
2019
*/
 
2020
                        zend_symtable_update(h, igsd->string0_buf.c, igsd->string0_buf.len + 1, &v, sizeof(v), NULL);
 
2021
                } else {
 
2022
/*
 
2023
                        if (zend_hash_index_find(h, key_index, (void **)&old_v) == SUCCESS) {
 
2024
                                var_push_dtor(var_hash, old_v);
 
2025
                        }
 
2026
*/
 
2027
                        zend_hash_index_update(h, key_index, &v, sizeof(v), NULL);
 
2028
                }
 
2029
        }
 
2030
 
 
2031
        return 0;
 
2032
}
 
2033
/* }}} */
 
2034
/* {{{ igbinary_unserialize_object_ser */
 
2035
/** Unserializes object's property array of objects implementing Serializable -interface. */
 
2036
inline static int igbinary_unserialize_object_ser(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z, zend_class_entry *ce TSRMLS_DC) {
 
2037
        size_t n;
 
2038
        int ret;
 
2039
        php_unserialize_data_t var_hash;
 
2040
 
 
2041
        if (ce->unserialize == NULL) {
 
2042
                zend_error(E_WARNING, "Class %s has no unserializer", ce->name);
 
2043
                return 1;
 
2044
        }
 
2045
 
 
2046
        if (t == igbinary_type_object_ser8) {
 
2047
                if (igsd->buffer_offset + 1 > igsd->buffer_size) {
 
2048
                        zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
 
2049
                        return 1;
 
2050
                }
 
2051
                n = igbinary_unserialize8(igsd TSRMLS_CC);
 
2052
        } else if (t == igbinary_type_object_ser16) {
 
2053
                if (igsd->buffer_offset + 2 > igsd->buffer_size) {
 
2054
                        zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
 
2055
                        return 1;
 
2056
                }
 
2057
                n = igbinary_unserialize16(igsd TSRMLS_CC);
 
2058
        } else if (t == igbinary_type_object_ser32) {
 
2059
                if (igsd->buffer_offset + 4 > igsd->buffer_size) {
 
2060
                        zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
 
2061
                        return 1;
 
2062
                }
 
2063
                n = igbinary_unserialize32(igsd TSRMLS_CC);
 
2064
        } else {
 
2065
                zend_error(E_WARNING, "igbinary_unserialize_object_ser: unknown type '%02x', position %zu", t, igsd->buffer_offset);
 
2066
                return 1;
 
2067
        }
 
2068
 
 
2069
        if (igsd->buffer_offset + n > igsd->buffer_size) {
 
2070
                zend_error(E_WARNING, "igbinary_unserialize_object_ser: end-of-data");
 
2071
                return 1;
 
2072
        }
 
2073
 
 
2074
        PHP_VAR_UNSERIALIZE_INIT(var_hash);
 
2075
        ret = ce->unserialize(z, ce,
 
2076
                (const unsigned char*)(igsd->buffer + igsd->buffer_offset), n,
 
2077
                (zend_unserialize_data *)&var_hash TSRMLS_CC);
 
2078
        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
 
2079
 
 
2080
        if (ret != SUCCESS || EG(exception)) {
 
2081
                return 1;
 
2082
        }
 
2083
 
 
2084
        igsd->buffer_offset += n;
 
2085
 
 
2086
        return 0;
 
2087
}
 
2088
/* }}} */
 
2089
/* {{{ igbinary_unserialize_object */
 
2090
/** Unserialize object.
 
2091
 * @see ext/standard/var_unserializer.c
 
2092
 */
 
2093
inline static int igbinary_unserialize_object(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC) {
 
2094
        zend_class_entry *ce;
 
2095
        zend_class_entry **pce;
 
2096
 
 
2097
        zval *h = NULL;
 
2098
        zval f;
 
2099
 
 
2100
        char *name = NULL;
 
2101
        size_t name_len = 0;
 
2102
 
 
2103
        int r;
 
2104
 
 
2105
        bool incomplete_class = false;
 
2106
 
 
2107
        zval *user_func;
 
2108
        zval *retval_ptr;
 
2109
        zval **args[1];
 
2110
        zval *arg_func_name;
 
2111
 
 
2112
        if (t == igbinary_type_object8 || t == igbinary_type_object16 || t == igbinary_type_object32) {
 
2113
                if (igbinary_unserialize_chararray(igsd, t, &name, &name_len TSRMLS_CC)) {
 
2114
                        return 1;
 
2115
                }
 
2116
        } else if (t == igbinary_type_object_id8 || t == igbinary_type_object_id16 || t == igbinary_type_object_id32) {
 
2117
                if (igbinary_unserialize_string(igsd, t, &name, &name_len TSRMLS_CC)) {
 
2118
                        return 1;
 
2119
                }
 
2120
        } else {
 
2121
                zend_error(E_WARNING, "igbinary_unserialize_object: unknown object type '%02x', position %zu", t, igsd->buffer_offset);
 
2122
                return 1;
 
2123
        }
 
2124
 
 
2125
        do {
 
2126
                /* Try to find class directly */
 
2127
                if (zend_lookup_class(name, name_len, &pce TSRMLS_CC) == SUCCESS) {
 
2128
                        ce = *pce;
 
2129
                        break;
 
2130
                }
 
2131
 
 
2132
                /* Check for unserialize callback */
 
2133
                if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
 
2134
                        incomplete_class = 1;
 
2135
                        ce = PHP_IC_ENTRY;
 
2136
                        break;
 
2137
                }
 
2138
 
 
2139
                /* Call unserialize callback */
 
2140
                MAKE_STD_ZVAL(user_func);
 
2141
                ZVAL_STRING(user_func, PG(unserialize_callback_func), 1);
 
2142
                args[0] = &arg_func_name;
 
2143
                MAKE_STD_ZVAL(arg_func_name);
 
2144
                ZVAL_STRING(arg_func_name, name, 1);
 
2145
                if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
 
2146
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", name);
 
2147
                        incomplete_class = 1;
 
2148
                        ce = PHP_IC_ENTRY;
 
2149
                        zval_ptr_dtor(&user_func);
 
2150
                        zval_ptr_dtor(&arg_func_name);
 
2151
                        break;
 
2152
                }
 
2153
                if (retval_ptr) {
 
2154
                        zval_ptr_dtor(&retval_ptr);
 
2155
                }
 
2156
 
 
2157
                /* The callback function may have defined the class */
 
2158
                if (zend_lookup_class(name, name_len, &pce TSRMLS_CC) == SUCCESS) {
 
2159
                        ce = *pce;
 
2160
                } else {
 
2161
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function %s() hasn't defined the class it was called for", name);
 
2162
                        incomplete_class = true;
 
2163
                        ce = PHP_IC_ENTRY;
 
2164
                }
 
2165
 
 
2166
                zval_ptr_dtor(&user_func);
 
2167
                zval_ptr_dtor(&arg_func_name);
 
2168
        } while (0);
 
2169
 
 
2170
        /* previous user function call may have raised an exception */
 
2171
        if (EG(exception)) {
 
2172
                return 1;
 
2173
        }
 
2174
 
 
2175
        object_init_ex(*z, ce);
 
2176
 
 
2177
        /* reference */
 
2178
        if (igsd->references_count + 1 >= igsd->references_capacity) {
 
2179
                while (igsd->references_count + 1 >= igsd->references_capacity) {
 
2180
                        igsd->references_capacity *= 2;
 
2181
                }
 
2182
 
 
2183
                igsd->references = (void **) erealloc(igsd->references, sizeof(void *) * igsd->references_capacity);
 
2184
                if (igsd->references == NULL)
 
2185
                        return 1;
 
2186
        }
 
2187
 
 
2188
        igsd->references[igsd->references_count++] = (void *) *z;
 
2189
 
 
2190
        /* store incomplete class name */
 
2191
        if (incomplete_class) {
 
2192
                php_store_class_name(*z, name, name_len);
 
2193
        }
 
2194
 
 
2195
        t = (enum igbinary_type) igbinary_unserialize8(igsd TSRMLS_CC);
 
2196
        switch (t) {
 
2197
                case igbinary_type_array8:
 
2198
                case igbinary_type_array16:
 
2199
                case igbinary_type_array32:
 
2200
                        r = igbinary_unserialize_array(igsd, t, z, 1 TSRMLS_CC);
 
2201
                        break;
 
2202
                case igbinary_type_object_ser8:
 
2203
                case igbinary_type_object_ser16:
 
2204
                case igbinary_type_object_ser32:
 
2205
                        r = igbinary_unserialize_object_ser(igsd, t, z, ce TSRMLS_CC);
 
2206
                        break;
 
2207
                default:
 
2208
                        zend_error(E_WARNING, "igbinary_unserialize_object: unknown object inner type '%02x', position %zu", t, igsd->buffer_offset);
 
2209
                        return 1;
 
2210
        }
 
2211
 
 
2212
        if (r) {
 
2213
                return r;
 
2214
        }
 
2215
 
 
2216
        if (Z_OBJCE_PP(z) != PHP_IC_ENTRY && zend_hash_exists(&Z_OBJCE_PP(z)->function_table, "__wakeup", sizeof("__wakeup"))) {
 
2217
                INIT_PZVAL(&f);
 
2218
                ZVAL_STRINGL(&f, "__wakeup", sizeof("__wakeup") - 1, 0);
 
2219
                call_user_function_ex(CG(function_table), z, &f, &h, 0, 0, 1, NULL TSRMLS_CC);
 
2220
 
 
2221
                if (h) {
 
2222
                        zval_ptr_dtor(&h);
 
2223
                }
 
2224
 
 
2225
                if (EG(exception)) {
 
2226
                        r = 1;
 
2227
                }
 
2228
        }
 
2229
 
 
2230
        return r;
 
2231
}
 
2232
/* }}} */
 
2233
/* {{{ igbinary_unserialize_ref */
 
2234
/** Unserializes array or object by reference. */
 
2235
inline static int igbinary_unserialize_ref(struct igbinary_unserialize_data *igsd, enum igbinary_type t, zval **z TSRMLS_DC) {
 
2236
        size_t n;
 
2237
 
 
2238
        if (t == igbinary_type_ref8 || t == igbinary_type_objref8) {
 
2239
                if (igsd->buffer_offset + 1 > igsd->buffer_size) {
 
2240
                        zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data");
 
2241
                        return 1;
 
2242
                }
 
2243
                n = igbinary_unserialize8(igsd TSRMLS_CC);
 
2244
        } else if (t == igbinary_type_ref16 || t == igbinary_type_objref16) {
 
2245
                if (igsd->buffer_offset + 2 > igsd->buffer_size) {
 
2246
                        zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data");
 
2247
                        return 1;
 
2248
                }
 
2249
                n = igbinary_unserialize16(igsd TSRMLS_CC);
 
2250
        } else if (t == igbinary_type_ref32 || t == igbinary_type_objref32) {
 
2251
                if (igsd->buffer_offset + 4 > igsd->buffer_size) {
 
2252
                        zend_error(E_WARNING, "igbinary_unserialize_ref: end-of-data");
 
2253
                        return 1;
 
2254
                }
 
2255
                n = igbinary_unserialize32(igsd TSRMLS_CC);
 
2256
        } else {
 
2257
                zend_error(E_WARNING, "igbinary_unserialize_ref: unknown type '%02x', position %zu", t, igsd->buffer_offset);
 
2258
                return 1;
 
2259
        }
 
2260
 
 
2261
        if (n >= igsd->references_count) {
 
2262
                zend_error(E_WARNING, "igbinary_unserialize_ref: invalid reference");
 
2263
                return 1;
 
2264
        }
 
2265
 
 
2266
        if (*z != NULL) {
 
2267
                zval_ptr_dtor(z);
 
2268
        }
 
2269
 
 
2270
        *z = igsd->references[n];
 
2271
        Z_ADDREF_PP(z);
 
2272
 
 
2273
        if (t == igbinary_type_objref8 || t == igbinary_type_objref16 || t == igbinary_type_objref32) {
 
2274
        Z_SET_ISREF_TO_PP(z, false);
 
2275
        }
 
2276
 
 
2277
        return 0;
 
2278
}
 
2279
/* }}} */
 
2280
/* {{{ igbinary_unserialize_zval */
 
2281
/** Unserialize zval. */
 
2282
static int igbinary_unserialize_zval(struct igbinary_unserialize_data *igsd, zval **z TSRMLS_DC) {
 
2283
        enum igbinary_type t;
 
2284
 
 
2285
        long tmp_long;
 
2286
        double tmp_double;
 
2287
        char *tmp_chararray;
 
2288
        size_t tmp_size_t;
 
2289
 
 
2290
        if (igsd->buffer_offset + 1 > igsd->buffer_size) {
 
2291
                zend_error(E_WARNING, "igbinary_unserialize_zval: end-of-data");
 
2292
                return 1;
 
2293
        }
 
2294
 
 
2295
        t = (enum igbinary_type) igbinary_unserialize8(igsd TSRMLS_CC);
 
2296
 
 
2297
        switch (t) {
 
2298
                case igbinary_type_ref:
 
2299
                        if (igbinary_unserialize_zval(igsd, z TSRMLS_CC)) {
 
2300
                                return 1;
 
2301
                        }
 
2302
                        /* Scalar types should be added to the references hash */
 
2303
                        /* unless they're already added */
 
2304
                        /* in references list: marked as ref */
 
2305
                        if (!Z_ISREF_PP(z)) switch (Z_TYPE_PP(z)) {
 
2306
                                case IS_STRING:
 
2307
                                case IS_LONG:
 
2308
                                case IS_NULL:
 
2309
                                case IS_DOUBLE:
 
2310
                                case IS_BOOL:
 
2311
                                        /* reference */
 
2312
                                        if (igsd->references_count + 1 >= igsd->references_capacity) {
 
2313
                                                while (igsd->references_count + 1 >= igsd->references_capacity) {
 
2314
                                                        igsd->references_capacity *= 2;
 
2315
                                                }
 
2316
 
 
2317
                                                igsd->references = (void **) erealloc(igsd->references, sizeof(void *) * igsd->references_capacity);
 
2318
                                                if (igsd->references == NULL)
 
2319
                                                        return 1;
 
2320
                                        }
 
2321
 
 
2322
                                        igsd->references[igsd->references_count++] = (void *) *z;
 
2323
                        }
 
2324
                        Z_SET_ISREF_TO_PP(z, true);
 
2325
                        break;
 
2326
                case igbinary_type_objref8:
 
2327
                case igbinary_type_objref16:
 
2328
                case igbinary_type_objref32:
 
2329
                case igbinary_type_ref8:
 
2330
                case igbinary_type_ref16:
 
2331
                case igbinary_type_ref32:
 
2332
                        if (igbinary_unserialize_ref(igsd, t, z TSRMLS_CC)) {
 
2333
                                return 1;
 
2334
                        }
 
2335
                        break;
 
2336
                case igbinary_type_object8:
 
2337
                case igbinary_type_object16:
 
2338
                case igbinary_type_object32:
 
2339
                case igbinary_type_object_id8:
 
2340
                case igbinary_type_object_id16:
 
2341
                case igbinary_type_object_id32:
 
2342
                        if (igbinary_unserialize_object(igsd, t, z TSRMLS_CC)) {
 
2343
                                return 1;
 
2344
                        }
 
2345
                        break;
 
2346
                case igbinary_type_array8:
 
2347
                case igbinary_type_array16:
 
2348
                case igbinary_type_array32:
 
2349
                        if (igbinary_unserialize_array(igsd, t, z, 0 TSRMLS_CC)) {
 
2350
                                return 1;
 
2351
                        }
 
2352
                        break;
 
2353
                case igbinary_type_string_empty:
 
2354
                        ZVAL_EMPTY_STRING(*z);
 
2355
                        break;
 
2356
                case igbinary_type_string_id8:
 
2357
                case igbinary_type_string_id16:
 
2358
                case igbinary_type_string_id32:
 
2359
                        if (igbinary_unserialize_string(igsd, t, &tmp_chararray, &tmp_size_t TSRMLS_CC)) {
 
2360
                                return 1;
 
2361
                        }
 
2362
                        ZVAL_STRINGL(*z, tmp_chararray, tmp_size_t, 1);
 
2363
                        break;
 
2364
                case igbinary_type_string8:
 
2365
                case igbinary_type_string16:
 
2366
                case igbinary_type_string32:
 
2367
                        if (igbinary_unserialize_chararray(igsd, t, &tmp_chararray, &tmp_size_t TSRMLS_CC)) {
 
2368
                                return 1;
 
2369
                        }
 
2370
                        ZVAL_STRINGL(*z, tmp_chararray, tmp_size_t, 1);
 
2371
                        break;
 
2372
                case igbinary_type_long8p:
 
2373
                case igbinary_type_long8n:
 
2374
                case igbinary_type_long16p:
 
2375
                case igbinary_type_long16n:
 
2376
                case igbinary_type_long32p:
 
2377
                case igbinary_type_long32n:
 
2378
                case igbinary_type_long64p:
 
2379
                case igbinary_type_long64n:
 
2380
                        if (igbinary_unserialize_long(igsd, t, &tmp_long TSRMLS_CC)) {
 
2381
                                return 1;
 
2382
                        }
 
2383
                        ZVAL_LONG(*z, tmp_long);
 
2384
                        break;
 
2385
                case igbinary_type_null:
 
2386
                        ZVAL_NULL(*z);
 
2387
                        break;
 
2388
                case igbinary_type_bool_false:
 
2389
                        ZVAL_BOOL(*z, 0);
 
2390
                        break;
 
2391
                case igbinary_type_bool_true:
 
2392
                        ZVAL_BOOL(*z, 1);
 
2393
                        break;
 
2394
                case igbinary_type_double:
 
2395
                        if (igbinary_unserialize_double(igsd, t, &tmp_double TSRMLS_CC)) {
 
2396
                                return 1;
 
2397
                        }
 
2398
                        ZVAL_DOUBLE(*z, tmp_double);
 
2399
                        break;
 
2400
                default:
 
2401
                        zend_error(E_WARNING, "igbinary_unserialize_zval: unknown type '%02x', position %zu", t, igsd->buffer_offset);
 
2402
                        return 1;
 
2403
        }
 
2404
 
 
2405
        return 0;
 
2406
}
 
2407
/* }}} */
 
2408
 
 
2409
/*
 
2410
 * Local variables:
 
2411
 * tab-width: 2
 
2412
 * c-basic-offset: 4
 
2413
 * End:
 
2414
 * vim600: noet sw=4 ts=4 fdm=marker
 
2415
 * vim<600: noet sw=4 ts=4
 
2416
 */