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