Annotation of embedaddon/php/ext/standard/var_unserializer.re, revision 1.1.1.2

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
                      5:   | Copyright (c) 1997-2012 The PHP Group                                |
                      6:   +----------------------------------------------------------------------+
                      7:   | This source file is subject to version 3.01 of the PHP license,      |
                      8:   | that is bundled with this package in the file LICENSE, and is        |
                      9:   | available through the world-wide-web at the following url:           |
                     10:   | http://www.php.net/license/3_01.txt                                  |
                     11:   | If you did not receive a copy of the PHP license and are unable to   |
                     12:   | obtain it through the world-wide-web, please send a note to          |
                     13:   | license@php.net so we can mail you a copy immediately.               |
                     14:   +----------------------------------------------------------------------+
                     15:   | Author: Sascha Schumann <sascha@schumann.cx>                         |
                     16:   +----------------------------------------------------------------------+
                     17: */
                     18: 
1.1.1.2 ! misho      19: /* $Id$ */
1.1       misho      20: 
                     21: #include "php.h"
                     22: #include "ext/standard/php_var.h"
                     23: #include "php_incomplete_class.h"
                     24: 
                     25: /* {{{ reference-handling for unserializer: var_* */
                     26: #define VAR_ENTRIES_MAX 1024
                     27: 
                     28: typedef struct {
                     29:        zval *data[VAR_ENTRIES_MAX];
                     30:        long used_slots;
                     31:        void *next;
                     32: } var_entries;
                     33: 
                     34: static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
                     35: {
1.1.1.2 ! misho      36:        var_entries *var_hash = (*var_hashx)->last;
        !            37: #if 0
        !            38:        fprintf(stderr, "var_push(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
        !            39: #endif
1.1       misho      40: 
1.1.1.2 ! misho      41:        if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
1.1       misho      42:                var_hash = emalloc(sizeof(var_entries));
                     43:                var_hash->used_slots = 0;
                     44:                var_hash->next = 0;
                     45: 
1.1.1.2 ! misho      46:                if (!(*var_hashx)->first) {
        !            47:                        (*var_hashx)->first = var_hash;
        !            48:                } else {
        !            49:                        ((var_entries *) (*var_hashx)->last)->next = var_hash;
        !            50:                }
        !            51: 
        !            52:                (*var_hashx)->last = var_hash;
1.1       misho      53:        }
                     54: 
                     55:        var_hash->data[var_hash->used_slots++] = *rval;
                     56: }
                     57: 
                     58: PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
                     59: {
1.1.1.2 ! misho      60:        var_entries *var_hash = (*var_hashx)->last_dtor;
        !            61: #if 0
        !            62:        fprintf(stderr, "var_push_dtor(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
        !            63: #endif
1.1       misho      64: 
1.1.1.2 ! misho      65:        if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
1.1       misho      66:                var_hash = emalloc(sizeof(var_entries));
                     67:                var_hash->used_slots = 0;
                     68:                var_hash->next = 0;
                     69: 
1.1.1.2 ! misho      70:                if (!(*var_hashx)->first_dtor) {
        !            71:                        (*var_hashx)->first_dtor = var_hash;
        !            72:                } else {
        !            73:                        ((var_entries *) (*var_hashx)->last_dtor)->next = var_hash;
        !            74:                }
        !            75: 
        !            76:                (*var_hashx)->last_dtor = var_hash;
1.1       misho      77:        }
                     78: 
                     79:        Z_ADDREF_PP(rval);
                     80:        var_hash->data[var_hash->used_slots++] = *rval;
                     81: }
                     82: 
                     83: PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval)
                     84: {
                     85:        long i;
1.1.1.2 ! misho      86:        var_entries *var_hash = (*var_hashx)->first;
        !            87: #if 0
        !            88:        fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(nzval));
        !            89: #endif
