#include "mediapipe/framework/tool/options_registry.h" #include #include #include "absl/synchronization/mutex.h" #include "mediapipe/framework/port/ret_check.h" #include "mediapipe/framework/tool/proto_util_lite.h" namespace mediapipe { namespace tool { namespace { // Returns a canonical message type name, with any leading "." removed. std::string CanonicalTypeName(const std::string& type_name) { return (absl::StartsWith(type_name, ".")) ? type_name.substr(1) : type_name; } // Returns the values from a protobuf field as typed FieldData. absl::StatusOr> GetFieldValues( const FieldData& message_data, std::string field_name) { std::string type_name = ProtoUtilLite::ParseTypeUrl(message_data.message_value().type_url()); const Descriptor* descriptor = OptionsRegistry::GetProtobufDescriptor(type_name); RET_CHECK_NE(descriptor, nullptr); const FieldDescriptor* field = descriptor->FindFieldByName(field_name); if (field == nullptr) { return std::vector(); } ProtoUtilLite::ProtoPath proto_path = {{field->number(), 0}}; ProtoUtilLite::FieldValue mesage_bytes = message_data.message_value().value(); int count; MP_RETURN_IF_ERROR(ProtoUtilLite::GetFieldCount(mesage_bytes, proto_path, field->type(), &count)); std::vector field_values; MP_RETURN_IF_ERROR(ProtoUtilLite::GetFieldRange( mesage_bytes, proto_path, count, field->type(), &field_values)); std::vector result; for (int i = 0; i < field_values.size(); ++i) { FieldData r; std::string message_type = field->message_type() ? field->message_type()->full_name() : ""; MP_RETURN_IF_ERROR(ProtoUtilLite::ReadValue(field_values[i], field->type(), message_type, &r)); result.push_back(std::move(r)); } return result; } // Returns a single value from a protobuf string field. std::string GetFieldString(const FieldData& message_data, std::string field_name) { auto values = GetFieldValues(message_data, field_name); if (!values->empty()) { return values->front().string_value(); } return ""; } // Registers the descriptors for the descriptor protobufs. These four // descriptors are required to deserialize descriptors for other protobufs. // This implementation avoids a code size problem introduced by // proto_ns::DescriptorProto. void RegisterDescriptorProtos( absl::flat_hash_map& result) { std::vector descriptors = { {"proto2.FileDescriptorSet", { {"file", 1, FieldType::TYPE_MESSAGE, "proto2.FileDescriptorProto"}, }}, {"proto2.FileDescriptorProto", { {"package", 2, FieldType::TYPE_STRING, ""}, {"message_type", 4, FieldType::TYPE_MESSAGE, "proto2.DescriptorProto"}, }}, {"proto2.DescriptorProto", { {"name", 1, FieldType::TYPE_STRING, ""}, {"field", 2, FieldType::TYPE_MESSAGE, "proto2.FieldDescriptorProto"}, {"extension", 6, FieldType::TYPE_MESSAGE, "proto2.FieldDescriptorProto"}, {"nested_type", 3, FieldType::TYPE_MESSAGE, "proto2.DescriptorProto"}, }}, {"proto2.FieldDescriptorProto", { {"name", 1, FieldType::TYPE_STRING, ""}, {"number", 3, FieldType::TYPE_INT32, ""}, {"type", 5, FieldType::TYPE_ENUM, ""}, {"type_name", 6, FieldType::TYPE_STRING, ""}, {"extendee", 2, FieldType::TYPE_STRING, ""}, }}, }; for (const auto& descriptor : descriptors) { result[descriptor.full_name()] = descriptor; } } } // namespace RegistrationToken OptionsRegistry::Register( const FieldData& file_descriptor_set) { auto files = GetFieldValues(file_descriptor_set, "file"); for (auto& file : *files) { std::string package_name = GetFieldString(file, "package"); auto message_types = GetFieldValues(file, "message_type"); for (auto& message_type : *message_types) { Register(message_type, package_name); } } return RegistrationToken([]() {}); } void OptionsRegistry::Register(const FieldData& message_type, const std::string& parent_name) { std::string name = GetFieldString(message_type, "name"); std::string full_name = absl::StrCat(parent_name, ".", name); Descriptor descriptor(full_name, message_type); { absl::MutexLock lock(&mutex()); descriptors()[full_name] = descriptor; } auto nested_types = GetFieldValues(message_type, "nested_type"); for (auto& nested : *nested_types) { Register(nested, full_name); } auto exts = GetFieldValues(message_type, "extension"); for (auto& extension : *exts) { FieldDescriptor field(extension); std::string extendee = GetFieldString(extension, "extendee"); { absl::MutexLock lock(&mutex()); extensions()[CanonicalTypeName(extendee)].push_back(field); } } } const Descriptor* OptionsRegistry::GetProtobufDescriptor( const std::string& type_name) { if (descriptors().count("proto2.DescriptorProto") == 0) { RegisterDescriptorProtos(descriptors()); } absl::ReaderMutexLock lock(&mutex()); auto it = descriptors().find(CanonicalTypeName(type_name)); return (it == descriptors().end()) ? nullptr : &it->second; } void OptionsRegistry::FindAllExtensions( absl::string_view extendee, std::vector* result) { absl::ReaderMutexLock lock(&mutex()); result->clear(); if (extensions().count(extendee) > 0) { for (const FieldDescriptor& field : extensions().at(extendee)) { result->push_back(&field); } } } absl::flat_hash_map& OptionsRegistry::descriptors() { static auto* descriptors = new absl::flat_hash_map(); return *descriptors; } absl::flat_hash_map>& OptionsRegistry::extensions() { static auto* extensions = new absl::flat_hash_map>(); return *extensions; } absl::Mutex& OptionsRegistry::mutex() { static auto* mutex = new absl::Mutex(); return *mutex; } Descriptor::Descriptor(const std::string& full_name, const FieldData& descriptor_proto) : full_name_(full_name) { auto fields = GetFieldValues(descriptor_proto, "field"); for (const auto& field : *fields) { FieldDescriptor f(field); fields_[f.name()] = f; } } Descriptor::Descriptor(const std::string& full_name, const std::vector& fields) : full_name_(full_name) { for (const auto& field : fields) { fields_[field.name()] = field; } } const std::string& Descriptor::full_name() const { return full_name_; } const FieldDescriptor* Descriptor::FindFieldByName( const std::string& name) const { auto it = fields_.find(name); return (it != fields_.end()) ? &it->second : nullptr; } FieldDescriptor::FieldDescriptor(const FieldData& field_proto) { name_ = GetFieldString(field_proto, "name"); number_ = GetFieldValues(field_proto, "number")->front().int32_value(); type_ = (FieldType)GetFieldValues(field_proto, "type")->front().enum_value(); message_type_ = CanonicalTypeName(GetFieldString(field_proto, "type_name")); } FieldDescriptor::FieldDescriptor(std::string name, int number, FieldType type, std::string message_type) : name_(name), number_(number), type_(type), message_type_(message_type) {} const std::string& FieldDescriptor::name() const { return name_; } int FieldDescriptor::number() const { return number_; } FieldType FieldDescriptor::type() const { return type_; } const Descriptor* FieldDescriptor::message_type() const { return OptionsRegistry::GetProtobufDescriptor(message_type_); } } // namespace tool } // namespace mediapipe