tests++
[awesomized/ext-ion] / ion_private.h
index 205c9b81ae03621d4f22887bb79ea76fd225bdf9..7233f464c4ec2b89b3b58068f4d519568782223e 100644 (file)
@@ -128,6 +128,26 @@ LOCAL int g_sym_init(void)
        return SUCCESS;
 }
 
+static struct {
+       zend_string *Year, *Month, *Day, *Min, *Sec, *Frac, *MinTZ, *SecTZ, *FracTZ;
+} g_intern_str;
+
+static void g_intern_str_init()
+{
+#define NEW_INTERN_STR(s) \
+       g_intern_str.s = zend_string_init_interned(#s, sizeof(#s)-1, 1)
+       NEW_INTERN_STR(Year);
+       NEW_INTERN_STR(Month);
+       NEW_INTERN_STR(Day);
+       NEW_INTERN_STR(Min);
+       NEW_INTERN_STR(Sec);
+       NEW_INTERN_STR(Frac);
+       NEW_INTERN_STR(MinTZ);
+       NEW_INTERN_STR(SecTZ);
+       NEW_INTERN_STR(FracTZ);
+#undef NEW_INTERN_STR
+}
+
 typedef struct php_ion_serializer {
        ION_WRITER *writer;
        ION_WRITER_OPTIONS *options;
@@ -223,6 +243,7 @@ static zend_class_entry
        *ce_Symbol_Table_Shared,
        *ce_Symbol_Table_System,
        *ce_Timestamp,
+       *ce_Timestamp_Format,
        *ce_Timestamp_Precision,
        *ce_Type,
        *ce_Unserializer,
@@ -368,6 +389,7 @@ LOCAL void *php_ion_obj_ex(void *obj, ptrdiff_t offset) {
                php_ion_ ## type *old_obj = php_ion_obj(type, std), \
                                                 *new_obj = php_ion_obj(type, create_ion_ ## cname(std->ce)); \
                php_ion_ ## type ## _copy(new_obj, old_obj); \
+               (void) old_obj; \
                return &new_obj->std; \
        }
 #define php_ion_register(type, cname, ...) do { \
@@ -860,23 +882,34 @@ LOCAL decQuad *ion_ts_frac_from_usec(decQuad *frac, int usec, decContext *ctx)
        return decQuadDivide(frac, decQuadFromInt32(&us, usec), decQuadFromInt32(&microsecs, 1000000), ctx);
 }
 
+LOCAL zend_string *php_ion_timestamp_format_fetch(zend_string *fmt_case)
+{
+       return Z_STR_P(zend_enum_fetch_case_value(zend_enum_get_case(ce_Timestamp_Format, fmt_case)));
+}
+
 LOCAL zend_string *php_dt_format_from_precision(uint8_t precision)
 {
-       switch (precision & 0x7f) {
+       switch (precision) {
+       case ION_TS_FRAC | 0x80:
+               return php_ion_timestamp_format_fetch(g_intern_str.FracTZ);
        case ION_TS_FRAC:
-               return zend_string_init(ZEND_STRL("c"), 0);
+               return php_ion_timestamp_format_fetch(g_intern_str.Frac);
+       case ION_TS_SEC | 0x80:
+               return php_ion_timestamp_format_fetch(g_intern_str.SecTZ);
        case ION_TS_SEC:
-               return zend_string_init(ZEND_STRL("Y-m-d\\TH:i:sP"), 0);
+               return php_ion_timestamp_format_fetch(g_intern_str.Sec);
+       case ION_TS_MIN | 0x80:
+               return php_ion_timestamp_format_fetch(g_intern_str.MinTZ);
        case ION_TS_MIN:
-               return zend_string_init(ZEND_STRL("Y-m-d\\TH:iP"), 0);
+               return php_ion_timestamp_format_fetch(g_intern_str.Min);
        case ION_TS_DAY:
-               return zend_string_init(ZEND_STRL("Y-m-d\\T"), 0);
+               return php_ion_timestamp_format_fetch(g_intern_str.Day);
        case ION_TS_MONTH:
-               return zend_string_init(ZEND_STRL("Y-m\\T"), 0);
+               return php_ion_timestamp_format_fetch(g_intern_str.Month);
        case ION_TS_YEAR:
-               return zend_string_init(ZEND_STRL("Y\\T"), 0);
+               return php_ion_timestamp_format_fetch(g_intern_str.Year);
        default:
-               return zend_string_init(ZEND_STRL("c"), 0);
+               return zend_one_char_string['c'];
        }
 }
 
@@ -884,9 +917,7 @@ LOCAL timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContext *ctx,
 {
        timelib_time *time = ecalloc(1, sizeof(*time));
 
-       int precision = ION_TS_FRAC;
-       ion_timestamp_get_precision(ts,  &precision);
-       switch (precision) {
+       switch (ts->precision & 0x7f) {
        case ION_TS_FRAC:
                time->us = php_usec_from_ion(&ts->fraction, ctx);
                /* fallthrough */
@@ -908,7 +939,7 @@ LOCAL timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContext *ctx,
                /* fallthrough */
        default:
                time->z = ts->tz_offset * 60;
-               if (time->z) {
+               if (time->z || ts->precision & 0x80) {
                        time->zone_type = TIMELIB_ZONETYPE_OFFSET;
                } else {
                        time->zone_type = TIMELIB_ZONETYPE_ID;
@@ -917,7 +948,7 @@ LOCAL timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContext *ctx,
        }
 
        if (fmt) {
-               *fmt = php_dt_format_from_precision(precision);
+               *fmt = php_dt_format_from_precision(ts->precision);
        }
        return time;
 }
@@ -929,10 +960,10 @@ LOCAL ION_TIMESTAMP *ion_timestamp_from_php(ION_TIMESTAMP *buf, php_ion_timestam
        zval tmp;
        int precision = Z_LVAL_P(zend_read_property(ts->std.ce, &ts->std, ZEND_STRL("precision"), 0, &tmp));
 
-       if (!precision || precision > ION_TS_FRAC) {
+       if (!precision || precision > (ION_TS_FRAC|0x80)) {
                zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG,
                                "Invalid precision (%d) of ion\\Timestamp", precision);
-       } else switch ((buf->precision = precision)) {
+       } else switch ((buf->precision = precision) & 0x7f) {
        case ION_TS_FRAC:
                ion_ts_frac_from_usec(&buf->fraction, (int) ts->time->us, ctx);
                /* fallthrough */
@@ -1996,6 +2027,8 @@ LOCAL zval *php_ion_unserialize_class(php_ion_unserializer *ser, zval *return_va
 LOCAL void php_ion_unserialize_object_enum(php_ion_unserializer *ser, zval *return_value)
 {
        zend_string *zs_case = zval_get_string(return_value);
+       zend_hash_next_index_insert(ser->tmp, return_value);
+       ZVAL_NULL(return_value);
        ION_CATCH();
 
        zend_class_entry *ce = zend_lookup_class(ser->annotations.object_class);
@@ -2019,6 +2052,7 @@ LOCAL void php_ion_unserialize_object_iface(php_ion_unserializer *ser, zval *ret
        zend_class_entry *ce = zend_lookup_class(ser->annotations.object_class);
        if (can_call_iface_unserialize(ser, ce)) {
                zend_string *s = zval_get_string(return_value);
+               zend_hash_next_index_insert(ser->tmp, return_value);
                ZVAL_NULL(return_value);
                zval *backref = zend_hash_next_index_insert(ser->ids, return_value);
                if (SUCCESS == ce->unserialize(backref, ce, (BYTE *) s->val, s->len, NULL)) {
@@ -2034,25 +2068,47 @@ LOCAL void php_ion_unserialize_object_iface(php_ion_unserializer *ser, zval *ret
        }
 }
 
-LOCAL void php_ion_unserialize_field_name(php_ion_unserializer *ser, zend_string **key)
+LOCAL void php_ion_unserialize_field_name_ex(php_ion_unserializer *ser, ION_STRING *name, SID *sid)
 {
-       // FIXME: symbol table
-       ION_STRING name;
-       ION_CHECK(ion_reader_get_field_name(ser->reader, &name));
-       if (!name.length) {
+       ION_CHECK(ion_reader_get_field_name(ser->reader, name));
+       if (!name->length) {
                ION_SYMBOL *is_ptr;
                ION_CHECK(ion_reader_get_field_name_symbol(ser->reader, &is_ptr));
                if (!ION_SYMBOL_IS_NULL(is_ptr) && is_ptr->value.length) {
-                       name = is_ptr->value;
-               } else if (is_ptr) {
-                       char buf[MAX_LENGTH_OF_LONG + 1 + 1] = {0}, *end = buf + sizeof(buf) - 1, *ptr;
-                       ptr = zend_print_long_to_buf(end, is_ptr->sid);
-                       *--ptr = '$';
-                       *key = zend_string_init(ptr, end - ptr, 0);
-                       return;
+                       ION_STRING_ASSIGN(name, &is_ptr->value);
+               } else {
+                       *sid = is_ptr->sid;
+               }
+       }
+}
+
+LOCAL void php_ion_unserialize_field_name(php_ion_unserializer *ser, zend_string **key, bool is_prop)
+{
+       // FIXME: symbol table
+       ION_STRING name;
+       SID sid = UNKNOWN_SID;
+       char buf[MAX_LENGTH_OF_LONG + 1 + 1] = {0}, *end = buf + sizeof(buf) - 1, *ptr;
+
+       php_ion_unserialize_field_name_ex(ser, &name, &sid);
+       ION_CATCH();
+
+       switch (name.length) {
+       case 0:
+               ptr = zend_print_long_to_buf(end, sid);
+               *--ptr = '$';
+               *key = zend_string_init(ptr, end - ptr, 0);
+               break;
+       case 1:
+               *key = zend_one_char_string[*name.value];
+               break;
+       default:
+               if (is_prop) {
+                       *key = zend_string_init_interned((char *) name.value, name.length, 0);
+               } else {
+                       *key = zend_string_from_ion(&name);
                }
+               break;
        }
-       *key = zend_string_from_ion(&name);
 }
 
 static void php_ion_unserialize_props(php_ion_unserializer *ser, zval *return_value)
@@ -2070,7 +2126,7 @@ static void php_ion_unserialize_props(php_ion_unserializer *ser, zval *return_va
                }
 
                zend_string *key;
-               php_ion_unserialize_field_name(ser, &key);
+               php_ion_unserialize_field_name(ser, &key, true);
                ION_CATCH();
 
                zval zvalue;
@@ -2111,7 +2167,7 @@ LOCAL void php_ion_unserialize_hash(php_ion_unserializer *ser, zval *return_valu
                }
 
                zend_string *key;
-               php_ion_unserialize_field_name(ser, &key);
+               php_ion_unserialize_field_name(ser, &key, false);
                ION_CATCH();
 
                zval zvalue;
@@ -2169,7 +2225,7 @@ LOCAL void php_ion_unserialize_object(php_ion_unserializer *ser, zval *return_va
 {
        // backup possible backref to array returned by magic/custom __serialize()
        zval *input = zend_hash_next_index_insert(ser->tmp, return_value);
-
+       ZVAL_NULL(return_value);
        php_ion_unserialize_class(ser, return_value);
        ION_CATCH();
 
@@ -2501,7 +2557,6 @@ LOCAL void php_ion_unserialize_zval(php_ion_unserializer *ser, zval *return_valu
                ION_CHECK(ion_reader_read_ion_symbol(ser->reader, &sym));
                php_ion_symbol_zval(&sym, return_value);
                if (ser->annotations.object_type) {
-                       zend_hash_next_index_insert(ser->tmp, return_value);
                        goto unserialize_struct;
                }
                zend_hash_next_index_insert(ser->ids, return_value);
@@ -2512,7 +2567,6 @@ LOCAL void php_ion_unserialize_zval(php_ion_unserializer *ser, zval *return_valu
                ION_CHECK(ion_reader_read_string(ser->reader, &str));
                RETVAL_STRINGL((char *) str.value, str.length);
                if (ser->annotations.object_type) {
-                       zend_hash_next_index_insert(ser->tmp, return_value);
                        goto unserialize_struct;
                }
                zend_hash_next_index_insert(ser->ids, return_value);
@@ -2522,7 +2576,6 @@ LOCAL void php_ion_unserialize_zval(php_ion_unserializer *ser, zval *return_valu
        case tid_BLOB_INT:
                php_ion_reader_read_lob(ser->reader, return_value);
                if (ser->annotations.object_type) {
-                       zend_hash_next_index_insert(ser->tmp, return_value);
                        goto unserialize_struct;
                }
                zend_hash_next_index_insert(ser->ids, return_value);
@@ -2608,7 +2661,8 @@ void php_ion_unserialize(php_ion_unserializer *ser, zval *zdata, zval *return_va
                reader->buffer = zval_get_string(zdata);
        } else {
                zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG,
-                               "Invalid source to unserialize; expected string or resource");
+                               "Invalid source to unserialize: expected string or resource, got %s",
+                                                               zend_zval_type_name(zdata));
                if (zo_ser) {
                        OBJ_RELEASE(zo_ser);
                }