1.1       misho      90:        
                     91:        while (var_hash) {
                     92:                for (i = 0; i < var_hash->used_slots; i++) {
                     93:                        if (var_hash->data[i] == ozval) {
                     94:                                var_hash->data[i] = *nzval;
                     95:                                /* do not break here */
                     96:                        }
                     97:                }
                     98:                var_hash = var_hash->next;
                     99:        }
                    100: }
                    101: 
                    102: static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store)
                    103: {
1.1.1.2 ! misho     104:        var_entries *var_hash = (*var_hashx)->first;
        !           105: #if 0
        !           106:        fprintf(stderr, "var_access(%ld): %ld\n", var_hash?var_hash->used_slots:-1L, id);
        !           107: #endif
        !           108:                
1.1       misho     109:        while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) {
                    110:                var_hash = var_hash->next;
                    111:                id -= VAR_ENTRIES_MAX;
                    112:        }
                    113: 
                    114:        if (!var_hash) return !SUCCESS;
                    115: 
                    116:        if (id < 0 || id >= var_hash->used_slots) return !SUCCESS;
                    117: 
                    118:        *store = &var_hash->data[id];
                    119: 
                    120:        return SUCCESS;
                    121: }
                    122: 
                    123: PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
                    124: {
                    125:        void *next;
                    126:        long i;
1.1.1.2 ! misho     127:        var_entries *var_hash = (*var_hashx)->first;
        !           128: #if 0
        !           129:        fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L);
        !           130: #endif
1.1       misho     131:        
                    132:        while (var_hash) {
                    133:                next = var_hash->next;
                    134:                efree(var_hash);
                    135:                var_hash = next;
                    136:        }
                    137: 
