diff --git a/msgpack.c b/msgpack.c index 6b92437..974d14f 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) @@ -71,6 +74,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->use_str8_serialization = 1; @@ -92,6 +96,8 @@ 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); return SUCCESS; } diff --git a/msgpack_class.c b/msgpack_class.c index 69f3803..c339982 100644 --- a/msgpack_class.c +++ b/msgpack_class.c @@ -9,6 +9,7 @@ typedef struct { long php_only; + zend_bool assoc; zend_object object; } php_msgpack_base_t; @@ -18,6 +19,7 @@ typedef struct { long offset; msgpack_unpack_t mp; long php_only; + zend_bool assoc; zend_bool finished; int error; zend_object object; @@ -175,6 +177,7 @@ static void php_msgpack_unpacker_free(zend_object *object) /* {{{ */ { /* MessagePack */ static ZEND_METHOD(msgpack, __construct) /* {{{ */ { zend_bool php_only = MSGPACK_G(php_only); + zend_bool assoc = MSGPACK_G(assoc); php_msgpack_base_t *base = Z_MSGPACK_BASE_P(getThis()); if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &php_only) == FAILURE) { @@ -182,6 +185,7 @@ static ZEND_METHOD(msgpack, __construct) /* {{{ */ { } base->php_only = php_only; + base->assoc = assoc; } /* }}} */ @@ -198,6 +202,9 @@ static ZEND_METHOD(msgpack, setOption) /* {{{ */ { case MSGPACK_CLASS_OPT_PHPONLY: base->php_only = i_zend_is_true(value); break; + case MSGPACK_CLASS_OPT_ASSOC: + base->assoc = i_zend_is_true(value); + break; default: MSGPACK_WARNING("[msgpack] (MessagePack::setOption) " "error setting msgpack option"); @@ -213,6 +220,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); php_msgpack_base_t *base = Z_MSGPACK_BASE_P(getThis()); if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", ¶meter) == FAILURE) { @@ -220,10 +228,12 @@ static ZEND_METHOD(msgpack, pack) /* {{{ */ { } MSGPACK_G(php_only) = base->php_only; + MSGPACK_G(assoc) = base->assoc; php_msgpack_serialize(&buf, parameter); MSGPACK_G(php_only) = php_only; + MSGPACK_G(assoc) = assoc; if (buf.s) { smart_str_0(&buf); ZVAL_STR(return_value, buf.s); @@ -238,6 +248,7 @@ static ZEND_METHOD(msgpack, unpack) /* {{{ */ { zend_string *str; zval *object = NULL; zend_bool php_only = MSGPACK_G(php_only); + zend_bool assoc = MSGPACK_G(assoc); php_msgpack_base_t *base = Z_MSGPACK_BASE_P(getThis()); if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &str, &object) == FAILURE) { @@ -249,6 +260,7 @@ static ZEND_METHOD(msgpack, unpack) /* {{{ */ { } MSGPACK_G(php_only) = base->php_only; + MSGPACK_G(assoc) = base->assoc; if (object == NULL) { php_msgpack_unserialize(return_value, ZSTR_VAL(str), ZSTR_LEN(str)); @@ -263,6 +275,7 @@ static ZEND_METHOD(msgpack, unpack) /* {{{ */ { } MSGPACK_G(php_only) = php_only; + MSGPACK_G(assoc) = assoc; } /* }}} */ @@ -283,6 +296,7 @@ static ZEND_METHOD(msgpack, unpacker) /* {{{ */ { /* MessagePackUnpacker */ static ZEND_METHOD(msgpack_unpacker, __construct) /* {{{ */ { zend_bool php_only = MSGPACK_G(php_only); + zend_bool assoc = MSGPACK_G(assoc); php_msgpack_unpacker_t *unpacker = Z_MSGPACK_UNPACKER_P(getThis()); if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &php_only) == FAILURE) { @@ -290,6 +304,7 @@ static ZEND_METHOD(msgpack_unpacker, __construct) /* {{{ */ { } unpacker->php_only = php_only; + unpacker->assoc = assoc; unpacker->buffer.s = NULL; unpacker->buffer.a = 0; @@ -322,6 +337,9 @@ static ZEND_METHOD(msgpack_unpacker, setOption) /* {{{ */ { case MSGPACK_CLASS_OPT_PHPONLY: unpacker->php_only = i_zend_is_true(value); break; + case MSGPACK_CLASS_OPT_ASSOC: + unpacker->assoc = i_zend_is_true(value); + break; default: MSGPACK_WARNING("[msgpack] (MessagePackUnpacker::setOption) " "error setting msgpack option"); @@ -356,6 +374,7 @@ static ZEND_METHOD(msgpack_unpacker, execute) /* {{{ */ { size_t len, off; zend_string *str = NULL; int ret, error_display = MSGPACK_G(error_display), php_only = MSGPACK_G(php_only); + zend_bool assoc = MSGPACK_G(assoc); zval *offset = NULL; php_msgpack_unpacker_t *unpacker = Z_MSGPACK_UNPACKER_P(getThis()); @@ -392,11 +411,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) { if (offset != NULL) { @@ -490,6 +511,7 @@ void msgpack_init_class() /* {{{ */ { msgpack_handlers.free_obj = php_msgpack_base_free; zend_declare_class_constant_long(msgpack_ce, ZEND_STRS("OPT_PHPONLY") - 1, MSGPACK_CLASS_OPT_PHPONLY); + zend_declare_class_constant_long(msgpack_ce, ZEND_STRS("OPT_ASSOC") - 1, MSGPACK_CLASS_OPT_ASSOC); /* unpacker */ INIT_CLASS_ENTRY(ce, "MessagePackUnpacker", msgpack_unpacker_methods); 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 c5da6d9..46ce165 100644 --- a/msgpack_pack.c +++ b/msgpack_pack.c @@ -247,7 +247,9 @@ static inline void msgpack_serialize_array(smart_str *buf, zval *val, HashTable } 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 (is_ref) { msgpack_pack_map(buf, n + 2); msgpack_pack_nil(buf); diff --git a/msgpack_unpack.c b/msgpack_unpack.c index 9ce1961..ffcd568 100644 --- a/msgpack_unpack.c +++ b/msgpack_unpack.c @@ -589,7 +589,7 @@ int msgpack_unserialize_map(msgpack_unserialize_data *unpack, unsigned int count unpack->count = count; if (count == 0) { - if (MSGPACK_G(php_only)) { + if (MSGPACK_G(php_only) || !MSGPACK_G(assoc)) { object_init(*obj); } else { array_init(*obj); @@ -708,6 +708,10 @@ int msgpack_unserialize_map_item(msgpack_unserialize_data *unpack, zval **contai container_val = Z_ISREF_P(*container) ? Z_REFVAL_P(*container) : *container; + if (!MSGPACK_G(assoc) && Z_TYPE_P(container_val) != IS_ARRAY && Z_TYPE_P(container_val) != IS_OBJECT) { + object_init(container_val); + } + if (Z_TYPE_P(container_val) == IS_OBJECT) { switch (Z_TYPE_P(key)) { case IS_LONG: diff --git a/package.xml b/package.xml index bfb53d7..8aa977b 100644 --- a/package.xml +++ b/package.xml @@ -173,6 +173,7 @@ + diff --git a/php_msgpack.h b/php_msgpack.h index 6bd4b4a..1574349 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 a7e3887..49fa0dd 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 => %s => %s msgpack.error_display => %s => %s msgpack.illegal_key_insert => %s => %s msgpack.php_only => %s => %s diff --git a/tests/assoc.phpt b/tests/assoc.phpt new file mode 100644 index 0000000..9f9047c --- /dev/null +++ b/tests/assoc.phpt @@ -0,0 +1,90 @@ +--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(14) "8201a14200a141" +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"