blob: 944280c0122dd96f41b5ba09a765f7044065d2f6 [file] [log] [blame]
// 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