Skip to content

Commit 6b1845a

Browse files
committed
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.
1 parent 7eb85f2 commit 6b1845a

9 files changed

+130
-2
lines changed

msgpack.c

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ STD_PHP_INI_BOOLEAN(
4242
STD_PHP_INI_BOOLEAN(
4343
"msgpack.php_only", "1", PHP_INI_ALL, OnUpdateBool,
4444
php_only, zend_msgpack_globals, msgpack_globals)
45+
STD_PHP_INI_BOOLEAN(
46+
"msgpack.assoc", "1", PHP_INI_ALL, OnUpdateBool,
47+
assoc, zend_msgpack_globals, msgpack_globals)
4548
STD_PHP_INI_BOOLEAN(
4649
"msgpack.illegal_key_insert", "0", PHP_INI_ALL, OnUpdateBool,
4750
illegal_key_insert, zend_msgpack_globals, msgpack_globals)
@@ -71,6 +74,7 @@ static void msgpack_init_globals(zend_msgpack_globals *msgpack_globals) /* {{{ *
7174
}
7275

7376
msgpack_globals->php_only = 1;
77+
msgpack_globals->assoc = 1;
7478

7579
msgpack_globals->illegal_key_insert = 0;
7680
msgpack_globals->use_str8_serialization = 1;
@@ -92,6 +96,8 @@ static ZEND_MINIT_FUNCTION(msgpack) /* {{{ */ {
9296

9397
REGISTER_LONG_CONSTANT("MESSAGEPACK_OPT_PHPONLY",
9498
MSGPACK_CLASS_OPT_PHPONLY, CONST_CS | CONST_PERSISTENT);
99+
REGISTER_LONG_CONSTANT("MESSAGEPACK_OPT_ASSOC",
100+
MSGPACK_CLASS_OPT_ASSOC, CONST_CS | CONST_PERSISTENT);
95101

96102
return SUCCESS;
97103
}

msgpack_class.c

+22
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
typedef struct {
1111
long php_only;
12+
zend_bool assoc;
1213
zend_object object;
1314
} php_msgpack_base_t;
1415

@@ -18,6 +19,7 @@ typedef struct {
1819
long offset;
1920
msgpack_unpack_t mp;
2021
long php_only;
22+
zend_bool assoc;
2123
zend_bool finished;
2224
int error;
2325
zend_object object;
@@ -175,13 +177,15 @@ static void php_msgpack_unpacker_free(zend_object *object) /* {{{ */ {
175177
/* MessagePack */
176178
static ZEND_METHOD(msgpack, __construct) /* {{{ */ {
177179
zend_bool php_only = MSGPACK_G(php_only);
180+
zend_bool assoc = MSGPACK_G(assoc);
178181
php_msgpack_base_t *base = Z_MSGPACK_BASE_P(getThis());
179182

180183
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &php_only) == FAILURE) {
181184
return;
182185
}
183186

184187
base->php_only = php_only;
188+
base->assoc = assoc;
185189
}
186190
/* }}} */
187191

@@ -198,6 +202,9 @@ static ZEND_METHOD(msgpack, setOption) /* {{{ */ {
198202
case MSGPACK_CLASS_OPT_PHPONLY:
199203
base->php_only = i_zend_is_true(value);
200204
break;
205+
case MSGPACK_CLASS_OPT_ASSOC:
206+
base->assoc = i_zend_is_true(value);
207+
break;
201208
default:
202209
MSGPACK_WARNING("[msgpack] (MessagePack::setOption) "
203210
"error setting msgpack option");
@@ -213,17 +220,20 @@ static ZEND_METHOD(msgpack, pack) /* {{{ */ {
213220
zval *parameter;
214221
smart_str buf = {0};
215222
int php_only = MSGPACK_G(php_only);
223+
zend_bool assoc = MSGPACK_G(assoc);
216224
php_msgpack_base_t *base = Z_MSGPACK_BASE_P(getThis());
217225

218226
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &parameter) == FAILURE) {
219227
return;
220228
}
221229

222230
MSGPACK_G(php_only) = base->php_only;
231+
MSGPACK_G(assoc) = base->assoc;
223232

224233
php_msgpack_serialize(&buf, parameter);
225234

226235
MSGPACK_G(php_only) = php_only;
236+
MSGPACK_G(assoc) = assoc;
227237
if (buf.s) {
228238
smart_str_0(&buf);
229239
ZVAL_STR(return_value, buf.s);
@@ -238,6 +248,7 @@ static ZEND_METHOD(msgpack, unpack) /* {{{ */ {
238248
zend_string *str;
239249
zval *object = NULL;
240250
zend_bool php_only = MSGPACK_G(php_only);
251+
zend_bool assoc = MSGPACK_G(assoc);
241252
php_msgpack_base_t *base = Z_MSGPACK_BASE_P(getThis());
242253

243254
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &str, &object) == FAILURE) {
@@ -249,6 +260,7 @@ static ZEND_METHOD(msgpack, unpack) /* {{{ */ {
249260
}
250261

251262
MSGPACK_G(php_only) = base->php_only;
263+
MSGPACK_G(assoc) = base->assoc;
252264

253265
if (object == NULL) {
254266
php_msgpack_unserialize(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
@@ -263,6 +275,7 @@ static ZEND_METHOD(msgpack, unpack) /* {{{ */ {
263275
}
264276

265277
MSGPACK_G(php_only) = php_only;
278+
MSGPACK_G(assoc) = assoc;
266279
}
267280
/* }}} */
268281

@@ -283,13 +296,15 @@ static ZEND_METHOD(msgpack, unpacker) /* {{{ */ {
283296
/* MessagePackUnpacker */
284297
static ZEND_METHOD(msgpack_unpacker, __construct) /* {{{ */ {
285298
zend_bool php_only = MSGPACK_G(php_only);
299+
zend_bool assoc = MSGPACK_G(assoc);
286300
php_msgpack_unpacker_t *unpacker = Z_MSGPACK_UNPACKER_P(getThis());
287301

288302
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &php_only) == FAILURE) {
289303
return;
290304
}
291305

292306
unpacker->php_only = php_only;
307+
unpacker->assoc = assoc;
293308

294309
unpacker->buffer.s = NULL;
295310
unpacker->buffer.a = 0;
@@ -322,6 +337,9 @@ static ZEND_METHOD(msgpack_unpacker, setOption) /* {{{ */ {
322337
case MSGPACK_CLASS_OPT_PHPONLY:
323338
unpacker->php_only = i_zend_is_true(value);
324339
break;
340+
case MSGPACK_CLASS_OPT_ASSOC:
341+
unpacker->assoc = i_zend_is_true(value);
342+
break;
325343
default:
326344
MSGPACK_WARNING("[msgpack] (MessagePackUnpacker::setOption) "
327345
"error setting msgpack option");
@@ -356,6 +374,7 @@ static ZEND_METHOD(msgpack_unpacker, execute) /* {{{ */ {
356374
size_t len, off;
357375
zend_string *str = NULL;
358376
int ret, error_display = MSGPACK_G(error_display), php_only = MSGPACK_G(php_only);
377+
zend_bool assoc = MSGPACK_G(assoc);
359378
zval *offset = NULL;
360379
php_msgpack_unpacker_t *unpacker = Z_MSGPACK_UNPACKER_P(getThis());
361380

@@ -392,11 +411,13 @@ static ZEND_METHOD(msgpack_unpacker, execute) /* {{{ */ {
392411

393412
MSGPACK_G(error_display) = 0;
394413
MSGPACK_G(php_only) = unpacker->php_only;
414+
MSGPACK_G(assoc) = unpacker->assoc;
395415

396416
ret = template_execute(&unpacker->mp, data, len, &off);
397417

398418
MSGPACK_G(error_display) = error_display;
399419
MSGPACK_G(php_only) = php_only;
420+
MSGPACK_G(assoc) = assoc;
400421

401422
if (str != NULL) {
402423
if (offset != NULL) {
@@ -490,6 +511,7 @@ void msgpack_init_class() /* {{{ */ {
490511
msgpack_handlers.free_obj = php_msgpack_base_free;
491512

492513
zend_declare_class_constant_long(msgpack_ce, ZEND_STRS("OPT_PHPONLY") - 1, MSGPACK_CLASS_OPT_PHPONLY);
514+
zend_declare_class_constant_long(msgpack_ce, ZEND_STRS("OPT_ASSOC") - 1, MSGPACK_CLASS_OPT_ASSOC);
493515

494516
/* unpacker */
495517
INIT_CLASS_ENTRY(ce, "MessagePackUnpacker", msgpack_unpacker_methods);

msgpack_class.h

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#define MSGPACK_CLASS_H
44

55
#define MSGPACK_CLASS_OPT_PHPONLY -1001
6+
#define MSGPACK_CLASS_OPT_ASSOC -1002
67

78
void msgpack_init_class();
89

msgpack_pack.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,9 @@ static inline void msgpack_serialize_array(smart_str *buf, zval *val, HashTable
247247
}
248248

249249
if (object) {
250-
if (MSGPACK_G(php_only)) {
250+
if (!MSGPACK_G(assoc) && (!MSGPACK_G(php_only) || !strcmp(class_name, "stdClass"))) {
251+
msgpack_pack_map(buf, n);
252+
} else if (MSGPACK_G(php_only)) {
251253
if (is_ref) {
252254
msgpack_pack_map(buf, n + 2);
253255
msgpack_pack_nil(buf);

msgpack_unpack.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ int msgpack_unserialize_map(msgpack_unserialize_data *unpack, unsigned int count
589589
unpack->count = count;
590590

591591
if (count == 0) {
592-
if (MSGPACK_G(php_only)) {
592+
if (MSGPACK_G(php_only) || !MSGPACK_G(assoc)) {
593593
object_init(*obj);
594594
} else {
595595
array_init(*obj);
@@ -708,6 +708,10 @@ int msgpack_unserialize_map_item(msgpack_unserialize_data *unpack, zval **contai
708708

709709
container_val = Z_ISREF_P(*container) ? Z_REFVAL_P(*container) : *container;
710710

711+
if (!MSGPACK_G(assoc) && Z_TYPE_P(container_val) != IS_ARRAY && Z_TYPE_P(container_val) != IS_OBJECT) {
712+
object_init(container_val);
713+
}
714+
711715
if (Z_TYPE_P(container_val) == IS_OBJECT) {
712716
switch (Z_TYPE_P(key)) {
713717
case IS_LONG:

package.xml

+1
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@
173173
<file name="137.phpt" role="test" />
174174
<file name="138.phpt" role="test" />
175175
<file name="139.phpt" role="test" />
176+
<file name="assoc.phpt" role="test" />
176177
<file name="bug002.phpt" role="test" />
177178
<file name="bug006.phpt" role="test" />
178179
<file name="bug011.phpt" role="test" />

php_msgpack.h

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ extern zend_module_entry msgpack_module_entry;
2323
ZEND_BEGIN_MODULE_GLOBALS(msgpack)
2424
zend_bool error_display;
2525
zend_bool php_only;
26+
zend_bool assoc;
2627
zend_bool illegal_key_insert;
2728
zend_bool use_str8_serialization;
2829
struct {

tests/029.phpt

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ extension Version => %s
4848
header Version => %s
4949

5050
Directive => Local Value => Master Value
51+
msgpack.assoc => %s => %s
5152
msgpack.error_display => %s => %s
5253
msgpack.illegal_key_insert => %s => %s
5354
msgpack.php_only => %s => %s

tests/assoc.phpt

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
--TEST--
2+
Map with assoc option
3+
--SKIPIF--
4+
--FILE--
5+
<?php
6+
7+
if (!extension_loaded('msgpack')) {
8+
dl('msgpack.' . PHP_SHLIB_SUFFIX);
9+
}
10+
11+
function test(string $type, $data, bool $phpOnly, bool $assoc)
12+
{
13+
$msgpack = new MessagePack();
14+
if (version_compare(PHP_VERSION, '5.1.0') <= 0) {
15+
$msgpack->setOption(MESSAGEPACK_OPT_PHPONLY, $phpOnly);
16+
$msgpack->setOption(MESSAGEPACK_OPT_ASSOC, $assoc);
17+
} else {
18+
$msgpack->setOption(MessagePack::OPT_PHPONLY, $phpOnly);
19+
$msgpack->setOption(MessagePack::OPT_ASSOC, $assoc);
20+
}
21+
if (is_string($data)) {
22+
$result = $msgpack->unpack(hex2bin($data));
23+
} else {
24+
$result = bin2hex($msgpack->pack($data));
25+
}
26+
27+
printf("%s, %d, %d\n", $type, $phpOnly, $assoc);
28+
var_dump($result);
29+
return $result;
30+
}
31+
32+
$emptyMapData = '80'; // {}
33+
test("empty map unpack", $emptyMapData, true, true);
34+
test("empty map unpack", $emptyMapData, false, true);
35+
test("empty map unpack", $emptyMapData, false, false);
36+
37+
$mapData = '82a131a142a130a141'; // {"1":"B","0":"A"}
38+
$map = test("map unpack", $mapData, true, true);
39+
test("map pack", $map, true, true);
40+
$map = test("map unpack", $mapData, true, false);
41+
test("map pack", $map, true, false);
42+
43+
$obj = new MyObj();
44+
$obj->member = 1;
45+
test("obj pack", $obj, true, true);
46+
test("obj pack", $obj, false, true);
47+
test("obj pack", $obj, true, false);
48+
test("obj pack", $obj, false, false);
49+
50+
class MyObj
51+
{
52+
public $member;
53+
}
54+
55+
--EXPECTF--
56+
empty map unpack, 1, 1
57+
object(stdClass)#%d (0) {
58+
}
59+
empty map unpack, 0, 1
60+
array(0) {
61+
}
62+
empty map unpack, 0, 0
63+
object(stdClass)#%d (0) {
64+
}
65+
map unpack, 1, 1
66+
array(2) {
67+
[1]=>
68+
string(1) "B"
69+
[0]=>
70+
string(1) "A"
71+
}
72+
map pack, 1, 1
73+
string(14) "8201a14200a141"
74+
map unpack, 1, 0
75+
object(stdClass)#%d (2) {
76+
["1"]=>
77+
string(1) "B"
78+
["0"]=>
79+
string(1) "A"
80+
}
81+
map pack, 1, 0
82+
string(18) "82a131a142a130a141"
83+
obj pack, 1, 1
84+
string(32) "82c0a54d794f626aa66d656d62657201"
85+
obj pack, 0, 1
86+
string(4) "9101"
87+
obj pack, 1, 0
88+
string(32) "82c0a54d794f626aa66d656d62657201"
89+
obj pack, 0, 0
90+
string(18) "81a66d656d62657201"

0 commit comments

Comments
 (0)