| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. |
| // http://code.google.com/p/protobuf/ |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // Author: kenton@google.com (Kenton Varda) |
| // Based on original Protocol Buffers design by |
| // Sanjay Ghemawat, Jeff Dean, and others. |
| |
| #include <google/protobuf/descriptor_database.h> |
| #include <google/protobuf/descriptor.pb.h> |
| #include <google/protobuf/stubs/stl_util-inl.h> |
| #include <google/protobuf/stubs/map-util.h> |
| |
| namespace google { |
| namespace protobuf { |
| |
| DescriptorDatabase::~DescriptorDatabase() {} |
| |
| // =================================================================== |
| |
| SimpleDescriptorDatabase::SimpleDescriptorDatabase() {} |
| SimpleDescriptorDatabase::~SimpleDescriptorDatabase() { |
| STLDeleteElements(&files_to_delete_); |
| } |
| |
| void SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) { |
| FileDescriptorProto* new_file = new FileDescriptorProto; |
| new_file->CopyFrom(file); |
| AddAndOwn(new_file); |
| } |
| |
| void SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) { |
| files_to_delete_.push_back(file); |
| InsertOrUpdate(&files_by_name_, file->name(), file); |
| |
| string path = file->package(); |
| if (!path.empty()) path += '.'; |
| |
| for (int i = 0; i < file->message_type_size(); i++) { |
| AddMessage(path, file->message_type(i), file); |
| } |
| for (int i = 0; i < file->enum_type_size(); i++) { |
| AddEnum(path, file->enum_type(i), file); |
| } |
| for (int i = 0; i < file->extension_size(); i++) { |
| AddField(path, file->extension(i), file); |
| } |
| for (int i = 0; i < file->service_size(); i++) { |
| AddService(path, file->service(i), file); |
| } |
| } |
| |
| void SimpleDescriptorDatabase::AddMessage( |
| const string& path, |
| const DescriptorProto& message_type, |
| const FileDescriptorProto* file) { |
| string full_name = path + message_type.name(); |
| InsertOrUpdate(&files_by_symbol_, full_name, file); |
| |
| string sub_path = full_name + '.'; |
| for (int i = 0; i < message_type.nested_type_size(); i++) { |
| AddMessage(sub_path, message_type.nested_type(i), file); |
| } |
| for (int i = 0; i < message_type.enum_type_size(); i++) { |
| AddEnum(sub_path, message_type.enum_type(i), file); |
| } |
| for (int i = 0; i < message_type.field_size(); i++) { |
| AddField(sub_path, message_type.field(i), file); |
| } |
| for (int i = 0; i < message_type.extension_size(); i++) { |
| AddField(sub_path, message_type.extension(i), file); |
| } |
| } |
| |
| void SimpleDescriptorDatabase::AddField( |
| const string& path, |
| const FieldDescriptorProto& field, |
| const FileDescriptorProto* file) { |
| string full_name = path + field.name(); |
| InsertOrUpdate(&files_by_symbol_, full_name, file); |
| |
| if (field.has_extendee()) { |
| // This field is an extension. |
| if (!field.extendee().empty() && field.extendee()[0] == '.') { |
| // The extension is fully-qualified. We can use it as a lookup key in |
| // the files_by_symbol_ table. |
| InsertOrUpdate(&files_by_extension_, |
| make_pair(field.extendee().substr(1), field.number()), |
| file); |
| } else { |
| // Not fully-qualified. We can't really do anything here, unfortunately. |
| } |
| } |
| } |
| |
| void SimpleDescriptorDatabase::AddEnum( |
| const string& path, |
| const EnumDescriptorProto& enum_type, |
| const FileDescriptorProto* file) { |
| string full_name = path + enum_type.name(); |
| InsertOrUpdate(&files_by_symbol_, full_name, file); |
| |
| string sub_path = full_name + '.'; |
| for (int i = 0; i < enum_type.value_size(); i++) { |
| InsertOrUpdate(&files_by_symbol_, |
| sub_path + enum_type.value(i).name(), |
| file); |
| } |
| } |
| |
| void SimpleDescriptorDatabase::AddService( |
| const string& path, |
| const ServiceDescriptorProto& service, |
| const FileDescriptorProto* file) { |
| string full_name = path + service.name(); |
| InsertOrUpdate(&files_by_symbol_, full_name, file); |
| |
| string sub_path = full_name + '.'; |
| for (int i = 0; i < service.method_size(); i++) { |
| InsertOrUpdate(&files_by_symbol_, |
| sub_path + service.method(i).name(), |
| file); |
| } |
| } |
| |
| bool SimpleDescriptorDatabase::FindFileByName( |
| const string& filename, |
| FileDescriptorProto* output) { |
| const FileDescriptorProto* result = FindPtrOrNull(files_by_name_, filename); |
| if (result == NULL) { |
| return false; |
| } else { |
| output->CopyFrom(*result); |
| return true; |
| } |
| } |
| |
| bool SimpleDescriptorDatabase::FindFileContainingSymbol( |
| const string& symbol_name, |
| FileDescriptorProto* output) { |
| const FileDescriptorProto* result = |
| FindPtrOrNull(files_by_symbol_, symbol_name); |
| if (result == NULL) { |
| return false; |
| } else { |
| output->CopyFrom(*result); |
| return true; |
| } |
| } |
| |
| bool SimpleDescriptorDatabase::FindFileContainingExtension( |
| const string& containing_type, |
| int field_number, |
| FileDescriptorProto* output) { |
| const FileDescriptorProto* result = |
| FindPtrOrNull(files_by_extension_, |
| make_pair(containing_type, field_number)); |
| if (result == NULL) { |
| return false; |
| } else { |
| output->CopyFrom(*result); |
| return true; |
| } |
| } |
| |
| // =================================================================== |
| |
| DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool) |
| : pool_(pool) {} |
| DescriptorPoolDatabase::~DescriptorPoolDatabase() {} |
| |
| bool DescriptorPoolDatabase::FindFileByName( |
| const string& filename, |
| FileDescriptorProto* output) { |
| const FileDescriptor* file = pool_.FindFileByName(filename); |
| if (file == NULL) return false; |
| output->Clear(); |
| file->CopyTo(output); |
| return true; |
| } |
| |
| bool DescriptorPoolDatabase::FindFileContainingSymbol( |
| const string& symbol_name, |
| FileDescriptorProto* output) { |
| const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name); |
| if (file == NULL) return false; |
| output->Clear(); |
| file->CopyTo(output); |
| return true; |
| } |
| |
| bool DescriptorPoolDatabase::FindFileContainingExtension( |
| const string& containing_type, |
| int field_number, |
| FileDescriptorProto* output) { |
| const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type); |
| if (extendee == NULL) return false; |
| |
| const FieldDescriptor* extension = |
| pool_.FindExtensionByNumber(extendee, field_number); |
| if (extension == NULL) return false; |
| |
| output->Clear(); |
| extension->file()->CopyTo(output); |
| return true; |
| } |
| |
| // =================================================================== |
| |
| MergedDescriptorDatabase::MergedDescriptorDatabase( |
| DescriptorDatabase* source1, |
| DescriptorDatabase* source2) { |
| sources_.push_back(source1); |
| sources_.push_back(source2); |
| } |
| MergedDescriptorDatabase::MergedDescriptorDatabase( |
| const vector<DescriptorDatabase*>& sources) |
| : sources_(sources) {} |
| MergedDescriptorDatabase::~MergedDescriptorDatabase() {} |
| |
| bool MergedDescriptorDatabase::FindFileByName( |
| const string& filename, |
| FileDescriptorProto* output) { |
| for (int i = 0; i < sources_.size(); i++) { |
| if (sources_[i]->FindFileByName(filename, output)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool MergedDescriptorDatabase::FindFileContainingSymbol( |
| const string& symbol_name, |
| FileDescriptorProto* output) { |
| for (int i = 0; i < sources_.size(); i++) { |
| if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) { |
| // The symbol was found in source i. However, if one of the previous |
| // sources defines a file with the same name (which presumably doesn't |
| // contain the symbol, since it wasn't found in that source), then we |
| // must hide it from the caller. |
| FileDescriptorProto temp; |
| for (int j = 0; j < i; j++) { |
| if (sources_[j]->FindFileByName(output->name(), &temp)) { |
| // Found conflicting file in a previous source. |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool MergedDescriptorDatabase::FindFileContainingExtension( |
| const string& containing_type, |
| int field_number, |
| FileDescriptorProto* output) { |
| for (int i = 0; i < sources_.size(); i++) { |
| if (sources_[i]->FindFileContainingExtension( |
| containing_type, field_number, output)) { |
| // The symbol was found in source i. However, if one of the previous |
| // sources defines a file with the same name (which presumably doesn't |
| // contain the symbol, since it wasn't found in that source), then we |
| // must hide it from the caller. |
| FileDescriptorProto temp; |
| for (int j = 0; j < i; j++) { |
| if (sources_[j]->FindFileByName(output->name(), &temp)) { |
| // Found conflicting file in a previous source. |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| } // namespace protobuf |
| } // namespace google |