Index: third_party/protobuf/ruby/ext/google/protobuf_c/encode_decode.c |
diff --git a/third_party/protobuf/ruby/ext/google/protobuf_c/encode_decode.c b/third_party/protobuf/ruby/ext/google/protobuf_c/encode_decode.c |
index 1c48281f3bf01113e48074b7887f4122e5447355..f6bea50f3966652a93f0ce56b133fa4cd73633ab 100644 |
--- a/third_party/protobuf/ruby/ext/google/protobuf_c/encode_decode.c |
+++ b/third_party/protobuf/ruby/ext/google/protobuf_c/encode_decode.c |
@@ -640,6 +640,14 @@ static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) { |
return desc->fill_method; |
} |
+static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) { |
+ if (desc->json_fill_method == NULL) { |
+ desc->json_fill_method = |
+ upb_json_parsermethod_new(desc->msgdef, &desc->json_fill_method); |
+ } |
+ return desc->json_fill_method; |
+} |
+ |
// Stack-allocated context during an encode/decode operation. Contains the upb |
// environment and its stack-based allocator, an initial buffer for allocations |
@@ -648,7 +656,6 @@ static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) { |
#define STACK_ENV_STACKBYTES 4096 |
typedef struct { |
upb_env env; |
- upb_seededalloc alloc; |
const char* ruby_error_template; |
char allocbuf[STACK_ENV_STACKBYTES]; |
} stackenv; |
@@ -673,16 +680,12 @@ static bool env_error_func(void* ud, const upb_status* status) { |
static void stackenv_init(stackenv* se, const char* errmsg) { |
se->ruby_error_template = errmsg; |
- upb_env_init(&se->env); |
- upb_seededalloc_init(&se->alloc, &se->allocbuf, STACK_ENV_STACKBYTES); |
- upb_env_setallocfunc( |
- &se->env, upb_seededalloc_getallocfunc(&se->alloc), &se->alloc); |
+ upb_env_init2(&se->env, se->allocbuf, sizeof(se->allocbuf), NULL); |
upb_env_seterrorfunc(&se->env, env_error_func, se); |
} |
static void stackenv_uninit(stackenv* se) { |
upb_env_uninit(&se->env); |
- upb_seededalloc_uninit(&se->alloc); |
} |
/* |
@@ -752,13 +755,14 @@ VALUE Message_decode_json(VALUE klass, VALUE data) { |
TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); |
{ |
+ const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc); |
stackenv se; |
upb_sink sink; |
upb_json_parser* parser; |
stackenv_init(&se, "Error occurred during parsing: %s"); |
upb_sink_reset(&sink, get_fill_handlers(desc), msg); |
- parser = upb_json_parser_create(&se.env, &sink); |
+ parser = upb_json_parser_create(&se.env, method, &sink); |
upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data), |
upb_json_parser_input(parser)); |
@@ -1041,6 +1045,7 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, |
!upb_msg_field_done(&i); |
upb_msg_field_next(&i)) { |
upb_fielddef *f = upb_msg_iter_field(&i); |
+ bool is_matching_oneof = false; |
uint32_t offset = |
desc->layout->fields[upb_fielddef_index(f)].offset + |
sizeof(MessageHeader); |
@@ -1057,6 +1062,7 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, |
} |
// Otherwise, fall through to the appropriate singular-field handler |
// below. |
+ is_matching_oneof = true; |
} |
if (is_map_field(f)) { |
@@ -1071,7 +1077,7 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, |
} |
} else if (upb_fielddef_isstring(f)) { |
VALUE str = DEREF(msg, offset, VALUE); |
- if (RSTRING_LEN(str) > 0) { |
+ if (is_matching_oneof || RSTRING_LEN(str) > 0) { |
putstr(str, f, sink); |
} |
} else if (upb_fielddef_issubmsg(f)) { |
@@ -1082,7 +1088,7 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, |
#define T(upbtypeconst, upbtype, ctype, default_value) \ |
case upbtypeconst: { \ |
ctype value = DEREF(msg, offset, ctype); \ |
- if (value != default_value) { \ |
+ if (is_matching_oneof || value != default_value) { \ |
upb_sink_put##upbtype(sink, sel, value); \ |
} \ |
} \ |
@@ -1119,13 +1125,23 @@ static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) { |
return desc->pb_serialize_handlers; |
} |
-static const upb_handlers* msgdef_json_serialize_handlers(Descriptor* desc) { |
- if (desc->json_serialize_handlers == NULL) { |
- desc->json_serialize_handlers = |
- upb_json_printer_newhandlers( |
- desc->msgdef, &desc->json_serialize_handlers); |
+static const upb_handlers* msgdef_json_serialize_handlers( |
+ Descriptor* desc, bool preserve_proto_fieldnames) { |
+ if (preserve_proto_fieldnames) { |
+ if (desc->json_serialize_handlers == NULL) { |
+ desc->json_serialize_handlers = |
+ upb_json_printer_newhandlers( |
+ desc->msgdef, true, &desc->json_serialize_handlers); |
+ } |
+ return desc->json_serialize_handlers; |
+ } else { |
+ if (desc->json_serialize_handlers_preserve == NULL) { |
+ desc->json_serialize_handlers_preserve = |
+ upb_json_printer_newhandlers( |
+ desc->msgdef, false, &desc->json_serialize_handlers_preserve); |
+ } |
+ return desc->json_serialize_handlers_preserve; |
} |
- return desc->json_serialize_handlers; |
} |
/* |
@@ -1170,16 +1186,33 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) { |
* |
* Encodes the given message object into its serialized JSON representation. |
*/ |
-VALUE Message_encode_json(VALUE klass, VALUE msg_rb) { |
+VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { |
VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); |
Descriptor* desc = ruby_to_Descriptor(descriptor); |
- |
+ VALUE msg_rb; |
+ VALUE preserve_proto_fieldnames = Qfalse; |
stringsink sink; |
+ |
+ if (argc < 1 || argc > 2) { |
+ rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); |
+ } |
+ |
+ msg_rb = argv[0]; |
+ |
+ if (argc == 2) { |
+ VALUE hash_args = argv[1]; |
+ if (TYPE(hash_args) != T_HASH) { |
+ rb_raise(rb_eArgError, "Expected hash arguments."); |
+ } |
+ preserve_proto_fieldnames = rb_hash_lookup2( |
+ hash_args, ID2SYM(rb_intern("preserve_proto_fieldnames")), Qfalse); |
+ } |
+ |
stringsink_init(&sink); |
{ |
const upb_handlers* serialize_handlers = |
- msgdef_json_serialize_handlers(desc); |
+ msgdef_json_serialize_handlers(desc, RTEST(preserve_proto_fieldnames)); |
upb_json_printer* printer; |
stackenv se; |
VALUE ret; |
@@ -1189,7 +1222,7 @@ VALUE Message_encode_json(VALUE klass, VALUE msg_rb) { |
putmsg(msg_rb, desc, upb_json_printer_input(printer), 0); |
- ret = rb_str_new(sink.ptr, sink.len); |
+ ret = rb_enc_str_new(sink.ptr, sink.len, rb_utf8_encoding()); |
stackenv_uninit(&se); |
stringsink_uninit(&sink); |