summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorSascha Schumann <sas@php.net>2001-11-10 21:18:34 +0000
committerSascha Schumann <sas@php.net>2001-11-10 21:18:34 +0000
commitf341f630d3fe6fe669f6a4cbf176f7a5e6f3f4db (patch)
tree3f7fbe4a27171ecd4da8da070d083be12aac5fc5 /ext
parent88c6758d4e326a9714e0bfccd3309c3e5a282ef9 (diff)
downloadphp-git-f341f630d3fe6fe669f6a4cbf176f7a5e6f3f4db.tar.gz
Rewrite of unserializer which should be more maintainable and extensible.
Changes pass `make test´ and a couple of custom tests. Enjoy.
Diffstat (limited to 'ext')
-rw-r--r--ext/session/php_session.h4
-rw-r--r--ext/session/session.c6
-rw-r--r--ext/standard/Makefile.in6
-rw-r--r--ext/standard/php_var.h36
-rw-r--r--ext/standard/var.c244
-rw-r--r--ext/standard/var_unserializer.c635
-rw-r--r--ext/standard/var_unserializer.re361
7 files changed, 1022 insertions, 270 deletions
diff --git a/ext/session/php_session.h b/ext/session/php_session.h
index 5d4f0ca5e8..f0c245ea9d 100644
--- a/ext/session/php_session.h
+++ b/ext/session/php_session.h
@@ -19,6 +19,8 @@
#ifndef PHP_SESSION_H
#define PHP_SESSION_H
+#include "ext/standard/php_var.h"
+
#define PS_OPEN_ARGS void **mod_data, const char *save_path, const char *session_name
#define PS_CLOSE_ARGS void **mod_data
#define PS_READ_ARGS void **mod_data, const char *key, char **val, int *vallen
@@ -148,7 +150,7 @@ typedef struct ps_serializer_struct {
PHPAPI void session_adapt_url(const char *, size_t, char **, size_t * TSRMLS_DC);
-void php_set_session_var(char *name, size_t namelen, zval *state_val,HashTable *var_hash TSRMLS_DC);
+void php_set_session_var(char *name, size_t namelen, zval *state_val, php_unserialize_data_t *var_hash TSRMLS_DC);
int php_get_session_var(char *name, size_t namelen, zval ***state_var TSRMLS_DC);
int php_session_register_module(ps_module *);
diff --git a/ext/session/session.c b/ext/session/session.c
index ff9be2052e..2a54c4c708 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -259,7 +259,7 @@ typedef struct {
#define MAX_STR 512
-void php_set_session_var(char *name, size_t namelen, zval *state_val,HashTable *var_hash TSRMLS_DC)
+void php_set_session_var(char *name, size_t namelen, zval *state_val, php_unserialize_data_t *var_hash TSRMLS_DC)
{
if (PG(register_globals)) {
@@ -344,7 +344,7 @@ PS_SERIALIZER_DECODE_FUNC(php_binary)
zval *current;
int namelen;
int has_value;
- php_serialize_data_t var_hash;
+ php_unserialize_data_t var_hash;
PHP_VAR_UNSERIALIZE_INIT(var_hash);
@@ -411,7 +411,7 @@ PS_SERIALIZER_DECODE_FUNC(php)
zval *current;
int namelen;
int has_value;
- php_serialize_data_t var_hash;
+ php_unserialize_data_t var_hash;
PHP_VAR_UNSERIALIZE_INIT(var_hash);
diff --git a/ext/standard/Makefile.in b/ext/standard/Makefile.in
index fdf2b59830..8a9cd780ac 100644
--- a/ext/standard/Makefile.in
+++ b/ext/standard/Makefile.in
@@ -8,11 +8,15 @@ LTLIBRARY_SOURCES=\
parsedate.c quot_print.c rand.c reg.c soundex.c string.c scanf.c \
syslog.c type.c uniqid.c url.c url_scanner.c var.c versioning.c assert.c \
strnatcmp.c levenshtein.c incomplete_class.c url_scanner_ex.c \
- ftp_fopen_wrapper.c http_fopen_wrapper.c php_fopen_wrapper.c credits.c
+ ftp_fopen_wrapper.c http_fopen_wrapper.c php_fopen_wrapper.c credits.c \
+ var_unserializer.c
include $(top_srcdir)/build/dynlib.mk
parsedate.c: $(srcdir)/parsedate.y
+$(srcdir)/var_unserializer.c: $(srcdir)/var_unserializer.re
+ re2c -b $(srcdir)/var_unserializer.re > $@
+
$(srcdir)/url_scanner_ex.c: $(srcdir)/url_scanner_ex.re
re2c -b $(srcdir)/url_scanner_ex.re > $@
diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h
index 6336e0fe8e..aa5e003955 100644
--- a/ext/standard/php_var.h
+++ b/ext/standard/php_var.h
@@ -32,8 +32,14 @@ void php_var_dump(zval **struc, int level TSRMLS_DC);
/* typdef HashTable php_serialize_data_t; */
#define php_serialize_data_t HashTable
+struct php_unserialize_data {
+ void *first;
+};
+
+typedef struct php_unserialize_data php_unserialize_data_t;
+
PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC);
-PHPAPI int php_var_unserialize(zval **rval, const char **p, const char *max, php_serialize_data_t *var_hash TSRMLS_DC);
+PHPAPI int php_var_unserialize(zval **rval, const char **p, const char *max, php_unserialize_data_t *var_hash TSRMLS_DC);
#define PHP_VAR_SERIALIZE_INIT(var_hash) \
zend_hash_init(&(var_hash), 10, NULL, NULL, 0)
@@ -41,30 +47,16 @@ PHPAPI int php_var_unserialize(zval **rval, const char **p, const char *max, php
zend_hash_destroy(&(var_hash))
#define PHP_VAR_UNSERIALIZE_INIT(var_hash) \
- zend_hash_init(&(var_hash), 10, NULL, NULL, 0)
+ (var_hash).first = 0
#define PHP_VAR_UNSERIALIZE_DESTROY(var_hash) \
- zend_hash_destroy(&(var_hash))
+ var_destroy(&(var_hash))
-#define PHP_VAR_UNSERIALIZE_ZVAL_CHANGED(var_hash, ozval, nzval) \
-if (var_hash) { \
- HashPosition pos; \
- zval **zval_ref; \
- zend_hash_internal_pointer_reset_ex(var_hash, &pos); \
- while (zend_hash_get_current_data_ex(var_hash, (void **) &zval_ref, &pos) == SUCCESS) { \
- if (*zval_ref == ozval) { \
- char *string_key; \
- uint str_key_len; \
- ulong num_key; \
- \
- zend_hash_get_current_key_ex(var_hash, &string_key, &str_key_len, &num_key, 1, &pos); \
- /* this is our hash and it _will_ be number indexed! */ \
- zend_hash_index_update(var_hash, num_key, &nzval, sizeof(zval *), NULL); \
- break; \
- } \
- zend_hash_move_forward_ex(var_hash, &pos); \
- } \
-}
+void var_replace(php_unserialize_data_t *var_hash, zval *ozval, zval **nzval);
+void var_destroy(php_unserialize_data_t *var_hash);
+#define PHP_VAR_UNSERIALIZE_ZVAL_CHANGED(var_hash, ozval, nzval) \
+ var_replace((var_hash), (ozval), &(nzval))
+
PHPAPI zend_class_entry *php_create_empty_class(char *class_name, int len);
#endif /* PHP_VAR_H */
diff --git a/ext/standard/var.c b/ext/standard/var.c
index 5b11a5247f..5e865cf29c 100644
--- a/ext/standard/var.c
+++ b/ext/standard/var.c
@@ -362,249 +362,7 @@ PHPAPI void php_var_serialize(smart_str *buf, zval **struc, HashTable *var_hash
}
/* }}} */
-/* {{{ php_var_unserialize */
-PHPAPI int php_var_unserialize(zval **rval, const char **p, const char *max, HashTable *var_hash TSRMLS_DC)
-{
- const char *q;
- char *str;
- int i;
- char cur;
- ulong id;
- HashTable *myht;
- zval **rval_ref;
-
- if (var_hash && **p != 'R') { /* references aren't counted by serializer! */
- zend_hash_next_index_insert(var_hash, rval, sizeof(*rval), NULL);
- }
-
- switch (cur = **p) {
- case 'R':
- if (*((*p) + 1) != ':') {
- return 0;
- }
- q = *p;
- while (**p && **p != ';') {
- (*p)++;
- }
- if (**p != ';') {
- return 0;
- }
- (*p)++;
- id = atol(q + 2)-1; /* count starts with 1 */
- if (!var_hash) {
- return 0;
- }
- if (zend_hash_index_find(var_hash, id, (void *)&rval_ref) != SUCCESS) {
- return 0;
- }
- zval_ptr_dtor(rval);
- *rval = *rval_ref;
- (*rval)->refcount++;
- (*rval)->is_ref = 1;
- return 1;
-
- case 'N':
- if (*((*p) + 1) != ';') {
- return 0;
- }
- (*p)++;
- INIT_PZVAL(*rval);
- ZVAL_NULL(*rval);
- (*p)++;
- return 1;
-
- case 'b': /* bool */
- case 'i':
- if (*((*p) + 1) != ':') {
- return 0;
- }
- q = *p;
- while (**p && **p != ';') {
- (*p)++;
- }
- if (**p != ';') {
- return 0;
- }
- (*p)++;
- INIT_PZVAL(*rval);
- if (cur == 'b') {
- ZVAL_BOOL(*rval, atol(q + 2));
- } else {
- ZVAL_LONG(*rval, atol(q + 2));
- }
- return 1;
-
- case 'd':
- if (*((*p) + 1) != ':') {
- return 0;
- }
- q = *p;
- while (**p && **p != ';') {
- (*p)++;
- }
- if (**p != ';') {
- return 0;
- }
- (*p)++;
- INIT_PZVAL(*rval);
- ZVAL_DOUBLE(*rval, atof(q + 2));
- return 1;
-
- case 's':
- if (*((*p) + 1) != ':') {
- return 0;
- }
- (*p) += 2;
- q = *p;
- while (**p && **p != ':') {
- (*p)++;
- }
- if (**p != ':') {
- return 0;
- }
- i = atoi(q);
- if (i < 0 || (*p + 3 + i) > max || *((*p) + 1) != '\"' ||
- *((*p) + 2 + i) != '\"' || *((*p) + 3 + i) != ';') {
- return 0;
- }
- (*p) += 2;
-
- if (i == 0) {
- str = empty_string;
- } else {
- str = estrndup(*p, i);
- }
- (*p) += i + 2;
- INIT_PZVAL(*rval);
- ZVAL_STRINGL(*rval, str, i, 0);
- return 1;
-
- case 'a':
- case 'o':
- case 'O': {
- zend_bool incomplete_class = 0;
- char *class_name = NULL;
- size_t name_len = 0;
- int pi;
-
- INIT_PZVAL(*rval);
-
- if (cur == 'a') {
- Z_TYPE_PP(rval) = IS_ARRAY;
- ALLOC_HASHTABLE(Z_ARRVAL_PP(rval));
- myht = Z_ARRVAL_PP(rval);
- } else {
- zend_class_entry *ce;
-
- if (cur == 'O') { /* php4 serialized - we get the class-name */
- if (*((*p) + 1) != ':') {
- return 0;
- }
- (*p) += 2;
- q = *p;
- while (**p && **p != ':') {
- (*p)++;
- }
- if (**p != ':') {
- return 0;
- }
- name_len = i = atoi(q);
- if (i < 0 || (*p + 3 + i) > max || *((*p) + 1) != '\"' ||
- *((*p) + 2 + i) != '\"' || *((*p) + 3 + i) != ':') {
- return 0;
- }
- (*p) += 2;
- class_name = emalloc(i + 1);
- for(pi=0;pi<i;pi++) {
- class_name[pi] = tolower((*p)[pi]);
- }
- class_name[i] = 0;
- (*p) += i;
-
- if (zend_hash_find(EG(class_table), class_name, i+1, (void **) &ce)==FAILURE) {
- incomplete_class = 1;
- ce = PHP_IC_ENTRY;
- }
- } else { /* old php 3.0 data 'o' */
- ce = &zend_standard_class_def;
- }
-
- object_init_ex(*rval, ce);
- myht = Z_OBJPROP_PP(rval);
-
- if (incomplete_class)
- php_store_class_name(*rval, class_name, name_len);
-
- if (class_name)
- efree(class_name);
- }
-
- (*p) += 2;
- i = atoi(*p);
-
- if (cur == 'a') { /* object_init_ex will init the HashTable for objects! */
- zend_hash_init(myht, i + 1, NULL, ZVAL_PTR_DTOR, 0);
- }
-
- while (**p && **p != ':') {
- (*p)++;
- }
- if (**p != ':' || *((*p) + 1) != '{') {
- return 0;
- }
- for ((*p) += 2; **p && **p != '}' && i > 0; i--) {
- zval *key;
- zval *data;
-
- ALLOC_INIT_ZVAL(key);
- ALLOC_INIT_ZVAL(data);
-
- if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) {
- zval_dtor(key);
- FREE_ZVAL(key);
- FREE_ZVAL(data);
- return 0;
- }
- if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) {
- zval_dtor(key);
- FREE_ZVAL(key);
- zval_dtor(data);
- FREE_ZVAL(data);
- return 0;
- }
- switch (Z_TYPE_P(key)) {
- case IS_LONG:
- zend_hash_index_update(myht, Z_LVAL_P(key), &data, sizeof(data), NULL);
- break;
- case IS_STRING:
- zend_hash_update(myht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
- break;
- }
- zval_dtor(key);
- FREE_ZVAL(key);
- }
-
- if (Z_TYPE_PP(rval) == IS_OBJECT) {
- zval *retval_ptr = NULL;
- zval fname;
-
- INIT_PZVAL(&fname);
- ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0);
- call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
-
- if (retval_ptr)
- zval_ptr_dtor(&retval_ptr);
- }
-
- return *((*p)++) == '}';
- }
- }
-
- return 0;
-}
-
-/* }}} */
/* {{{ proto string serialize(mixed variable)
Returns a string representation of variable (which can later be unserialized) */
PHP_FUNCTION(serialize)
@@ -635,7 +393,7 @@ PHP_FUNCTION(serialize)
PHP_FUNCTION(unserialize)
{
zval **buf;
- php_serialize_data_t var_hash;
+ php_unserialize_data_t var_hash;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &buf) == FAILURE) {
WRONG_PARAM_COUNT;
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
new file mode 100644
index 0000000000..fe2fdcbf00
--- /dev/null
+++ b/ext/standard/var_unserializer.c
@@ -0,0 +1,635 @@
+/* Generated by re2c 0.5 on Fri Nov 9 14:39:34 2001 */
+#line 1 "/home/sas/src/php4/ext/standard/var_unserializer.re"
+#include "php.h"
+#include "ext/standard/php_var.h"
+#include "php_incomplete_class.h"
+
+/* {{{ reference-handling for unserializer: var_* */
+#define VAR_ENTRIES_MAX 1024
+
+typedef struct {
+ zval *data[VAR_ENTRIES_MAX];
+ int used_slots;
+ void *next;
+} var_entries;
+
+static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
+{
+ var_entries *var_hash = var_hashx->first, *prev = NULL;
+
+ while (var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) {
+ prev = var_hash;
+ var_hash = var_hash->next;
+ }
+
+ if (!var_hash) {
+ var_hash = emalloc(sizeof(var_entries));
+ var_hash->used_slots = 0;
+ var_hash->next = 0;
+
+ if (!var_hashx->first)
+ var_hashx->first = var_hash;
+ else
+ prev->next = var_hash;
+ }
+
+ var_hash->data[var_hash->used_slots++] = *rval;
+}
+
+void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval)
+{
+ int i;
+ var_entries *var_hash = var_hashx->first;
+
+ while (var_hash) {
+ for (i = 0; i < var_hash->used_slots; i++) {
+ if (var_hash->data[i] == ozval) {
+ var_hash->data[i] = *nzval;
+ return;
+ }
+ }
+ var_hash = var_hash->next;
+ }
+}
+
+static int var_access(php_unserialize_data_t *var_hashx, int id, zval ***store)
+{
+ var_entries *var_hash = var_hashx->first;
+
+ while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) {
+ var_hash = var_hash->next;
+ id -= VAR_ENTRIES_MAX;
+ }
+
+ if (!var_hash) return !SUCCESS;
+
+ if (id >= var_hash->used_slots) return !SUCCESS;
+
+ *store = &var_hash->data[id];
+
+ return SUCCESS;
+}
+
+void var_destroy(php_unserialize_data_t *var_hashx)
+{
+ void *next;
+ var_entries *var_hash = var_hashx->first;
+
+ while (var_hash) {
+ next = var_hash->next;
+ efree(var_hash);
+ var_hash = next;
+ }
+}
+
+/* }}} */
+
+#define YYFILL(n) do { } while (0)
+#define YYCTYPE unsigned char
+#define YYCURSOR cursor
+#define YYLIMIT limit
+#define YYMARKER marker
+
+
+#line 97
+
+
+
+
+static inline int parse_iv2(const char *p, const char **q)
+{
+ char cursor;
+ int result = 0;
+
+ while (1) {
+ cursor = *p;
+ if (cursor >= '0' && cursor <= '9') {
+ result = result * 10 + cursor - '0';
+ } else {
+ break;
+ }
+ p++;
+ }
+ if (q) *q = p;
+ return result;
+}
+
+static inline int parse_iv(const char *p)
+{
+ return parse_iv2(p, NULL);
+}
+
+#define UNSERIALIZE_PARAMETER zval **rval, const char **p, const char *max, php_unserialize_data_t *var_hash TSRMLS_DC
+#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC
+
+static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements)
+{
+ while (elements-- > 0) {
+ zval *key, *data;
+
+ ALLOC_INIT_ZVAL(key);
+
+ if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) {
+ zval_dtor(key);
+ FREE_ZVAL(key);
+ return 0;
+ }
+
+ ALLOC_INIT_ZVAL(data);
+
+ if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) {
+ zval_dtor(key);
+ FREE_ZVAL(key);
+ zval_dtor(data);
+ FREE_ZVAL(data);
+ return 0;
+ }
+
+ switch (Z_TYPE_P(key)) {
+ case IS_LONG:
+ zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
+ break;
+ case IS_STRING:
+ zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
+ break;
+
+ }
+
+ zval_dtor(key);
+ FREE_ZVAL(key);
+ }
+
+ return 1;
+}
+
+static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
+{
+ if (*((*p)++) == '}')
+ return 1;
+
+ zval_ptr_dtor(rval);
+ return 0;
+}
+
+static inline int object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
+{
+ int elements;
+
+ elements = parse_iv2((*p) + 2, p);
+
+ (*p) += 2;
+
+ object_init_ex(*rval, ce);
+ return elements;
+}
+
+static inline int object_common2(UNSERIALIZE_PARAMETER, int elements)
+{
+ zval *retval_ptr = NULL;
+ zval fname;
+
+ if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements)) {
+ return 0;
+ }
+
+ INIT_PZVAL(&fname);
+ ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0);
+ call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
+
+ if (retval_ptr)
+ zval_ptr_dtor(&retval_ptr);
+
+ return finish_nested_data(UNSERIALIZE_PASSTHRU);
+
+}
+
+PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
+{
+ const unsigned char *cursor, *limit, *marker, *start;
+ zval **rval_ref;
+
+ cursor = *p;
+
+ if (var_hash && cursor[0] != 'R') {
+ var_push(var_hash, rval);
+ }
+
+ start = cursor;
+
+
+
+{
+ YYCTYPE yych;
+ unsigned int yyaccept;
+ static unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ goto yy0;
+yy1: ++YYCURSOR;
+yy0:
+ if((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
+ yych = *YYCURSOR;
+ if(yych <= 'c'){
+ if(yych <= 'Q'){
+ if(yych <= 'M') goto yy13;
+ if(yych <= 'N') goto yy5;
+ if(yych <= 'O') goto yy12;
+ goto yy13;
+ } else {
+ if(yych <= '`'){
+ if(yych <= 'R') goto yy3;
+ goto yy13;
+ } else {
+ if(yych <= 'a') goto yy10;
+ if(yych <= 'b') goto yy6;
+ goto yy13;
+ }
+ }
+ } else {
+ if(yych <= 'n'){
+ if(yych <= 'd') goto yy8;
+ if(yych == 'i') goto yy7;
+ goto yy13;
+ } else {
+ if(yych <= 'r'){
+ if(yych <= 'o') goto yy11;
+ goto yy13;
+ } else {
+ if(yych <= 's') goto yy9;
+ if(yych <= '\277') goto yy13;
+ }
+ }
+ }
+yy2: YYCURSOR = YYMARKER;
+ switch(yyaccept){
+ case 0: goto yy4;
+ }
+yy3: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych == ':') goto yy65;
+yy4:
+#line 356
+ { return 0; }
+yy5: yych = *++YYCURSOR;
+ if(yych == ';') goto yy63;
+ goto yy4;
+yy6: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych == ':') goto yy58;
+ goto yy4;
+yy7: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych == ':') goto yy53;
+ goto yy4;
+yy8: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych == ':') goto yy38;
+ goto yy4;
+yy9: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych == ':') goto yy32;
+ goto yy4;
+yy10: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych == ':') goto yy26;
+ goto yy4;
+yy11: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych == ':') goto yy20;
+ goto yy4;
+yy12: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yych == ':') goto yy14;
+ goto yy4;
+yy13: yych = *++YYCURSOR;
+ goto yy4;
+yy14: yych = *++YYCURSOR;
+ if(yybm[0+yych] & 128) goto yy15;
+ goto yy2;
+yy15: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy16: if(yybm[0+yych] & 128) goto yy15;
+ if(yych != ':') goto yy2;
+yy17: yych = *++YYCURSOR;
+ if(yych != '"') goto yy2;
+yy18: yych = *++YYCURSOR;
+yy19:
+#line 317
+ {
+ int len;
+ int elements;
+ int len2;
+ char *class_name;
+ zend_class_entry *ce;
+ int incomplete_class = 0;
+
+ INIT_PZVAL(*rval);
+ len2 = len = parse_iv(start + 2);
+ if (len == 0)
+ return 0;
+
+ class_name = estrndup(YYCURSOR, len);
+ YYCURSOR += len;
+
+ while (len-- > 0) {
+ if (class_name[len] >= 'A' && class_name[len] <= 'Z') {
+ class_name[len] = class_name[len] - 'A' + 'a';
+ }
+ }
+
+ if (zend_hash_find(EG(class_table), class_name, len2 + 1, (void **) &ce) != SUCCESS) {
+ incomplete_class = 1;
+ ce = PHP_IC_ENTRY;
+ } else
+ efree(class_name);
+
+ *p = YYCURSOR;
+ elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
+
+ if (incomplete_class) {
+ php_store_class_name(*rval, class_name, len2);
+ efree(class_name);
+ }
+
+ return object_common2(UNSERIALIZE_PASSTHRU, elements);
+}
+yy20: yych = *++YYCURSOR;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy21: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy22: if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy21;
+ if(yych >= ';') goto yy2;
+yy23: yych = *++YYCURSOR;
+ if(yych != '"') goto yy2;
+yy24: yych = *++YYCURSOR;
+yy25:
+#line 309
+ {
+
+ INIT_PZVAL(*rval);
+
+ return object_common2(UNSERIALIZE_PASSTHRU,
+ object_common1(UNSERIALIZE_PASSTHRU, &zend_standard_class_def));
+}
+yy26: yych = *++YYCURSOR;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy27: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy28: if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy27;
+ if(yych >= ';') goto yy2;
+yy29: yych = *++YYCURSOR;
+ if(yych != '{') goto yy2;
+yy30: yych = *++YYCURSOR;
+yy31:
+#line 291
+ {
+ int elements = parse_iv(start + 2);
+
+ *p = YYCURSOR;
+
+ INIT_PZVAL(*rval);
+ Z_TYPE_PP(rval) = IS_ARRAY;
+ ALLOC_HASHTABLE(Z_ARRVAL_PP(rval));
+
+ zend_hash_init(Z_ARRVAL_PP(rval), elements + 1, NULL, ZVAL_PTR_DTOR, 0);
+
+ if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements)) {
+ return 0;
+ }
+
+ return finish_nested_data(UNSERIALIZE_PASSTHRU);
+}
+yy32: yych = *++YYCURSOR;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy33: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy34: if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy33;
+ if(yych >= ';') goto yy2;
+yy35: yych = *++YYCURSOR;
+ if(yych != '"') goto yy2;
+yy36: yych = *++YYCURSOR;
+yy37:
+#line 271
+ {
+ int len;
+ char *str;
+
+ len = parse_iv(start + 2);
+
+ if (len == 0) {
+ str = empty_string;
+ } else {
+ str = estrndup(YYCURSOR, len);
+ }
+
+ YYCURSOR += len + 2;
+ *p = YYCURSOR;
+
+ INIT_PZVAL(*rval);
+ ZVAL_STRINGL(*rval, str, len, 0);
+ return 1;
+}
+yy38: yych = *++YYCURSOR;
+ if(yych == '.') goto yy41;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy39: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy40: if(yych <= '/'){
+ if(yych == '.') goto yy50;
+ goto yy2;
+ } else {
+ if(yych <= '9') goto yy39;
+ if(yych == ';') goto yy44;
+ goto yy2;
+ }
+yy41: yych = *++YYCURSOR;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy42: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy43: if(yych <= ';'){
+ if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy42;
+ if(yych <= ':') goto yy2;
+ } else {
+ if(yych <= 'E'){
+ if(yych <= 'D') goto yy2;
+ goto yy46;
+ } else {
+ if(yych == 'e') goto yy46;
+ goto yy2;
+ }
+ }
+yy44: yych = *++YYCURSOR;
+yy45:
+#line 264
+ {
+ *p = YYCURSOR;
+ INIT_PZVAL(*rval);
+ ZVAL_DOUBLE(*rval, atof(start + 2));
+ return 1;
+}
+yy46: yych = *++YYCURSOR;
+ if(yych <= ','){
+ if(yych != '+') goto yy2;
+ } else {
+ if(yych <= '-') goto yy47;
+ if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy48;
+ goto yy2;
+ }
+yy47: yych = *++YYCURSOR;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy48: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy49: if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy48;
+ if(yych == ';') goto yy44;
+ goto yy2;
+yy50: yych = *++YYCURSOR;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy51: ++YYCURSOR;
+ if((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+ yych = *YYCURSOR;
+yy52: if(yych <= ';'){
+ if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy51;
+ if(yych <= ':') goto yy2;
+ goto yy44;
+ } else {
+ if(yych <= 'E'){
+ if(yych <= 'D') goto yy2;
+ goto yy46;
+ } else {
+ if(yych == 'e') goto yy46;
+ goto yy2;
+ }
+ }
+yy53: yych = *++YYCURSOR;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy54: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy55: if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy54;
+ if(yych != ';') goto yy2;
+yy56: yych = *++YYCURSOR;
+yy57:
+#line 257
+ {
+ *p = YYCURSOR;
+ INIT_PZVAL(*rval);
+ ZVAL_LONG(*rval, parse_iv(start + 2));
+ return 1;
+}
+yy58: yych = *++YYCURSOR;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy59: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy60: if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy59;
+ if(yych != ';') goto yy2;
+yy61: yych = *++YYCURSOR;
+yy62:
+#line 250
+ {
+ *p = YYCURSOR;
+ INIT_PZVAL(*rval);
+ ZVAL_BOOL(*rval, parse_iv(start + 2));
+ return 1;
+}
+yy63: yych = *++YYCURSOR;
+yy64:
+#line 243
+ {
+ *p = YYCURSOR;
+ INIT_PZVAL(*rval);
+ ZVAL_NULL(*rval);
+ return 1;
+}
+yy65: yych = *++YYCURSOR;
+ if(yych <= '/') goto yy2;
+ if(yych >= ':') goto yy2;
+yy66: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+yy67: if(yych <= '/') goto yy2;
+ if(yych <= '9') goto yy66;
+ if(yych != ';') goto yy2;
+yy68: yych = *++YYCURSOR;
+yy69:
+#line 224
+ {
+ int id;
+
+ *p = YYCURSOR;
+ if (!var_hash) return 0;
+
+ id = parse_iv(start + 2) - 1;
+ if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
+ return 0;
+ }
+
+ zval_ptr_dtor(rval);
+ *rval = *rval_ref;
+ (*rval)->refcount++;
+ (*rval)->is_ref = 1;
+
+ return 1;
+}
+}
+#line 358
+
+
+ return 0;
+}
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
new file mode 100644
index 0000000000..02c1fce66b
--- /dev/null
+++ b/ext/standard/var_unserializer.re
@@ -0,0 +1,361 @@
+#include "php.h"
+#include "ext/standard/php_var.h"
+#include "php_incomplete_class.h"
+
+/* {{{ reference-handling for unserializer: var_* */
+#define VAR_ENTRIES_MAX 1024
+
+typedef struct {
+ zval *data[VAR_ENTRIES_MAX];
+ int used_slots;
+ void *next;
+} var_entries;
+
+static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
+{
+ var_entries *var_hash = var_hashx->first, *prev = NULL;
+
+ while (var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) {
+ prev = var_hash;
+ var_hash = var_hash->next;
+ }
+
+ if (!var_hash) {
+ var_hash = emalloc(sizeof(var_entries));
+ var_hash->used_slots = 0;
+ var_hash->next = 0;
+
+ if (!var_hashx->first)
+ var_hashx->first = var_hash;
+ else
+ prev->next = var_hash;
+ }
+
+ var_hash->data[var_hash->used_slots++] = *rval;
+}
+
+void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval)
+{
+ int i;
+ var_entries *var_hash = var_hashx->first;
+
+ while (var_hash) {
+ for (i = 0; i < var_hash->used_slots; i++) {
+ if (var_hash->data[i] == ozval) {
+ var_hash->data[i] = *nzval;
+ return;
+ }
+ }
+ var_hash = var_hash->next;
+ }
+}
+
+static int var_access(php_unserialize_data_t *var_hashx, int id, zval ***store)
+{
+ var_entries *var_hash = var_hashx->first;
+
+ while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) {
+ var_hash = var_hash->next;
+ id -= VAR_ENTRIES_MAX;
+ }
+
+ if (!var_hash) return !SUCCESS;
+
+ if (id >= var_hash->used_slots) return !SUCCESS;
+
+ *store = &var_hash->data[id];
+
+ return SUCCESS;
+}
+
+void var_destroy(php_unserialize_data_t *var_hashx)
+{
+ void *next;
+ var_entries *var_hash = var_hashx->first;
+
+ while (var_hash) {
+ next = var_hash->next;
+ efree(var_hash);
+ var_hash = next;
+ }
+}
+
+/* }}} */
+
+#define YYFILL(n) do { } while (0)
+#define YYCTYPE unsigned char
+#define YYCURSOR cursor
+#define YYLIMIT limit
+#define YYMARKER marker
+
+
+/*!re2c
+iv = [0-9]+;
+nv = ([0-9]* "." [0-9]+|[0-9]+ "." [0-9]+);
+nvexp = nv [eE] [+-]? iv;
+any = [\000-\277];
+*/
+
+
+
+static inline int parse_iv2(const char *p, const char **q)
+{
+ char cursor;
+ int result = 0;
+
+ while (1) {
+ cursor = *p;
+ if (cursor >= '0' && cursor <= '9') {
+ result = result * 10 + cursor - '0';
+ } else {
+ break;
+ }
+ p++;
+ }
+ if (q) *q = p;
+ return result;
+}
+
+static inline int parse_iv(const char *p)
+{
+ return parse_iv2(p, NULL);
+}
+
+#define UNSERIALIZE_PARAMETER zval **rval, const char **p, const char *max, php_unserialize_data_t *var_hash TSRMLS_DC
+#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC
+
+static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements)
+{
+ while (elements-- > 0) {
+ zval *key, *data;
+
+ ALLOC_INIT_ZVAL(key);
+
+ if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) {
+ zval_dtor(key);
+ FREE_ZVAL(key);
+ return 0;
+ }
+
+ ALLOC_INIT_ZVAL(data);
+
+ if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) {
+ zval_dtor(key);
+ FREE_ZVAL(key);
+ zval_dtor(data);
+ FREE_ZVAL(data);
+ return 0;
+ }
+
+ switch (Z_TYPE_P(key)) {
+ case IS_LONG:
+ zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
+ break;
+ case IS_STRING:
+ zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
+ break;
+
+ }
+
+ zval_dtor(key);
+ FREE_ZVAL(key);
+ }
+
+ return 1;
+}
+
+static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
+{
+ if (*((*p)++) == '}')
+ return 1;
+
+ zval_ptr_dtor(rval);
+ return 0;
+}
+
+static inline int object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
+{
+ int elements;
+
+ elements = parse_iv2((*p) + 2, p);
+
+ (*p) += 2;
+
+ object_init_ex(*rval, ce);
+ return elements;
+}
+
+static inline int object_common2(UNSERIALIZE_PARAMETER, int elements)
+{
+ zval *retval_ptr = NULL;
+ zval fname;
+
+ if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements)) {
+ return 0;
+ }
+
+ INIT_PZVAL(&fname);
+ ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0);
+ call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
+
+ if (retval_ptr)
+ zval_ptr_dtor(&retval_ptr);
+
+ return finish_nested_data(UNSERIALIZE_PASSTHRU);
+
+}
+
+PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
+{
+ const unsigned char *cursor, *limit, *marker, *start;
+ zval **rval_ref;
+
+ cursor = *p;
+
+ if (var_hash && cursor[0] != 'R') {
+ var_push(var_hash, rval);
+ }
+
+ start = cursor;
+
+
+
+/*!re2c
+"R:" iv ";" {
+ int id;
+
+ *p = YYCURSOR;
+ if (!var_hash) return 0;
+
+ id = parse_iv(start + 2) - 1;
+ if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
+ return 0;
+ }
+
+ zval_ptr_dtor(rval);
+ *rval = *rval_ref;
+ (*rval)->refcount++;
+ (*rval)->is_ref = 1;
+
+ return 1;
+}
+
+"N;" {
+ *p = YYCURSOR;
+ INIT_PZVAL(*rval);
+ ZVAL_NULL(*rval);
+ return 1;
+}
+
+"b:" iv ";" {
+ *p = YYCURSOR;
+ INIT_PZVAL(*rval);
+ ZVAL_BOOL(*rval, parse_iv(start + 2));
+ return 1;
+}
+
+"i:" iv ";" {
+ *p = YYCURSOR;
+ INIT_PZVAL(*rval);
+ ZVAL_LONG(*rval, parse_iv(start + 2));
+ return 1;
+}
+
+"d:" (iv | nv | nvexp) ";" {
+ *p = YYCURSOR;
+ INIT_PZVAL(*rval);
+ ZVAL_DOUBLE(*rval, atof(start + 2));
+ return 1;
+}
+
+"s:" iv ":" ["] {
+ int len;
+ char *str;
+
+ len = parse_iv(start + 2);
+
+ if (len == 0) {
+ str = empty_string;
+ } else {
+ str = estrndup(YYCURSOR, len);
+ }
+
+ YYCURSOR += len + 2;
+ *p = YYCURSOR;
+
+ INIT_PZVAL(*rval);
+ ZVAL_STRINGL(*rval, str, len, 0);
+ return 1;
+}
+
+"a:" iv ":" "{" {
+ int elements = parse_iv(start + 2);
+
+ *p = YYCURSOR;
+
+ INIT_PZVAL(*rval);
+ Z_TYPE_PP(rval) = IS_ARRAY;
+ ALLOC_HASHTABLE(Z_ARRVAL_PP(rval));
+
+ zend_hash_init(Z_ARRVAL_PP(rval), elements + 1, NULL, ZVAL_PTR_DTOR, 0);
+
+ if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements)) {
+ return 0;
+ }
+
+ return finish_nested_data(UNSERIALIZE_PASSTHRU);
+}
+
+"o:" iv ":" ["] {
+
+ INIT_PZVAL(*rval);
+
+ return object_common2(UNSERIALIZE_PASSTHRU,
+ object_common1(UNSERIALIZE_PASSTHRU, &zend_standard_class_def));
+}
+
+"O:" iv ":" ["] {
+ int len;
+ int elements;
+ int len2;
+ char *class_name;
+ zend_class_entry *ce;
+ int incomplete_class = 0;
+
+ INIT_PZVAL(*rval);
+ len2 = len = parse_iv(start + 2);
+ if (len == 0)
+ return 0;
+
+ class_name = estrndup(YYCURSOR, len);
+ YYCURSOR += len;
+
+ while (len-- > 0) {
+ if (class_name[len] >= 'A' && class_name[len] <= 'Z') {
+ class_name[len] = class_name[len] - 'A' + 'a';
+ }
+ }
+
+ if (zend_hash_find(EG(class_table), class_name, len2 + 1, (void **) &ce) != SUCCESS) {
+ incomplete_class = 1;
+ ce = PHP_IC_ENTRY;
+ } else
+ efree(class_name);
+
+ *p = YYCURSOR;
+ elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
+
+ if (incomplete_class) {
+ php_store_class_name(*rval, class_name, len2);
+ efree(class_name);
+ }
+
+ return object_common2(UNSERIALIZE_PASSTHRU, elements);
+}
+
+any { return 0; }
+
+*/
+
+ return 0;
+}