/* * call-seq: * MessageClass.decode_json(data) => message * * Decodes the given data (as a string containing bytes in protocol buffers wire * format) under the interpretration given by this message class's definition * and returns a message object with the corresponding field values. */ VALUE Message_decode_json(VALUE klass, VALUE data) { VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); Descriptor* desc = ruby_to_Descriptor(descriptor); VALUE msgklass = Descriptor_msgclass(descriptor); VALUE msg_rb; MessageHeader* msg; if (TYPE(data) != T_STRING) { rb_raise(rb_eArgError, "Expected string for JSON data."); } // TODO(cfallin): Check and respect string encoding. If not UTF-8, we need to // convert, because string handlers pass data directly to message string // fields. msg_rb = rb_class_new_instance(0, NULL, msgklass); TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); { 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); upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data), upb_json_parser_input(parser)); stackenv_uninit(&se); } return msg_rb; }
/* * call-seq: * MessageClass.decode(data) => message * * Decodes the given data (as a string containing bytes in protocol buffers wire * format) under the interpretration given by this message class's definition * and returns a message object with the corresponding field values. */ VALUE Message_decode(VALUE klass, VALUE data) { VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); Descriptor* desc = ruby_to_Descriptor(descriptor); VALUE msgklass = Descriptor_msgclass(descriptor); VALUE msg_rb; MessageHeader* msg; if (TYPE(data) != T_STRING) { rb_raise(rb_eArgError, "Expected string for binary protobuf data."); } msg_rb = rb_class_new_instance(0, NULL, msgklass); TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); { const upb_pbdecodermethod* method = msgdef_decodermethod(desc); const upb_handlers* h = upb_pbdecodermethod_desthandlers(method); stackenv se; upb_sink sink; upb_pbdecoder* decoder; stackenv_init(&se, "Error occurred during parsing: %s"); upb_sink_reset(&sink, h, msg); decoder = upb_pbdecoder_create(&se.env, method, &sink); upb_bufsrc_putbuf(RSTRING_PTR(data), RSTRING_LEN(data), upb_pbdecoder_input(decoder)); stackenv_uninit(&se); } return msg_rb; }
/* * call-seq: * MessageClass.encode_json(msg) => json_string * * Encodes the given message object into its serialized JSON representation. */ VALUE Message_encode_json(VALUE klass, VALUE msg_rb) { VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); Descriptor* desc = ruby_to_Descriptor(descriptor); stringsink sink; stringsink_init(&sink); { const upb_handlers* serialize_handlers = msgdef_json_serialize_handlers(desc); upb_json_printer* printer; stackenv se; VALUE ret; stackenv_init(&se, "Error occurred during encoding: %s"); printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink); putmsg(msg_rb, desc, upb_json_printer_input(printer), 0); ret = rb_str_new(sink.ptr, sink.len); stackenv_uninit(&se); stringsink_uninit(&sink); return ret; } }
// Callback invoked by upb if any error occurs during parsing or serialization. static bool env_error_func(void* ud, const upb_status* status) { stackenv* se = ud; // Free the env -- rb_raise will longjmp up the stack past the encode/decode // function so it would not otherwise have been freed. stackenv_uninit(se); rb_raise(rb_eRuntimeError, se->ruby_error_template, upb_status_errmsg(status)); // Never reached: rb_raise() always longjmp()s up the stack, past all of our // code, back to Ruby. return false; }
// Callback invoked by upb if any error occurs during parsing or serialization. static bool env_error_func(void* ud, const upb_status* status) { stackenv* se = ud; // Free the env -- rb_raise will longjmp up the stack past the encode/decode // function so it would not otherwise have been freed. stackenv_uninit(se); // TODO(haberman): have a way to verify that this is actually a parse error, // instead of just throwing "parse error" unconditionally. rb_raise(cParseError, se->ruby_error_template, upb_status_errmsg(status)); // Never reached: rb_raise() always longjmp()s up the stack, past all of our // code, back to Ruby. return false; }
/* * call-seq: * MessageClass.encode_json(msg) => json_string * * Encodes the given message object into its serialized JSON representation. */ 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, RTEST(preserve_proto_fieldnames)); upb_json_printer* printer; stackenv se; VALUE ret; stackenv_init(&se, "Error occurred during encoding: %s"); printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink); putmsg(msg_rb, desc, upb_json_printer_input(printer), 0); ret = rb_enc_str_new(sink.ptr, sink.len, rb_utf8_encoding()); stackenv_uninit(&se); stringsink_uninit(&sink); return ret; } }