1.1.1.2 ! misho     138:        var_hash = (*var_hashx)->first_dtor;
1.1       misho     139:        
                    140:        while (var_hash) {
                    141:                for (i = 0; i < var_hash->used_slots; i++) {
                    142:                        zval_ptr_dtor(&var_hash->data[i]);
                    143:                }
                    144:                next = var_hash->next;
                    145:                efree(var_hash);
                    146:                var_hash = next;
                    147:        }
                    148: }
                    149: 
                    150: /* }}} */
                    151: 
                    152: static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen)
                    153: {
                    154:        size_t i, j;
                    155:        char *str = safe_emalloc(*len, 1, 1);
                    156:        unsigned char *end = *(unsigned char **)p+maxlen;
                    157: 
                    158:        if (end < *p) {
                    159:                efree(str);
                    160:                return NULL;
                    161:        }
                    162: 
                    163:        for (i = 0; i < *len; i++) {
                    164:                if (*p >= end) {
                    165:                        efree(str);
                    166:                        return NULL;
                    167:                }
                    168:                if (**p != '\\') {
                    169:                        str[i] = (char)**p;
                    170:                } else {
                    171:                        unsigned char ch = 0;
                    172: 
                    173:                        for (j = 0; j < 2; j++) {
                    174:                                (*p)++;
                    175:                                if (**p >= '0' && **p <= '9') {
                    176:                                        ch = (ch << 4) + (**p -'0');
                    177:                                } else if (**p >= 'a' && **p <= 'f') {
                    178:                                        ch = (ch << 4) + (**p -'a'+10);
                    179:                                } else if (**p >= 'A' && **p <= 'F') {
                    180:                                        ch = (ch << 4) + (**p -'A'+10);
                    181:                                } else {
                    182:                                        efree(str);
                    183:                                        return NULL;
                    184:                                }
                    185:                        }
                    186:                        str[i] = (char)ch;
                    187:                }
                    188:                (*p)++;
                    189:        }
                    190:        str[i] = 0;
                    191:        *len = i;
                    192:        return str;
                    193: }
                    194: 
                    195: #define YYFILL(n) do { } while (0)
                    196: #define YYCTYPE unsigned char
                    197: #define YYCURSOR cursor
                    198: #define YYLIMIT limit
                    199: #define YYMARKER marker
                    200: 
                    201: 
                    202: /*!re2c
                    203: uiv = [+]? [0-9]+;
                    204: iv = [+-]? [0-9]+;
                    205: nv = [+-]? ([0-9]* "." [0-9]+|[0-9]+ "." [0-9]*);
                    206: nvexp = (iv | nv) [eE] [+-]? iv;
                    207: any = [\000-\377];
                    208: object = [OC];
                    209: */
                    210: 
                    211: 
                    212: 
                    213: static inline long parse_iv2(const unsigned char *p, const unsigned char **q)
                    214: {
                    215:        char cursor;
                    216:        long result = 0;
                    217:        int neg = 0;
                    218: 
                    219:        switch (*p) {
                    220:                case '-':
                    221:                        neg++;
                    222:                        /* fall-through */
                    223:                case '+':
                    224:                        p++;
                    225:        }
                    226:        
                    227:        while (1) {
                    228:                cursor = (char)*p;
                    229:                if (cursor >= '0' && cursor <= '9') {
                    230:                        result = result * 10 + (size_t)(cursor - (unsigned char)'0');
                    231:                } else {
                    232:                        break;
                    233:                }
                    234:                p++;
                    235:        }
                    236:        if (q) *q = p;
                    237:        if (neg) return -result;
                    238:        return result;
                    239: }
                    240: 
                    241: static inline long parse_iv(const unsigned char *p)
                    242: {
                    243:        return parse_iv2(p, NULL);
                    244: }
                    245: 
                    246: /* no need to check for length - re2c already did */
                    247: static inline size_t parse_uiv(const unsigned char *p)
                    248: {
                    249:        unsigned char cursor;
                    250:        size_t result = 0;
                    251: 
                    252:        if (*p == '+') {
                    253:                p++;
                    254:        }
                    255:        
                    256:        while (1) {
                    257:                cursor = *p;
                    258:                if (cursor >= '0' && cursor <= '9') {
                    259:                        result = result * 10 + (size_t)(cursor - (unsigned char)'0');
                    260:                } else {
                    261:                        break;
                    262:                }
                    263:                p++;
                    264:        }
                    265:        return result;
                    266: }
                    267: 
                    268: #define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC
                    269: #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC
                    270: 
                    271: static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements, int objprops)
                    272: {
                    273:        while (elements-- > 0) {
                    274:                zval *key, *data, **old_data;
                    275: 
                    276:                ALLOC_INIT_ZVAL(key);
                    277: 
                    278:                if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) {
                    279:                        zval_dtor(key);
                    280:                        FREE_ZVAL(key);
                    281:                        return 0;
                    282:                }
                    283: 
                    284:                if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
                    285:                        zval_dtor(key);
                    286:                        FREE_ZVAL(key);
                    287:                        return 0;
                    288:                }
                    289: 
                    290:                ALLOC_INIT_ZVAL(data);
                    291: 
                    292:                if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) {
                    293:                        zval_dtor(key);
                    294:                        FREE_ZVAL(key);
                    295:                        zval_dtor(data);
                    296:                        FREE_ZVAL(data);
                    297:                        return 0;
                    298:                }
                    299: 
                    300:                if (!objprops) {
                    301:                        switch (Z_TYPE_P(key)) {
                    302:                        case IS_LONG:
                    303:                                if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) {
                    304:                                        var_push_dtor(var_hash, old_data);
                    305:                                }
                    306:                                zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
                    307:                                break;
                    308:                        case IS_STRING:
                    309:                                if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
                    310:                                        var_push_dtor(var_hash, old_data);
                    311:                                }
                    312:                                zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
                    313:                                break;
                    314:                        }
                    315:                } else {
                    316:                        /* object properties should include no integers */
                    317:                        convert_to_string(key);
                    318:                        zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data,
                    319:                                        sizeof data, NULL);
                    320:                }
                    321:                
                    322:                zval_dtor(key);
                    323:                FREE_ZVAL(key);
                    324: 
                    325:                if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
                    326:                        (*p)--;
                    327:                        return 0;
                    328:                }
                    329:        }
                    330: 
                    331:        return 1;
                    332: }
                    333: 
                    334: static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
                    335: {
                    336:        if (*((*p)++) == '}')
                    337:                return 1;
                    338: 
                    339: #if SOMETHING_NEW_MIGHT_LEAD_TO_CRASH_ENABLE_IF_YOU_ARE_BRAVE
                    340:        zval_ptr_dtor(rval);
                    341: #endif
                    342:        return 0;
                    343: }
                    344: 
                    345: static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
                    346: {
                    347:        long datalen;
                    348: 
                    349:        datalen = parse_iv2((*p) + 2, p);
                    350: 
                    351:        (*p) += 2;
                    352: 
                    353:        if (datalen < 0 || (*p) + datalen >= max) {
                    354:                zend_error(E_WARNING, "Insufficient data for unserializing - %ld required, %ld present", datalen, (long)(max - (*p)));
                    355:                return 0;
                    356:        }
                    357: 
                    358:        if (ce->unserialize == NULL) {
                    359:                zend_error(E_WARNING, "Class %s has no unserializer", ce->name);
                    360:                object_init_ex(*rval, ce);
                    361:        } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) {
                    362:                return 0;
                    363:        }
                    364: 
                    365:        (*p) += datalen;
                    366: 
                    367:        return finish_nested_data(UNSERIALIZE_PASSTHRU);
                    368: }
                    369: 
                    370: static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
                    371: {
                    372:        long elements;
                    373:        
                    374:        elements = parse_iv2((*p) + 2, p);
                    375: 
                    376:        (*p) += 2;
                    377:        
                    378:        object_init_ex(*rval, ce);
                    379:        return elements;
                    380: }
                    381: 
