Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OPT_ASSOC for roundtrip serialization of map. #58

Merged
merged 1 commit into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions msgpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
22 changes: 22 additions & 0 deletions msgpack_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

typedef struct {
long php_only;
zend_bool assoc;
zend_object object;
} php_msgpack_base_t;

Expand All @@ -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;
Expand Down Expand Up @@ -175,13 +177,15 @@ 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) {
return;
}

base->php_only = php_only;
base->assoc = assoc;
}
/* }}} */

Expand All @@ -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");
Expand All @@ -213,17 +220,20 @@ 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", &parameter) == FAILURE) {
return;
}

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);
Expand All @@ -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) {
Expand All @@ -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));
Expand All @@ -263,6 +275,7 @@ static ZEND_METHOD(msgpack, unpack) /* {{{ */ {
}

MSGPACK_G(php_only) = php_only;
MSGPACK_G(assoc) = assoc;
}
/* }}} */

Expand All @@ -283,13 +296,15 @@ 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) {
return;
}

unpacker->php_only = php_only;
unpacker->assoc = assoc;

unpacker->buffer.s = NULL;
unpacker->buffer.a = 0;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions msgpack_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#define MSGPACK_CLASS_H

#define MSGPACK_CLASS_OPT_PHPONLY -1001
#define MSGPACK_CLASS_OPT_ASSOC -1002

void msgpack_init_class();

Expand Down
4 changes: 3 additions & 1 deletion msgpack_pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 5 additions & 1 deletion msgpack_unpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@
<file name="137.phpt" role="test" />
<file name="138.phpt" role="test" />
<file name="139.phpt" role="test" />
<file name="assoc.phpt" role="test" />
<file name="bug002.phpt" role="test" />
<file name="bug006.phpt" role="test" />
<file name="bug011.phpt" role="test" />
Expand Down
1 change: 1 addition & 0 deletions php_msgpack.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions tests/029.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
90 changes: 90 additions & 0 deletions tests/assoc.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
--TEST--
Map with assoc option
--SKIPIF--
--FILE--
<?php

if (!extension_loaded('msgpack')) {
dl('msgpack.' . PHP_SHLIB_SUFFIX);
}

function test(string $type, $data, bool $phpOnly, bool $assoc)
{
$msgpack = new MessagePack();
if (version_compare(PHP_VERSION, '5.1.0') <= 0) {
$msgpack->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"