// // Note that we have received an exception from c-style-artiters regarding // dynamic_cast<> in this file: // https://groups.google.com/a/google.com/d/msg/c-style/7Zp_XCX0e7s/I6dpzno4l-MJ // // IMPORTANT NOTE! This file is compiled TWICE, once with UPB_GOOGLE3 defined // and once without! This allows us to provide functionality against proto2 // and protobuf opensource both in a single binary without the two conflicting. // However we must be careful not to violate the ODR. #include "upb/bindings/googlepb/proto2.int.h" #include #include "upb/bindings/googlepb/proto1.int.h" #include "upb/def.h" #include "upb/handlers.h" #include "upb/msg.h" #include "upb/sink.h" namespace { template To CheckDownCast(From* f) { UPB_ASSERT(f == NULL || dynamic_cast(f) != NULL); return static_cast(f); } } // Unconditionally evaluate, but also assert in debug mode. #define CHKRET(x) do { bool ok = (x); UPB_ASSERT(ok); } while (0) namespace upb { namespace google_google3 { class GMR_Handlers; } namespace google_opensource { class GMR_Handlers; } } // namespace upb // BEGIN DOUBLE COMPILATION TRICKERY. ////////////////////////////////////////// #ifdef UPB_GOOGLE3 // TODO(haberman): Add public functionality to ExtensionSet for populating // LazyFields. #define private public #include "net/proto2/public/extension_set.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/repeated_field.h" #include "net/proto2/public/string_piece_field_support.h" namespace goog = ::proto2; namespace me = ::upb::google_google3; #else // TODO(haberman): remove these once new versions of protobuf that "friend" // upb are pervasive in the wild. #define protected public #include "google/protobuf/repeated_field.h" #undef protected #define private public #include "google/protobuf/generated_message_reflection.h" #undef private #define private public #include "google/protobuf/extension_set.h" #undef private #include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/message.h" namespace goog = ::google::protobuf; namespace me = ::upb::google_opensource; using goog::int32; using goog::int64; using goog::uint32; using goog::uint64; using goog::scoped_ptr; #endif // ifdef UPB_GOOGLE3 // END DOUBLE COMPILATION TRICKERY. //////////////////////////////////////////// // Have to define this manually since older versions of proto2 didn't define // an enum value for STRING. #define UPB_CTYPE_STRING 0 template static T* GetPointer(void* message, size_t offset) { return reinterpret_cast(static_cast(message) + offset); } template static const T* GetConstPointer(const void* message, size_t offset) { return reinterpret_cast(static_cast(message) + offset); } // This class contains handlers that can write into a proto2 class whose // reflection class is GeneratedMessageReflection. (Despite the name, even // DynamicMessage uses GeneratedMessageReflection, so this covers all proto2 // messages generated by the compiler.) To do this it must break the // encapsulation of GeneratedMessageReflection and therefore depends on // internal interfaces that are not guaranteed to be stable. This class will // need to be updated if any non-backward-compatible changes are made to // GeneratedMessageReflection. class me::GMR_Handlers { 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 goog::FieldDescriptor* proto2_f, const goog::Message& m, const upb::FieldDef* upb_f, upb::Handlers* h) { const goog::Reflection* base_r = m.GetReflection(); // See file comment re: dynamic_cast. const goog::internal::GeneratedMessageReflection* r = dynamic_cast(base_r); if (!r) return false; #define PRIMITIVE_TYPE(cpptype, cident) \ case goog::FieldDescriptor::cpptype: \ SetPrimitiveHandlers(proto2_f, r, upb_f, h); \ return true; switch (proto2_f->cpp_type()) { PRIMITIVE_TYPE(CPPTYPE_INT32, int32); PRIMITIVE_TYPE(CPPTYPE_INT64, int64); PRIMITIVE_TYPE(CPPTYPE_UINT32, uint32); PRIMITIVE_TYPE(CPPTYPE_UINT64, uint64); PRIMITIVE_TYPE(CPPTYPE_DOUBLE, double); PRIMITIVE_TYPE(CPPTYPE_FLOAT, float); PRIMITIVE_TYPE(CPPTYPE_BOOL, bool); case goog::FieldDescriptor::CPPTYPE_ENUM: if (proto2_f->is_extension()) { SetEnumExtensionHandlers(proto2_f, r, upb_f, h); } else { SetEnumHandlers(proto2_f, r, upb_f, h); } return true; case goog::FieldDescriptor::CPPTYPE_STRING: { if (proto2_f->is_extension()) { #ifdef UPB_GOOGLE3 SetStringExtensionHandlers(proto2_f, r, upb_f, h); #else SetStringExtensionHandlers(proto2_f, r, upb_f, h); #endif return true; } // 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; switch (ctype) { #ifdef UPB_GOOGLE3 case goog::FieldOptions::STRING: SetStringHandlers(proto2_f, r, upb_f, h); return true; case goog::FieldOptions::CORD: SetCordHandlers(proto2_f, r, upb_f, h); return true; case goog::FieldOptions::STRING_PIECE: SetStringPieceHandlers(proto2_f, r, upb_f, h); return true; #else case UPB_CTYPE_STRING: SetStringHandlers(proto2_f, r, upb_f, h); return true; #endif default: return false; } } case goog::FieldDescriptor::CPPTYPE_MESSAGE: #ifdef UPB_GOOGLE3 if (proto2_f->options().lazy() && // proto2 lets you set lazy=true on a repeated field, but doesn't // actually support lazy repeated messages, so just ignore // lazy=true for repeated messages. !proto2_f->is_repeated()) { // Supports lazy fields and lazy extensions. SetLazyFieldHandlers(proto2_f, m, r, upb_f, h); return true; } #endif if (proto2_f->is_extension()) { SetSubMessageExtensionHandlers(proto2_f, m, r, upb_f, h); return true; } SetSubMessageHandlers(proto2_f, m, r, upb_f, h); return true; default: return false; } } #undef PRIMITIVE_TYPE static const goog::Message* GetFieldPrototype( const goog::Message& m, const goog::FieldDescriptor* f) { // 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(). // See file comment re: dynamic_cast. const goog::internal::GeneratedMessageReflection* r = dynamic_cast( m.GetReflection()); if (!r) return NULL; return r->message_factory_->GetPrototype(f->message_type()); } private: static upb_selector_t GetSelector(const upb::FieldDef* f, upb::Handlers::Type type) { upb::Handlers::Selector selector; bool ok = upb::Handlers::GetSelector(f, type, &selector); UPB_ASSERT(ok); return selector; } static int64_t GetHasbit( const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r) { // proto2 does not store hasbits for repeated fields. UPB_ASSERT(!f->is_repeated()); return (r->has_bits_offset_ * 8) + f->index(); } #ifdef GOOGLE_PROTOBUF_HAS_ONEOF static size_t GetOneofDiscriminantOffset( const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r) { UPB_ASSERT(f->containing_oneof()); return r->oneof_case_offset_ + f->containing_oneof()->index(); } #endif static uint16_t GetOffset( const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r) { int index = f->index(); #ifdef GOOGLE_PROTOBUF_HAS_ONEOF if (f->containing_oneof()) { index = f->containing_type()->field_count() + f->containing_oneof()->index(); } #endif return r->offsets_[index]; } // Base class that provides access to elements of the message as a whole, such // as the unknown-field set, and is inherited by context classes for specific // field handlers. class FieldDataBase { public: FieldDataBase(const goog::internal::GeneratedMessageReflection* r) : unknown_fields_offset_(r->unknown_fields_offset_) #ifdef GOOGLE_PROTOBUF_HAS_ARENAS , arena_offset_(r->arena_offset_) #endif // GOOGLE_PROTOBUF_HAS_ARENAS {} #ifdef GOOGLE_PROTOBUF_HAS_ARENAS goog::Arena* GetArena(const goog::Message& message) const { if (unknown_fields_offset_ == goog::internal::GeneratedMessageReflection:: kUnknownFieldSetInMetadata) { const goog::internal::InternalMetadataWithArena* metadata = GetConstPointer( &message, arena_offset_); return metadata->arena(); } else if (arena_offset_ != goog::internal::GeneratedMessageReflection::kNoArenaPointer) { return *GetConstPointer(&message, arena_offset_); } else { return NULL; } } goog::UnknownFieldSet* GetUnknownFieldSet(goog::Message* message) const { if (unknown_fields_offset_ == goog::internal::GeneratedMessageReflection:: kUnknownFieldSetInMetadata) { goog::internal::InternalMetadataWithArena* metadata = GetPointer( message, arena_offset_); return metadata->mutable_unknown_fields(); } return GetPointer(message, unknown_fields_offset_); } #else // ifdef GOOGLE_PROTOBUF_HAS_ARENAS goog::UnknownFieldSet* GetUnknownFieldSet(goog::Message* message) const { return GetPointer(message, unknown_fields_offset_); } #endif // ifdef !GOOGLE_PROTOBUF_HAS_ARENAS private: int unknown_fields_offset_; #ifdef GOOGLE_PROTOBUF_HAS_ARENAS int arena_offset_; #endif // GOOGLE_PROTOBUF_HAS_ARENAS }; class FieldOffset : public FieldDataBase { public: FieldOffset(const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r) : FieldDataBase(r), offset_(GetOffset(f, r)), is_repeated_(f->is_repeated()) { if (!is_repeated_) { int64_t hasbit = GetHasbit(f, r); hasbyte_ = hasbit / 8; mask_ = 1 << (hasbit % 8); } } template T* GetFieldPointer(goog::Message* message) const { return GetPointer(message, offset_); } void SetHasbit(void* m) const { UPB_ASSERT(!is_repeated_); uint8_t* byte = GetPointer(m, hasbyte_); *byte |= mask_; } private: const size_t offset_; bool is_repeated_; // Only for non-repeated fields. int32_t hasbyte_; int8_t mask_; }; #ifdef GOOGLE_PROTOBUF_HAS_ONEOF class OneofFieldData : public FieldDataBase { public: OneofFieldData(const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r) : FieldDataBase(r), field_number_offset_(GetOneofDiscriminantOffset(f, r)), field_number_(f->number()) { const goog::OneofDescriptor* oneof = f->containing_oneof(); // Determine the type of each discriminant value, so we know what kind of // value to delete if we are changing the type. // // For example, we may find that the oneof has three possible values: an // int32, a message, and a string. For the int32 there is nothing to // delete, but the message and the string need to be deleted when we // switch to another oneof type, to avoid leaking it. // // TODO(haberman): share this map of types between all fields in the // oneof. Right now we duplicate it for each one, which is wasteful. for (int i = 0; i < oneof->field_count(); i++) { const goog::FieldDescriptor* oneof_f = oneof->field(i); OneofType& type = types_[oneof_f->number()]; switch (oneof_f->cpp_type()) { case goog::FieldDescriptor::CPPTYPE_STRING: type = GetTypeForString(oneof_f); break; case goog::FieldDescriptor::CPPTYPE_MESSAGE: #ifdef UPB_GOOGLE3 if (oneof_f->options().lazy()) { type = ONEOF_TYPE_LAZYFIELD; break; } #endif type = ONEOF_TYPE_MESSAGE; break; default: type = ONEOF_TYPE_NONE; break; } } // "0" indicates that the field is not set. types_[0] = ONEOF_TYPE_NONE; } int32_t* GetFieldPointer(goog::Message* message) const { return GetPointer(message, field_number_offset_); } void ClearOneof(goog::Message* m, const FieldOffset* ofs, int field_number) const { #ifdef GOOGLE_PROTOBUF_HAS_ARENAS if (GetArena(*m) != NULL) { return; } #endif switch (types_.at(field_number)) { case ONEOF_TYPE_NONE: break; case ONEOF_TYPE_STRING: delete *ofs->GetFieldPointer(m); break; case ONEOF_TYPE_MESSAGE: delete *ofs->GetFieldPointer(m); break; #ifdef UPB_GOOGLE3 case ONEOF_TYPE_GLOBALSTRING: delete *ofs->GetFieldPointer(m); break; case ONEOF_TYPE_CORD: delete *ofs->GetFieldPointer(m); break; case ONEOF_TYPE_STRINGPIECE: delete *ofs->GetFieldPointer< goog::internal::StringPieceField*>(m); break; case ONEOF_TYPE_LAZYFIELD: delete *ofs->GetFieldPointer(m); break; #endif } } // Returns whether this is different than the previous value of the // field_number; this implies that the current value was freed (if // necessary) and the caller should allocate a new instance. bool SetOneofHas(goog::Message* m, const FieldOffset* ofs) const { int32_t *field_number = GetFieldPointer(m); if (*field_number == field_number_) { return false; } else { ClearOneof(m, ofs, *field_number); *field_number = field_number_; return true; } } private: enum OneofType { ONEOF_TYPE_NONE, ONEOF_TYPE_STRING, ONEOF_TYPE_MESSAGE #ifdef UPB_GOOGLE3 , ONEOF_TYPE_GLOBALSTRING, ONEOF_TYPE_CORD, ONEOF_TYPE_STRINGPIECE, ONEOF_TYPE_LAZYFIELD #endif }; OneofType GetTypeForString(const goog::FieldDescriptor* f) { switch (f->options().ctype()) { case goog::FieldOptions::STRING: #ifdef UPB_GOOGLE3 return ONEOF_TYPE_GLOBALSTRING; #else return ONEOF_TYPE_STRING; #endif #ifdef UPB_GOOGLE3 case goog::FieldOptions::CORD: return ONEOF_TYPE_CORD; case goog::FieldOptions::STRING_PIECE: return ONEOF_TYPE_STRINGPIECE; #endif default: UPB_ASSERT(false); return ONEOF_TYPE_NONE; } } // Offset of the uint32 that specifies which field is set. size_t field_number_offset_; // Field number for this field. int32_t field_number_; // The types of the oneof fields, indexed by field_number_. std::map types_; }; class OneofFieldHandlerData : public FieldOffset { public: OneofFieldHandlerData(const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r) : FieldOffset(f, r), oneof_data_(f, r) {} bool SetOneofHas(goog::Message* message) const { return oneof_data_.SetOneofHas(message, this); } public: OneofFieldData oneof_data_; }; #endif // GOOGLE_PROTOBUF_HAS_ONEOF class ExtensionFieldData { public: ExtensionFieldData( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r) : offset_(r->extensions_offset_), field_descriptor_(proto2_f) { } int number() const { return field_descriptor_->number(); } goog::internal::FieldType type() const { return field_descriptor_->type(); } const goog::FieldDescriptor* field_descriptor() const { return field_descriptor_; } goog::internal::ExtensionSet* GetExtensionSet(goog::Message* m) const { return GetPointer(m, offset_); } private: const size_t offset_; // We know it will outlive because we require that the input message used to // build these handlers outlives us, and the descriptor will outlive the // message. const goog::FieldDescriptor* field_descriptor_; }; // StartSequence ///////////////////////////////////////////////////////////// template static void SetStartRepeatedField( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { CHKRET(h->SetStartSequenceHandler( f, UpbBindT(&PushOffset >, new FieldOffset(proto2_f, r)))); } template static void SetStartRepeatedPtrField( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { CHKRET(h->SetStartSequenceHandler( f, UpbBindT(&PushOffset >, new FieldOffset(proto2_f, r)))); } static void SetStartRepeatedSubmessageField( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { CHKRET(h->SetStartSequenceHandler( f, UpbBind(&PushOffset, new FieldOffset(proto2_f, r)))); } template static T* PushOffset(goog::Message* message, const FieldOffset* offset) { return offset->GetFieldPointer(message); } // Primitive Value (numeric, bool) /////////////////////////////////////////// template static void SetPrimitiveHandlers( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { if (proto2_f->is_extension()) { scoped_ptr data(new ExtensionFieldData(proto2_f, r)); if (f->IsSequence()) { CHKRET(h->SetValueHandler( f, UpbBindT(AppendPrimitiveExtension, data.release()))); } else { CHKRET(h->SetValueHandler( f, UpbBindT(SetPrimitiveExtension, data.release()))); } } #ifdef GOOGLE_PROTOBUF_HAS_ONEOF else if (proto2_f->containing_oneof()) { UPB_ASSERT(!proto2_f->is_repeated()); CHKRET(h->SetValueHandler( f, UpbBindT(SetOneofPrimitive, new OneofFieldHandlerData(proto2_f, r)))); } #endif else { if (f->IsSequence()) { SetStartRepeatedField(proto2_f, r, f, h); CHKRET(h->SetValueHandler(f, UpbMakeHandlerT(AppendPrimitive))); } else { CHKRET(upb_msg_setscalarhandler(h, f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r))); } } } template static void AppendPrimitive(goog::RepeatedField* r, T val) { r->Add(val); } template static void AppendPrimitiveExtension(goog::Message* m, const ExtensionFieldData* data, T val) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); // TODO(haberman): give an accurate value for "packed" goog::internal::RepeatedPrimitiveTypeTraits::Add( data->number(), data->type(), true, val, set); } template static void SetPrimitiveExtension(goog::Message* m, const ExtensionFieldData* data, T val) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); goog::internal::PrimitiveTypeTraits::Set(data->number(), data->type(), val, set); } #ifdef GOOGLE_PROTOBUF_HAS_ONEOF template static void SetOneofPrimitive(goog::Message* m, const OneofFieldHandlerData* data, T val) { data->SetOneofHas(m); const FieldOffset* ofs = data; T* ptr = ofs->GetFieldPointer(m); *ptr = val; } #endif // Enum ////////////////////////////////////////////////////////////////////// class EnumHandlerData : public FieldOffset { public: EnumHandlerData(const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f) : FieldOffset(proto2_f, r), field_number_(f->number()), enum_(upb_downcast_enumdef(f->subdef())) {} bool IsValidValue(int32_t val) const { return enum_->FindValueByNumber(val) != NULL; } int32_t field_number() const { return field_number_; } private: int32_t field_number_; const upb::EnumDef* enum_; }; static void SetEnumHandlers( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { UPB_ASSERT(!proto2_f->is_extension()); scoped_ptr data(new EnumHandlerData(proto2_f, r, f)); if (f->IsSequence()) { CHKRET(h->SetInt32Handler(f, UpbBind(AppendEnum, data.release()))); } else { CHKRET(h->SetInt32Handler(f, UpbBind(SetEnum, data.release()))); } } static void SetEnum(goog::Message* m, const EnumHandlerData* data, int32_t val) { if (data->IsValidValue(val)) { int32_t* message_val = data->GetFieldPointer(m); *message_val = val; data->SetHasbit(m); } else { data->GetUnknownFieldSet(m)->AddVarint(data->field_number(), val); } } static void AppendEnum(goog::Message* m, const EnumHandlerData* data, int32_t val) { // Closure is the enclosing message. We can't use the RepeatedField<> as // the closure because we need to go back to the message for unrecognized // enum values, which go into the unknown field set. if (data->IsValidValue(val)) { goog::RepeatedField* r = data->GetFieldPointer >(m); r->Add(val); } else { data->GetUnknownFieldSet(m)->AddVarint(data->field_number(), val); } } // EnumExtension ///////////////////////////////////////////////////////////// static void SetEnumExtensionHandlers( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { UPB_ASSERT(proto2_f->is_extension()); scoped_ptr data(new ExtensionFieldData(proto2_f, r)); if (f->IsSequence()) { CHKRET( h->SetInt32Handler(f, UpbBind(AppendEnumExtension, data.release()))); } else { CHKRET(h->SetInt32Handler(f, UpbBind(SetEnumExtension, data.release()))); } } static void SetEnumExtension(goog::Message* m, const ExtensionFieldData* data, int32_t val) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); set->SetEnum(data->number(), data->type(), val, NULL); } static void AppendEnumExtension(goog::Message* m, const ExtensionFieldData* data, int32_t val) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); // TODO(haberman): give an accurate value for "packed" set->AddEnum(data->number(), data->type(), true, val, NULL); } // String //////////////////////////////////////////////////////////////////// // For scalar (non-repeated) string fields. template class StringHandlerData : public FieldOffset { public: StringHandlerData(const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r) : FieldOffset(proto2_f, r), prototype_(*GetConstPointer(r->default_instance_, GetOffset(proto2_f, r))) {} const T* prototype() const { return prototype_; } T** GetStringPointer(goog::Message* message) const { return GetFieldPointer(message); } private: const T* prototype_; }; template static void SetStringHandlers( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { UPB_ASSERT(!proto2_f->is_extension()); CHKRET(h->SetStringHandler(f, UpbMakeHandlerT(&OnStringBuf))); #ifdef GOOGLE_PROTOBUF_HAS_ONEOF if (proto2_f->containing_oneof()) { UPB_ASSERT(!f->IsSequence()); CHKRET(h->SetStartStringHandler( f, UpbBindT(&StartOneofString, new OneofFieldHandlerData(proto2_f, r)))); } else #endif if (f->IsSequence()) { SetStartRepeatedPtrField(proto2_f, r, f, h); CHKRET( h->SetStartStringHandler(f, UpbMakeHandlerT(StartRepeatedString))); } else { CHKRET(h->SetStartStringHandler( f, UpbBindT(StartString, new StringHandlerData(proto2_f, r)))); } } // This needs to be templated because google3 string is not std::string. template static T* StartString(goog::Message* m, const StringHandlerData* data, size_t size_hint) { UPB_UNUSED(size_hint); T** str = data->GetStringPointer(m); data->SetHasbit(m); // If it points to the default instance, we must create a new instance. if (*str == data->prototype()) { *str = new T(); #ifdef GOOGLE_PROTOBUF_HAS_ARENAS if (data->GetArena(*m)) { data->GetArena(*m)->Own(*str); } #endif } (*str)->clear(); // reserve() here appears to hurt performance rather than help. return *str; } template static void OnStringBuf(T* str, const char* buf, size_t n) { str->append(buf, n); } template static T* StartRepeatedString(goog::RepeatedPtrField* r, size_t size_hint) { UPB_UNUSED(size_hint); T* str = r->Add(); str->clear(); // reserve() here appears to hurt performance rather than help. return str; } #ifdef GOOGLE_PROTOBUF_HAS_ONEOF template static T* StartOneofString(goog::Message* m, const OneofFieldHandlerData* data, size_t size_hint) { UPB_UNUSED(size_hint); const FieldOffset* ofs = data; T** str = ofs->GetFieldPointer(m); if (data->SetOneofHas(m)) { *str = new T(); #ifdef GOOGLE_PROTOBUF_HAS_ARENAS // Note that in the main proto2-arenas implementation, the parsing code // creates ArenaString instances for string field data, and the // implementation later dynamically converts to ::string if a mutable // version is requested. To keep complexity down in this binding, we // create an ordinary string and allow the arena to own its destruction. if (data->GetArena(*m) != NULL) { data->GetArena(*m)->Own(*str); } #endif } else { (*str)->clear(); } return *str; } #endif // StringExtension /////////////////////////////////////////////////////////// template static void SetStringExtensionHandlers( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { UPB_ASSERT(proto2_f->is_extension()); CHKRET(h->SetStringHandler(f, UpbMakeHandlerT(OnStringBuf))); scoped_ptr data(new ExtensionFieldData(proto2_f, r)); if (f->IsSequence()) { CHKRET(h->SetStartStringHandler( f, UpbBindT(StartRepeatedStringExtension, data.release()))); } else { CHKRET(h->SetStartStringHandler( f, UpbBindT(StartStringExtension, data.release()))); } } // Templated because google3 is not std::string. template static T* StartStringExtension(goog::Message* m, const ExtensionFieldData* data, size_t size_hint) { UPB_UNUSED(size_hint); goog::internal::ExtensionSet* set = data->GetExtensionSet(m); return set->MutableString(data->number(), data->type(), NULL); } template static T* StartRepeatedStringExtension(goog::Message* m, const ExtensionFieldData* data, size_t size_hint) { UPB_UNUSED(size_hint); goog::internal::ExtensionSet* set = data->GetExtensionSet(m); return set->AddString(data->number(), data->type(), NULL); } // SubMessage //////////////////////////////////////////////////////////////// class SubMessageHandlerData : public FieldOffset { public: SubMessageHandlerData(const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r, const goog::Message* prototype) : FieldOffset(f, r), prototype_(prototype) {} const goog::Message* prototype() const { return prototype_; } private: const goog::Message* const prototype_; }; #ifdef GOOGLE_PROTOBUF_HAS_ONEOF class OneofSubMessageHandlerData : public SubMessageHandlerData { public: OneofSubMessageHandlerData(const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r, const goog::Message* prototype) : SubMessageHandlerData(f, r, prototype), oneof_data_(f, r) {} bool SetOneofHas(goog::Message* m) const { return oneof_data_.SetOneofHas(m, this); } private: OneofFieldData oneof_data_; }; #endif static void SetSubMessageHandlers( const goog::FieldDescriptor* proto2_f, const goog::Message& m, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f); scoped_ptr data( new SubMessageHandlerData(proto2_f, r, field_prototype)); #ifdef GOOGLE_PROTOBUF_HAS_ONEOF if (proto2_f->containing_oneof()) { UPB_ASSERT(!f->IsSequence()); CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartOneofSubMessage, new OneofSubMessageHandlerData( proto2_f, r, field_prototype)))); } else #endif if (f->IsSequence()) { SetStartRepeatedSubmessageField(proto2_f, r, f, h); CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartRepeatedSubMessage, data.release()))); } else { CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartSubMessage, data.release()))); } } static goog::Message* StartSubMessage(goog::Message* m, const SubMessageHandlerData* data) { data->SetHasbit(m); goog::Message** subm = data->GetFieldPointer(m); if (*subm == NULL || *subm == data->prototype()) { #ifdef GOOGLE_PROTOBUF_HAS_ARENAS *subm = data->prototype()->New(data->GetArena(*m)); #else *subm = data->prototype()->New(); #endif } return *subm; } class RepeatedMessageTypeHandler { public: typedef goog::Message Type; #ifdef GOOGLE_PROTOBUF_HAS_ARENAS static goog::Arena* GetArena(Type* t) { return t->GetArena(); } static void* GetMaybeArenaPointer(Type* t) { return t->GetMaybeArenaPointer(); } static inline Type* NewFromPrototype( const Type* prototype, goog::Arena* arena = NULL) { return prototype->New(arena); } static void Delete(Type* t, goog::Arena* arena = NULL) { if (arena == NULL) { delete t; } } #else // ifdef GOOGLE_PROTOBUF_HAS_ARENAS static inline Type* NewFromPrototype(const Type* prototype) { return prototype->New(); } // AddAllocated() calls this, but only if other objects are sitting // around waiting for reuse, which we will not do. static void Delete(Type* t) { UPB_UNUSED(t); UPB_ASSERT(false); } #endif // ifdef GOOGLE_PROTOBUF_HAS_ARENAS static void Merge(const Type& from, Type* to) { to->MergeFrom(from); } }; // Closure is a RepeatedPtrField*, but we access it through // its base class RepeatedPtrFieldBase*. static goog::Message* StartRepeatedSubMessage( goog::internal::RepeatedPtrFieldBase* r, const SubMessageHandlerData* data) { #ifdef GOOGLE_PROTOBUF_HAS_ARENAS return r->Add( const_cast(data->prototype())); #else // This code path is required not because of arena-related API changes but // because the variant of Add<>() that takes a prototype object was added // only recently. Without the prototype, there's no way for Add<>() to // create a new submessage with out typehandler implementation because we // don't have New() (because we don't template-specialize our typehandler // class on concrete message types). So we have to implement the runtime // polymorphism externally (in this function) and then use AddAllocated to // insert the pointer. goog::Message* submsg = r->AddFromCleared(); if (!submsg) { submsg = data->prototype()->New(); r->AddAllocated(submsg); } return submsg; #endif } #ifdef GOOGLE_PROTOBUF_HAS_ONEOF static goog::Message* StartOneofSubMessage( goog::Message* m, const OneofSubMessageHandlerData* data) { const FieldOffset* ofs = data; goog::Message** subm = ofs->GetFieldPointer(m); if (data->SetOneofHas(m)) { #ifdef GOOGLE_PROTOBUF_HAS_ARENAS *subm = data->prototype()->New(data->GetArena(*m)); #else *subm = data->prototype()->New(); #endif } return *subm; } #endif // SubMessageExtension /////////////////////////////////////////////////////// class SubMessageExtensionHandlerData : public ExtensionFieldData { public: SubMessageExtensionHandlerData( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const goog::Message* prototype) : ExtensionFieldData(proto2_f, r), prototype_(prototype) { } const goog::Message* prototype() const { return prototype_; } private: const goog::Message* const prototype_; }; static void SetSubMessageExtensionHandlers( const goog::FieldDescriptor* proto2_f, const goog::Message& m, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f); scoped_ptr data( new SubMessageExtensionHandlerData(proto2_f, r, field_prototype)); if (f->IsSequence()) { CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartRepeatedSubMessageExtension, data.release()))); } else { CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartSubMessageExtension, data.release()))); } } static goog::Message* StartRepeatedSubMessageExtension( goog::Message* m, const SubMessageExtensionHandlerData* data) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); // Because we found this message via a descriptor, we know it has a // descriptor and is therefore a Message and not a MessageLite. // Alternatively we could just use goog::MessageLite everywhere to avoid // this, but since they are in fact goog::Messages, it seems most clear // to refer to them as such. return CheckDownCast(set->AddMessage( data->number(), data->type(), *data->prototype(), NULL)); } static goog::Message* StartSubMessageExtension( goog::Message* m, const SubMessageExtensionHandlerData* data) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); // See comment above re: this down cast. return CheckDownCast(set->MutableMessage( data->number(), data->type(), *data->prototype(), NULL)); } // TODO(haberman): handle Unknown Fields. #ifdef UPB_GOOGLE3 // Handlers for types/features only included in internal proto2 release: // Cord, StringPiece, LazyField, and MessageSet. // TODO(haberman): MessageSet. // Cord ////////////////////////////////////////////////////////////////////// static void AppendBufToCord(const char* buf, size_t n, const upb::BufferHandle* handle, Cord* c) { const Cord* source_cord = handle->GetAttachedObject(); if (source_cord) { // This TODO is copied from CordReader::CopyToCord(): // "We could speed this up by using CordReader internals." Cord piece(*source_cord); piece.RemovePrefix(handle->object_offset() + (buf - handle->buffer())); UPB_ASSERT(piece.size() >= n); piece.RemoveSuffix(piece.size() - n); c->Append(piece); } else { c->Append(StringPiece(buf, n)); } } static void SetCordHandlers( const proto2::FieldDescriptor* proto2_f, const proto2::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { UPB_ASSERT(!proto2_f->is_extension()); CHKRET(h->SetStringHandler(f, UpbMakeHandler(&OnCordBuf))); if (f->IsSequence()) { SetStartRepeatedField(proto2_f, r, f, h); CHKRET(h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedCord))); } else { CHKRET(h->SetStartStringHandler( f, UpbBind(StartCord, new FieldOffset(proto2_f, r)))); } } static Cord* StartCord(goog::Message* m, const FieldOffset* offset, size_t size_hint) { UPB_UNUSED(size_hint); offset->SetHasbit(m); Cord* field = offset->GetFieldPointer(m); field->Clear(); return field; } static void OnCordBuf(Cord* c, const char* buf, size_t n, const upb::BufferHandle* handle) { AppendBufToCord(buf, n, handle, c); } static Cord* StartRepeatedCord(proto2::RepeatedField* r, size_t size_hint) { UPB_UNUSED(size_hint); return r->Add(); } // StringPiece /////////////////////////////////////////////////////////////// static void SetStringPieceHandlers( const proto2::FieldDescriptor* proto2_f, const proto2::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { UPB_ASSERT(!proto2_f->is_extension()); CHKRET(h->SetStringHandler(f, UpbMakeHandler(OnStringPieceBuf))); if (f->IsSequence()) { SetStartRepeatedPtrField(proto2_f, r, f, h); CHKRET(h->SetStartStringHandler( f, UpbMakeHandler(StartRepeatedStringPiece))); } else { CHKRET(h->SetStartStringHandler( f, UpbBind(StartStringPiece, new FieldOffset(proto2_f, r)))); } } static void OnStringPieceBuf(proto2::internal::StringPieceField* field, const char* buf, size_t len) { // 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. size_t new_len = field->size() + len; char* data = new char[new_len]; memcpy(data, field->data(), field->size()); memcpy(data + field->size(), buf, len); field->CopyFrom(StringPiece(data, new_len)); delete[] data; } static proto2::internal::StringPieceField* StartStringPiece( goog::Message* m, const FieldOffset* offset, size_t size_hint) { UPB_UNUSED(size_hint); offset->SetHasbit(m); proto2::internal::StringPieceField* field = offset->GetFieldPointer(m); field->Clear(); return field; } static proto2::internal::StringPieceField* StartRepeatedStringPiece( proto2::RepeatedPtrField* r, size_t size_hint) { UPB_UNUSED(size_hint); proto2::internal::StringPieceField* field = r->Add(); field->Clear(); return field; } // LazyField ///////////////////////////////////////////////////////////////// // For lazy fields we set both lazy and eager handlers. The user can // configure the data source to call either, though lazy handlers may only be // used when the source data is binary protobuf. static void SetLazyFieldHandlers( const proto2::FieldDescriptor* proto2_f, const proto2::Message& m, const proto2::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { UPB_ASSERT(!proto2_f->is_repeated()); const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f); CHKRET(h->SetStringHandler(f, UpbMakeHandler(OnLazyFieldBuf))); if (proto2_f->is_extension()) { CHKRET(h->SetStartStringHandler( f, UpbBind(StartLazyExtension, new ExtensionFieldData(proto2_f, r)))); CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartSubMessageExtension, new SubMessageExtensionHandlerData(proto2_f, r, field_prototype)))); } else { CHKRET(h->SetStartStringHandler( f, UpbBind(StartLazyField, new FieldOffset(proto2_f, r)))); CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartLazyFieldEager, new SubMessageHandlerData(proto2_f, r, field_prototype)))); } } static proto2::internal::LazyField* StartLazyField(proto2::Message* m, const FieldOffset* offset, size_t size_hint) { UPB_UNUSED(size_hint); offset->SetHasbit(m); proto2::internal::LazyField* field = offset->GetFieldPointer(m); field->Clear(); return field; } // For when the field has a lazy representation but we parse it eagerly anyway // (either because we want to or because we're parsing from a format other // than binary protobuf). static proto2::Message* StartLazyFieldEager( proto2::Message* m, const SubMessageHandlerData* data) { data->SetHasbit(m); proto2::internal::LazyField* field = data->GetFieldPointer(m); return field->MutableByPrototype(*data->prototype()); } class LazyMessageExtensionImpl : public proto2::internal::ExtensionSet::LazyMessageExtension { public: LazyMessageExtensionImpl() {} virtual ~LazyMessageExtensionImpl() {} #ifdef GOOGLE_PROTOBUF_HAS_ARENAS virtual LazyMessageExtension* New() const { return New(NULL); } virtual LazyMessageExtension* New(proto2::Arena* arena) const { LazyMessageExtensionImpl* message = ::proto2::Arena::Create(arena); return message; } #else // ifdef GOOGLE_PROTOBUF_HAS_ARENAS virtual LazyMessageExtension* New() const { return new LazyMessageExtensionImpl(); } #endif // ifdef GOOGLE_PROTOBUF_HAS_ARENAS virtual const proto2::MessageLite& GetMessage( const proto2::MessageLite& prototype) const { return lazy_field_.GetByPrototype( static_cast(prototype)); } virtual proto2::MessageLite* MutableMessage( const proto2::MessageLite& prototype) { return lazy_field_.MutableByPrototype( static_cast(prototype)); } virtual void SetAllocatedMessage(proto2::MessageLite* message) { return lazy_field_.SetAllocated(static_cast(message)); } virtual void UnsafeArenaSetAllocatedMessage(proto2::MessageLite* message) { return lazy_field_.UnsafeArenaSetAllocated( static_cast(message)); } virtual proto2::MessageLite* ReleaseMessage( const proto2::MessageLite& prototype) { return lazy_field_.ReleaseByPrototype( static_cast(prototype)); } virtual proto2::MessageLite* UnsafeArenaReleaseMessage( const proto2::MessageLite& prototype) { return lazy_field_.UnsafeArenaReleaseByPrototype( static_cast(prototype)); } virtual bool IsInitialized() const { return true; } virtual int ByteSize() const { return lazy_field_.MessageByteSize(); } int SpaceUsed() const { return sizeof(*this) + lazy_field_.SpaceUsedExcludingSelf(); } virtual void MergeFrom(const LazyMessageExtension& other) { MergeFrom(*static_cast(&other)); } virtual void MergeFrom(const LazyMessageExtensionImpl& other) { lazy_field_.MergeFrom(other.lazy_field_); } virtual void Clear() { lazy_field_.Clear(); } virtual bool ReadMessage(const proto2::MessageLite& prototype, proto2::io::CodedInputStream* input) { return lazy_field_.Read(input); } virtual void WriteMessage(int number, proto2::io::CodedOutputStream* output) const { lazy_field_.Write(number, output); } virtual uint8* WriteMessageToArray(int number, uint8* target) const { return lazy_field_.WriteToArray(number, target); } proto2::internal::LazyField& lazy_field() { return lazy_field_; } private: proto2::internal::LazyField lazy_field_; DISALLOW_COPY_AND_ASSIGN(LazyMessageExtensionImpl); }; static proto2::internal::LazyField* StartLazyExtension( proto2::Message* m, const ExtensionFieldData* data, size_t size_hint) { proto2::internal::ExtensionSet* set = data->GetExtensionSet(m); // We have to break encapsulation here since no public accessors expose the // LazyField. // // TODO(haberman): add a function to ExtensionSet that allows us to set the // lazy field directly. proto2::internal::ExtensionSet::Extension* item; LazyMessageExtensionImpl* lazy_extension; if (set->MaybeNewExtension(data->number(), data->field_descriptor(), &item)) { #ifdef GOOGLE_PROTOBUF_HAS_ARENAS lazy_extension = ::proto2::Arena::Create( m->GetArena()); #else lazy_extension = new LazyMessageExtensionImpl(); #endif item->type = UPB_DESCRIPTOR_TYPE_MESSAGE; item->is_repeated = false; item->is_lazy = true; item->lazymessage_value = lazy_extension; } else { lazy_extension = CheckDownCast(item->lazymessage_value); } item->is_cleared = false; return &lazy_extension->lazy_field(); } static void OnLazyFieldBuf(proto2::internal::LazyField* field, const char* buf, size_t len, const upb::BufferHandle* handle) { Cord encoded(field->GetEncoded()); AppendBufToCord(buf, len, handle, &encoded); field->SetEncoded(encoded); } #endif // UPB_GOOGLE3 }; namespace upb { namespace googlepb { bool TrySetWriteHandlers(const goog::FieldDescriptor* proto2_f, const goog::Message& prototype, const upb::FieldDef* upb_f, upb::Handlers* h) { return me::GMR_Handlers::TrySet(proto2_f, prototype, upb_f, h); } const goog::Message* GetProto2FieldPrototype(const goog::Message& m, const goog::FieldDescriptor* f) { if (f->cpp_type() != goog::FieldDescriptor::CPPTYPE_MESSAGE) { return NULL; } return me::GMR_Handlers::GetFieldPrototype(m, f); } } // namespace googlepb } // namespace upb