• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // Author: kenton@google.com (Kenton Varda)
32 //  Based on original Protocol Buffers design by
33 //  Sanjay Ghemawat, Jeff Dean, and others.
34 
35 #include <google/protobuf/descriptor_database.h>
36 
37 #include <set>
38 
39 #include <google/protobuf/descriptor.pb.h>
40 #include <google/protobuf/stubs/strutil.h>
41 
42 #include <google/protobuf/stubs/map_util.h>
43 #include <google/protobuf/stubs/stl_util.h>
44 
45 namespace google {
46 namespace protobuf {
47 
48 namespace {
RecordMessageNames(const DescriptorProto & desc_proto,const std::string & prefix,std::set<std::string> * output)49 void RecordMessageNames(const DescriptorProto& desc_proto,
50                         const std::string& prefix,
51                         std::set<std::string>* output) {
52   GOOGLE_CHECK(desc_proto.has_name());
53   std::string full_name = prefix.empty()
54                               ? desc_proto.name()
55                               : StrCat(prefix, ".", desc_proto.name());
56   output->insert(full_name);
57 
58   for (const auto& d : desc_proto.nested_type()) {
59     RecordMessageNames(d, full_name, output);
60   }
61 }
62 
RecordMessageNames(const FileDescriptorProto & file_proto,std::set<std::string> * output)63 void RecordMessageNames(const FileDescriptorProto& file_proto,
64                         std::set<std::string>* output) {
65   for (const auto& d : file_proto.message_type()) {
66     RecordMessageNames(d, file_proto.package(), output);
67   }
68 }
69 
70 template <typename Fn>
ForAllFileProtos(DescriptorDatabase * db,Fn callback,std::vector<std::string> * output)71 bool ForAllFileProtos(DescriptorDatabase* db, Fn callback,
72                       std::vector<std::string>* output) {
73   std::vector<std::string> file_names;
74   if (!db->FindAllFileNames(&file_names)) {
75     return false;
76   }
77   std::set<std::string> set;
78   FileDescriptorProto file_proto;
79   for (const auto& f : file_names) {
80     file_proto.Clear();
81     if (!db->FindFileByName(f, &file_proto)) {
82       GOOGLE_LOG(ERROR) << "File not found in database (unexpected): " << f;
83       return false;
84     }
85     callback(file_proto, &set);
86   }
87   output->insert(output->end(), set.begin(), set.end());
88   return true;
89 }
90 }  // namespace
91 
~DescriptorDatabase()92 DescriptorDatabase::~DescriptorDatabase() {}
93 
FindAllPackageNames(std::vector<std::string> * output)94 bool DescriptorDatabase::FindAllPackageNames(std::vector<std::string>* output) {
95   return ForAllFileProtos(
96       this,
97       [](const FileDescriptorProto& file_proto, std::set<std::string>* set) {
98         set->insert(file_proto.package());
99       },
100       output);
101 }
102 
FindAllMessageNames(std::vector<std::string> * output)103 bool DescriptorDatabase::FindAllMessageNames(std::vector<std::string>* output) {
104   return ForAllFileProtos(
105       this,
106       [](const FileDescriptorProto& file_proto, std::set<std::string>* set) {
107         RecordMessageNames(file_proto, set);
108       },
109       output);
110 }
111 
112 // ===================================================================
113 
114 template <typename Value>
AddFile(const FileDescriptorProto & file,Value value)115 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddFile(
116     const FileDescriptorProto& file, Value value) {
117   if (!InsertIfNotPresent(&by_name_, file.name(), value)) {
118     GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
119     return false;
120   }
121 
122   // We must be careful here -- calling file.package() if file.has_package() is
123   // false could access an uninitialized static-storage variable if we are being
124   // run at startup time.
125   std::string path = file.has_package() ? file.package() : std::string();
126   if (!path.empty()) path += '.';
127 
128   for (int i = 0; i < file.message_type_size(); i++) {
129     if (!AddSymbol(path + file.message_type(i).name(), value)) return false;
130     if (!AddNestedExtensions(file.name(), file.message_type(i), value))
131       return false;
132   }
133   for (int i = 0; i < file.enum_type_size(); i++) {
134     if (!AddSymbol(path + file.enum_type(i).name(), value)) return false;
135   }
136   for (int i = 0; i < file.extension_size(); i++) {
137     if (!AddSymbol(path + file.extension(i).name(), value)) return false;
138     if (!AddExtension(file.name(), file.extension(i), value)) return false;
139   }
140   for (int i = 0; i < file.service_size(); i++) {
141     if (!AddSymbol(path + file.service(i).name(), value)) return false;
142   }
143 
144   return true;
145 }
146 
147 template <typename Value>
AddSymbol(const std::string & name,Value value)148 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
149     const std::string& name, Value value) {
150   // We need to make sure not to violate our map invariant.
151 
152   // If the symbol name is invalid it could break our lookup algorithm (which
153   // relies on the fact that '.' sorts before all other characters that are
154   // valid in symbol names).
155   if (!ValidateSymbolName(name)) {
156     GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name;
157     return false;
158   }
159 
160   // Try to look up the symbol to make sure a super-symbol doesn't already
161   // exist.
162   typename std::map<std::string, Value>::iterator iter =
163       FindLastLessOrEqual(name);
164 
165   if (iter == by_symbol_.end()) {
166     // Apparently the map is currently empty.  Just insert and be done with it.
167     by_symbol_.insert(
168         typename std::map<std::string, Value>::value_type(name, value));
169     return true;
170   }
171 
172   if (IsSubSymbol(iter->first, name)) {
173     GOOGLE_LOG(ERROR) << "Symbol name \"" << name
174                << "\" conflicts with the existing "
175                   "symbol \""
176                << iter->first << "\".";
177     return false;
178   }
179 
180   // OK, that worked.  Now we have to make sure that no symbol in the map is
181   // a sub-symbol of the one we are inserting.  The only symbol which could
182   // be so is the first symbol that is greater than the new symbol.  Since
183   // |iter| points at the last symbol that is less than or equal, we just have
184   // to increment it.
185   ++iter;
186 
187   if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) {
188     GOOGLE_LOG(ERROR) << "Symbol name \"" << name
189                << "\" conflicts with the existing "
190                   "symbol \""
191                << iter->first << "\".";
192     return false;
193   }
194 
195   // OK, no conflicts.
196 
197   // Insert the new symbol using the iterator as a hint, the new entry will
198   // appear immediately before the one the iterator is pointing at.
199   by_symbol_.insert(
200       iter, typename std::map<std::string, Value>::value_type(name, value));
201 
202   return true;
203 }
204 
205 template <typename Value>
AddNestedExtensions(const std::string & filename,const DescriptorProto & message_type,Value value)206 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddNestedExtensions(
207     const std::string& filename, const DescriptorProto& message_type,
208     Value value) {
209   for (int i = 0; i < message_type.nested_type_size(); i++) {
210     if (!AddNestedExtensions(filename, message_type.nested_type(i), value))
211       return false;
212   }
213   for (int i = 0; i < message_type.extension_size(); i++) {
214     if (!AddExtension(filename, message_type.extension(i), value)) return false;
215   }
216   return true;
217 }
218 
219 template <typename Value>
AddExtension(const std::string & filename,const FieldDescriptorProto & field,Value value)220 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
221     const std::string& filename, const FieldDescriptorProto& field,
222     Value value) {
223   if (!field.extendee().empty() && field.extendee()[0] == '.') {
224     // The extension is fully-qualified.  We can use it as a lookup key in
225     // the by_symbol_ table.
226     if (!InsertIfNotPresent(
227             &by_extension_,
228             std::make_pair(field.extendee().substr(1), field.number()),
229             value)) {
230       GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
231                     "extend "
232                  << field.extendee() << " { " << field.name() << " = "
233                  << field.number() << " } from:" << filename;
234       return false;
235     }
236   } else {
237     // Not fully-qualified.  We can't really do anything here, unfortunately.
238     // We don't consider this an error, though, because the descriptor is
239     // valid.
240   }
241   return true;
242 }
243 
244 template <typename Value>
FindFile(const std::string & filename)245 Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
246     const std::string& filename) {
247   return FindWithDefault(by_name_, filename, Value());
248 }
249 
250 template <typename Value>
FindSymbol(const std::string & name)251 Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindSymbol(
252     const std::string& name) {
253   typename std::map<std::string, Value>::iterator iter =
254       FindLastLessOrEqual(name);
255 
256   return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name))
257              ? iter->second
258              : Value();
259 }
260 
261 template <typename Value>
FindExtension(const std::string & containing_type,int field_number)262 Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
263     const std::string& containing_type, int field_number) {
264   return FindWithDefault(
265       by_extension_, std::make_pair(containing_type, field_number), Value());
266 }
267 
268 template <typename Value>
FindAllExtensionNumbers(const std::string & containing_type,std::vector<int> * output)269 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
270     const std::string& containing_type, std::vector<int>* output) {
271   typename std::map<std::pair<std::string, int>, Value>::const_iterator it =
272       by_extension_.lower_bound(std::make_pair(containing_type, 0));
273   bool success = false;
274 
275   for (; it != by_extension_.end() && it->first.first == containing_type;
276        ++it) {
277     output->push_back(it->first.second);
278     success = true;
279   }
280 
281   return success;
282 }
283 
284 template <typename Value>
FindAllFileNames(std::vector<std::string> * output)285 void SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllFileNames(
286     std::vector<std::string>* output) {
287   output->resize(by_name_.size());
288   int i = 0;
289   for (const auto& kv : by_name_) {
290     (*output)[i] = kv.first;
291     i++;
292   }
293 }
294 
295 template <typename Value>
296 typename std::map<std::string, Value>::iterator
FindLastLessOrEqual(const std::string & name)297 SimpleDescriptorDatabase::DescriptorIndex<Value>::FindLastLessOrEqual(
298     const std::string& name) {
299   // Find the last key in the map which sorts less than or equal to the
300   // symbol name.  Since upper_bound() returns the *first* key that sorts
301   // *greater* than the input, we want the element immediately before that.
302   typename std::map<std::string, Value>::iterator iter =
303       by_symbol_.upper_bound(name);
304   if (iter != by_symbol_.begin()) --iter;
305   return iter;
306 }
307 
308 template <typename Value>
IsSubSymbol(const std::string & sub_symbol,const std::string & super_symbol)309 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::IsSubSymbol(
310     const std::string& sub_symbol, const std::string& super_symbol) {
311   return sub_symbol == super_symbol ||
312          (HasPrefixString(super_symbol, sub_symbol) &&
313           super_symbol[sub_symbol.size()] == '.');
314 }
315 
316 template <typename Value>
ValidateSymbolName(const std::string & name)317 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::ValidateSymbolName(
318     const std::string& name) {
319   for (int i = 0; i < name.size(); i++) {
320     // I don't trust ctype.h due to locales.  :(
321     if (name[i] != '.' && name[i] != '_' && (name[i] < '0' || name[i] > '9') &&
322         (name[i] < 'A' || name[i] > 'Z') && (name[i] < 'a' || name[i] > 'z')) {
323       return false;
324     }
325   }
326   return true;
327 }
328 
329 // -------------------------------------------------------------------
330 
SimpleDescriptorDatabase()331 SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
~SimpleDescriptorDatabase()332 SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
333   STLDeleteElements(&files_to_delete_);
334 }
335 
Add(const FileDescriptorProto & file)336 bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
337   FileDescriptorProto* new_file = new FileDescriptorProto;
338   new_file->CopyFrom(file);
339   return AddAndOwn(new_file);
340 }
341 
AddAndOwn(const FileDescriptorProto * file)342 bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
343   files_to_delete_.push_back(file);
344   return index_.AddFile(*file, file);
345 }
346 
FindFileByName(const std::string & filename,FileDescriptorProto * output)347 bool SimpleDescriptorDatabase::FindFileByName(const std::string& filename,
348                                               FileDescriptorProto* output) {
349   return MaybeCopy(index_.FindFile(filename), output);
350 }
351 
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)352 bool SimpleDescriptorDatabase::FindFileContainingSymbol(
353     const std::string& symbol_name, FileDescriptorProto* output) {
354   return MaybeCopy(index_.FindSymbol(symbol_name), output);
355 }
356 
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)357 bool SimpleDescriptorDatabase::FindFileContainingExtension(
358     const std::string& containing_type, int field_number,
359     FileDescriptorProto* output) {
360   return MaybeCopy(index_.FindExtension(containing_type, field_number), output);
361 }
362 
FindAllExtensionNumbers(const std::string & extendee_type,std::vector<int> * output)363 bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
364     const std::string& extendee_type, std::vector<int>* output) {
365   return index_.FindAllExtensionNumbers(extendee_type, output);
366 }
367 
368 
FindAllFileNames(std::vector<std::string> * output)369 bool SimpleDescriptorDatabase::FindAllFileNames(
370     std::vector<std::string>* output) {
371   index_.FindAllFileNames(output);
372   return true;
373 }
374 
MaybeCopy(const FileDescriptorProto * file,FileDescriptorProto * output)375 bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
376                                          FileDescriptorProto* output) {
377   if (file == NULL) return false;
378   output->CopyFrom(*file);
379   return true;
380 }
381 
382 // -------------------------------------------------------------------
383 
EncodedDescriptorDatabase()384 EncodedDescriptorDatabase::EncodedDescriptorDatabase() {}
~EncodedDescriptorDatabase()385 EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
386   for (int i = 0; i < files_to_delete_.size(); i++) {
387     operator delete(files_to_delete_[i]);
388   }
389 }
390 
Add(const void * encoded_file_descriptor,int size)391 bool EncodedDescriptorDatabase::Add(const void* encoded_file_descriptor,
392                                     int size) {
393   FileDescriptorProto file;
394   if (file.ParseFromArray(encoded_file_descriptor, size)) {
395     return index_.AddFile(file, std::make_pair(encoded_file_descriptor, size));
396   } else {
397     GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
398                   "EncodedDescriptorDatabase::Add().";
399     return false;
400   }
401 }
402 
AddCopy(const void * encoded_file_descriptor,int size)403 bool EncodedDescriptorDatabase::AddCopy(const void* encoded_file_descriptor,
404                                         int size) {
405   void* copy = operator new(size);
406   memcpy(copy, encoded_file_descriptor, size);
407   files_to_delete_.push_back(copy);
408   return Add(copy, size);
409 }
410 
FindFileByName(const std::string & filename,FileDescriptorProto * output)411 bool EncodedDescriptorDatabase::FindFileByName(const std::string& filename,
412                                                FileDescriptorProto* output) {
413   return MaybeParse(index_.FindFile(filename), output);
414 }
415 
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)416 bool EncodedDescriptorDatabase::FindFileContainingSymbol(
417     const std::string& symbol_name, FileDescriptorProto* output) {
418   return MaybeParse(index_.FindSymbol(symbol_name), output);
419 }
420 
FindNameOfFileContainingSymbol(const std::string & symbol_name,std::string * output)421 bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol(
422     const std::string& symbol_name, std::string* output) {
423   std::pair<const void*, int> encoded_file = index_.FindSymbol(symbol_name);
424   if (encoded_file.first == NULL) return false;
425 
426   // Optimization:  The name should be the first field in the encoded message.
427   //   Try to just read it directly.
428   io::CodedInputStream input(reinterpret_cast<const uint8*>(encoded_file.first),
429                              encoded_file.second);
430 
431   const uint32 kNameTag = internal::WireFormatLite::MakeTag(
432       FileDescriptorProto::kNameFieldNumber,
433       internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
434 
435   if (input.ReadTagNoLastTag() == kNameTag) {
436     // Success!
437     return internal::WireFormatLite::ReadString(&input, output);
438   } else {
439     // Slow path.  Parse whole message.
440     FileDescriptorProto file_proto;
441     if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) {
442       return false;
443     }
444     *output = file_proto.name();
445     return true;
446   }
447 }
448 
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)449 bool EncodedDescriptorDatabase::FindFileContainingExtension(
450     const std::string& containing_type, int field_number,
451     FileDescriptorProto* output) {
452   return MaybeParse(index_.FindExtension(containing_type, field_number),
453                     output);
454 }
455 
FindAllExtensionNumbers(const std::string & extendee_type,std::vector<int> * output)456 bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
457     const std::string& extendee_type, std::vector<int>* output) {
458   return index_.FindAllExtensionNumbers(extendee_type, output);
459 }
460 
FindAllFileNames(std::vector<std::string> * output)461 bool EncodedDescriptorDatabase::FindAllFileNames(
462     std::vector<std::string>* output) {
463   index_.FindAllFileNames(output);
464   return true;
465 }
466 
MaybeParse(std::pair<const void *,int> encoded_file,FileDescriptorProto * output)467 bool EncodedDescriptorDatabase::MaybeParse(
468     std::pair<const void*, int> encoded_file, FileDescriptorProto* output) {
469   if (encoded_file.first == NULL) return false;
470   return output->ParseFromArray(encoded_file.first, encoded_file.second);
471 }
472 
473 // ===================================================================
474 
DescriptorPoolDatabase(const DescriptorPool & pool)475 DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
476     : pool_(pool) {}
~DescriptorPoolDatabase()477 DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
478 
FindFileByName(const std::string & filename,FileDescriptorProto * output)479 bool DescriptorPoolDatabase::FindFileByName(const std::string& filename,
480                                             FileDescriptorProto* output) {
481   const FileDescriptor* file = pool_.FindFileByName(filename);
482   if (file == NULL) return false;
483   output->Clear();
484   file->CopyTo(output);
485   return true;
486 }
487 
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)488 bool DescriptorPoolDatabase::FindFileContainingSymbol(
489     const std::string& symbol_name, FileDescriptorProto* output) {
490   const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
491   if (file == NULL) return false;
492   output->Clear();
493   file->CopyTo(output);
494   return true;
495 }
496 
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)497 bool DescriptorPoolDatabase::FindFileContainingExtension(
498     const std::string& containing_type, int field_number,
499     FileDescriptorProto* output) {
500   const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
501   if (extendee == NULL) return false;
502 
503   const FieldDescriptor* extension =
504       pool_.FindExtensionByNumber(extendee, field_number);
505   if (extension == NULL) return false;
506 
507   output->Clear();
508   extension->file()->CopyTo(output);
509   return true;
510 }
511 
FindAllExtensionNumbers(const std::string & extendee_type,std::vector<int> * output)512 bool DescriptorPoolDatabase::FindAllExtensionNumbers(
513     const std::string& extendee_type, std::vector<int>* output) {
514   const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type);
515   if (extendee == NULL) return false;
516 
517   std::vector<const FieldDescriptor*> extensions;
518   pool_.FindAllExtensions(extendee, &extensions);
519 
520   for (int i = 0; i < extensions.size(); ++i) {
521     output->push_back(extensions[i]->number());
522   }
523 
524   return true;
525 }
526 
527 // ===================================================================
528 
MergedDescriptorDatabase(DescriptorDatabase * source1,DescriptorDatabase * source2)529 MergedDescriptorDatabase::MergedDescriptorDatabase(
530     DescriptorDatabase* source1, DescriptorDatabase* source2) {
531   sources_.push_back(source1);
532   sources_.push_back(source2);
533 }
MergedDescriptorDatabase(const std::vector<DescriptorDatabase * > & sources)534 MergedDescriptorDatabase::MergedDescriptorDatabase(
535     const std::vector<DescriptorDatabase*>& sources)
536     : sources_(sources) {}
~MergedDescriptorDatabase()537 MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
538 
FindFileByName(const std::string & filename,FileDescriptorProto * output)539 bool MergedDescriptorDatabase::FindFileByName(const std::string& filename,
540                                               FileDescriptorProto* output) {
541   for (int i = 0; i < sources_.size(); i++) {
542     if (sources_[i]->FindFileByName(filename, output)) {
543       return true;
544     }
545   }
546   return false;
547 }
548 
FindFileContainingSymbol(const std::string & symbol_name,FileDescriptorProto * output)549 bool MergedDescriptorDatabase::FindFileContainingSymbol(
550     const std::string& symbol_name, FileDescriptorProto* output) {
551   for (int i = 0; i < sources_.size(); i++) {
552     if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) {
553       // The symbol was found in source i.  However, if one of the previous
554       // sources defines a file with the same name (which presumably doesn't
555       // contain the symbol, since it wasn't found in that source), then we
556       // must hide it from the caller.
557       FileDescriptorProto temp;
558       for (int j = 0; j < i; j++) {
559         if (sources_[j]->FindFileByName(output->name(), &temp)) {
560           // Found conflicting file in a previous source.
561           return false;
562         }
563       }
564       return true;
565     }
566   }
567   return false;
568 }
569 
FindFileContainingExtension(const std::string & containing_type,int field_number,FileDescriptorProto * output)570 bool MergedDescriptorDatabase::FindFileContainingExtension(
571     const std::string& containing_type, int field_number,
572     FileDescriptorProto* output) {
573   for (int i = 0; i < sources_.size(); i++) {
574     if (sources_[i]->FindFileContainingExtension(containing_type, field_number,
575                                                  output)) {
576       // The symbol was found in source i.  However, if one of the previous
577       // sources defines a file with the same name (which presumably doesn't
578       // contain the symbol, since it wasn't found in that source), then we
579       // must hide it from the caller.
580       FileDescriptorProto temp;
581       for (int j = 0; j < i; j++) {
582         if (sources_[j]->FindFileByName(output->name(), &temp)) {
583           // Found conflicting file in a previous source.
584           return false;
585         }
586       }
587       return true;
588     }
589   }
590   return false;
591 }
592 
FindAllExtensionNumbers(const std::string & extendee_type,std::vector<int> * output)593 bool MergedDescriptorDatabase::FindAllExtensionNumbers(
594     const std::string& extendee_type, std::vector<int>* output) {
595   std::set<int> merged_results;
596   std::vector<int> results;
597   bool success = false;
598 
599   for (int i = 0; i < sources_.size(); i++) {
600     if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
601       std::copy(results.begin(), results.end(),
602                 std::insert_iterator<std::set<int> >(merged_results,
603                                                      merged_results.begin()));
604       success = true;
605     }
606     results.clear();
607   }
608 
609   std::copy(merged_results.begin(), merged_results.end(),
610             std::insert_iterator<std::vector<int> >(*output, output->end()));
611 
612   return success;
613 }
614 
615 
616 }  // namespace protobuf
617 }  // namespace google
618