// // upb - a minimalist implementation of protocol buffers. // // Copyright (c) 2011-2012 Google Inc. See LICENSE for details. // Author: Josh Haberman #include #include #include "upb/bytestream.hpp" #include "upb/def.hpp" #include "upb/handlers.hpp" #include "upb/msg.hpp" #include "upb/proto2_bridge.hpp" namespace { static void* GetFieldPointer(void *message, const upb::FieldDef* f) { return static_cast(message) + f->offset(); } } // namespace #ifdef UPB_GOOGLE3 // TODO(haberman): friend upb so that this isn't required. #define protected public #include "net/proto2/public/repeated_field.h" #undef private #define private public #include "net/proto/proto2_reflection.h" #undef private #include "net/proto2/proto/descriptor.pb.h" #include "net/proto2/public/descriptor.h" #include "net/proto2/public/generated_message_reflection.h" #include "net/proto2/public/lazy_field.h" #include "net/proto2/public/message.h" #include "net/proto2/public/string_piece_field_support.h" #include "net/proto/internal_layout.h" #include "strings/cord.h" using ::proto2::Descriptor; using ::proto2::EnumDescriptor; using ::proto2::EnumValueDescriptor; using ::proto2::FieldDescriptor; using ::proto2::FieldOptions; using ::proto2::FileDescriptor; using ::proto2::internal::GeneratedMessageReflection; using ::proto2::internal::RepeatedPtrFieldBase; using ::proto2::internal::StringPieceField; using ::proto2::Message; using ::proto2::MessageFactory; using ::proto2::Reflection; using ::proto2::RepeatedField; using ::proto2::RepeatedPtrField; namespace upb { static const Message* GetPrototypeForField(const Message& m, const FieldDescriptor* f); namespace proto2_bridge_google3 { class FieldAccessor; } using ::upb::proto2_bridge_google3::FieldAccessor; namespace proto2_bridge_google3 { static void AssignToCord(const ByteRegion* r, Cord* cord) { // TODO(haberman): ref source data if source is a cord. cord->Clear(); uint64_t ofs = r->start_ofs(); while (ofs < r->end_ofs()) { size_t len; const char *buf = r->GetPtr(ofs, &len); cord->Append(StringPiece(buf, len)); ofs += len; } } #else // TODO(haberman): friend upb so that this isn't required. #define protected public #include "google/protobuf/repeated_field.h" #undef protected #define private public #include "google/protobuf/generated_message_reflection.h" #undef private #include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/message.h" using ::google::protobuf::Descriptor; using ::google::protobuf::EnumDescriptor; using ::google::protobuf::EnumValueDescriptor; using ::google::protobuf::FieldDescriptor; using ::google::protobuf::FieldOptions; using ::google::protobuf::FileDescriptor; using ::google::protobuf::internal::GeneratedMessageReflection; using ::google::protobuf::internal::RepeatedPtrFieldBase; using ::google::protobuf::Message; using ::google::protobuf::MessageFactory; using ::google::protobuf::Reflection; using ::google::protobuf::RepeatedField; using ::google::protobuf::RepeatedPtrField; namespace upb { static const Message* GetPrototypeForField(const Message& m, const FieldDescriptor* f); namespace proto2_bridge_opensource { class FieldAccessor; } using ::upb::proto2_bridge_opensource::FieldAccessor; namespace proto2_bridge_opensource { #endif // ifdef UPB_GOOGLE3 // Have to define this manually since older versions of proto2 didn't define // an enum value for STRING. #define UPB_CTYPE_STRING 0 // The code in this class depends on the internal representation of the proto2 // generated classes, which is an internal implementation detail of proto2 and // is not a public interface. As a result, this class's implementation may // need to be changed if/when proto2 changes its internal representation. It // is intended that this class is the only code that depends on these internal, // non-public interfaces. // // This class only works with messages that use GeneratedMessageReflection. // Other reflection classes will need other accessor implementations. class FieldAccessor { public: // Returns true if we were able to set an accessor and any other properties // of the FieldDef that are necessary to read/write this field to a // proto2::Message. static bool TrySet(const FieldDescriptor* proto2_f, const upb::MessageDef* md, upb::FieldDef* upb_f) { const Message* prototype = static_cast(md->prototype); const Reflection* base_r = prototype->GetReflection(); const GeneratedMessageReflection* r = dynamic_cast(base_r); // Old versions of the open-source protobuf release erroneously default to // Cord even though that has never been supported in the open-source // release. int32_t ctype = proto2_f->options().has_ctype() ? proto2_f->options().ctype() : UPB_CTYPE_STRING; if (!r) return false; // Extensions not supported yet. if (proto2_f->is_extension()) return false; upb_f->set_accessor(GetForFieldDescriptor(proto2_f, ctype)); upb_f->set_hasbit(GetHasbit(proto2_f, r)); upb_f->set_offset(GetOffset(proto2_f, r)); if (upb_f->IsSubmessage()) { upb_f->set_subtype_name(proto2_f->message_type()->full_name()); upb_f->prototype = GetPrototypeForField(*prototype, proto2_f); } if (upb_f->IsString() && !upb_f->IsSequence() && ctype == UPB_CTYPE_STRING) { upb_f->prototype = &r->GetStringReference(*prototype, proto2_f, NULL); } return true; } static MessageFactory* GetMessageFactory(const Message& m) { const GeneratedMessageReflection* r = dynamic_cast(m.GetReflection()); return r ? r->message_factory_ : NULL; } private: static int64_t GetHasbit(const FieldDescriptor* f, const GeneratedMessageReflection* r) { if (f->is_repeated()) { // proto2 does not store hasbits for repeated fields. return -1; } else { return (r->has_bits_offset_ * 8) + f->index(); } } static uint16_t GetOffset(const FieldDescriptor* f, const GeneratedMessageReflection* r) { return r->offsets_[f->index()]; } static AccessorVTable *GetForFieldDescriptor(const FieldDescriptor* f, int32_t ctype) { switch (f->cpp_type()) { case FieldDescriptor::CPPTYPE_ENUM: // Should handlers validate enum membership to match proto2? case FieldDescriptor::CPPTYPE_INT32: return Get(); case FieldDescriptor::CPPTYPE_INT64: return Get(); case FieldDescriptor::CPPTYPE_UINT32: return Get(); case FieldDescriptor::CPPTYPE_UINT64: return Get(); case FieldDescriptor::CPPTYPE_DOUBLE: return Get(); case FieldDescriptor::CPPTYPE_FLOAT: return Get(); case FieldDescriptor::CPPTYPE_BOOL: return Get(); case FieldDescriptor::CPPTYPE_STRING: switch (ctype) { #ifdef UPB_GOOGLE3 case FieldOptions::STRING: return GetForString(); case FieldOptions::CORD: return GetForCord(); case FieldOptions::STRING_PIECE: return GetForStringPiece(); #else case UPB_CTYPE_STRING: return GetForString(); #endif default: return NULL; } case FieldDescriptor::CPPTYPE_MESSAGE: #ifdef UPB_GOOGLE3 if (f->options().lazy()) { return NULL; // Not yet implemented. } else { return GetForMessage(); } #else return GetForMessage(); #endif default: return NULL; } } // PushOffset handler (used for StartSequence and others) /////////////////// static SubFlow PushOffset(void *m, Value fval) { const FieldDef *f = GetValue(fval); return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); } // Primitive Value (numeric, enum, bool) ///////////////////////////////////// template static AccessorVTable *Get() { static upb_accessor_vtbl vtbl = { NULL, // StartSubMessage handler GetValueHandler(), &PushOffset, // StartSequence handler NULL, // StartRepeatedSubMessage handler &Append, NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } template static Flow Append(void *_r, Value fval, Value val) { (void)fval; RepeatedField* r = static_cast*>(_r); r->Add(GetValue(val)); return UPB_CONTINUE; } // String //////////////////////////////////////////////////////////////////// template static AccessorVTable *GetForString() { static upb_accessor_vtbl vtbl = { NULL, // StartSubMessage handler &SetString, &PushOffset, // StartSequence handler NULL, // StartRepeatedSubMessage handler &AppendString, NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } // This needs to be templated because google3 string is not std::string. template static Flow SetString(void *m, Value fval, Value val) { const FieldDef* f = GetValue(fval); T **str = static_cast(GetFieldPointer(m, f)); // If it points to the default instance, we must create a new instance. if (*str == f->prototype) *str = new T(); GetValue(val)->AssignToString(*str); return UPB_CONTINUE; } template static Flow AppendString(void *_r, Value fval, Value val) { (void)fval; RepeatedPtrField* r = static_cast*>(_r); GetValue(val)->AssignToString(r->Add()); return UPB_CONTINUE; } // SubMessage //////////////////////////////////////////////////////////////// static AccessorVTable *GetForMessage() { static upb_accessor_vtbl vtbl = { &StartSubMessage, NULL, // Value handler &PushOffset, // StartSequence handler &StartRepeatedSubMessage, NULL, // Repeated value handler NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } static SubFlow StartSubMessage(void *m, Value fval) { const FieldDef* f = GetValue(fval); void **subm = static_cast(GetFieldPointer(m, f)); if (*subm == NULL || *subm == f->prototype) { const Message* prototype = static_cast(f->prototype); *subm = prototype->New(); } return UPB_CONTINUE_WITH(*subm); } class RepeatedMessageTypeHandler { public: typedef void Type; // AddAllocated() calls this, but only if other objects are sitting // around waiting for reuse, which we will not do. static void Delete(Type* t) { (void)t; assert(false); } }; // Closure is a RepeatedPtrField*, but we access it through // its base class RepeatedPtrFieldBase*. static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { const FieldDef* f = GetValue(fval); RepeatedPtrFieldBase *r = static_cast(_r); void *submsg = r->AddFromCleared(); if (!submsg) { const Message* prototype = static_cast(f->prototype); submsg = prototype->New(); r->AddAllocated(submsg); } return UPB_CONTINUE_WITH(submsg); } // TODO(haberman): handle Extensions, Unknown Fields. #ifdef UPB_GOOGLE3 // Handlers for types/features only included in internal proto2 release: // Cord, StringPiece, LazyField, and MessageSet. // TODO(haberman): LazyField, MessageSet. // Cord ////////////////////////////////////////////////////////////////////// static AccessorVTable *GetForCord() { static upb_accessor_vtbl vtbl = { NULL, // StartSubMessage handler &SetCord, &PushOffset, // StartSequence handler NULL, // StartRepeatedSubMessage handler &AppendCord, NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } static Flow SetCord(void *m, Value fval, Value val) { const FieldDef* f = GetValue(fval); Cord* field = static_cast(GetFieldPointer(m, f)); AssignToCord(GetValue(val), field); return UPB_CONTINUE; } static Flow AppendCord(void *_r, Value fval, Value val) { RepeatedField* r = static_cast*>(_r); AssignToCord(GetValue(val), r->Add()); return UPB_CONTINUE; } // StringPiece /////////////////////////////////////////////////////////////// static AccessorVTable *GetForStringPiece() { static upb_accessor_vtbl vtbl = { NULL, // StartSubMessage handler &SetStringPiece, &PushOffset, // StartSequence handler NULL, // StartRepeatedSubMessage handler &AppendStringPiece, NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } static void AssignToStringPieceField(const ByteRegion* r, proto2::internal::StringPieceField* f) { // TODO(haberman): alias if possible and enabled on the input stream. // TODO(haberman): add a method to StringPieceField that lets us avoid // this copy/malloc/free. char *data = new char[r->Length()]; r->Copy(r->start_ofs(), r->Length(), data); f->CopyFrom(StringPiece(data, r->Length())); delete[] data; } static Flow SetStringPiece(void *m, Value fval, Value val) { const FieldDef* f = GetValue(fval); StringPieceField* field = static_cast(GetFieldPointer(m, f)); AssignToStringPieceField(GetValue(val), field); return UPB_CONTINUE; } static Flow AppendStringPiece(void* _r, Value fval, Value val) { RepeatedPtrField* r = static_cast*>(_r); AssignToStringPieceField(GetValue(val), r->Add()); return UPB_CONTINUE; } #endif // UPB_GOOGLE3 }; #ifdef UPB_GOOGLE3 // Proto1 accessor -- only needed inside Google. class Proto1FieldAccessor { public: // Returns true if we were able to set an accessor and any other properties // of the FieldDef that are necessary to read/write this field to a // proto2::Message. static bool TrySet(const FieldDescriptor* proto2_f, const upb::MessageDef* md, upb::FieldDef* upb_f) { const Message* m = static_cast(md->prototype); const proto2::Reflection* base_r = m->GetReflection(); const _pi::Proto2Reflection* r = dynamic_cast(base_r); if (!r) return false; // Extensions not supported yet. if (proto2_f->is_extension()) return false; const _pi::Field* f = r->GetFieldLayout(proto2_f); if (f->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK) { // Override the BYTES type that proto2 descriptors have for weak fields. upb_f->set_type(UPB_TYPE(MESSAGE)); } if (upb_f->IsSubmessage()) { const Message* prototype = upb::GetPrototypeForField(*m, proto2_f); upb_f->set_subtype_name(prototype->GetDescriptor()->full_name()); upb_f->prototype = prototype; } upb_f->set_accessor(GetForCrep(f->crep)); upb_f->set_hasbit(GetHasbit(proto2_f, r)); upb_f->set_offset(GetOffset(proto2_f, r)); return true; } private: static int16_t GetHasbit(const FieldDescriptor* f, const _pi::Proto2Reflection* r) { if (f->is_repeated()) { // proto1 does not store hasbits for repeated fields. return -1; } else { return (r->layout_->has_bit_offset * 8) + r->GetFieldLayout(f)->has_index; } } static uint16_t GetOffset(const FieldDescriptor* f, const _pi::Proto2Reflection* r) { return r->GetFieldLayout(f)->offset; } static AccessorVTable *GetForCrep(int crep) { #define PRIMITIVE(name, type_name) \ case _pi::CREP_REQUIRED_ ## name: \ case _pi::CREP_OPTIONAL_ ## name: \ case _pi::CREP_REPEATED_ ## name: return Get(); switch (crep) { PRIMITIVE(DOUBLE, double); PRIMITIVE(FLOAT, float); PRIMITIVE(INT64, int64_t); PRIMITIVE(UINT64, uint64_t); PRIMITIVE(INT32, int32_t); PRIMITIVE(FIXED64, uint64_t); PRIMITIVE(FIXED32, uint32_t); PRIMITIVE(BOOL, bool); case _pi::CREP_REQUIRED_STRING: case _pi::CREP_OPTIONAL_STRING: case _pi::CREP_REPEATED_STRING: return GetForString(); case _pi::CREP_OPTIONAL_OUTOFLINE_STRING: return GetForOutOfLineString(); case _pi::CREP_REQUIRED_CORD: case _pi::CREP_OPTIONAL_CORD: case _pi::CREP_REPEATED_CORD: return GetForCord(); case _pi::CREP_REQUIRED_GROUP: case _pi::CREP_REQUIRED_FOREIGN: case _pi::CREP_REQUIRED_FOREIGN_PROTO2: return GetForRequiredMessage(); case _pi::CREP_OPTIONAL_GROUP: case _pi::CREP_REPEATED_GROUP: case _pi::CREP_OPTIONAL_FOREIGN: case _pi::CREP_REPEATED_FOREIGN: case _pi::CREP_OPTIONAL_FOREIGN_PROTO2: case _pi::CREP_REPEATED_FOREIGN_PROTO2: return GetForMessage(); case _pi::CREP_OPTIONAL_FOREIGN_WEAK: return GetForWeakMessage(); default: assert(false); return NULL; } #undef PRIMITIVE } // PushOffset handler (used for StartSequence and others) /////////////////// // We can find a RepeatedField* or a RepeatedPtrField* at f->offset(). static SubFlow PushOffset(void *m, Value fval) { const FieldDef *f = GetValue(fval); return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); } // Primitive Value (numeric, enum, bool) ///////////////////////////////////// template static AccessorVTable *Get() { static upb_accessor_vtbl vtbl = { NULL, // StartSubMessage handler GetValueHandler(), &PushOffset, // StartSequence handler NULL, // StartRepeatedSubMessage handler &Append, NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } template static Flow Append(void *_r, Value fval, Value val) { (void)fval; // Proto1's ProtoArray class derives from RepeatedField. RepeatedField* r = static_cast*>(_r); r->Add(GetValue(val)); return UPB_CONTINUE; } // String //////////////////////////////////////////////////////////////////// static AccessorVTable *GetForString() { static upb_accessor_vtbl vtbl = { NULL, // StartSubMessage handler &SetString, &PushOffset, // StartSequence handler NULL, // StartRepeatedSubMessage handler &AppendString, NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } static Flow SetString(void *m, Value fval, Value val) { const FieldDef* f = GetValue(fval); string *str = static_cast(GetFieldPointer(m, f)); GetValue(val)->AssignToString(str); return UPB_CONTINUE; } static Flow AppendString(void *_r, Value fval, Value val) { (void)fval; RepeatedPtrField* r = static_cast*>(_r); GetValue(val)->AssignToString(r->Add()); return UPB_CONTINUE; } // Out-of-line string //////////////////////////////////////////////////////// static AccessorVTable *GetForOutOfLineString() { static upb_accessor_vtbl vtbl = { NULL, &SetOutOfLineString, // This type is only used for non-repeated string fields. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } static Flow SetOutOfLineString(void *m, Value fval, Value val) { const FieldDef* f = GetValue(fval); string **str = static_cast(GetFieldPointer(m, f)); if (*str == &::ProtocolMessage::___empty_internal_proto_string_) *str = new string(); GetValue(val)->AssignToString(*str); return UPB_CONTINUE; } // Cord ////////////////////////////////////////////////////////////////////// static AccessorVTable *GetForCord() { static upb_accessor_vtbl vtbl = { NULL, // StartSubMessage handler &SetCord, &PushOffset, // StartSequence handler NULL, // StartRepeatedSubMessage handler &AppendCord, NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } static Flow SetCord(void *m, Value fval, Value val) { const FieldDef* f = GetValue(fval); Cord* field = static_cast(GetFieldPointer(m, f)); AssignToCord(GetValue(val), field); return UPB_CONTINUE; } static Flow AppendCord(void *_r, Value fval, Value val) { RepeatedField* r = static_cast*>(_r); AssignToCord(GetValue(val), r->Add()); return UPB_CONTINUE; } // SubMessage //////////////////////////////////////////////////////////////// static AccessorVTable *GetForRequiredMessage() { static upb_accessor_vtbl vtbl = { &PushOffset, // StartSubMessage handler NULL, // Value handler &PushOffset, // StartSequence handler &StartRepeatedSubMessage, NULL, // Repeated value handler NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } static AccessorVTable *GetForWeakMessage() { static upb_accessor_vtbl vtbl = { &StartWeakSubMessage, // StartSubMessage handler NULL, // Value handler &PushOffset, // StartSequence handler &StartRepeatedSubMessage, NULL, // Repeated value handler NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } static AccessorVTable *GetForMessage() { static upb_accessor_vtbl vtbl = { &StartSubMessage, NULL, // Value handler &PushOffset, // StartSequence handler &StartRepeatedSubMessage, NULL, // Repeated value handler NULL, NULL, NULL, NULL, NULL, NULL}; return &vtbl; } static SubFlow StartSubMessage(void *m, Value fval) { const FieldDef* f = GetValue(fval); Message **subm = static_cast(GetFieldPointer(m, f)); if (*subm == f->prototype) *subm = (*subm)->New(); return UPB_CONTINUE_WITH(*subm); } static SubFlow StartWeakSubMessage(void *m, Value fval) { const FieldDef* f = GetValue(fval); Message **subm = static_cast(GetFieldPointer(m, f)); if (*subm == NULL) { const Message* prototype = static_cast(f->prototype); *subm = prototype->New(); } return UPB_CONTINUE_WITH(*subm); } class RepeatedMessageTypeHandler { public: typedef void Type; // AddAllocated() calls this, but only if other objects are sitting // around waiting for reuse, which we will not do. static void Delete(Type* t) { (void)t; assert(false); } }; // Closure is a RepeatedPtrField*, but we access it through // its base class RepeatedPtrFieldBase*. static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { const FieldDef* f = GetValue(fval); RepeatedPtrFieldBase *r = static_cast(_r); void *submsg = r->AddFromCleared(); if (!submsg) { const Message* prototype = static_cast(f->prototype); submsg = prototype->New(); r->AddAllocated(submsg); } return UPB_CONTINUE_WITH(submsg); } }; #endif } // namespace proto2_bridge_{google3,opensource} static const Message* GetPrototypeForMessage(const Message& m) { const Message* ret = NULL; MessageFactory* factory = FieldAccessor::GetMessageFactory(m); if (factory) { // proto2 generated message or DynamicMessage. ret = factory->GetPrototype(m.GetDescriptor()); assert(ret); } else { // Proto1 message; since proto1 has no dynamic message, it must be // from the generated factory. ret = MessageFactory::generated_factory()->GetPrototype(m.GetDescriptor()); assert(ret); // If NULL, then wasn't a proto1 message, can't handle it. } assert(ret->GetReflection() == m.GetReflection()); return ret; } static const Message* GetPrototypeForField(const Message& m, const FieldDescriptor* f) { #ifdef UPB_GOOGLE3 if (f->type() == FieldDescriptor::TYPE_BYTES) { // Proto1 weak field: the proto2 descriptor says their type is BYTES. const _pi::Proto2Reflection* r = dynamic_cast(m.GetReflection()); assert(r); const _pi::Field* field = r->GetFieldLayout(f); assert(field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK); return GetPrototypeForMessage( *static_cast(field->weak_layout()->default_instance)); } else if (dynamic_cast(m.GetReflection())) { // Proto1 message; since proto1 has no dynamic message, it must be from // the generated factory. const Message* ret = MessageFactory::generated_factory()->GetPrototype(f->message_type()); assert(ret); return ret; } #endif assert(f->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); // We assume that all submessages (and extensions) will be constructed using // the same MessageFactory as this message. This doesn't cover the case of // CodedInputStream::SetExtensionRegistry(). MessageFactory* factory = FieldAccessor::GetMessageFactory(m); assert(factory); // If neither proto1 nor proto2 we can't handle it. const Message* ret = factory->GetPrototype(f->message_type()); assert(ret); return ret; } namespace proto2_bridge { upb::FieldDef* AddFieldDef(const FieldDescriptor* f, upb::MessageDef* md) { upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f); upb_f->set_number(f->number()); upb_f->set_name(f->name()); upb_f->set_label(static_cast(f->label())); upb_f->set_type(static_cast(f->type())); if (!FieldAccessor::TrySet(f, md, upb_f) #ifdef UPB_GOOGLE3 && !proto2_bridge_google3::Proto1FieldAccessor::TrySet(f, md, upb_f) #endif ) { // Unsupported reflection class. assert(false); } if (upb_f->type() == UPB_TYPE(ENUM)) { // We set the enum default symbolically. upb_f->set_default(f->default_value_enum()->name()); upb_f->set_subtype_name(f->enum_type()->full_name()); } else { // Set field default for primitive types. Need to switch on the upb type // rather than the proto2 type, because upb_f->type() may have been changed // from BYTES to MESSAGE for a weak field. switch (upb_types[upb_f->type()].inmemory_type) { case UPB_CTYPE_INT32: upb_f->set_default(MakeValue(f->default_value_int32())); break; case UPB_CTYPE_INT64: upb_f->set_default( MakeValue(static_cast(f->default_value_int64()))); break; case UPB_CTYPE_UINT32: upb_f->set_default(MakeValue(f->default_value_uint32())); break; case UPB_CTYPE_UINT64: upb_f->set_default( MakeValue(static_cast(f->default_value_uint64()))); break; case UPB_CTYPE_DOUBLE: upb_f->set_default(MakeValue(f->default_value_double())); break; case UPB_CTYPE_FLOAT: upb_f->set_default(MakeValue(f->default_value_float())); break; case UPB_CTYPE_BOOL: upb_f->set_default(MakeValue(f->default_value_bool())); break; case UPB_CTYPE_BYTEREGION: upb_f->set_default(f->default_value_string()); break; } } return md->AddField(upb_f, &upb_f) ? upb_f : NULL; } upb::MessageDef *NewEmptyMessageDef(const Message& m, void *owner) { upb::MessageDef *md = upb::MessageDef::New(owner); md->set_full_name(m.GetDescriptor()->full_name()); md->prototype = GetPrototypeForMessage(m); return md; } upb::EnumDef* NewEnumDef(const EnumDescriptor* desc, void *owner) { upb::EnumDef* e = upb::EnumDef::New(owner); e->set_full_name(desc->full_name()); for (int i = 0; i < desc->value_count(); i++) { const EnumValueDescriptor* val = desc->value(i); bool success = e->AddValue(val->name(), val->number()); assert(success); (void)success; } return e; } void AddAllFields(upb::MessageDef* md) { const Descriptor* d = static_cast(md->prototype)->GetDescriptor(); for (int i = 0; i < d->field_count(); i++) { #ifdef UPB_GOOGLE3 // Skip lazy fields for now since we can't properly handle them. if (d->field(i)->options().lazy()) continue; #endif // Extensions not supported yet. if (d->field(i)->is_extension()) continue; AddFieldDef(d->field(i), md); } } upb::MessageDef *NewFullMessageDef(const Message& m, void *owner) { upb::MessageDef* md = NewEmptyMessageDef(m, owner); AddAllFields(md); // TODO(haberman): add unknown field handler and extensions. return md; } typedef std::map SymbolMap; static upb::MessageDef* NewFinalMessageDefHelper(const Message& m, void *owner, SymbolMap* symbols) { upb::MessageDef* md = NewFullMessageDef(m, owner); // Must do this before processing submessages to prevent infinite recursion. (*symbols)[std::string(md->full_name())] = md->AsDef(); for (upb::MessageDef::Iterator i(md); !i.Done(); i.Next()) { upb::FieldDef* f = i.field(); if (!f->HasSubDef()) continue; SymbolMap::iterator iter = symbols->find(f->subtype_name()); upb::Def* subdef; if (iter != symbols->end()) { subdef = iter->second; } else { const FieldDescriptor* proto2_f = m.GetDescriptor()->FindFieldByNumber(f->number()); if (f->type() == UPB_TYPE(ENUM)) { subdef = NewEnumDef(proto2_f->enum_type(), owner)->AsDef(); (*symbols)[std::string(subdef->full_name())] = subdef; } else { assert(f->IsSubmessage()); const Message* prototype = GetPrototypeForField(m, proto2_f); subdef = NewFinalMessageDefHelper(*prototype, owner, symbols)->AsDef(); } } f->set_subdef(subdef); } return md; } const upb::MessageDef* NewFinalMessageDef(const Message& m, void *owner) { SymbolMap symbols; upb::MessageDef* ret = NewFinalMessageDefHelper(m, owner, &symbols); // Finalize defs. std::vector defs; SymbolMap::iterator iter; for (iter = symbols.begin(); iter != symbols.end(); ++iter) { defs.push_back(iter->second); } Status status; bool success = Def::Finalize(defs, &status); assert(success); (void)success; // Unref all defs except the top-level one that we are returning. for (int i = 0; i < static_cast(defs.size()); i++) { if (defs[i] != ret->AsDef()) defs[i]->Unref(owner); } return ret; } } // namespace proto2_bridge } // namespace upb