Unverified Commit 9bda1f19 authored by Paul Yang's avatar Paul Yang Committed by GitHub

Adopt upb change for timestamp and duration json to php (#5106)

* Adopt upb change for timestamp and duration json to php

* Remove unused code

* Re-sync upb

* Fix php implementation timestamp json parsing

* Fix strptime use local timezone on mac.

* Remove succeeding tests

* Resync

* Add tests for values

* Fix php tests

* Fix encoder handlers change default value

Previously, oneofsubmsg_handler and submsg_handler change zval's default value directly.
The fix use REPLACE_ZVAL_VALUE which create a copy of parsed value and assign it to zval.
parent 47d33e75
...@@ -5,8 +5,6 @@ Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput ...@@ -5,8 +5,6 @@ Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput
Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput
Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator
Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator
Recommended.Proto3.JsonInput.DurationHas9FractionalDigits.Validator
Recommended.Proto3.JsonInput.DurationHasZeroFractionalDigit.Validator
Recommended.Proto3.JsonInput.Int64FieldBeString.Validator Recommended.Proto3.JsonInput.Int64FieldBeString.Validator
Recommended.Proto3.JsonInput.MapFieldValueIsNull Recommended.Proto3.JsonInput.MapFieldValueIsNull
Recommended.Proto3.JsonInput.OneofZeroBytes.JsonOutput Recommended.Proto3.JsonInput.OneofZeroBytes.JsonOutput
...@@ -18,13 +16,12 @@ Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate ...@@ -18,13 +16,12 @@ Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate
Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate
Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator
Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator
Recommended.Proto3.JsonInput.TimestampHas9FractionalDigits.Validator
Recommended.Proto3.JsonInput.TimestampHasZeroFractionalDigit.Validator
Recommended.Proto3.JsonInput.TimestampZeroNormalized.Validator
Recommended.Proto3.JsonInput.Uint64FieldBeString.Validator Recommended.Proto3.JsonInput.Uint64FieldBeString.Validator
Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput
Required.DurationProtoInputTooLarge.JsonOutput Required.DurationProtoInputTooLarge.JsonOutput
Required.DurationProtoInputTooSmall.JsonOutput Required.DurationProtoInputTooSmall.JsonOutput
Required.TimestampProtoInputTooLarge.JsonOutput
Required.TimestampProtoInputTooSmall.JsonOutput
Required.Proto3.JsonInput.Any.JsonOutput Required.Proto3.JsonInput.Any.JsonOutput
Required.Proto3.JsonInput.Any.ProtobufOutput Required.Proto3.JsonInput.Any.ProtobufOutput
Required.Proto3.JsonInput.AnyNested.JsonOutput Required.Proto3.JsonInput.AnyNested.JsonOutput
...@@ -51,12 +48,8 @@ Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput ...@@ -51,12 +48,8 @@ Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput
Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput
Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput
Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput
Required.Proto3.JsonInput.DurationMaxValue.JsonOutput
Required.Proto3.JsonInput.DurationMaxValue.ProtobufOutput
Required.Proto3.JsonInput.DurationMinValue.JsonOutput Required.Proto3.JsonInput.DurationMinValue.JsonOutput
Required.Proto3.JsonInput.DurationMinValue.ProtobufOutput
Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput
Required.Proto3.JsonInput.DurationRepeatedValue.ProtobufOutput
Required.Proto3.JsonInput.FieldMask.JsonOutput Required.Proto3.JsonInput.FieldMask.JsonOutput
Required.Proto3.JsonInput.FieldMask.ProtobufOutput Required.Proto3.JsonInput.FieldMask.ProtobufOutput
Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
...@@ -73,36 +66,8 @@ Required.Proto3.JsonInput.StringFieldUnicodeEscape.JsonOutput ...@@ -73,36 +66,8 @@ Required.Proto3.JsonInput.StringFieldUnicodeEscape.JsonOutput
Required.Proto3.JsonInput.StringFieldUnicodeEscape.ProtobufOutput Required.Proto3.JsonInput.StringFieldUnicodeEscape.ProtobufOutput
Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOutput Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOutput
Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput Required.Proto3.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
Required.Proto3.JsonInput.Struct.JsonOutput
Required.Proto3.JsonInput.Struct.ProtobufOutput
Required.Proto3.JsonInput.TimestampMaxValue.JsonOutput
Required.Proto3.JsonInput.TimestampMaxValue.ProtobufOutput
Required.Proto3.JsonInput.TimestampMinValue.JsonOutput
Required.Proto3.JsonInput.TimestampMinValue.ProtobufOutput
Required.Proto3.JsonInput.TimestampRepeatedValue.JsonOutput
Required.Proto3.JsonInput.TimestampRepeatedValue.ProtobufOutput
Required.Proto3.JsonInput.TimestampWithNegativeOffset.JsonOutput
Required.Proto3.JsonInput.TimestampWithNegativeOffset.ProtobufOutput
Required.Proto3.JsonInput.TimestampWithPositiveOffset.JsonOutput
Required.Proto3.JsonInput.TimestampWithPositiveOffset.ProtobufOutput
Required.Proto3.JsonInput.ValueAcceptBool.JsonOutput
Required.Proto3.JsonInput.ValueAcceptBool.ProtobufOutput
Required.Proto3.JsonInput.ValueAcceptFloat.JsonOutput
Required.Proto3.JsonInput.ValueAcceptFloat.ProtobufOutput
Required.Proto3.JsonInput.ValueAcceptInteger.JsonOutput
Required.Proto3.JsonInput.ValueAcceptInteger.ProtobufOutput
Required.Proto3.JsonInput.ValueAcceptList.JsonOutput
Required.Proto3.JsonInput.ValueAcceptList.ProtobufOutput
Required.Proto3.JsonInput.ValueAcceptNull.JsonOutput
Required.Proto3.JsonInput.ValueAcceptNull.ProtobufOutput
Required.Proto3.JsonInput.ValueAcceptObject.JsonOutput
Required.Proto3.JsonInput.ValueAcceptObject.ProtobufOutput
Required.Proto3.JsonInput.ValueAcceptString.JsonOutput
Required.Proto3.JsonInput.ValueAcceptString.ProtobufOutput
Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput
Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput
Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput
Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput
Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.JsonOutput
Required.TimestampProtoInputTooLarge.JsonOutput
Required.TimestampProtoInputTooSmall.JsonOutput
...@@ -132,6 +132,12 @@ static void stackenv_uninit(stackenv* se) { ...@@ -132,6 +132,12 @@ static void stackenv_uninit(stackenv* se) {
// Parsing. // Parsing.
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// TODO(teboring): This shoud be a bit in upb_msgdef
static bool is_wrapper_msg(const upb_msgdef *msg) {
return !strcmp(upb_filedef_name(upb_msgdef_upcast(msg)->file),
"google/protobuf/wrappers.proto");
}
#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs) #define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs)
// Creates a handlerdata that simply contains the offset for this field. // Creates a handlerdata that simply contains the offset for this field.
...@@ -420,13 +426,13 @@ static void *submsg_handler(void *closure, const void *hd) { ...@@ -420,13 +426,13 @@ static void *submsg_handler(void *closure, const void *hd) {
if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(message_data(msg), submsgdata->ofs, if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(message_data(msg), submsgdata->ofs,
CACHED_VALUE*))) == IS_NULL) { CACHED_VALUE*))) == IS_NULL) {
#if PHP_MAJOR_VERSION < 7 #if PHP_MAJOR_VERSION < 7
zval* val = NULL; zval val;
MAKE_STD_ZVAL(val); ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC));
ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC)); MessageHeader* intern = UNBOX(MessageHeader, &val);
MessageHeader* intern = UNBOX(MessageHeader, val);
custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC); custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
php_proto_zval_ptr_dtor(*DEREF(message_data(msg), submsgdata->ofs, zval**)); REPLACE_ZVAL_VALUE(DEREF(message_data(msg), submsgdata->ofs, zval**),
*DEREF(message_data(msg), submsgdata->ofs, zval**) = val; &val, 1);
zval_dtor(&val);
#else #else
zend_object* obj = subklass->create_object(subklass TSRMLS_CC); zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
ZVAL_OBJ(DEREF(message_data(msg), submsgdata->ofs, zval*), obj); ZVAL_OBJ(DEREF(message_data(msg), submsgdata->ofs, zval*), obj);
...@@ -765,9 +771,16 @@ static void* oneofsubmsg_handler(void* closure, const void* hd) { ...@@ -765,9 +771,16 @@ static void* oneofsubmsg_handler(void* closure, const void* hd) {
// Create new message. // Create new message.
DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) = DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) =
OBJ_PROP(&msg->std, oneofdata->property_ofs); OBJ_PROP(&msg->std, oneofdata->property_ofs);
ZVAL_OBJ(CACHED_PTR_TO_ZVAL_PTR( #if PHP_MAJOR_VERSION < 7
DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)), zval val;
subklass->create_object(subklass TSRMLS_CC)); ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC));
REPLACE_ZVAL_VALUE(DEREF(message_data(msg), oneofdata->ofs, zval**),
&val, 1);
zval_dtor(&val);
#else
zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
ZVAL_OBJ(DEREF(message_data(msg), oneofdata->ofs, zval*), obj);
#endif
} }
DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) =
...@@ -1080,24 +1093,25 @@ static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) { ...@@ -1080,24 +1093,25 @@ static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
static void putmsg(zval* msg, const Descriptor* desc, upb_sink* sink, static void putmsg(zval* msg, const Descriptor* desc, upb_sink* sink,
int depth TSRMLS_DC); int depth, bool is_json TSRMLS_DC);
static void putrawmsg(MessageHeader* msg, const Descriptor* desc, static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
upb_sink* sink, int depth TSRMLS_DC); upb_sink* sink, int depth, bool is_json TSRMLS_DC);
static void putstr(zval* str, const upb_fielddef* f, upb_sink* sink); static void putstr(zval* str, const upb_fielddef* f, upb_sink* sink,
bool force_default);
static void putrawstr(const char* str, int len, const upb_fielddef* f, static void putrawstr(const char* str, int len, const upb_fielddef* f,
upb_sink* sink); upb_sink* sink, bool force_default);
static void putsubmsg(zval* submsg, const upb_fielddef* f, upb_sink* sink, static void putsubmsg(zval* submsg, const upb_fielddef* f, upb_sink* sink,
int depth TSRMLS_DC); int depth, bool is_json TSRMLS_DC);
static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f, static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
upb_sink* sink, int depth TSRMLS_DC); upb_sink* sink, int depth, bool is_json TSRMLS_DC);
static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink, static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
int depth TSRMLS_DC); int depth, bool is_json TSRMLS_DC);
static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink, static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
int depth TSRMLS_DC); int depth, bool is_json TSRMLS_DC);
static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) { static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) {
upb_selector_t ret; upb_selector_t ret;
...@@ -1106,8 +1120,10 @@ static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) { ...@@ -1106,8 +1120,10 @@ static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) {
return ret; return ret;
} }
static void put_optional_value(const void* memory, int len, const upb_fielddef* f, static void put_optional_value(const void* memory, int len,
int depth, upb_sink* sink TSRMLS_DC) { const upb_fielddef* f,
int depth, upb_sink* sink,
bool is_json TSRMLS_DC) {
assert(upb_fielddef_label(f) == UPB_LABEL_OPTIONAL); assert(upb_fielddef_label(f) == UPB_LABEL_OPTIONAL);
switch (upb_fielddef_type(f)) { switch (upb_fielddef_type(f)) {
...@@ -1132,7 +1148,8 @@ static void put_optional_value(const void* memory, int len, const upb_fielddef* ...@@ -1132,7 +1148,8 @@ static void put_optional_value(const void* memory, int len, const upb_fielddef*
#undef T #undef T
case UPB_TYPE_STRING: case UPB_TYPE_STRING:
case UPB_TYPE_BYTES: case UPB_TYPE_BYTES:
putrawstr(memory, len, f, sink); putrawstr(memory, len, f, sink,
is_json && is_wrapper_msg(upb_fielddef_containingtype(f)));
break; break;
case UPB_TYPE_MESSAGE: { case UPB_TYPE_MESSAGE: {
#if PHP_MAJOR_VERSION < 7 #if PHP_MAJOR_VERSION < 7
...@@ -1142,7 +1159,7 @@ static void put_optional_value(const void* memory, int len, const upb_fielddef* ...@@ -1142,7 +1159,7 @@ static void put_optional_value(const void* memory, int len, const upb_fielddef*
(MessageHeader*)((char*)(*(zend_object**)memory) - (MessageHeader*)((char*)(*(zend_object**)memory) -
XtOffsetOf(MessageHeader, std)); XtOffsetOf(MessageHeader, std));
#endif #endif
putrawsubmsg(submsg, f, sink, depth TSRMLS_CC); putrawsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC);
break; break;
} }
default: default:
...@@ -1181,7 +1198,7 @@ static int raw_value_len(void* memory, int len, const upb_fielddef* f) { ...@@ -1181,7 +1198,7 @@ static int raw_value_len(void* memory, int len, const upb_fielddef* f) {
} }
static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink, static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
int depth TSRMLS_DC) { int depth, bool is_json TSRMLS_DC) {
upb_sink subsink; upb_sink subsink;
const upb_fielddef* key_field; const upb_fielddef* key_field;
const upb_fielddef* value_field; const upb_fielddef* value_field;
...@@ -1209,13 +1226,14 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink, ...@@ -1209,13 +1226,14 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
// Serialize key. // Serialize key.
const char *key = map_iter_key(&it, &len); const char *key = map_iter_key(&it, &len);
put_optional_value(key, len, key_field, depth + 1, &entry_sink TSRMLS_CC); put_optional_value(key, len, key_field, depth + 1,
&entry_sink, is_json TSRMLS_CC);
// Serialize value. // Serialize value.
upb_value value = map_iter_value(&it, &len); upb_value value = map_iter_value(&it, &len);
put_optional_value(raw_value(upb_value_memory(&value), value_field), put_optional_value(raw_value(upb_value_memory(&value), value_field),
raw_value_len(upb_value_memory(&value), len, value_field), raw_value_len(upb_value_memory(&value), len, value_field),
value_field, depth + 1, &entry_sink TSRMLS_CC); value_field, depth + 1, &entry_sink, is_json TSRMLS_CC);
upb_sink_endmsg(&entry_sink, &status); upb_sink_endmsg(&entry_sink, &status);
upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG)); upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
...@@ -1225,13 +1243,13 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink, ...@@ -1225,13 +1243,13 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
} }
static void putmsg(zval* msg_php, const Descriptor* desc, upb_sink* sink, static void putmsg(zval* msg_php, const Descriptor* desc, upb_sink* sink,
int depth TSRMLS_DC) { int depth, bool is_json TSRMLS_DC) {
MessageHeader* msg = UNBOX(MessageHeader, msg_php); MessageHeader* msg = UNBOX(MessageHeader, msg_php);
putrawmsg(msg, desc, sink, depth TSRMLS_CC); putrawmsg(msg, desc, sink, depth, is_json TSRMLS_CC);
} }
static void putrawmsg(MessageHeader* msg, const Descriptor* desc, static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
upb_sink* sink, int depth TSRMLS_DC) { upb_sink* sink, int depth, bool is_json TSRMLS_DC) {
upb_msg_field_iter i; upb_msg_field_iter i;
upb_status status; upb_status status;
...@@ -1268,31 +1286,34 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc, ...@@ -1268,31 +1286,34 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
zval* map = CACHED_PTR_TO_ZVAL_PTR( zval* map = CACHED_PTR_TO_ZVAL_PTR(
DEREF(message_data(msg), offset, CACHED_VALUE*)); DEREF(message_data(msg), offset, CACHED_VALUE*));
if (map != NULL) { if (map != NULL) {
putmap(map, f, sink, depth TSRMLS_CC); putmap(map, f, sink, depth, is_json TSRMLS_CC);
} }
} else if (upb_fielddef_isseq(f)) { } else if (upb_fielddef_isseq(f)) {
zval* array = CACHED_PTR_TO_ZVAL_PTR( zval* array = CACHED_PTR_TO_ZVAL_PTR(
DEREF(message_data(msg), offset, CACHED_VALUE*)); DEREF(message_data(msg), offset, CACHED_VALUE*));
if (array != NULL) { if (array != NULL) {
putarray(array, f, sink, depth TSRMLS_CC); putarray(array, f, sink, depth, is_json TSRMLS_CC);
} }
} else if (upb_fielddef_isstring(f)) { } else if (upb_fielddef_isstring(f)) {
zval* str = CACHED_PTR_TO_ZVAL_PTR( zval* str = CACHED_PTR_TO_ZVAL_PTR(
DEREF(message_data(msg), offset, CACHED_VALUE*)); DEREF(message_data(msg), offset, CACHED_VALUE*));
if (containing_oneof || Z_STRLEN_P(str) > 0) { if (containing_oneof || (is_json && is_wrapper_msg(desc->msgdef)) ||
putstr(str, f, sink); Z_STRLEN_P(str) > 0) {
putstr(str, f, sink, is_json && is_wrapper_msg(desc->msgdef));
} }
} else if (upb_fielddef_issubmsg(f)) { } else if (upb_fielddef_issubmsg(f)) {
putsubmsg(CACHED_PTR_TO_ZVAL_PTR( putsubmsg(CACHED_PTR_TO_ZVAL_PTR(
DEREF(message_data(msg), offset, CACHED_VALUE*)), DEREF(message_data(msg), offset, CACHED_VALUE*)),
f, sink, depth TSRMLS_CC); f, sink, depth, is_json TSRMLS_CC);
} else { } else {
upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
#define T(upbtypeconst, upbtype, ctype, default_value) \ #define T(upbtypeconst, upbtype, ctype, default_value) \
case upbtypeconst: { \ case upbtypeconst: { \
ctype value = DEREF(message_data(msg), offset, ctype); \ ctype value = DEREF(message_data(msg), offset, ctype); \
if (containing_oneof || value != default_value) { \ if (containing_oneof || \
(is_json && is_wrapper_msg(desc->msgdef)) || \
value != default_value) { \
upb_sink_put##upbtype(sink, sel, value); \ upb_sink_put##upbtype(sink, sel, value); \
} \ } \
} break; } break;
...@@ -1325,7 +1346,8 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc, ...@@ -1325,7 +1346,8 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
upb_sink_endmsg(sink, &status); upb_sink_endmsg(sink, &status);
} }
static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) { static void putstr(zval* str, const upb_fielddef *f,
upb_sink *sink, bool force_default) {
upb_sink subsink; upb_sink subsink;
if (ZVAL_IS_NULL(str)) return; if (ZVAL_IS_NULL(str)) return;
...@@ -1336,7 +1358,7 @@ static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) { ...@@ -1336,7 +1358,7 @@ static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) {
&subsink); &subsink);
// For oneof string field, we may get here with string length is zero. // For oneof string field, we may get here with string length is zero.
if (Z_STRLEN_P(str) > 0) { if (Z_STRLEN_P(str) > 0 || force_default) {
// Ensure that the string has the correct encoding. We also check at // Ensure that the string has the correct encoding. We also check at
// field-set time, but the user may have mutated the string object since // field-set time, but the user may have mutated the string object since
// then. // then.
...@@ -1353,10 +1375,10 @@ static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) { ...@@ -1353,10 +1375,10 @@ static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) {
} }
static void putrawstr(const char* str, int len, const upb_fielddef* f, static void putrawstr(const char* str, int len, const upb_fielddef* f,
upb_sink* sink) { upb_sink* sink, bool force_default) {
upb_sink subsink; upb_sink subsink;
if (len == 0) return; if (len == 0 && !force_default) return;
// Ensure that the string has the correct encoding. We also check at field-set // Ensure that the string has the correct encoding. We also check at field-set
// time, but the user may have mutated the string object since then. // time, but the user may have mutated the string object since then.
...@@ -1372,27 +1394,27 @@ static void putrawstr(const char* str, int len, const upb_fielddef* f, ...@@ -1372,27 +1394,27 @@ static void putrawstr(const char* str, int len, const upb_fielddef* f,
} }
static void putsubmsg(zval* submsg_php, const upb_fielddef* f, upb_sink* sink, static void putsubmsg(zval* submsg_php, const upb_fielddef* f, upb_sink* sink,
int depth TSRMLS_DC) { int depth, bool is_json TSRMLS_DC) {
if (Z_TYPE_P(submsg_php) == IS_NULL) return; if (Z_TYPE_P(submsg_php) == IS_NULL) return;
MessageHeader *submsg = UNBOX(MessageHeader, submsg_php); MessageHeader *submsg = UNBOX(MessageHeader, submsg_php);
putrawsubmsg(submsg, f, sink, depth TSRMLS_CC); putrawsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC);
} }
static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f, static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
upb_sink* sink, int depth TSRMLS_DC) { upb_sink* sink, int depth, bool is_json TSRMLS_DC) {
upb_sink subsink; upb_sink subsink;
Descriptor* subdesc = Descriptor* subdesc =
UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(upb_fielddef_msgsubdef(f))); UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(upb_fielddef_msgsubdef(f)));
upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink); upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
putrawmsg(submsg, subdesc, &subsink, depth + 1 TSRMLS_CC); putrawmsg(submsg, subdesc, &subsink, depth + 1, is_json TSRMLS_CC);
upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG)); upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
} }
static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink, static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
int depth TSRMLS_DC) { int depth, bool is_json TSRMLS_DC) {
upb_sink subsink; upb_sink subsink;
upb_fieldtype_t type = upb_fielddef_type(f); upb_fieldtype_t type = upb_fielddef_type(f);
upb_selector_t sel = 0; upb_selector_t sel = 0;
...@@ -1436,7 +1458,8 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink, ...@@ -1436,7 +1458,8 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
const char* rawstr = ZSTR_VAL(*(zend_string**)memory); const char* rawstr = ZSTR_VAL(*(zend_string**)memory);
int len = ZSTR_LEN(*(zend_string**)memory); int len = ZSTR_LEN(*(zend_string**)memory);
#endif #endif
putrawstr(rawstr, len, f, &subsink); putrawstr(rawstr, len, f, &subsink,
is_json && is_wrapper_msg(upb_fielddef_containingtype(f)));
break; break;
} }
case UPB_TYPE_MESSAGE: { case UPB_TYPE_MESSAGE: {
...@@ -1447,7 +1470,7 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink, ...@@ -1447,7 +1470,7 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
(MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) - (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) -
XtOffsetOf(MessageHeader, std)); XtOffsetOf(MessageHeader, std));
#endif #endif
putrawsubmsg(submsg, f, &subsink, depth TSRMLS_CC); putrawsubmsg(submsg, f, &subsink, depth, is_json TSRMLS_CC);
break; break;
} }
...@@ -1504,7 +1527,7 @@ void serialize_to_string(zval* val, zval* return_value TSRMLS_DC) { ...@@ -1504,7 +1527,7 @@ void serialize_to_string(zval* val, zval* return_value TSRMLS_DC) {
stackenv_init(&se, "Error occurred during encoding: %s"); stackenv_init(&se, "Error occurred during encoding: %s");
encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink); encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
putmsg(val, desc, upb_pb_encoder_input(encoder), 0 TSRMLS_CC); putmsg(val, desc, upb_pb_encoder_input(encoder), 0, false TSRMLS_CC);
PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1); PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1);
...@@ -1571,7 +1594,7 @@ PHP_METHOD(Message, serializeToJsonString) { ...@@ -1571,7 +1594,7 @@ PHP_METHOD(Message, serializeToJsonString) {
stackenv_init(&se, "Error occurred during encoding: %s"); stackenv_init(&se, "Error occurred during encoding: %s");
printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink); printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
putmsg(getThis(), desc, upb_json_printer_input(printer), 0 TSRMLS_CC); putmsg(getThis(), desc, upb_json_printer_input(printer), 0, true TSRMLS_CC);
PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1); PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -438,8 +438,8 @@ class GPBUtil ...@@ -438,8 +438,8 @@ class GPBUtil
$nanoseconds = intval($nanoseconds); $nanoseconds = intval($nanoseconds);
// remove the nanoseconds and preceding period from the timestamp // remove the nanoseconds and preceding period from the timestamp
$date = substr($timestamp, 0, $periodIndex - 1); $date = substr($timestamp, 0, $periodIndex);
$timezone = substr($timestamp, $periodIndex + $nanosecondsLength); $timezone = substr($timestamp, $periodIndex + $nanosecondsLength + 1);
$timestamp = $date.$timezone; $timestamp = $date.$timezone;
} }
} }
......
...@@ -1157,9 +1157,17 @@ class Message ...@@ -1157,9 +1157,17 @@ class Message
public function parseFromJsonStream($input) public function parseFromJsonStream($input)
{ {
$array = json_decode($input->getData(), true, 512, JSON_BIGINT_AS_STRING); $array = json_decode($input->getData(), true, 512, JSON_BIGINT_AS_STRING);
if ($this instanceof \Google\Protobuf\ListValue) {
$array = ["values"=>$array];
}
if (is_null($array)) { if (is_null($array)) {
throw new GPBDecodeException( if ($this instanceof \Google\Protobuf\Value) {
"Cannot decode json string."); $this->setNullValue(\Google\Protobuf\NullValue::NULL_VALUE);
return;
} else {
throw new GPBDecodeException(
"Cannot decode json string: " . $input->getData());
}
} }
try { try {
$this->mergeFromJsonArray($array); $this->mergeFromJsonArray($array);
......
...@@ -20,6 +20,9 @@ use Google\Protobuf\UInt64Value; ...@@ -20,6 +20,9 @@ use Google\Protobuf\UInt64Value;
use Google\Protobuf\BoolValue; use Google\Protobuf\BoolValue;
use Google\Protobuf\StringValue; use Google\Protobuf\StringValue;
use Google\Protobuf\BytesValue; use Google\Protobuf\BytesValue;
use Google\Protobuf\Value;
use Google\Protobuf\ListValue;
use Google\Protobuf\Struct;
class EncodeDecodeTest extends TestBase class EncodeDecodeTest extends TestBase
{ {
...@@ -40,6 +43,13 @@ class EncodeDecodeTest extends TestBase ...@@ -40,6 +43,13 @@ class EncodeDecodeTest extends TestBase
$this->assertEquals(false, $m->getValue()); $this->assertEquals(false, $m->getValue());
} }
public function testEncodeTopLevelBoolValue()
{
$m = new BoolValue();
$m->setValue(true);
$this->assertSame("true", $m->serializeToJsonString());
}
public function testDecodeTopLevelDoubleValue() public function testDecodeTopLevelDoubleValue()
{ {
$m = new DoubleValue(); $m = new DoubleValue();
...@@ -47,6 +57,13 @@ class EncodeDecodeTest extends TestBase ...@@ -47,6 +57,13 @@ class EncodeDecodeTest extends TestBase
$this->assertEquals(1.5, $m->getValue()); $this->assertEquals(1.5, $m->getValue());
} }
public function testEncodeTopLevelDoubleValue()
{
$m = new DoubleValue();
$m->setValue(1.5);
$this->assertSame("1.5", $m->serializeToJsonString());
}
public function testDecodeTopLevelFloatValue() public function testDecodeTopLevelFloatValue()
{ {
$m = new FloatValue(); $m = new FloatValue();
...@@ -54,6 +71,13 @@ class EncodeDecodeTest extends TestBase ...@@ -54,6 +71,13 @@ class EncodeDecodeTest extends TestBase
$this->assertEquals(1.5, $m->getValue()); $this->assertEquals(1.5, $m->getValue());
} }
public function testEncodeTopLevelFloatValue()
{
$m = new FloatValue();
$m->setValue(1.5);
$this->assertSame("1.5", $m->serializeToJsonString());
}
public function testDecodeTopLevelInt32Value() public function testDecodeTopLevelInt32Value()
{ {
$m = new Int32Value(); $m = new Int32Value();
...@@ -61,6 +85,13 @@ class EncodeDecodeTest extends TestBase ...@@ -61,6 +85,13 @@ class EncodeDecodeTest extends TestBase
$this->assertEquals(1, $m->getValue()); $this->assertEquals(1, $m->getValue());
} }
public function testEncodeTopLevelInt32Value()
{
$m = new Int32Value();
$m->setValue(1);
$this->assertSame("1", $m->serializeToJsonString());
}
public function testDecodeTopLevelUInt32Value() public function testDecodeTopLevelUInt32Value()
{ {
$m = new UInt32Value(); $m = new UInt32Value();
...@@ -68,6 +99,13 @@ class EncodeDecodeTest extends TestBase ...@@ -68,6 +99,13 @@ class EncodeDecodeTest extends TestBase
$this->assertEquals(1, $m->getValue()); $this->assertEquals(1, $m->getValue());
} }
public function testEncodeTopLevelUInt32Value()
{
$m = new UInt32Value();
$m->setValue(1);
$this->assertSame("1", $m->serializeToJsonString());
}
public function testDecodeTopLevelInt64Value() public function testDecodeTopLevelInt64Value()
{ {
$m = new Int64Value(); $m = new Int64Value();
...@@ -75,6 +113,13 @@ class EncodeDecodeTest extends TestBase ...@@ -75,6 +113,13 @@ class EncodeDecodeTest extends TestBase
$this->assertEquals(1, $m->getValue()); $this->assertEquals(1, $m->getValue());
} }
# public function testEncodeTopLevelInt64Value()
# {
# $m = new Int64Value();
# $m->setValue(1);
# $this->assertSame("\"1\"", $m->serializeToJsonString());
# }
public function testDecodeTopLevelUInt64Value() public function testDecodeTopLevelUInt64Value()
{ {
$m = new UInt64Value(); $m = new UInt64Value();
...@@ -82,6 +127,13 @@ class EncodeDecodeTest extends TestBase ...@@ -82,6 +127,13 @@ class EncodeDecodeTest extends TestBase
$this->assertEquals(1, $m->getValue()); $this->assertEquals(1, $m->getValue());
} }
# public function testEncodeTopLevelUInt64Value()
# {
# $m = new UInt64Value();
# $m->setValue(1);
# $this->assertSame("\"1\"", $m->serializeToJsonString());
# }
public function testDecodeTopLevelStringValue() public function testDecodeTopLevelStringValue()
{ {
$m = new StringValue(); $m = new StringValue();
...@@ -89,6 +141,13 @@ class EncodeDecodeTest extends TestBase ...@@ -89,6 +141,13 @@ class EncodeDecodeTest extends TestBase
$this->assertSame("a", $m->getValue()); $this->assertSame("a", $m->getValue());
} }
public function testEncodeTopLevelStringValue()
{
$m = new StringValue();
$m->setValue("a");
$this->assertSame("\"a\"", $m->serializeToJsonString());
}
public function testDecodeTopLevelBytesValue() public function testDecodeTopLevelBytesValue()
{ {
$m = new BytesValue(); $m = new BytesValue();
...@@ -96,6 +155,13 @@ class EncodeDecodeTest extends TestBase ...@@ -96,6 +155,13 @@ class EncodeDecodeTest extends TestBase
$this->assertSame("a", $m->getValue()); $this->assertSame("a", $m->getValue());
} }
public function testEncodeTopLevelBytesValue()
{
$m = new BytesValue();
$m->setValue("a");
$this->assertSame("\"YQ==\"", $m->serializeToJsonString());
}
public function testEncode() public function testEncode()
{ {
$from = new TestMessage(); $from = new TestMessage();
...@@ -603,4 +669,120 @@ class EncodeDecodeTest extends TestBase ...@@ -603,4 +669,120 @@ class EncodeDecodeTest extends TestBase
$to->mergeFromJsonString($data); $to->mergeFromJsonString($data);
$this->expectFields($to); $this->expectFields($to);
} }
public function testDecodeDuration()
{
$m = new Google\Protobuf\Duration();
$m->mergeFromJsonString("\"1234.5678s\"");
$this->assertEquals(1234, $m->getSeconds());
$this->assertEquals(567800000, $m->getNanos());
}
public function testEncodeDuration()
{
$m = new Google\Protobuf\Duration();
$m->setSeconds(1234);
$m->setNanos(999999999);
$this->assertEquals("\"1234.999999999s\"", $m->serializeToJsonString());
}
public function testDecodeTimestamp()
{
$m = new Google\Protobuf\Timestamp();
$m->mergeFromJsonString("\"2000-01-01T00:00:00.123456789Z\"");
$this->assertEquals(946684800, $m->getSeconds());
$this->assertEquals(123456789, $m->getNanos());
}
public function testEncodeTimestamp()
{
$m = new Google\Protobuf\Timestamp();
$m->setSeconds(946684800);
$m->setNanos(123456789);
$this->assertEquals("\"2000-01-01T00:00:00.123456789Z\"",
$m->serializeToJsonString());
}
public function testDecodeTopLevelValue()
{
$m = new Value();
$m->mergeFromJsonString("\"a\"");
$this->assertSame("a", $m->getStringValue());
$m = new Value();
$m->mergeFromJsonString("1.5");
$this->assertSame(1.5, $m->getNumberValue());
$m = new Value();
$m->mergeFromJsonString("true");
$this->assertSame(true, $m->getBoolValue());
$m = new Value();
$m->mergeFromJsonString("null");
$this->assertSame("null_value", $m->getKind());
$m = new Value();
$m->mergeFromJsonString("[1]");
$this->assertSame("list_value", $m->getKind());
$m = new Value();
$m->mergeFromJsonString("{\"a\":1}");
$this->assertSame("struct_value", $m->getKind());
}
public function testEncodeTopLevelValue()
{
$m = new Value();
$m->setStringValue("a");
$this->assertSame("\"a\"", $m->serializeToJsonString());
$m = new Value();
$m->setNumberValue(1.5);
$this->assertSame("1.5", $m->serializeToJsonString());
$m = new Value();
$m->setBoolValue(true);
$this->assertSame("true", $m->serializeToJsonString());
$m = new Value();
$m->setNullValue(0);
$this->assertSame("null", $m->serializeToJsonString());
}
public function testDecodeTopLevelListValue()
{
$m = new ListValue();
$m->mergeFromJsonString("[1]");
$this->assertSame(1.0, $m->getValues()[0]->getNumberValue());
}
public function testEncodeTopLevelListValue()
{
$m = new ListValue();
$arr = $m->getValues();
$sub = new Value();
$sub->setNumberValue(1.5);
$arr[] = $sub;
$this->assertSame("[1.5]", $m->serializeToJsonString());
}
public function testDecodeTopLevelStruct()
{
$m = new Struct();
$m->mergeFromJsonString("{\"a\":{\"b\":1}}");
$this->assertSame(1.0, $m->getFields()["a"]
->getStructValue()
->getFields()["b"]->getNumberValue());
}
public function testEncodeTopLevelStruct()
{
$m = new Struct();
$map = $m->getFields();
$sub = new Value();
$sub->setNumberValue(1.5);
$map["a"] = $sub;
$this->assertSame("{\"a\":1.5}", $m->serializeToJsonString());
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment