Skip to content

Commit

Permalink
Add OPT_ASSOC for roundtrip serialization of map.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ranvis committed Dec 18, 2019
1 parent 7eb85f2 commit 6b1845a
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 2 deletions.
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"

0 comments on commit 6b1845a

Please sign in to comment.