fix userland string serialization
authorMichael Wallner <mike@php.net>
Tue, 26 Apr 2022 09:34:59 +0000 (11:34 +0200)
committerMichael Wallner <mike@php.net>
Tue, 26 Apr 2022 09:34:59 +0000 (11:34 +0200)
ion_private.h
tests/~integration/detect_utf8.phpt [new file with mode: 0644]
tests/~integration/no_decimals.phpt

index 2d1c54aff4f11df7b341f2d876fc51fefd208da0..344d20e6d172920c1696727e052ff86960175d30 100644 (file)
@@ -1950,7 +1950,9 @@ static void php_ion_serialize_string(php_ion_serializer *ser, zend_string *str)
                ION_STRING is;
                ION_CHECK(ion_writer_write_string(php_ion_obj(writer, ser->wri)->writer, ion_string_from_zend(&is, str)));
        } else {
-
+               zval zs;
+               ZVAL_STR(&zs, str);
+               zend_call_method_with_1_params(ser->wri, NULL, NULL, "writeString", NULL, &zs);
        }
 }
 
diff --git a/tests/~integration/detect_utf8.phpt b/tests/~integration/detect_utf8.phpt
new file mode 100644 (file)
index 0000000..e9fee64
--- /dev/null
@@ -0,0 +1,56 @@
+--TEST--
+integration: custom serializer which naïvly decides to write strings/clobs/blobs
+--EXTENSIONS--
+ion
+--FILE--
+TEST
+<?php
+
+class AutoUtf8 extends ion\Serializer\Serializer {
+       public function serialize(mixed $data, \ion\Writer\Options|\ion\Writer|array|null $writer = null): mixed {
+               return parent::serialize($data, new class extends \ion\Writer\Buffer\Writer {
+                       private function iterate(string $s) : Generator {
+                               for ($i = 0; $i < grapheme_strlen($s); ++$i) {
+                                       yield grapheme_substr($s, $i, 1);
+                               }
+                       }
+                       private function classify(string $c) : bool {
+                               if (strlen($c) > 1) {
+                                       return false;
+                               } elseif ($c < "\040") return match ($c) {
+                                       "\n", "\r", "\t" => false,
+                                       default => true
+                               };
+                               return $c >= "\177";
+                       }
+                       public function writeString(string $value) : void {
+                               $dist = [0, 0];
+                               foreach ($this->iterate($value) as $c) {
+                                       if (false === $c) {
+                                               goto binary;
+                                       }
+                                       ++$dist[$this->classify($c)];
+                               }
+                               if ($dist[0] <= $dist[1]) {
+                               binary:
+                                       parent::writeBLob($value);
+                               } elseif ($dist[1]) {
+                                       parent::writeCLob($value);
+                               } else {
+                                       parent::writeString($value);
+                               }
+                       }
+               });
+       }
+}
+
+$data = ["abc", "äöü", "\nabc\n", "foo\0bar", hex2bin("1f8b08003d96676200034bcacc4b2caae40200f5127b4207000000")];
+echo ion\serialize($data), "\n";
+echo ion\serialize($data, new AutoUtf8), "\n";
+?>
+DONE
+--EXPECTF--
+TEST
+["abc","äöü","\nabc\n","foo\0bar","\x1F%s\x12{B\a\0\0\0"]
+["abc","äöü","\nabc\n",{{"foo\0bar"}},{{H4sIAD2WZ2IAA0vKzEssquQCAPUSe0IHAAAA}}]
+DONE
index d9382308cb2795143cd6b309a991101e42ce0d6b..c81c3ab80727e2baa4ff1c08b87d133d23399cb8 100644 (file)
@@ -1,12 +1,12 @@
 --TEST--
-integration: do not write decimals but native floats only
+integration: custom serializer which does not write decimals but native floats only
 --EXTENSIONS--
 ion
 --FILE--
 TEST
 <?php
 
-class NoDecimals  extends ion\Serializer\Serializer {
+class NoDecimals extends ion\Serializer\Serializer {
        public function serialize(mixed $data, \ion\Writer\Options|\ion\Writer|array|null $writer = null): mixed {
                return parent::serialize($data, new class extends \ion\Writer\Buffer\Writer {
                        public function writeDecimal(\ion\Decimal|string $value): void {