1.1.1.2 ! misho     382: #ifdef PHP_WIN32
        !           383: # pragma optimize("", off)
        !           384: #endif
1.1       misho     385: static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
                    386: {
                    387:        zval *retval_ptr = NULL;
                    388:        zval fname;
                    389: 
                    390:        if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
                    391:                return 0;
                    392:        }
                    393: 
                    394:        if (Z_OBJCE_PP(rval) != PHP_IC_ENTRY &&
                    395:                zend_hash_exists(&Z_OBJCE_PP(rval)->function_table, "__wakeup", sizeof("__wakeup"))) {
                    396:                INIT_PZVAL(&fname);
                    397:                ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0);
1.1.1.2 ! misho     398:                BG(serialize_lock)++;
1.1       misho     399:                call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
1.1.1.2 ! misho     400:                BG(serialize_lock)--;
1.1       misho     401:        }
                    402: 
                    403:        if (retval_ptr)
                    404:                zval_ptr_dtor(&retval_ptr);
                    405: 
                    406:        return finish_nested_data(UNSERIALIZE_PASSTHRU);
                    407: 
                    408: }
1.1.1.2 ! misho     409: #ifdef PHP_WIN32
        !           410: # pragma optimize("", on)
        !           411: #endif
1.1       misho     412: 
                    413: PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
                    414: {
                    415:        const unsigned char *cursor, *limit, *marker, *start;
                    416:        zval **rval_ref;
                    417: 
1.1.1.2 ! misho     418:        limit = max;
        !           419:        cursor = *p;
        !           420:        
        !           421:        if (YYCURSOR >= YYLIMIT) {
        !           422:                return 0;
        !           423:        }
1.1       misho     424:        
                    425:        if (var_hash && cursor[0] != 'R') {
                    426:                var_push(var_hash, rval);
                    427:        }
                    428: 
                    429:        start = cursor;
                    430: 
                    431:        
                    432:        
                    433: /*!re2c
                    434: 
                    435: "R:" iv ";"            {
                    436:        long id;
                    437: 
                    438:        *p = YYCURSOR;
                    439:        if (!var_hash) return 0;
                    440: 
                    441:        id = parse_iv(start + 2) - 1;
                    442:        if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
                    443:                return 0;
                    444:        }
                    445: 
                    446:        if (*rval != NULL) {
                    447:                zval_ptr_dtor(rval);
                    448:        }
                    449:        *rval = *rval_ref;
                    450:        Z_ADDREF_PP(rval);
                    451:        Z_SET_ISREF_PP(rval);
                    452:        
                    453:        return 1;
                    454: }
                    455: 
                    456: "r:" iv ";"            {
                    457:        long id;
                    458: 
                    459:        *p = YYCURSOR;
                    460:        if (!var_hash) return 0;
                    461: 
                    462:        id = parse_iv(start + 2) - 1;
                    463:        if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
                    464:                return 0;
                    465:        }
                    466: 
                    467:        if (*rval == *rval_ref) return 0;
                    468: 
                    469:        if (*rval != NULL) {
                    470:                zval_ptr_dtor(rval);
                    471:        }
                    472:        *rval = *rval_ref;
                    473:        Z_ADDREF_PP(rval);
                    474:        Z_UNSET_ISREF_PP(rval);
                    475:        
                    476:        return 1;
                    477: }
                    478: 
                    479: "N;"   {
                    480:        *p = YYCURSOR;
                    481:        INIT_PZVAL(*rval);
                    482:        ZVAL_NULL(*rval);
                    483:        return 1;
                    484: }
                    485: 
                    486: "b:" [01] ";"  {
                    487:        *p = YYCURSOR;
                    488:        INIT_PZVAL(*rval);
                    489:        ZVAL_BOOL(*rval, parse_iv(start + 2));
                    490:        return 1;
                    491: }
                    492: 
                    493: "i:" iv ";"    {
                    494: #if SIZEOF_LONG == 4
                    495:        int digits = YYCURSOR - start - 3;
                    496: 
                    497:        if (start[2] == '-' || start[2] == '+') {
                    498:                digits--;
                    499:        }
                    500: 
                    501:        /* Use double for large long values that were serialized on a 64-bit system */
                    502:        if (digits >= MAX_LENGTH_OF_LONG - 1) {
                    503:                if (digits == MAX_LENGTH_OF_LONG - 1) {
                    504:                        int cmp = strncmp(YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1);
                    505: 
                    506:                        if (!(cmp < 0 || (cmp == 0 && start[2] == '-'))) {
                    507:                                goto use_double;
                    508:                        }
                    509:                } else {
                    510:                        goto use_double;
                    511:                }
                    512:        }
                    513: #endif
                    514:        *p = YYCURSOR;
                    515:        INIT_PZVAL(*rval);
                    516:        ZVAL_LONG(*rval, parse_iv(start + 2));
                    517:        return 1;
                    518: }
                    519: 
                    520: "d:" ("NAN" | "-"? "INF") ";"  {
                    521:        *p = YYCURSOR;
                    522:        INIT_PZVAL(*rval);
                    523: 
                    524:        if (!strncmp(start + 2, "NAN", 3)) {
                    525:                ZVAL_DOUBLE(*rval, php_get_nan());
                    526:        } else if (!strncmp(start + 2, "INF", 3)) {
                    527:                ZVAL_DOUBLE(*rval, php_get_inf());
                    528:        } else if (!strncmp(start + 2, "-INF", 4)) {
                    529:                ZVAL_DOUBLE(*rval, -php_get_inf());
                    530:        }
                    531: 
                    532:        return 1;
                    533: }
                    534: 
                    535: "d:" (iv | nv | nvexp) ";"     {
                    536: #if SIZEOF_LONG == 4
                    537: use_double:
                    538: #endif
                    539:        *p = YYCURSOR;
                    540:        INIT_PZVAL(*rval);
                    541:        ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
                    542:        return 1;
                    543: }
                    544: 
                    545: "s:" uiv ":" ["]       {
                    546:        size_t len, maxlen;
                    547:        char *str;
                    548: 
                    549:        len = parse_uiv(start + 2);
                    550:        maxlen = max - YYCURSOR;
                    551:        if (maxlen < len) {
                    552:                *p = start + 2;
                    553:                return 0;
                    554:        }
                    555: 
                    556:        str = (char*)YYCURSOR;
                    557: 
                    558:        YYCURSOR += len;
                    559: 
                    560:        if (*(YYCURSOR) != '"') {
                    561:                *p = YYCURSOR;
                    562:                return 0;
                    563:        }
                    564: 
                    565:        YYCURSOR += 2;
                    566:        *p = YYCURSOR;
                    567: 
                    568:        INIT_PZVAL(*rval);
                    569:        ZVAL_STRINGL(*rval, str, len, 1);
                    570:        return 1;
                    571: }
                    572: 
                    573: "S:" uiv ":" ["]       {
                    574:        size_t len, maxlen;
                    575:        char *str;
                    576: 
                    577:        len = parse_uiv(start + 2);
                    578:        maxlen = max - YYCURSOR;
                    579:        if (maxlen < len) {
                    580:                *p = start + 2;
                    581:                return 0;
                    582:        }
                    583: 
                    584:        if ((str = unserialize_str(&YYCURSOR, &len, maxlen)) == NULL) {
                    585:                return 0;
                    586:        }
                    587: 
                    588:        if (*(YYCURSOR) != '"') {
                    589:                efree(str);
                    590:                *p = YYCURSOR;
                    591:                return 0;
                    592:        }
                    593: 
                    594:        YYCURSOR += 2;
                    595:        *p = YYCURSOR;
                    596: 
                    597:        INIT_PZVAL(*rval);
                    598:        ZVAL_STRINGL(*rval, str, len, 0);
                    599:        return 1;
                    600: }
                    601: 
                    602: "a:" uiv ":" "{" {
                    603:        long elements = parse_iv(start + 2);
                    604:        /* use iv() not uiv() in order to check data range */
                    605:        *p = YYCURSOR;
                    606: 
                    607:        if (elements < 0) {
                    608:                return 0;
                    609:        }
                    610: 
                    611:        INIT_PZVAL(*rval);
                    612: 
                    613:        array_init_size(*rval, elements);
                    614: 
                    615:        if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
                    616:                return 0;
                    617:        }
                    618: 
                    619:        return finish_nested_data(UNSERIALIZE_PASSTHRU);
                    620: }
                    621: 
                    622: "o:" iv ":" ["] {
                    623: 
                    624:        INIT_PZVAL(*rval);
                    625:        
                    626:        return object_common2(UNSERIALIZE_PASSTHRU,
                    627:                        object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
                    628: }
                    629: 
                    630: object ":" uiv ":" ["] {
                    631:        size_t len, len2, len3, maxlen;
                    632:        long elements;
                    633:        char *class_name;
                    634:        zend_class_entry *ce;
                    635:        zend_class_entry **pce;
                    636:        int incomplete_class = 0;
                    637: 
                    638:        int custom_object = 0;
                    639: 
                    640:        zval *user_func;
                    641:        zval *retval_ptr;
                    642:        zval **args[1];
                    643:        zval *arg_func_name;
                    644: 
                    645:        if (*start == 'C') {
                    646:                custom_object = 1;
                    647:        }
                    648:        
                    649:        INIT_PZVAL(*rval);
                    650:        len2 = len = parse_uiv(start + 2);
                    651:        maxlen = max - YYCURSOR;
                    652:        if (maxlen < len || len == 0) {
                    653:                *p = start + 2;
                    654:                return 0;
                    655:        }
                    656: 
                    657:        class_name = (char*)YYCURSOR;
                    658: 
                    659:        YYCURSOR += len;
                    660: 
                    661:        if (*(YYCURSOR) != '"') {
                    662:                *p = YYCURSOR;
                    663:                return 0;
                    664:        }
                    665:        if (*(YYCURSOR+1) != ':') {
                    666:                *p = YYCURSOR+1;
                    667:                return 0;
                    668:        }
                    669: 
                    670:        len3 = strspn(class_name, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\");
                    671:        if (len3 != len)
                    672:        {
                    673:                *p = YYCURSOR + len3 - len;
                    674:                return 0;
                    675:        }
                    676: 
                    677:        class_name = estrndup(class_name, len);
                    678: 
                    679:        do {
                    680:                /* Try to find class directly */
                    681:                if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
                    682:                        ce = *pce;
                    683:                        break;
                    684:                }
                    685:                
                    686:                /* Check for unserialize callback */
                    687:                if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
                    688:                        incomplete_class = 1;
                    689:                        ce = PHP_IC_ENTRY;
                    690:                        break;
                    691:                }
                    692:                
                    693:                /* Call unserialize callback */
                    694:                MAKE_STD_ZVAL(user_func);
                    695:                ZVAL_STRING(user_func, PG(unserialize_callback_func), 1);
                    696:                args[0] = &arg_func_name;
                    697:                MAKE_STD_ZVAL(arg_func_name);
                    698:                ZVAL_STRING(arg_func_name, class_name, 1);
                    699:                if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
                    700:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", user_func->value.str.val);
                    701:                        incomplete_class = 1;
                    702:                        ce = PHP_IC_ENTRY;
                    703:                        zval_ptr_dtor(&user_func);
                    704:                        zval_ptr_dtor(&arg_func_name);
                    705:                        break;
                    706:                }
                    707:                if (retval_ptr) {
                    708:                        zval_ptr_dtor(&retval_ptr);
                    709:                }
                    710:                
                    711:                /* The callback function may have defined the class */
                    712:                if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
                    713:                        ce = *pce;
                    714:                } else {
                    715:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function %s() hasn't defined the class it was called for", user_func->value.str.val);
                    716:                        incomplete_class = 1;
                    717:                        ce = PHP_IC_ENTRY;
                    718:                }
                    719: 
                    720:                zval_ptr_dtor(&user_func);
                    721:                zval_ptr_dtor(&arg_func_name);
                    722:                break;
                    723:        } while (1);
                    724: 
                    725:        *p = YYCURSOR;
                    726: 
                    727:        if (custom_object) {
                    728:                int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
                    729: 
                    730:                if (ret && incomplete_class) {
                    731:                        php_store_class_name(*rval, class_name, len2);
                    732:                }
                    733:                efree(class_name);
                    734:                return ret;
                    735:        }
                    736:        
                    737:        elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
                    738: 
                    739:        if (incomplete_class) {
                    740:                php_store_class_name(*rval, class_name, len2);
                    741:        }
                    742:        efree(class_name);
                    743: 
                    744:        return object_common2(UNSERIALIZE_PASSTHRU, elements);
                    745: }
                    746: 
                    747: "}" {
                    748:        /* this is the case where we have less data than planned */
                    749:        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data");
                    750:        return 0; /* not sure if it should be 0 or 1 here? */
                    751: }
                    752: 
                    753: any    { return 0; }
                    754: 
                    755: */
                    756: 
                    757:        return 0;
                    758: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>