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(&by_extension_,
157 make_pair(field.extendee().substr(1),
158 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(by_extension_,
193 make_pair(containing_type, field_number),
194 Value());
195 }
196
197 template <typename Value>
FindAllExtensionNumbers(const string & containing_type,vector<int> * output)198 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
199 const string& containing_type,
200 vector<int>* output) {
201 typename map<pair<string, int>, Value >::const_iterator it =
202 by_extension_.lower_bound(make_pair(containing_type, 0));
203 bool success = false;
204
205 for (; it != by_extension_.end() && it->first.first == containing_type;
206 ++it) {
207 output->push_back(it->first.second);
208 success = true;
209 }
210
211 return success;
212 }
213
214 template <typename Value>
215 typename map<string, Value>::iterator
FindLastLessOrEqual(const string & name)216 SimpleDescriptorDatabase::DescriptorIndex<Value>::FindLastLessOrEqual(
217 const string& name) {
218 // Find the last key in the map which sorts less than or equal to the
219 // symbol name. Since upper_bound() returns the *first* key that sorts
220 // *greater* than the input, we want the element immediately before that.
221 typename map<string, Value>::iterator iter = by_symbol_.upper_bound(name);
222 if (iter != by_symbol_.begin()) --iter;
223 return iter;
224 }
225
226 template <typename Value>
IsSubSymbol(const string & sub_symbol,const string & super_symbol)227 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::IsSubSymbol(
228 const string& sub_symbol, const string& super_symbol) {
229 return sub_symbol == super_symbol ||
230 (HasPrefixString(super_symbol, sub_symbol) &&
231 super_symbol[sub_symbol.size()] == '.');
232 }
233
234 template <typename Value>
ValidateSymbolName(const string & name)235 bool SimpleDescriptorDatabase::DescriptorIndex<Value>::ValidateSymbolName(
236 const string& name) {
237 for (int i = 0; i < name.size(); i++) {
238 // I don't trust ctype.h due to locales. :(
239 if (name[i] != '.' && name[i] != '_' &&
240 (name[i] < '0' || name[i] > '9') &&
241 (name[i] < 'A' || name[i] > 'Z') &&
242 (name[i] < 'a' || name[i] > 'z')) {
243 return false;
244 }
245 }
246 return true;
247 }
248
249 // -------------------------------------------------------------------
250
SimpleDescriptorDatabase()251 SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
~SimpleDescriptorDatabase()252 SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
253 STLDeleteElements(&files_to_delete_);
254 }
255
Add(const FileDescriptorProto & file)256 bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
257 FileDescriptorProto* new_file = new FileDescriptorProto;
258 new_file->CopyFrom(file);
259 return AddAndOwn(new_file);
260 }
261
AddAndOwn(const FileDescriptorProto * file)262 bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
263 files_to_delete_.push_back(file);
264 return index_.AddFile(*file, file);
265 }
266
FindFileByName(const string & filename,FileDescriptorProto * output)267 bool SimpleDescriptorDatabase::FindFileByName(
268 const string& filename,
269 FileDescriptorProto* output) {
270 return MaybeCopy(index_.FindFile(filename), output);
271 }
272
FindFileContainingSymbol(const string & symbol_name,FileDescriptorProto * output)273 bool SimpleDescriptorDatabase::FindFileContainingSymbol(
274 const string& symbol_name,
275 FileDescriptorProto* output) {
276 return MaybeCopy(index_.FindSymbol(symbol_name), output);
277 }
278
FindFileContainingExtension(const string & containing_type,int field_number,FileDescriptorProto * output)279 bool SimpleDescriptorDatabase::FindFileContainingExtension(
280 const string& containing_type,
281 int field_number,
282 FileDescriptorProto* output) {
283 return MaybeCopy(index_.FindExtension(containing_type, field_number), output);
284 }
285
FindAllExtensionNumbers(const string & extendee_type,vector<int> * output)286 bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
287 const string& extendee_type,
288 vector<int>* output) {
289 return index_.FindAllExtensionNumbers(extendee_type, output);
290 }
291
292
MaybeCopy(const FileDescriptorProto * file,FileDescriptorProto * output)293 bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
294 FileDescriptorProto* output) {
295 if (file == NULL) return false;
296 output->CopyFrom(*file);
297 return true;
298 }
299
300 // -------------------------------------------------------------------
301
EncodedDescriptorDatabase()302 EncodedDescriptorDatabase::EncodedDescriptorDatabase() {}
~EncodedDescriptorDatabase()303 EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
304 for (int i = 0; i < files_to_delete_.size(); i++) {
305 operator delete(files_to_delete_[i]);
306 }
307 }
308
Add(const void * encoded_file_descriptor,int size)309 bool EncodedDescriptorDatabase::Add(
310 const void* encoded_file_descriptor, int size) {
311 FileDescriptorProto file;
312 if (file.ParseFromArray(encoded_file_descriptor, size)) {
313 return index_.AddFile(file, make_pair(encoded_file_descriptor, size));
314 } else {
315 GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
316 "EncodedDescriptorDatabase::Add().";
317 return false;
318 }
319 }
320
AddCopy(const void * encoded_file_descriptor,int size)321 bool EncodedDescriptorDatabase::AddCopy(
322 const void* encoded_file_descriptor, int size) {
323 void* copy = operator new(size);
324 memcpy(copy, encoded_file_descriptor, size);
325 files_to_delete_.push_back(copy);
326 return Add(copy, size);
327 }
328
FindFileByName(const string & filename,FileDescriptorProto * output)329 bool EncodedDescriptorDatabase::FindFileByName(
330 const string& filename,
331 FileDescriptorProto* output) {
332 return MaybeParse(index_.FindFile(filename), output);
333 }
334
FindFileContainingSymbol(const string & symbol_name,FileDescriptorProto * output)335 bool EncodedDescriptorDatabase::FindFileContainingSymbol(
336 const string& symbol_name,
337 FileDescriptorProto* output) {
338 return MaybeParse(index_.FindSymbol(symbol_name), output);
339 }
340
FindNameOfFileContainingSymbol(const string & symbol_name,string * output)341 bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol(
342 const string& symbol_name,
343 string* output) {
344 pair<const void*, int> encoded_file = index_.FindSymbol(symbol_name);
345 if (encoded_file.first == NULL) return false;
346
347 // Optimization: The name should be the first field in the encoded message.
348 // Try to just read it directly.
349 io::CodedInputStream input(reinterpret_cast<const uint8*>(encoded_file.first),
350 encoded_file.second);
351
352 const uint32 kNameTag = internal::WireFormatLite::MakeTag(
353 FileDescriptorProto::kNameFieldNumber,
354 internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
355
356 if (input.ReadTag() == kNameTag) {
357 // Success!
358 return internal::WireFormatLite::ReadString(&input, output);
359 } else {
360 // Slow path. Parse whole message.
361 FileDescriptorProto file_proto;
362 if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) {
363 return false;
364 }
365 *output = file_proto.name();
366 return true;
367 }
368 }
369
FindFileContainingExtension(const string & containing_type,int field_number,FileDescriptorProto * output)370 bool EncodedDescriptorDatabase::FindFileContainingExtension(
371 const string& containing_type,
372 int field_number,
373 FileDescriptorProto* output) {
374 return MaybeParse(index_.FindExtension(containing_type, field_number),
375 output);
376 }
377
FindAllExtensionNumbers(const string & extendee_type,vector<int> * output)378 bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
379 const string& extendee_type,
380 vector<int>* output) {
381 return index_.FindAllExtensionNumbers(extendee_type, output);
382 }
383
MaybeParse(pair<const void *,int> encoded_file,FileDescriptorProto * output)384 bool EncodedDescriptorDatabase::MaybeParse(
385 pair<const void*, int> encoded_file,
386 FileDescriptorProto* output) {
387 if (encoded_file.first == NULL) return false;
388 return output->ParseFromArray(encoded_file.first, encoded_file.second);
389 }
390
391 // ===================================================================
392
DescriptorPoolDatabase(const DescriptorPool & pool)393 DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
394 : pool_(pool) {}
~DescriptorPoolDatabase()395 DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
396
FindFileByName(const string & filename,FileDescriptorProto * output)397 bool DescriptorPoolDatabase::FindFileByName(
398 const string& filename,
399 FileDescriptorProto* output) {
400 const FileDescriptor* file = pool_.FindFileByName(filename);
401 if (file == NULL) return false;
402 output->Clear();
403 file->CopyTo(output);
404 return true;
405 }
406
FindFileContainingSymbol(const string & symbol_name,FileDescriptorProto * output)407 bool DescriptorPoolDatabase::FindFileContainingSymbol(
408 const string& symbol_name,
409 FileDescriptorProto* output) {
410 const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
411 if (file == NULL) return false;
412 output->Clear();
413 file->CopyTo(output);
414 return true;
415 }
416
FindFileContainingExtension(const string & containing_type,int field_number,FileDescriptorProto * output)417 bool DescriptorPoolDatabase::FindFileContainingExtension(
418 const string& containing_type,
419 int field_number,
420 FileDescriptorProto* output) {
421 const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
422 if (extendee == NULL) return false;
423
424 const FieldDescriptor* extension =
425 pool_.FindExtensionByNumber(extendee, field_number);
426 if (extension == NULL) return false;
427
428 output->Clear();
429 extension->file()->CopyTo(output);
430 return true;
431 }
432
FindAllExtensionNumbers(const string & extendee_type,vector<int> * output)433 bool DescriptorPoolDatabase::FindAllExtensionNumbers(
434 const string& extendee_type,
435 vector<int>* output) {
436 const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type);
437 if (extendee == NULL) return false;
438
439 vector<const FieldDescriptor*> extensions;
440 pool_.FindAllExtensions(extendee, &extensions);
441
442 for (int i = 0; i < extensions.size(); ++i) {
443 output->push_back(extensions[i]->number());
444 }
445
446 return true;
447 }
448
449 // ===================================================================
450
MergedDescriptorDatabase(DescriptorDatabase * source1,DescriptorDatabase * source2)451 MergedDescriptorDatabase::MergedDescriptorDatabase(
452 DescriptorDatabase* source1,
453 DescriptorDatabase* source2) {
454 sources_.push_back(source1);
455 sources_.push_back(source2);
456 }
MergedDescriptorDatabase(const vector<DescriptorDatabase * > & sources)457 MergedDescriptorDatabase::MergedDescriptorDatabase(
458 const vector<DescriptorDatabase*>& sources)
459 : sources_(sources) {}
~MergedDescriptorDatabase()460 MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
461
FindFileByName(const string & filename,FileDescriptorProto * output)462 bool MergedDescriptorDatabase::FindFileByName(
463 const string& filename,
464 FileDescriptorProto* output) {
465 for (int i = 0; i < sources_.size(); i++) {
466 if (sources_[i]->FindFileByName(filename, output)) {
467 return true;
468 }
469 }
470 return false;
471 }
472
FindFileContainingSymbol(const string & symbol_name,FileDescriptorProto * output)473 bool MergedDescriptorDatabase::FindFileContainingSymbol(
474 const string& symbol_name,
475 FileDescriptorProto* output) {
476 for (int i = 0; i < sources_.size(); i++) {
477 if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) {
478 // The symbol was found in source i. However, if one of the previous
479 // sources defines a file with the same name (which presumably doesn't
480 // contain the symbol, since it wasn't found in that source), then we
481 // must hide it from the caller.
482 FileDescriptorProto temp;
483 for (int j = 0; j < i; j++) {
484 if (sources_[j]->FindFileByName(output->name(), &temp)) {
485 // Found conflicting file in a previous source.
486 return false;
487 }
488 }
489 return true;
490 }
491 }
492 return false;
493 }
494
FindFileContainingExtension(const string & containing_type,int field_number,FileDescriptorProto * output)495 bool MergedDescriptorDatabase::FindFileContainingExtension(
496 const string& containing_type,
497 int field_number,
498 FileDescriptorProto* output) {
499 for (int i = 0; i < sources_.size(); i++) {
500 if (sources_[i]->FindFileContainingExtension(
501 containing_type, field_number, output)) {
502 // The symbol was found in source i. However, if one of the previous
503 // sources defines a file with the same name (which presumably doesn't
504 // contain the symbol, since it wasn't found in that source), then we
505 // must hide it from the caller.
506 FileDescriptorProto temp;
507 for (int j = 0; j < i; j++) {
508 if (sources_[j]->FindFileByName(output->name(), &temp)) {
509 // Found conflicting file in a previous source.
510 return false;
511 }
512 }
513 return true;
514 }
515 }
516 return false;
517 }
518
FindAllExtensionNumbers(const string & extendee_type,vector<int> * output)519 bool MergedDescriptorDatabase::FindAllExtensionNumbers(
520 const string& extendee_type,
521 vector<int>* output) {
522 set<int> merged_results;
523 vector<int> results;
524 bool success = false;
525
526 for (int i = 0; i < sources_.size(); i++) {
527 if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
528 copy(results.begin(), results.end(),
529 insert_iterator<set<int> >(merged_results, merged_results.begin()));
530 success = true;
531 }
532 results.clear();
533 }
534
535 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