|  | @@ -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);
 | 
	
		
			
				|  |  |  
 |