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 Aug 28, 2015
1 parent 7b321ea commit 13c076b
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 6 deletions.
7 changes: 7 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 @@ -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;
Expand All @@ -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;
Expand Down
26 changes: 26 additions & 0 deletions msgpack_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
typedef struct {
zend_object object;
long php_only;
zend_bool assoc;
} php_msgpack_base_t;

typedef struct {
Expand All @@ -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;
Expand Down Expand Up @@ -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(
Expand All @@ -283,6 +286,7 @@ static ZEND_METHOD(msgpack, __construct)
}

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

static ZEND_METHOD(msgpack, setOption)
Expand All @@ -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");
Expand All @@ -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(
Expand All @@ -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);

Expand All @@ -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(
Expand All @@ -358,6 +370,7 @@ static ZEND_METHOD(msgpack, unpack)
}

MSGPACK_G(php_only) = base->php_only;
MSGPACK_G(assoc) = base->assoc;

if (object == NULL)
{
Expand All @@ -377,6 +390,7 @@ static ZEND_METHOD(msgpack, unpack)
}

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

static ZEND_METHOD(msgpack, unpacker)
Expand All @@ -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(
Expand All @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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 */
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
6 changes: 5 additions & 1 deletion msgpack_pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down
28 changes: 23 additions & 5 deletions msgpack_unpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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))
Expand All @@ -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(
Expand All @@ -737,6 +754,7 @@ int msgpack_unserialize_map_item(
}
zval_ptr_dtor(&key);
break;
}
default:
MSGPACK_WARNING("[msgpack] (%s) illegal key type", __FUNCTION__);

Expand Down
1 change: 1 addition & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@
<file name="136.phpt" role="test" />
<file name="136b.phpt" role="test" />
<file name="137.phpt" role="test" />
<file name="assoc.phpt" role="test" />
<file name="bug006.phpt" role="test" />
<file name="bug011.phpt" role="test" />
<file name="bug012.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 => On => On
msgpack.error_display => On => On
msgpack.illegal_key_insert => Off => Off
msgpack.php_only => On => On
Expand Down
92 changes: 92 additions & 0 deletions tests/assoc.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
--TEST--
Map with assoc option
--SKIPIF--
--FILE--
<?php
if(!extension_loaded('msgpack'))
{
dl('msgpack.' . PHP_SHLIB_SUFFIX);
}

function test($type, $data, $phpOnly, $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(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"

0 comments on commit 13c076b

Please sign in to comment.