Home | History | Annotate | Download | only in protobuf
      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 (at) 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 
     48 DescriptorDatabase::~DescriptorDatabase() {}
     49 
     50 // ===================================================================
     51 
     52 template <typename 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>
     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>
    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>
    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>
    174 Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
    175     const string& filename) {
    176   return FindWithDefault(by_name_, filename, Value());
    177 }
    178 
    179 template <typename Value>
    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>
    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>
    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
    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>
    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>
    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 
    250 SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
    251 SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
    252   STLDeleteElements(&files_to_delete_);
    253 }
    254 
    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 
    261 bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
    262   files_to_delete_.push_back(file);
    263   return index_.AddFile(*file, file);
    264 }
    265 
    266 bool SimpleDescriptorDatabase::FindFileByName(
    267     const string& filename,
    268     FileDescriptorProto* output) {
    269   return MaybeCopy(index_.FindFile(filename), output);
    270 }
    271 
    272 bool SimpleDescriptorDatabase::FindFileContainingSymbol(
    273     const string& symbol_name,
    274     FileDescriptorProto* output) {
    275   return MaybeCopy(index_.FindSymbol(symbol_name), output);
    276 }
    277 
    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 
    285 bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
    286     const string& extendee_type,
    287     vector<int>* output) {
    288   return index_.FindAllExtensionNumbers(extendee_type, output);
    289 }
    290 
    291 
    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 
    301 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 
    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 
    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 
    328 bool EncodedDescriptorDatabase::FindFileByName(
    329     const string& filename,
    330     FileDescriptorProto* output) {
    331   return MaybeParse(index_.FindFile(filename), output);
    332 }
    333 
    334 bool EncodedDescriptorDatabase::FindFileContainingSymbol(
    335     const string& symbol_name,
    336     FileDescriptorProto* output) {
    337   return MaybeParse(index_.FindSymbol(symbol_name), output);
    338 }
    339 
    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 
    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 
    377 bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
    378     const string& extendee_type,
    379     vector<int>* output) {
    380   return index_.FindAllExtensionNumbers(extendee_type, output);
    381 }
    382 
    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 
    392 DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
    393   : pool_(pool) {}
    394 DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
    395 
    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 
    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 
    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 
    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 
    450 MergedDescriptorDatabase::MergedDescriptorDatabase(
    451     DescriptorDatabase* source1,
    452     DescriptorDatabase* source2) {
    453   sources_.push_back(source1);
    454   sources_.push_back(source2);
    455 }
    456 MergedDescriptorDatabase::MergedDescriptorDatabase(
    457     const vector<DescriptorDatabase*>& sources)
    458   : sources_(sources) {}
    459 MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
    460 
    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 
    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 
    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 
    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