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