コード例 #1
0
ファイル: encode_decode.c プロジェクト: Holygitzdq/ElVis
/*
 * 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;
}
コード例 #2
0
ファイル: encode_decode.c プロジェクト: Holygitzdq/ElVis
/*
 * 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;
}
コード例 #3
0
ファイル: encode_decode.c プロジェクト: Holygitzdq/ElVis
/*
 * 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;
    }
}
コード例 #4
0
ファイル: defs.c プロジェクト: Overruler/protobuf
/*
 * call-seq:
 *     Builder.finalize_to_pool(pool)
 *
 * Adds all accumulated message and enum descriptors created in this builder
 * context to the given pool. The operation occurs atomically, and all
 * descriptors can refer to each other (including in cycles). This is the only
 * way to build (co)recursive message definitions.
 *
 * This method is usually called automatically by DescriptorPool#build after it
 * invokes the given user block in the context of the builder. The user should
 * not normally need to call this manually because a Builder is not normally
 * created manually.
 */
VALUE Builder_finalize_to_pool(VALUE _self, VALUE pool_rb) {
  DEFINE_SELF(Builder, self, _self);

  DescriptorPool* pool = ruby_to_DescriptorPool(pool_rb);

  REALLOC_N(self->defs, upb_def*, RARRAY_LEN(self->pending_list));

  for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) {
    VALUE def_rb = rb_ary_entry(self->pending_list, i);
    if (CLASS_OF(def_rb) == cDescriptor) {
      self->defs[i] = (upb_def*)ruby_to_Descriptor(def_rb)->msgdef;
      validate_msgdef((const upb_msgdef*)self->defs[i]);
    } else if (CLASS_OF(def_rb) == cEnumDescriptor) {
      self->defs[i] = (upb_def*)ruby_to_EnumDescriptor(def_rb)->enumdef;
      validate_enumdef((const upb_enumdef*)self->defs[i]);
    }
  }

  CHECK_UPB(upb_symtab_add(pool->symtab, (upb_def**)self->defs,
                           RARRAY_LEN(self->pending_list), NULL, &status),
            "Unable to add defs to DescriptorPool");

  for (int i = 0; i < RARRAY_LEN(self->pending_list); i++) {
    VALUE def_rb = rb_ary_entry(self->pending_list, i);
    add_def_obj(self->defs[i], def_rb);
  }

  self->pending_list = rb_ary_new();
  return Qnil;
}
コード例 #5
0
ファイル: encode_decode.c プロジェクト: 6116353/protobuf
static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
                      int depth) {
  if (submsg == Qnil) return;

  upb_sink subsink;
  VALUE descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
  Descriptor* subdesc = ruby_to_Descriptor(descriptor);

  upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
  putmsg(submsg, subdesc, &subsink, depth + 1);
  upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
}
コード例 #6
0
ファイル: defs.c プロジェクト: Overruler/protobuf
/*
 * call-seq:
 *     DescriptorPool.add(descriptor)
 *
 * Adds the given Descriptor or EnumDescriptor to this pool. All references to
 * other types in a Descriptor's fields must be resolvable within this pool or
 * an exception will be raised.
 */
VALUE DescriptorPool_add(VALUE _self, VALUE def) {
  DEFINE_SELF(DescriptorPool, self, _self);
  VALUE def_klass = rb_obj_class(def);
  if (def_klass == cDescriptor) {
    add_descriptor_to_pool(self, ruby_to_Descriptor(def));
  } else if (def_klass == cEnumDescriptor) {
    add_enumdesc_to_pool(self, ruby_to_EnumDescriptor(def));
  } else {
    rb_raise(rb_eArgError,
             "Second argument must be a Descriptor or EnumDescriptor.");
  }
  return Qnil;
}
コード例 #7
0
ファイル: message.c プロジェクト: goodleon/protobuf
VALUE Message_alloc(VALUE klass) {
  VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar);
  Descriptor* desc = ruby_to_Descriptor(descriptor);
  MessageHeader* msg = (MessageHeader*)ALLOC_N(
      uint8_t, sizeof(MessageHeader) + desc->layout->size);
  memset(Message_data(msg), 0, desc->layout->size);

  // We wrap first so that everything in the message object is GC-rooted in case
  // a collection happens during object creation in layout_init().
  VALUE ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
  msg->descriptor = desc;
  rb_iv_set(ret, kDescriptorInstanceVar, descriptor);

  layout_init(desc->layout, Message_data(msg));

  return ret;
}
コード例 #8
0
ファイル: encode_decode.c プロジェクト: 1nf1corp/protobuf
/*
 * 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;
  }
}
コード例 #9
0
ファイル: encode_decode.c プロジェクト: Holygitzdq/ElVis
static void add_handlers_for_message(const void *closure, upb_handlers *h) {
    const upb_msgdef* msgdef = upb_handlers_msgdef(h);
    Descriptor* desc = ruby_to_Descriptor(get_def_obj((void*)msgdef));
    upb_msg_field_iter i;

    // If this is a mapentry message type, set up a special set of handlers and
    // bail out of the normal (user-defined) message type handling.
    if (upb_msgdef_mapentry(msgdef)) {
        add_handlers_for_mapentry(msgdef, h, desc);
        return;
    }

    // Ensure layout exists. We may be invoked to create handlers for a given
    // message if we are included as a submsg of another message type before our
    // class is actually built, so to work around this, we just create the layout
    // (and handlers, in the class-building function) on-demand.
    if (desc->layout == NULL) {
        desc->layout = create_layout(desc->msgdef);
    }

    for (upb_msg_field_begin(&i, desc->msgdef);
            !upb_msg_field_done(&i);
            upb_msg_field_next(&i)) {
        const upb_fielddef *f = upb_msg_iter_field(&i);
        size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset +
                        sizeof(MessageHeader);

        if (upb_fielddef_containingoneof(f)) {
            size_t oneof_case_offset =
                desc->layout->fields[upb_fielddef_index(f)].case_offset +
                sizeof(MessageHeader);
            add_handlers_for_oneof_field(h, f, offset, oneof_case_offset);
        } else if (is_map_field(f)) {
            add_handlers_for_mapfield(h, f, offset, desc);
        } else if (upb_fielddef_isseq(f)) {
            add_handlers_for_repeated_field(h, f, offset);
        } else {
            add_handlers_for_singular_field(h, f, offset);
        }
    }
}
コード例 #10
0
ファイル: defs.c プロジェクト: Overruler/protobuf
/*
 * call-seq:
 *     MessageBuilderContext.map(name, key_type, value_type, number,
 *                               value_type_class = nil)
 *
 * Defines a new map field on this message type with the given key and value
 * types, tag number, and type class (for message and enum value types). The key
 * type must be :int32/:uint32/:int64/:uint64, :bool, or :string. The value type
 * type must be a Ruby symbol (as accepted by FieldDescriptor#type=) and the
 * type_class must be a string, if present (as accepted by
 * FieldDescriptor#submsg_name=).
 */
