diff options
Diffstat (limited to 'php/ext/google/protobuf/encode_decode.c')
-rw-r--r-- | php/ext/google/protobuf/encode_decode.c | 115 |
1 files changed, 69 insertions, 46 deletions
diff --git a/php/ext/google/protobuf/encode_decode.c b/php/ext/google/protobuf/encode_decode.c index 899b99f0..2bb5f521 100644 --- a/php/ext/google/protobuf/encode_decode.c +++ b/php/ext/google/protobuf/encode_decode.c @@ -132,6 +132,12 @@ static void stackenv_uninit(stackenv* se) { // 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) // Creates a handlerdata that simply contains the offset for this field. @@ -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, CACHED_VALUE*))) == IS_NULL) { #if PHP_MAJOR_VERSION < 7 - zval* val = NULL; - MAKE_STD_ZVAL(val); - ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC)); - MessageHeader* intern = UNBOX(MessageHeader, val); + zval val; + ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC)); + MessageHeader* intern = UNBOX(MessageHeader, &val); custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC); - php_proto_zval_ptr_dtor(*DEREF(message_data(msg), submsgdata->ofs, zval**)); - *DEREF(message_data(msg), submsgdata->ofs, zval**) = val; + REPLACE_ZVAL_VALUE(DEREF(message_data(msg), submsgdata->ofs, zval**), + &val, 1); + zval_dtor(&val); #else zend_object* obj = subklass->create_object(subklass TSRMLS_CC); ZVAL_OBJ(DEREF(message_data(msg), submsgdata->ofs, zval*), obj); @@ -765,9 +771,16 @@ static void* oneofsubmsg_handler(void* closure, const void* hd) { // Create new message. DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) = OBJ_PROP(&msg->std, oneofdata->property_ofs); - ZVAL_OBJ(CACHED_PTR_TO_ZVAL_PTR( - DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)), - subklass->create_object(subklass TSRMLS_CC)); +#if PHP_MAJOR_VERSION < 7 + zval val; + 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) = @@ -1080,24 +1093,25 @@ static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) { // ----------------------------------------------------------------------------- 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, - 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, - upb_sink* sink); + upb_sink* sink, bool force_default); 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, - 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, - int depth TSRMLS_DC); + int depth, bool is_json TSRMLS_DC); 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) { upb_selector_t ret; @@ -1106,8 +1120,10 @@ static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) { return ret; } -static void put_optional_value(const void* memory, int len, const upb_fielddef* f, - int depth, upb_sink* sink TSRMLS_DC) { +static void put_optional_value(const void* memory, int len, + const upb_fielddef* f, + int depth, upb_sink* sink, + bool is_json TSRMLS_DC) { assert(upb_fielddef_label(f) == UPB_LABEL_OPTIONAL); switch (upb_fielddef_type(f)) { @@ -1132,7 +1148,8 @@ static void put_optional_value(const void* memory, int len, const upb_fielddef* #undef T case UPB_TYPE_STRING: case UPB_TYPE_BYTES: - putrawstr(memory, len, f, sink); + putrawstr(memory, len, f, sink, + is_json && is_wrapper_msg(upb_fielddef_containingtype(f))); break; case UPB_TYPE_MESSAGE: { #if PHP_MAJOR_VERSION < 7 @@ -1142,7 +1159,7 @@ static void put_optional_value(const void* memory, int len, const upb_fielddef* (MessageHeader*)((char*)(*(zend_object**)memory) - XtOffsetOf(MessageHeader, std)); #endif - putrawsubmsg(submsg, f, sink, depth TSRMLS_CC); + putrawsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC); break; } default: @@ -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, - int depth TSRMLS_DC) { + int depth, bool is_json TSRMLS_DC) { upb_sink subsink; const upb_fielddef* key_field; const upb_fielddef* value_field; @@ -1209,13 +1226,14 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink, // Serialize key. 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. upb_value value = map_iter_value(&it, &len); put_optional_value(raw_value(upb_value_memory(&value), 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_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG)); @@ -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, - int depth TSRMLS_DC) { + int depth, bool is_json TSRMLS_DC) { 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, - upb_sink* sink, int depth TSRMLS_DC) { + upb_sink* sink, int depth, bool is_json TSRMLS_DC) { upb_msg_field_iter i; upb_status status; @@ -1268,31 +1286,34 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc, zval* map = CACHED_PTR_TO_ZVAL_PTR( DEREF(message_data(msg), offset, CACHED_VALUE*)); 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)) { zval* array = CACHED_PTR_TO_ZVAL_PTR( DEREF(message_data(msg), offset, CACHED_VALUE*)); 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)) { zval* str = CACHED_PTR_TO_ZVAL_PTR( DEREF(message_data(msg), offset, CACHED_VALUE*)); - if (containing_oneof || Z_STRLEN_P(str) > 0) { - putstr(str, f, sink); + if (containing_oneof || (is_json && is_wrapper_msg(desc->msgdef)) || + Z_STRLEN_P(str) > 0) { + putstr(str, f, sink, is_json && is_wrapper_msg(desc->msgdef)); } } else if (upb_fielddef_issubmsg(f)) { putsubmsg(CACHED_PTR_TO_ZVAL_PTR( DEREF(message_data(msg), offset, CACHED_VALUE*)), - f, sink, depth TSRMLS_CC); + f, sink, depth, is_json TSRMLS_CC); } else { upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); #define T(upbtypeconst, upbtype, ctype, default_value) \ case upbtypeconst: { \ 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); \ } \ } break; @@ -1325,7 +1346,8 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc, 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; if (ZVAL_IS_NULL(str)) return; @@ -1336,7 +1358,7 @@ static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) { &subsink); // 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 // field-set time, but the user may have mutated the string object since // then. @@ -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, - upb_sink* sink) { + upb_sink* sink, bool force_default) { 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 // 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, } 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; 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, - upb_sink* sink, int depth TSRMLS_DC) { + upb_sink* sink, int depth, bool is_json TSRMLS_DC) { upb_sink subsink; Descriptor* subdesc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(upb_fielddef_msgsubdef(f))); 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)); } 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_fieldtype_t type = upb_fielddef_type(f); upb_selector_t sel = 0; @@ -1436,7 +1458,8 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink, const char* rawstr = ZSTR_VAL(*(zend_string**)memory); int len = ZSTR_LEN(*(zend_string**)memory); #endif - putrawstr(rawstr, len, f, &subsink); + putrawstr(rawstr, len, f, &subsink, + is_json && is_wrapper_msg(upb_fielddef_containingtype(f))); break; } case UPB_TYPE_MESSAGE: { @@ -1447,7 +1470,7 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink, (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) - XtOffsetOf(MessageHeader, std)); #endif - putrawsubmsg(submsg, f, &subsink, depth TSRMLS_CC); + putrawsubmsg(submsg, f, &subsink, depth, is_json TSRMLS_CC); break; } @@ -1504,7 +1527,7 @@ void serialize_to_string(zval* val, zval* return_value TSRMLS_DC) { stackenv_init(&se, "Error occurred during encoding: %s"); 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); @@ -1571,7 +1594,7 @@ PHP_METHOD(Message, serializeToJsonString) { stackenv_init(&se, "Error occurred during encoding: %s"); 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); |