|
@@ -122,12 +122,29 @@ 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_file(msg)),
|
|
|
- "google/protobuf/wrappers.proto");
|
|
|
+bool is_wrapper_msg(const upb_msgdef* m) {
|
|
|
+ switch (upb_msgdef_wellknowntype(m)) {
|
|
|
+ case UPB_WELLKNOWN_DOUBLEVALUE:
|
|
|
+ case UPB_WELLKNOWN_FLOATVALUE:
|
|
|
+ case UPB_WELLKNOWN_INT64VALUE:
|
|
|
+ case UPB_WELLKNOWN_UINT64VALUE:
|
|
|
+ case UPB_WELLKNOWN_INT32VALUE:
|
|
|
+ case UPB_WELLKNOWN_UINT32VALUE:
|
|
|
+ case UPB_WELLKNOWN_STRINGVALUE:
|
|
|
+ case UPB_WELLKNOWN_BYTESVALUE:
|
|
|
+ case UPB_WELLKNOWN_BOOLVALUE:
|
|
|
+ return true;
|
|
|
+ default:
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+typedef struct {
|
|
|
+ void* closure;
|
|
|
+ void* submsg;
|
|
|
+ bool is_msg;
|
|
|
+} wrapperfields_parseframe_t;
|
|
|
+
|
|
|
#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs)
|
|
|
|
|
|
// Creates a handlerdata that simply contains the offset for this field.
|
|
@@ -432,6 +449,40 @@ static void *appendsubmsg_handler(void *closure, const void *hd) {
|
|
|
return submsg;
|
|
|
}
|
|
|
|
|
|
+// Appends a wrapper submessage to a repeated field.
|
|
|
+static void *appendwrappersubmsg_handler(void *closure, const void *hd) {
|
|
|
+ zval* array = (zval*)closure;
|
|
|
+ TSRMLS_FETCH();
|
|
|
+ RepeatedField* intern = UNBOX(RepeatedField, array);
|
|
|
+
|
|
|
+ const submsg_handlerdata_t *submsgdata = hd;
|
|
|
+ Descriptor* subdesc =
|
|
|
+ UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)submsgdata->md));
|
|
|
+ zend_class_entry* subklass = subdesc->klass;
|
|
|
+ MessageHeader* submsg;
|
|
|
+ wrapperfields_parseframe_t* frame =
|
|
|
+ (wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t));
|
|
|
+
|
|
|
+#if PHP_MAJOR_VERSION < 7
|
|
|
+ zval* val = NULL;
|
|
|
+ MAKE_STD_ZVAL(val);
|
|
|
+ ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC));
|
|
|
+ repeated_field_push_native(intern, &val);
|
|
|
+ submsg = UNBOX(MessageHeader, val);
|
|
|
+#else
|
|
|
+ zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
|
|
|
+ repeated_field_push_native(intern, &obj);
|
|
|
+ submsg = (MessageHeader*)((char*)obj - XtOffsetOf(MessageHeader, std));
|
|
|
+#endif
|
|
|
+ custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC);
|
|
|
+
|
|
|
+ frame->closure = closure;
|
|
|
+ frame->submsg = submsg;
|
|
|
+ frame->is_msg = true;
|
|
|
+
|
|
|
+ return frame;
|
|
|
+}
|
|
|
+
|
|
|
// Sets a non-repeated submessage field in a message.
|
|
|
static void *submsg_handler(void *closure, const void *hd) {
|
|
|
MessageHeader* msg = closure;
|
|
@@ -502,6 +553,46 @@ static void *map_submsg_handler(void *closure, const void *hd) {
|
|
|
return submsg;
|
|
|
}
|
|
|
|
|
|
+static void *map_wrapper_submsg_handler(void *closure, const void *hd) {
|
|
|
+ MessageHeader* msg = closure;
|
|
|
+ const submsg_handlerdata_t* submsgdata = hd;
|
|
|
+ TSRMLS_FETCH();
|
|
|
+ Descriptor* subdesc =
|
|
|
+ UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)submsgdata->md));
|
|
|
+ zend_class_entry* subklass = subdesc->klass;
|
|
|
+ zval* submsg_php;
|
|
|
+ MessageHeader* submsg;
|
|
|
+ wrapperfields_parseframe_t* frame =
|
|
|
+ (wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t));
|
|
|
+
|
|
|
+ CACHED_VALUE* cached =
|
|
|
+ DEREF(message_data(msg), submsgdata->ofs, CACHED_VALUE*);
|
|
|
+
|
|
|
+ if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_NULL) {
|
|
|
+#if PHP_MAJOR_VERSION < 7
|
|
|
+ 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);
|
|
|
+ REPLACE_ZVAL_VALUE(cached, &val, 1);
|
|
|
+ zval_dtor(&val);
|
|
|
+#else
|
|
|
+ zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
|
|
|
+ ZVAL_OBJ(cached, obj);
|
|
|
+ MessageHeader* intern = UNBOX_HASHTABLE_VALUE(MessageHeader, obj);
|
|
|
+ custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ submsg_php = CACHED_PTR_TO_ZVAL_PTR(cached);
|
|
|
+
|
|
|
+ submsg = UNBOX(MessageHeader, submsg_php);
|
|
|
+ frame->closure = closure;
|
|
|
+ frame->submsg = submsg;
|
|
|
+ frame->is_msg = true;
|
|
|
+ return frame;
|
|
|
+}
|
|
|
+
|
|
|
// Handler data for startmap/endmap handlers.
|
|
|
typedef struct {
|
|
|
const upb_fielddef* fd;
|
|
@@ -887,6 +978,78 @@ static void* oneofsubmsg_handler(void* closure, const void* hd) {
|
|
|
return submsg;
|
|
|
}
|
|
|
|
|
|
+// Sets a non-repeated wrapper submessage field in a message.
|
|
|
+static void* wrapper_submsg_handler(void* closure, const void* hd) {
|
|
|
+ MessageHeader* msg = closure;
|
|
|
+ const submsg_handlerdata_t* submsgdata = hd;
|
|
|
+ TSRMLS_FETCH();
|
|
|
+ Descriptor* subdesc =
|
|
|
+ UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)submsgdata->md));
|
|
|
+ zend_class_entry* subklass = subdesc->klass;
|
|
|
+ zval* submsg_php;
|
|
|
+ MessageHeader* submsg;
|
|
|
+ wrapperfields_parseframe_t* frame =
|
|
|
+ (wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t));
|
|
|
+
|
|
|
+ CACHED_VALUE* cached = find_zval_property(msg, submsgdata->fd);
|
|
|
+ submsg_php = CACHED_PTR_TO_ZVAL_PTR(cached);
|
|
|
+ frame->closure = closure;
|
|
|
+
|
|
|
+ if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_OBJECT) {
|
|
|
+ submsg = UNBOX(MessageHeader, submsg_php);
|
|
|
+ frame->submsg = submsg;
|
|
|
+ frame->is_msg = true;
|
|
|
+ } else {
|
|
|
+ // In this case, wrapper message hasn't been created and value will be
|
|
|
+ // stored in cache directly.
|
|
|
+ frame->submsg = cached;
|
|
|
+ frame->is_msg = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return frame;
|
|
|
+}
|
|
|
+
|
|
|
+// Handler for a wrapper submessage field in a oneof.
|
|
|
+static void* wrapper_oneofsubmsg_handler(void* closure, const void* hd) {
|
|
|
+ MessageHeader* msg = closure;
|
|
|
+ const oneof_handlerdata_t *oneofdata = hd;
|
|
|
+ uint32_t oldcase = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t);
|
|
|
+ TSRMLS_FETCH();
|
|
|
+ Descriptor* subdesc =
|
|
|
+ UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)oneofdata->md));
|
|
|
+ zend_class_entry* subklass = subdesc->klass;
|
|
|
+ wrapperfields_parseframe_t* frame =
|
|
|
+ (wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t));
|
|
|
+ CACHED_VALUE* cached = OBJ_PROP(&msg->std, oneofdata->property_ofs);
|
|
|
+ MessageHeader* submsg;
|
|
|
+
|
|
|
+ if (oldcase != oneofdata->oneof_case_num) {
|
|
|
+ oneof_cleanup(msg, oneofdata);
|
|
|
+ frame->submsg = cached;
|
|
|
+ frame->is_msg = false;
|
|
|
+ } else if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_OBJECT) {
|
|
|
+ submsg = UNBOX(MessageHeader, CACHED_PTR_TO_ZVAL_PTR(cached));
|
|
|
+ frame->submsg = submsg;
|
|
|
+ frame->is_msg = true;
|
|
|
+ } else {
|
|
|
+ // In this case, wrapper message hasn't been created and value will be
|
|
|
+ // stored in cache directly.
|
|
|
+ frame->submsg = cached;
|
|
|
+ frame->is_msg = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) =
|
|
|
+ oneofdata->oneof_case_num;
|
|
|
+
|
|
|
+ return frame;
|
|
|
+}
|
|
|
+
|
|
|
+static bool wrapper_submsg_end_handler(void *closure, const void *hd) {
|
|
|
+ wrapperfields_parseframe_t* frame = closure;
|
|
|
+ free(frame);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
// Set up handlers for a repeated field.
|
|
|
static void add_handlers_for_repeated_field(upb_handlers *h,
|
|
|
const upb_fielddef *f,
|
|
@@ -923,7 +1086,12 @@ static void add_handlers_for_repeated_field(upb_handlers *h,
|
|
|
case UPB_TYPE_MESSAGE: {
|
|
|
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
|
|
|
attr.handler_data = newsubmsghandlerdata(h, 0, f);
|
|
|
- upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
|
|
|
+ if (is_wrapper_msg(upb_fielddef_msgsubdef(f))) {
|
|
|
+ upb_handlers_setstartsubmsg(h, f, appendwrappersubmsg_handler, &attr);
|
|
|
+ upb_handlers_setendsubmsg(h, f, wrapper_submsg_end_handler, &attr);
|
|
|
+ } else {
|
|
|
+ upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
|
|
|
+ }
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -974,7 +1142,16 @@ static void add_handlers_for_singular_field(upb_handlers *h,
|
|
|
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
|
|
|
if (is_map) {
|
|
|
attr.handler_data = newsubmsghandlerdata(h, offset, f);
|
|
|
- upb_handlers_setstartsubmsg(h, f, map_submsg_handler, &attr);
|
|
|
+ if (is_wrapper_msg(upb_fielddef_msgsubdef(f))) {
|
|
|
+ upb_handlers_setstartsubmsg(h, f, map_wrapper_submsg_handler, &attr);
|
|
|
+ upb_handlers_setendsubmsg(h, f, wrapper_submsg_end_handler, &attr);
|
|
|
+ } else {
|
|
|
+ upb_handlers_setstartsubmsg(h, f, map_submsg_handler, &attr);
|
|
|
+ }
|
|
|
+ } else if (is_wrapper_msg(upb_fielddef_msgsubdef(f))) {
|
|
|
+ attr.handler_data = newsubmsghandlerdata(h, 0, f);
|
|
|
+ upb_handlers_setstartsubmsg(h, f, wrapper_submsg_handler, &attr);
|
|
|
+ upb_handlers_setendsubmsg(h, f, wrapper_submsg_end_handler, &attr);
|
|
|
} else {
|
|
|
attr.handler_data = newsubmsghandlerdata(h, 0, f);
|
|
|
upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
|
|
@@ -1056,9 +1233,106 @@ static void add_handlers_for_oneof_field(upb_handlers *h,
|
|
|
break;
|
|
|
}
|
|
|
case UPB_TYPE_MESSAGE: {
|
|
|
- upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr);
|
|
|
+ if (is_wrapper_msg(upb_fielddef_msgsubdef(f))) {
|
|
|
+ upb_handlers_setstartsubmsg(h, f, wrapper_oneofsubmsg_handler, &attr);
|
|
|
+ upb_handlers_setendsubmsg(h, f, wrapper_submsg_end_handler, &attr);
|
|
|
+ } else {
|
|
|
+ upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#define DEFINE_WRAPPER_HANDLER(utype, type, ctype) \
|
|
|
+ static bool type##wrapper_handler( \
|
|
|
+ void* closure, const void* hd, ctype val) { \
|
|
|
+ wrapperfields_parseframe_t* frame = closure; \
|
|
|
+ if (frame->is_msg) { \
|
|
|
+ MessageHeader* msg = frame->submsg; \
|
|
|
+ const size_t *ofs = hd; \
|
|
|
+ DEREF(message_data(msg), *ofs, ctype) = val; \
|
|
|
+ } else { \
|
|
|
+ TSRMLS_FETCH(); \
|
|
|
+ native_slot_get(utype, &val, frame->submsg TSRMLS_CC); \
|
|
|
+ } \
|
|
|
+ return true; \
|
|
|
+ }
|
|
|
+
|
|
|
+DEFINE_WRAPPER_HANDLER(UPB_TYPE_BOOL, bool, bool)
|
|
|
+DEFINE_WRAPPER_HANDLER(UPB_TYPE_INT32, int32, int32_t)
|
|
|
+DEFINE_WRAPPER_HANDLER(UPB_TYPE_UINT32, uint32, uint32_t)
|
|
|
+DEFINE_WRAPPER_HANDLER(UPB_TYPE_FLOAT, float, float)
|
|
|
+DEFINE_WRAPPER_HANDLER(UPB_TYPE_INT64, int64, int64_t)
|
|
|
+DEFINE_WRAPPER_HANDLER(UPB_TYPE_UINT64, uint64, uint64_t)
|
|
|
+DEFINE_WRAPPER_HANDLER(UPB_TYPE_DOUBLE, double, double)
|
|
|
+
|
|
|
+#undef DEFINE_WRAPPER_HANDLER
|
|
|
+
|
|
|
+static bool strwrapper_end_handler(void *closure, const void *hd) {
|
|
|
+ stringfields_parseframe_t* frame = closure;
|
|
|
+ const upb_fielddef **field = (const upb_fielddef **) hd;
|
|
|
+ wrapperfields_parseframe_t* wrapper_frame = frame->closure;
|
|
|
+ MessageHeader* msg;
|
|
|
+ CACHED_VALUE* cached;
|
|
|
+
|
|
|
+ if (wrapper_frame->is_msg) {
|
|
|
+ msg = wrapper_frame->submsg;
|
|
|
+ cached = find_zval_property(msg, *field);
|
|
|
+ } else {
|
|
|
+ cached = wrapper_frame->submsg;
|
|
|
+ }
|
|
|
+
|
|
|
+ new_php_string(cached, frame->sink.ptr, frame->sink.len);
|
|
|
+
|
|
|
+ stringsink_uninit(&frame->sink);
|
|
|
+ free(frame);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static void add_handlers_for_wrapper(const upb_msgdef* msgdef,
|
|
|
+ upb_handlers* h) {
|
|
|
+ const upb_fielddef* f = upb_msgdef_itof(msgdef, 1);
|
|
|
+ Descriptor* desc;
|
|
|
+ size_t offset;
|
|
|
+
|
|
|
+ TSRMLS_FETCH();
|
|
|
+ desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)msgdef));
|
|
|
+ offset = desc->layout->fields[upb_fielddef_index(f)].offset;
|
|
|
+
|
|
|
+ switch (upb_msgdef_wellknowntype(msgdef)) {
|
|
|
+#define SET_HANDLER(utype, ltype) \
|
|
|
+ case utype: { \
|
|
|
+ upb_handlerattr attr = UPB_HANDLERATTR_INIT; \
|
|
|
+ attr.handler_data = newhandlerdata(h, offset); \
|
|
|
+ upb_handlers_set##ltype(h, f, ltype##wrapper_handler, &attr); \
|
|
|
+ break; \
|
|
|
+ }
|
|
|
+
|
|
|
+ SET_HANDLER(UPB_WELLKNOWN_BOOLVALUE, bool);
|
|
|
+ SET_HANDLER(UPB_WELLKNOWN_INT32VALUE, int32);
|
|
|
+ SET_HANDLER(UPB_WELLKNOWN_UINT32VALUE, uint32);
|
|
|
+ SET_HANDLER(UPB_WELLKNOWN_FLOATVALUE, float);
|
|
|
+ SET_HANDLER(UPB_WELLKNOWN_INT64VALUE, int64);
|
|
|
+ SET_HANDLER(UPB_WELLKNOWN_UINT64VALUE, uint64);
|
|
|
+ SET_HANDLER(UPB_WELLKNOWN_DOUBLEVALUE, double);
|
|
|
+
|
|
|
+#undef SET_HANDLER
|
|
|
+
|
|
|
+ case UPB_WELLKNOWN_STRINGVALUE:
|
|
|
+ case UPB_WELLKNOWN_BYTESVALUE: {
|
|
|
+ upb_handlerattr attr = UPB_HANDLERATTR_INIT;
|
|
|
+ attr.handler_data = newhandlerfielddata(h, f);
|
|
|
+
|
|
|
+ upb_handlers_setstartstr(h, f, str_handler, &attr);
|
|
|
+ upb_handlers_setstring(h, f, stringdata_handler, &attr);
|
|
|
+ upb_handlers_setendstr(h, f, strwrapper_end_handler, &attr);
|
|
|
break;
|
|
|
}
|
|
|
+ default:
|
|
|
+ // Cannot reach here.
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1102,6 +1376,14 @@ void add_handlers_for_message(const void* closure, upb_handlers* h) {
|
|
|
desc->layout = create_layout(desc->msgdef);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ // If this is a wrapper message type, set up a special set of handlers and
|
|
|
+ // bail out of the normal (user-defined) message type handling.
|
|
|
+ if (is_wrapper_msg(msgdef)) {
|
|
|
+ add_handlers_for_wrapper(msgdef, h);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
upb_handlerattr attr = UPB_HANDLERATTR_INIT;
|
|
|
attr.handler_data = newunknownfieldshandlerdata(h);
|
|
|
upb_handlers_setunknown(h, add_unknown_handler, &attr);
|
|
@@ -1152,6 +1434,9 @@ static void putmsg(zval* msg, const Descriptor* desc, upb_sink sink,
|
|
|
static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
|
|
|
upb_sink sink, int depth, bool is_json,
|
|
|
bool open_msg TSRMLS_DC);
|
|
|
+static void putwrappervalue(
|
|
|
+ zval* value, const upb_fielddef* f,
|
|
|
+ upb_sink sink, int depth, bool is_json TSRMLS_DC);
|
|
|
static void putjsonany(MessageHeader* msg, const Descriptor* desc,
|
|
|
upb_sink sink, int depth TSRMLS_DC);
|
|
|
static void putjsonlistvalue(
|
|
@@ -1299,7 +1584,7 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink sink,
|
|
|
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));
|
|
|
+ upb_sink_endsubmsg(subsink, entry_sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
|
|
|
}
|
|
|
|
|
|
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
|
|
@@ -1535,7 +1820,12 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
|
|
|
}
|
|
|
} else if (upb_fielddef_issubmsg(f)) {
|
|
|
zval* submsg = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f));
|
|
|
- putsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC);
|
|
|
+ if (is_wrapper_msg(upb_fielddef_msgsubdef(f)) &&
|
|
|
+ Z_TYPE_P(submsg) != IS_NULL && Z_TYPE_P(submsg) != IS_OBJECT) {
|
|
|
+ putwrappervalue(submsg, f, sink, depth, is_json TSRMLS_CC);
|
|
|
+ } else {
|
|
|
+ putsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC);
|
|
|
+ }
|
|
|
} else {
|
|
|
upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
|
|
|
|
|
@@ -1634,6 +1924,54 @@ static void putsubmsg(zval* submsg_php, const upb_fielddef* f, upb_sink sink,
|
|
|
putrawsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC);
|
|
|
}
|
|
|
|
|
|
+static void putwrappervalue(
|
|
|
+ zval* value, const upb_fielddef* f,
|
|
|
+ upb_sink sink, int depth, bool is_json TSRMLS_DC) {
|
|
|
+ upb_sink subsink;
|
|
|
+ const upb_msgdef* msgdef = upb_fielddef_msgsubdef(f);
|
|
|
+ const upb_fielddef* value_field = upb_msgdef_itof(msgdef, 1);
|
|
|
+ upb_selector_t sel =
|
|
|
+ getsel(value_field, upb_handlers_getprimitivehandlertype(value_field));
|
|
|
+
|
|
|
+ upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
|
|
|
+
|
|
|
+#define T(upbtypeconst, upbtype, ctype, default_value) \
|
|
|
+ case upbtypeconst: { \
|
|
|
+ ctype value_raw; \
|
|
|
+ native_slot_set(upb_fielddef_type(value_field), NULL, \
|
|
|
+ &value_raw, value PHP_PROTO_TSRMLS_CC); \
|
|
|
+ if ((is_json && is_wrapper_msg(msgdef)) || \
|
|
|
+ value_raw != default_value) { \
|
|
|
+ upb_sink_put##upbtype(subsink, sel, value_raw); \
|
|
|
+ } \
|
|
|
+ } break;
|
|
|
+
|
|
|
+ switch (upb_fielddef_type(value_field)) {
|
|
|
+ T(UPB_TYPE_FLOAT, float, float, 0.0)
|
|
|
+ T(UPB_TYPE_DOUBLE, double, double, 0.0)
|
|
|
+ T(UPB_TYPE_BOOL, bool, uint8_t, 0)
|
|
|
+ T(UPB_TYPE_INT32, int32, int32_t, 0)
|
|
|
+ T(UPB_TYPE_UINT32, uint32, uint32_t, 0)
|
|
|
+ T(UPB_TYPE_INT64, int64, int64_t, 0)
|
|
|
+ T(UPB_TYPE_UINT64, uint64, uint64_t, 0)
|
|
|
+ case UPB_TYPE_STRING:
|
|
|
+ case UPB_TYPE_BYTES: {
|
|
|
+ if ((is_json && is_wrapper_msg(msgdef)) ||
|
|
|
+ Z_STRLEN_P(value) > 0) {
|
|
|
+ putstr(value, value_field, subsink, is_json && is_wrapper_msg(msgdef));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case UPB_TYPE_ENUM:
|
|
|
+ case UPB_TYPE_MESSAGE:
|
|
|
+ zend_error(E_ERROR, "Internal error.");
|
|
|
+ }
|
|
|
+
|
|
|
+#undef T
|
|
|
+
|
|
|
+ upb_sink_endsubmsg(sink, subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
|
|
|
+}
|
|
|
+
|
|
|
static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
|
|
|
upb_sink sink, int depth, bool is_json TSRMLS_DC) {
|
|
|
upb_sink subsink;
|
|
@@ -1643,7 +1981,7 @@ static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
|
|
|
|
|
|
upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
|
|
|
putrawmsg(submsg, subdesc, subsink, depth + 1, is_json, true TSRMLS_CC);
|
|
|
- upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
|
|
|
+ upb_sink_endsubmsg(sink, subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
|
|
|
}
|
|
|
|
|
|
static void putarray(zval* array, const upb_fielddef* f, upb_sink sink,
|
|
@@ -1769,12 +2107,28 @@ void merge_from_string(const char* data, int data_len, Descriptor* desc,
|
|
|
stackenv se;
|
|
|
upb_sink sink;
|
|
|
upb_pbdecoder* decoder;
|
|
|
+ void* closure;
|
|
|
stackenv_init(&se, "Error occurred during parsing: %s");
|
|
|
|
|
|
- upb_sink_reset(&sink, h, msg);
|
|
|
+ if (is_wrapper_msg(desc->msgdef)) {
|
|
|
+ wrapperfields_parseframe_t* frame =
|
|
|
+ (wrapperfields_parseframe_t*)malloc(
|
|
|
+ sizeof(wrapperfields_parseframe_t));
|
|
|
+ frame->submsg = msg;
|
|
|
+ frame->is_msg = true;
|
|
|
+ closure = frame;
|
|
|
+ } else {
|
|
|
+ closure = msg;
|
|
|
+ }
|
|
|
+
|
|
|
+ upb_sink_reset(&sink, h, closure);
|
|
|
decoder = upb_pbdecoder_create(se.arena, method, sink, &se.status);
|
|
|
upb_bufsrc_putbuf(data, data_len, upb_pbdecoder_input(decoder));
|
|
|
|
|
|
+ if (is_wrapper_msg(desc->msgdef)) {
|
|
|
+ free((wrapperfields_parseframe_t*)closure);
|
|
|
+ }
|
|
|
+
|
|
|
stackenv_uninit(&se);
|
|
|
}
|
|
|
|
|
@@ -1852,13 +2206,28 @@ PHP_METHOD(Message, mergeFromJsonString) {
|
|
|
stackenv se;
|
|
|
upb_sink sink;
|
|
|
upb_json_parser* parser;
|
|
|
+ void* closure;
|
|
|
stackenv_init(&se, "Error occurred during parsing: %s");
|
|
|
|
|
|
- upb_sink_reset(&sink, get_fill_handlers(desc), msg);
|
|
|
+ if (is_wrapper_msg(desc->msgdef)) {
|
|
|
+ wrapperfields_parseframe_t* frame =
|
|
|
+ (wrapperfields_parseframe_t*)malloc(
|
|
|
+ sizeof(wrapperfields_parseframe_t));
|
|
|
+ frame->submsg = msg;
|
|
|
+ frame->is_msg = true;
|
|
|
+ closure = frame;
|
|
|
+ } else {
|
|
|
+ closure = msg;
|
|
|
+ }
|
|
|
+
|
|
|
+ upb_sink_reset(&sink, get_fill_handlers(desc), closure);
|
|
|
parser = upb_json_parser_create(se.arena, method, generated_pool->symtab,
|
|
|
sink, &se.status, ignore_json_unknown);
|
|
|
upb_bufsrc_putbuf(data, data_len, upb_json_parser_input(parser));
|
|
|
|
|
|
+ if (is_wrapper_msg(desc->msgdef)) {
|
|
|
+ free((wrapperfields_parseframe_t*)closure);
|
|
|
+ }
|
|
|
stackenv_uninit(&se);
|
|
|
}
|
|
|
}
|