improve field name unserialization
authorMichael Wallner <mike@php.net>
Mon, 10 Jan 2022 20:48:08 +0000 (21:48 +0100)
committerMichael Wallner <mike@php.net>
Mon, 10 Jan 2022 20:48:08 +0000 (21:48 +0100)
Makefile.frag
ion_private.h
tests/unserialize/multifield.phpt [new file with mode: 0644]
tests/unserialize/sid.phpt [new file with mode: 0644]

index 463c78bd5d705600b5e670bfe5b418d9928f5c0b..1106dc513ca898cf4bfbae5161c70bd831977828 100644 (file)
@@ -26,4 +26,4 @@ clean-ion:
 gcov-ion:
        @rm -rf $@
        @mkdir -p $@
-       gcovr -j $$(nproc) -sr . --html --html-details --html-title $@ -o $@/index.html -f '.*/(php_)?ion.*'
+       @gcovr -j $$(nproc) -sr . --html --html-details --html-title $@ -o $@/index.html -f '.*/(php_)?ion.*' 2>/dev/null
index acb2403cff905110818b2c6657c55664e5ab1316..4f49088d8365df4d3acf84379e385e3bf547bce5 100644 (file)
@@ -389,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 { \
@@ -2064,25 +2065,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)
@@ -2100,7 +2123,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;
@@ -2141,7 +2164,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;
diff --git a/tests/unserialize/multifield.phpt b/tests/unserialize/multifield.phpt
new file mode 100644 (file)
index 0000000..6a6e707
--- /dev/null
@@ -0,0 +1,26 @@
+--TEST--
+ion\unserialize/multifield
+--EXTENSIONS--
+ion
+--FILE--
+TEST
+<?php
+var_dump(ion\unserialize("{a: 1, a: 2, a: 3, b: 4}"));
+?>
+DONE
+--EXPECT--
+TEST
+array(2) {
+  ["a"]=>
+  array(3) {
+    [0]=>
+    int(1)
+    [1]=>
+    int(2)
+    [2]=>
+    int(3)
+  }
+  ["b"]=>
+  int(4)
+}
+DONE
diff --git a/tests/unserialize/sid.phpt b/tests/unserialize/sid.phpt
new file mode 100644 (file)
index 0000000..73c9bc3
--- /dev/null
@@ -0,0 +1,50 @@
+--TEST--
+ion\unserialize/sid
+--EXTENSIONS--
+ion
+--FILE--
+TEST
+<?php
+$ION = <<<'ION'
+$ion_symbol_table::{
+       imports: [
+               {name: "st", version: 1, max_id: 90}
+       ],
+       symbols:["foo"]
+}
+[$33, {$99: $100}]
+ION;
+var_dump(ion\unserialize($ION));
+?>
+DONE
+--EXPECTF--
+TEST
+array(2) {
+  [0]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(0) ""
+    ["sid"]=>
+    int(33)
+    ["importLocation"]=>
+    object(ion\Symbol\ImportLocation)#%d (2) {
+      ["name"]=>
+      string(2) "st"
+      ["location"]=>
+      int(24)
+    }
+  }
+  [1]=>
+  array(1) {
+    ["$99"]=>
+    object(ion\Symbol)#%d (3) {
+      ["value"]=>
+      string(3) "foo"
+      ["sid"]=>
+      int(100)
+      ["importLocation"]=>
+      NULL
+    }
+  }
+}
+DONE