VALUE MessageBuilderContext_map(int argc, VALUE* argv, VALUE _self) {
  DEFINE_SELF(MessageBuilderContext, self, _self);

  if (argc < 4) {
    rb_raise(rb_eArgError, "Expected at least 4 arguments.");
  }
  VALUE name = argv[0];
  VALUE key_type = argv[1];
  VALUE value_type = argv[2];
  VALUE number = argv[3];
  VALUE type_class = (argc > 4) ? argv[4] : Qnil;

  // Validate the key type. We can't accept enums, messages, or floats/doubles
  // as map keys. (We exclude these explicitly, and the field-descriptor setter
  // below then ensures that the type is one of the remaining valid options.)
  if (SYM2ID(key_type) == rb_intern("float") ||
      SYM2ID(key_type) == rb_intern("double") ||
      SYM2ID(key_type) == rb_intern("enum") ||
      SYM2ID(key_type) == rb_intern("message")) {
    rb_raise(rb_eArgError,
             "Cannot add a map field with a float, double, enum, or message "
             "type.");
  }

  // Create a new message descriptor for the map entry message, and create a
  // repeated submessage field here with that type.
  VALUE mapentry_desc = rb_class_new_instance(0, NULL, cDescriptor);
  VALUE mapentry_desc_name = rb_funcall(self->descriptor, rb_intern("name"), 0);
  mapentry_desc_name = rb_str_cat2(mapentry_desc_name, "_MapEntry_");
  mapentry_desc_name = rb_str_cat2(mapentry_desc_name,
                                   rb_id2name(SYM2ID(name)));
  Descriptor_name_set(mapentry_desc, mapentry_desc_name);

  // The 'mapentry' attribute has no Ruby setter because we do not want the user
  // attempting to DIY the setup below; we want to ensure that the fields are
  // correct. So we reach into the msgdef here to set the bit manually.
  Descriptor* mapentry_desc_self = ruby_to_Descriptor(mapentry_desc);
  upb_msgdef_setmapentry((upb_msgdef*)mapentry_desc_self->msgdef, true);

  // optional <type> key = 1;
  VALUE key_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
  FieldDescriptor_name_set(key_field, rb_str_new2("key"));
  FieldDescriptor_label_set(key_field, ID2SYM(rb_intern("optional")));
  FieldDescriptor_number_set(key_field, INT2NUM(1));
  FieldDescriptor_type_set(key_field, key_type);
  Descriptor_add_field(mapentry_desc, key_field);

  // optional <type> value = 2;
  VALUE value_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
  FieldDescriptor_name_set(value_field, rb_str_new2("value"));
  FieldDescriptor_label_set(value_field, ID2SYM(rb_intern("optional")));
  FieldDescriptor_number_set(value_field, INT2NUM(2));
  FieldDescriptor_type_set(value_field, value_type);
  if (type_class != Qnil) {
    VALUE submsg_name = rb_str_new2("."); // prepend '.' to make name absolute.
    submsg_name = rb_str_append(submsg_name, type_class);
    FieldDescriptor_submsg_name_set(value_field, submsg_name);
  }
  Descriptor_add_field(mapentry_desc, value_field);

  // Add the map-entry message type to the current builder, and use the type to
  // create the map field itself.
  Builder* builder_self = ruby_to_Builder(self->builder);
  rb_ary_push(builder_self->pending_list, mapentry_desc);

  VALUE map_field = rb_class_new_instance(0, NULL, cFieldDescriptor);
  VALUE name_str = rb_str_new2(rb_id2name(SYM2ID(name)));
  FieldDescriptor_name_set(map_field, name_str);
  FieldDescriptor_number_set(map_field, number);
  FieldDescriptor_label_set(map_field, ID2SYM(rb_intern("repeated")));
  FieldDescriptor_type_set(map_field, ID2SYM(rb_intern("message")));
  VALUE submsg_name = rb_str_new2("."); // prepend '.' to make name absolute.
  submsg_name = rb_str_append(submsg_name, mapentry_desc_name);
  FieldDescriptor_submsg_name_set(map_field, submsg_name);
  Descriptor_add_field(self->descriptor, map_field);

  return Qnil;
}