From 13c076bc543836fe9d189cece43a9a2c3414fe1c Mon Sep 17 00:00:00 2001 From: SATO Kentaro Date: Fri, 28 Aug 2015 00:21:23 +0900 Subject: [PATCH] Add OPT_ASSOC for roundtrip serialization of map. Set OPT_ASSOC to false to pack stdClass instance in map and vice versa. Set OPT_PHPONLY to false in addition to pack any object into map. --- msgpack.c | 7 ++++ msgpack_class.c | 26 ++++++++++++++ msgpack_class.h | 1 + msgpack_pack.c | 6 +++- msgpack_unpack.c | 28 ++++++++++++--- package.xml | 1 + php_msgpack.h | 1 + tests/029.phpt | 1 + tests/assoc.phpt | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 tests/assoc.phpt diff --git a/msgpack.c b/msgpack.c index 1876ec3..241f50b 100644 --- a/msgpack.c +++ b/msgpack.c @@ -42,6 +42,9 @@ STD_PHP_INI_BOOLEAN( STD_PHP_INI_BOOLEAN( "msgpack.php_only", "1", PHP_INI_ALL, OnUpdateBool, php_only, zend_msgpack_globals, msgpack_globals) +STD_PHP_INI_BOOLEAN( + "msgpack.assoc", "1", PHP_INI_ALL, OnUpdateBool, + assoc, zend_msgpack_globals, msgpack_globals) STD_PHP_INI_BOOLEAN( "msgpack.illegal_key_insert", "0", PHP_INI_ALL, OnUpdateBool, illegal_key_insert, zend_msgpack_globals, msgpack_globals) @@ -76,6 +79,7 @@ static void msgpack_init_globals(zend_msgpack_globals *msgpack_globals) } msgpack_globals->php_only = 1; + msgpack_globals->assoc = 1; msgpack_globals->illegal_key_insert = 0; msgpack_globals->serialize.var_hash = NULL; @@ -101,6 +105,9 @@ static ZEND_MINIT_FUNCTION(msgpack) REGISTER_LONG_CONSTANT( "MESSAGEPACK_OPT_PHPONLY", MSGPACK_CLASS_OPT_PHPONLY, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT( + "MESSAGEPACK_OPT_ASSOC", MSGPACK_CLASS_OPT_ASSOC, + CONST_CS | CONST_PERSISTENT); #endif return SUCCESS; diff --git a/msgpack_class.c b/msgpack_class.c index 740ca7a..8862b43 100644 --- a/msgpack_class.c +++ b/msgpack_class.c @@ -10,6 +10,7 @@ typedef struct { zend_object object; long php_only; + zend_bool assoc; } php_msgpack_base_t; typedef struct { @@ -20,6 +21,7 @@ typedef struct { msgpack_unpack_t mp; msgpack_unserialize_data_t var_hash; long php_only; + zend_bool assoc; zend_bool finished; int error; } php_msgpack_unpacker_t; @@ -274,6 +276,7 @@ static zend_object_value php_msgpack_unpacker_new( static ZEND_METHOD(msgpack, __construct) { zend_bool php_only = MSGPACK_G(php_only); + zend_bool assoc = MSGPACK_G(assoc); MSGPACK_BASE_OBJECT; if (zend_parse_parameters( @@ -283,6 +286,7 @@ static ZEND_METHOD(msgpack, __construct) } base->php_only = php_only; + base->assoc = assoc; } static ZEND_METHOD(msgpack, setOption) @@ -303,6 +307,10 @@ static ZEND_METHOD(msgpack, setOption) convert_to_boolean(value); base->php_only = Z_BVAL_P(value); break; + case MSGPACK_CLASS_OPT_ASSOC: + convert_to_boolean(value); + base->assoc = Z_BVAL_P(value); + break; default: MSGPACK_WARNING("[msgpack] (MessagePack::setOption) " "error setting msgpack option"); @@ -318,6 +326,7 @@ static ZEND_METHOD(msgpack, pack) zval *parameter; smart_str buf = {0}; int php_only = MSGPACK_G(php_only); + zend_bool assoc = MSGPACK_G(assoc); MSGPACK_BASE_OBJECT; if (zend_parse_parameters( @@ -327,10 +336,12 @@ static ZEND_METHOD(msgpack, pack) } MSGPACK_G(php_only) = base->php_only; + MSGPACK_G(assoc) = base->assoc; php_msgpack_serialize(&buf, parameter TSRMLS_CC); MSGPACK_G(php_only) = php_only; + MSGPACK_G(assoc) = assoc; ZVAL_STRINGL(return_value, buf.c, buf.len, 1); @@ -343,6 +354,7 @@ static ZEND_METHOD(msgpack, unpack) int str_len; zval *object = NULL; int php_only = MSGPACK_G(php_only); + zend_bool assoc = MSGPACK_G(assoc); MSGPACK_BASE_OBJECT; if (zend_parse_parameters( @@ -358,6 +370,7 @@ static ZEND_METHOD(msgpack, unpack) } MSGPACK_G(php_only) = base->php_only; + MSGPACK_G(assoc) = base->assoc; if (object == NULL) { @@ -377,6 +390,7 @@ static ZEND_METHOD(msgpack, unpack) } MSGPACK_G(php_only) = php_only; + MSGPACK_G(assoc) = assoc; } static ZEND_METHOD(msgpack, unpacker) @@ -398,6 +412,7 @@ static ZEND_METHOD(msgpack, unpacker) static ZEND_METHOD(msgpack_unpacker, __construct) { zend_bool php_only = MSGPACK_G(php_only); + zend_bool assoc = MSGPACK_G(assoc); MSGPACK_UNPACKER_OBJECT; if (zend_parse_parameters( @@ -407,6 +422,7 @@ static ZEND_METHOD(msgpack_unpacker, __construct) } unpacker->php_only = php_only; + unpacker->assoc = assoc; unpacker->buffer.c = NULL; unpacker->buffer.len = 0; @@ -456,6 +472,10 @@ static ZEND_METHOD(msgpack_unpacker, setOption) convert_to_boolean(value); unpacker->php_only = Z_BVAL_P(value); break; + case MSGPACK_CLASS_OPT_ASSOC: + convert_to_boolean(value); + unpacker->assoc = Z_BVAL_P(value); + break; default: MSGPACK_WARNING("[msgpack] (MessagePackUnpacker::setOption) " "error setting msgpack option"); @@ -497,6 +517,7 @@ static ZEND_METHOD(msgpack_unpacker, execute) size_t len, off; int error_display = MSGPACK_G(error_display); int php_only = MSGPACK_G(php_only); + zend_bool assoc = MSGPACK_G(assoc); MSGPACK_UNPACKER_OBJECT; if (zend_parse_parameters( @@ -550,11 +571,13 @@ static ZEND_METHOD(msgpack_unpacker, execute) MSGPACK_G(error_display) = 0; MSGPACK_G(php_only) = unpacker->php_only; + MSGPACK_G(assoc) = unpacker->assoc; ret = template_execute(&unpacker->mp, data, len, &off); MSGPACK_G(error_display) = error_display; MSGPACK_G(php_only) = php_only; + MSGPACK_G(assoc) = assoc; if (str != NULL) { @@ -677,6 +700,9 @@ void msgpack_init_class() zend_declare_class_constant_long( msgpack_ce, ZEND_STRS("OPT_PHPONLY") - 1, MSGPACK_CLASS_OPT_PHPONLY TSRMLS_CC); + zend_declare_class_constant_long( + msgpack_ce, ZEND_STRS("OPT_ASSOC") - 1, + MSGPACK_CLASS_OPT_ASSOC TSRMLS_CC); #endif /* unpacker */ diff --git a/msgpack_class.h b/msgpack_class.h index f197523..3dcbf40 100644 --- a/msgpack_class.h +++ b/msgpack_class.h @@ -3,6 +3,7 @@ #define MSGPACK_CLASS_H #define MSGPACK_CLASS_OPT_PHPONLY -1001 +#define MSGPACK_CLASS_OPT_ASSOC -1002 void msgpack_init_class(); diff --git a/msgpack_pack.c b/msgpack_pack.c index 0e11f4c..de3c745 100644 --- a/msgpack_pack.c +++ b/msgpack_pack.c @@ -276,7 +276,11 @@ inline static void msgpack_serialize_array( if (object) { - if (MSGPACK_G(php_only)) + if (!MSGPACK_G(assoc) && (!MSGPACK_G(php_only) || !strcmp(class_name, "stdClass"))) + { + msgpack_pack_map(buf, n); + } + else if (MSGPACK_G(php_only)) { if (Z_ISREF_P(val)) { diff --git a/msgpack_unpack.c b/msgpack_unpack.c index 45701ba..90c2329 100644 --- a/msgpack_unpack.c +++ b/msgpack_unpack.c @@ -555,7 +555,7 @@ int msgpack_unserialize_map( if (count == 0) { - if (MSGPACK_G(php_only)) + if (MSGPACK_G(php_only) || !MSGPACK_G(assoc)) { object_init(*obj); } @@ -708,7 +708,14 @@ int msgpack_unserialize_map_item( if (Z_TYPE_PP(container) != IS_ARRAY && Z_TYPE_PP(container) != IS_OBJECT) { - array_init(*container); + if (MSGPACK_G(assoc)) + { + array_init(*container); + } + else + { + object_init(*container); + } } switch (Z_TYPE_P(key)) @@ -726,9 +733,19 @@ int msgpack_unserialize_map_item( zval_ptr_dtor(&key); break; case IS_STRING: - if (zend_symtable_update( - HASH_OF(*container), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, - &val, sizeof(val), NULL) == FAILURE) + { + int result; + + if (MSGPACK_G(assoc) || Z_TYPE_PP(container) == IS_ARRAY) { + result = zend_symtable_update( + HASH_OF(*container), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, + &val, sizeof(val), NULL); + } else { + result = zend_hash_update( + HASH_OF(*container), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, + &val, sizeof(val), NULL); + } + if (result == FAILURE) { zval_ptr_dtor(&val); MSGPACK_WARNING( @@ -737,6 +754,7 @@ int msgpack_unserialize_map_item( } zval_ptr_dtor(&key); break; + } default: MSGPACK_WARNING("[msgpack] (%s) illegal key type", __FUNCTION__); diff --git a/package.xml b/package.xml index b5503ff..8df1d95 100644 --- a/package.xml +++ b/package.xml @@ -250,6 +250,7 @@ + diff --git a/php_msgpack.h b/php_msgpack.h index ac9ddd9..cdb687a 100644 --- a/php_msgpack.h +++ b/php_msgpack.h @@ -23,6 +23,7 @@ extern zend_module_entry msgpack_module_entry; ZEND_BEGIN_MODULE_GLOBALS(msgpack) zend_bool error_display; zend_bool php_only; + zend_bool assoc; zend_bool illegal_key_insert; zend_bool use_str8_serialization; struct { diff --git a/tests/029.phpt b/tests/029.phpt index d623ce9..cf684fc 100644 --- a/tests/029.phpt +++ b/tests/029.phpt @@ -48,6 +48,7 @@ extension Version => %s header Version => %s Directive => Local Value => Master Value +msgpack.assoc => On => On msgpack.error_display => On => On msgpack.illegal_key_insert => Off => Off msgpack.php_only => On => On diff --git a/tests/assoc.phpt b/tests/assoc.phpt new file mode 100644 index 0000000..bae97bc --- /dev/null +++ b/tests/assoc.phpt @@ -0,0 +1,92 @@ +--TEST-- +Map with assoc option +--SKIPIF-- +--FILE-- +setOption(MESSAGEPACK_OPT_PHPONLY, $phpOnly); + $msgpack->setOption(MESSAGEPACK_OPT_ASSOC, $assoc); + } + else + { + $msgpack->setOption(MessagePack::OPT_PHPONLY, $phpOnly); + $msgpack->setOption(MessagePack::OPT_ASSOC, $assoc); + } + if (is_string($data)) { + $result = $msgpack->unpack(hex2bin($data)); + } else { + $result = bin2hex($msgpack->pack($data)); + } + + printf("%s, %d, %d\n", $type, $phpOnly, $assoc); + var_dump($result); + return $result; +} + +$emptyMapData = '80'; // {} +test("empty map unpack", $emptyMapData, true, true); +test("empty map unpack", $emptyMapData, false, true); +test("empty map unpack", $emptyMapData, false, false); + +$mapData = '82a131a142a130a141'; // {"1":"B","0":"A"} +$map = test("map unpack", $mapData, true, true); +test("map pack", $map, true, true); +$map = test("map unpack", $mapData, true, false); +test("map pack", $map, true, false); + +$obj = new MyObj; +$obj->member = 1; +test("obj pack", $obj, true, true); +test("obj pack", $obj, false, true); +test("obj pack", $obj, true, false); +test("obj pack", $obj, false, false); + +class MyObj { + public $member; +} + +--EXPECTF-- +empty map unpack, 1, 1 +object(stdClass)#%d (0) { +} +empty map unpack, 0, 1 +array(0) { +} +empty map unpack, 0, 0 +object(stdClass)#%d (0) { +} +map unpack, 1, 1 +array(2) { + [1]=> + string(1) "B" + [0]=> + string(1) "A" +} +map pack, 1, 1 +string(10) "92a141a142" +map unpack, 1, 0 +object(stdClass)#%d (2) { + ["1"]=> + string(1) "B" + ["0"]=> + string(1) "A" +} +map pack, 1, 0 +string(18) "82a131a142a130a141" +obj pack, 1, 1 +string(32) "82c0a54d794f626aa66d656d62657201" +obj pack, 0, 1 +string(4) "9101" +obj pack, 1, 0 +string(32) "82c0a54d794f626aa66d656d62657201" +obj pack, 0, 0 +string(18) "81a66d656d62657201"