]> granicus.if.org Git - php/commitdiff
Rewrite of unserializer which should be more maintainable and extensible.
authorSascha Schumann <sas@php.net>
Sat, 10 Nov 2001 21:18:34 +0000 (21:18 +0000)
committerSascha Schumann <sas@php.net>
Sat, 10 Nov 2001 21:18:34 +0000 (21:18 +0000)
Changes pass `make test´ and a couple of custom tests.

Enjoy.

ext/session/php_session.h
ext/session/session.c
ext/standard/Makefile.in
ext/standard/php_var.h
ext/standard/var.c
ext/standard/var_unserializer.c [new file with mode: 0644]
ext/standard/var_unserializer.re [new file with mode: 0644]
win32/php4dll.dsp
win32/php4dllts.dsp

index 5d4f0ca5e88b149aec4a1c4a223ebcb7002ce7a3..f0c245ea9daeffb9fd598232a3500a73563a5ce7 100644 (file)
@@ -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 *);
index ff9be2052ee33be8676c6a9c589a29690f425847..2a54c4c708ffada4b044cede050a5f5469630ded 100644 (file)
@@ -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);
 
index fdf2b598302003be5d9a2f85fa346cee4b214880..8a9cd780acca4b297ca3b28596a7397f99596929 100644 (file)
@@ -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 > $@
index 6336e0fe8ec36febbb07c92199df879014a8f742..aa5e00395506caaaac17df8f44f86881e7563372 100644 (file)
@@ -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 */
index 5b11a5247f9d86226d9fbd97a629ce9dfc73db19..5e865cf29ccec816f2cf64000f214163bf6621dc 100644 (file)
@@ -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 (file)
index 0000000..fe2fdcb
--- /dev/null
@@ -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 (file)
index 0000000..02c1fce
--- /dev/null
@@ -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;
+}
index ace1ec305e8de96f8a4ee474959b8082cb65316f..b8f8a89b59cbc626ed2570e72892b5b312944354 100644 (file)
@@ -544,6 +544,10 @@ SOURCE=..\ext\standard\var.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=..\ext\standard\var_unserializer.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=..\ext\standard\versioning.c\r
 # End Source File\r
 # End Group\r
index b518a211a0ca29d55685366fbb7840be60026c66..bee9271cd026ce6f6ad6688bb89e3ddd73b8018a 100644 (file)
@@ -579,6 +579,10 @@ SOURCE=..\ext\standard\var.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=..\ext\standard\var_unserializer.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=..\ext\standard\versioning.c\r
 # End Source File\r
 # End Group\r