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
45namespace google {
46namespace protobuf {
47
48DescriptorDatabase::~DescriptorDatabase() {}
49
50// ===================================================================
51
52template <typename Value>
53bool 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
85template <typename Value>
86bool 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
136template <typename Value>
137bool 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
149template <typename Value>
150bool 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
173template <typename Value>
174Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
175    const string& filename) {
176  return FindWithDefault(by_name_, filename, Value());
177}
178
179template <typename Value>
180Value 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
188template <typename Value>
189Value 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
197template <typename Value>
198bool 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
214template <typename Value>
215typename map<string, Value>::iterator
216SimpleDescriptorDatabase::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
226template <typename Value>
227bool 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
234template <typename Value>
235bool 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
251SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
252SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
253  STLDeleteElements(&files_to_delete_);
254}
255
256bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
257  FileDescriptorProto* new_file = new FileDescriptorProto;
258  new_file->CopyFrom(file);
259  return AddAndOwn(new_file);
260}
261
262bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
263  files_to_delete_.push_back(file);
264  return index_.AddFile(*file, file);
265}
266
267bool SimpleDescriptorDatabase::FindFileByName(
268    const string& filename,
269    FileDescriptorProto* output) {
270  return MaybeCopy(index_.FindFile(filename), output);
271}
272
273bool SimpleDescriptorDatabase::FindFileContainingSymbol(
274    const string& symbol_name,
275    FileDescriptorProto* output) {
276  return MaybeCopy(index_.FindSymbol(symbol_name), output);
277}
278
279bool 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
286bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
287    const string& extendee_type,
288    vector<int>* output) {
289  return index_.FindAllExtensionNumbers(extendee_type, output);
290}
291
292
293bool 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
302EncodedDescriptorDatabase::EncodedDescriptorDatabase() {}
303EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
304  for (int i = 0; i < files_to_delete_.size(); i++) {
305    operator delete(files_to_delete_[i]);
306  }
307}
308
309bool 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
321bool 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
329bool EncodedDescriptorDatabase::FindFileByName(
330    const string& filename,
331    FileDescriptorProto* output) {
332  return MaybeParse(index_.FindFile(filename), output);
333}
334
335bool EncodedDescriptorDatabase::FindFileContainingSymbol(
336    const string& symbol_name,
337    FileDescriptorProto* output) {
338  return MaybeParse(index_.FindSymbol(symbol_name), output);
339}
340
341bool 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
370bool 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
378bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
379    const string& extendee_type,
380    vector<int>* output) {
381  return index_.FindAllExtensionNumbers(extendee_type, output);
382}
383
384bool 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
393DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
394  : pool_(pool) {}
395DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
396
397bool 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
407bool 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
417bool 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
433bool 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
451MergedDescriptorDatabase::MergedDescriptorDatabase(
452    DescriptorDatabase* source1,
453    DescriptorDatabase* source2) {
454  sources_.push_back(source1);
455  sources_.push_back(source2);
456}
457MergedDescriptorDatabase::MergedDescriptorDatabase(
458    const vector<DescriptorDatabase*>& sources)
459  : sources_(sources) {}
460MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
461
462bool 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
473bool 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
495bool 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
519bool 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