Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-25 09:18:39

0001 // Protocol Buffers - Google's data interchange format
0002 // Copyright 2008 Google Inc.  All rights reserved.
0003 //
0004 // Use of this source code is governed by a BSD-style
0005 // license that can be found in the LICENSE file or at
0006 // https://developers.google.com/open-source/licenses/bsd
0007 
0008 // Author: kenton@google.com (Kenton Varda)
0009 //  Based on original Protocol Buffers design by
0010 //  Sanjay Ghemawat, Jeff Dean, and others.
0011 //
0012 // Interface for manipulating databases of descriptors.
0013 
0014 #ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
0015 #define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
0016 
0017 #include <memory>
0018 #include <string>
0019 #include <type_traits>
0020 #include <utility>
0021 #include <vector>
0022 
0023 #include "absl/container/btree_map.h"
0024 #include "absl/strings/string_view.h"
0025 #include "google/protobuf/descriptor.h"
0026 
0027 // Must be included last.
0028 #include "google/protobuf/port_def.inc"
0029 
0030 #ifdef SWIG
0031 #error "You cannot SWIG proto headers"
0032 #endif
0033 
0034 namespace google {
0035 namespace protobuf {
0036 
0037 // Defined in this file.
0038 class DescriptorDatabase;
0039 class SimpleDescriptorDatabase;
0040 class EncodedDescriptorDatabase;
0041 class DescriptorPoolDatabase;
0042 class MergedDescriptorDatabase;
0043 
0044 // Abstract interface for a database of descriptors.
0045 //
0046 // This is useful if you want to create a DescriptorPool which loads
0047 // descriptors on-demand from some sort of large database.  If the database
0048 // is large, it may be inefficient to enumerate every .proto file inside it
0049 // calling DescriptorPool::BuildFile() for each one.  Instead, a DescriptorPool
0050 // can be created which wraps a DescriptorDatabase and only builds particular
0051 // descriptors when they are needed.
0052 class PROTOBUF_EXPORT DescriptorDatabase {
0053  protected:
0054   // Alias to enable the migration from const std::string& to absl::string_view
0055   // in virtual methods. Controlled by
0056   // PROTOBUF_FUTURE_STRING_VIEW_DESCRIPTOR_DATABASE to allow a global switch
0057   // when ready for consistent transition.
0058 #ifdef PROTOBUF_FUTURE_STRING_VIEW_DESCRIPTOR_DATABASE
0059   using StringViewArg = absl::string_view;
0060 #else
0061   using StringViewArg = const std::string&;
0062 #endif
0063 
0064  public:
0065   inline DescriptorDatabase() {}
0066   DescriptorDatabase(const DescriptorDatabase&) = delete;
0067   DescriptorDatabase& operator=(const DescriptorDatabase&) = delete;
0068   virtual ~DescriptorDatabase();
0069 
0070   // Find a file by file name.  Fills in in *output and returns true if found.
0071   // Otherwise, returns false, leaving the contents of *output undefined.
0072   virtual bool FindFileByName(StringViewArg filename,
0073                               FileDescriptorProto* PROTOBUF_NONNULL output) = 0;
0074 
0075   // Find the file that declares the given fully-qualified symbol name.
0076   // If found, fills in *output and returns true, otherwise returns false
0077   // and leaves *output undefined.
0078   virtual bool FindFileContainingSymbol(StringViewArg symbol_name,
0079                                         FileDescriptorProto* PROTOBUF_NONNULL
0080                                             output) = 0;
0081 
0082   // Find the file which defines an extension extending the given message type
0083   // with the given field number.  If found, fills in *output and returns true,
0084   // otherwise returns false and leaves *output undefined.  containing_type
0085   // must be a fully-qualified type name.
0086   virtual bool FindFileContainingExtension(
0087       StringViewArg containing_type, int field_number,
0088       FileDescriptorProto* PROTOBUF_NONNULL output) = 0;
0089 
0090   // Finds the tag numbers used by all known extensions of
0091   // extendee_type, and appends them to output in an undefined
0092   // order. This method is best-effort: it's not guaranteed that the
0093   // database will find all extensions, and it's not guaranteed that
0094   // FindFileContainingExtension will return true on all of the found
0095   // numbers. Returns true if the search was successful, otherwise
0096   // returns false and leaves output unchanged.
0097   //
0098   // This method has a default implementation that always returns
0099   // false.
0100   virtual bool FindAllExtensionNumbers(
0101       StringViewArg /* extendee_type */,
0102       std::vector<int>* PROTOBUF_NONNULL /* output */) {
0103     return false;
0104   }
0105 
0106 
0107   // Finds the file names and appends them to the output in an
0108   // undefined order. This method is best-effort: it's not guaranteed that the
0109   // database will find all files. Returns true if the database supports
0110   // searching all file names, otherwise returns false and leaves output
0111   // unchanged.
0112   //
0113   // This method has a default implementation that always returns
0114   // false.
0115   virtual bool FindAllFileNames(
0116       std::vector<std::string>* PROTOBUF_NONNULL /*output*/) {
0117     return false;
0118   }
0119 
0120   // Finds the package names and appends them to the output in an
0121   // undefined order. This method is best-effort: it's not guaranteed that the
0122   // database will find all packages. Returns true if the database supports
0123   // searching all package names, otherwise returns false and leaves output
0124   // unchanged.
0125   bool FindAllPackageNames(std::vector<std::string>* PROTOBUF_NONNULL output);
0126 
0127   // Finds the message names and appends them to the output in an
0128   // undefined order. This method is best-effort: it's not guaranteed that the
0129   // database will find all messages. Returns true if the database supports
0130   // searching all message names, otherwise returns false and leaves output
0131   // unchanged.
0132   bool FindAllMessageNames(std::vector<std::string>* PROTOBUF_NONNULL output);
0133 
0134  private:
0135   static_assert(std::is_same<StringViewArg, absl::string_view>::value ||
0136                     std::is_same<StringViewArg, const std::string&>::value,
0137                 "StringViewArg must be either "
0138                 "absl::string_view or const std::string&");
0139 };
0140 
0141 // A DescriptorDatabase into which you can insert files manually.
0142 //
0143 // FindFileContainingSymbol() is fully-implemented.  When you add a file, its
0144 // symbols will be indexed for this purpose.  Note that the implementation
0145 // may return false positives, but only if it isn't possible for the symbol
0146 // to be defined in any other file.  In particular, if a file defines a symbol
0147 // "Foo", then searching for "Foo.[anything]" will match that file.  This way,
0148 // the database does not need to aggressively index all children of a symbol.
0149 //
0150 // FindFileContainingExtension() is mostly-implemented.  It works if and only
0151 // if the original FieldDescriptorProto defining the extension has a
0152 // fully-qualified type name in its "extendee" field (i.e. starts with a '.').
0153 // If the extendee is a relative name, SimpleDescriptorDatabase will not
0154 // attempt to resolve the type, so it will not know what type the extension is
0155 // extending.  Therefore, calling FindFileContainingExtension() with the
0156 // extension's containing type will never actually find that extension.  Note
0157 // that this is an unlikely problem, as all FileDescriptorProtos created by the
0158 // protocol compiler (as well as ones created by calling
0159 // FileDescriptor::CopyTo()) will always use fully-qualified names for all
0160 // types.  You only need to worry if you are constructing FileDescriptorProtos
0161 // yourself, or are calling compiler::Parser directly.
0162 class PROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
0163  public:
0164   SimpleDescriptorDatabase();
0165   SimpleDescriptorDatabase(const SimpleDescriptorDatabase&) = delete;
0166   SimpleDescriptorDatabase& operator=(const SimpleDescriptorDatabase&) = delete;
0167   ~SimpleDescriptorDatabase() override;
0168 
0169   // Adds the FileDescriptorProto to the database, making a copy.  The object
0170   // can be deleted after Add() returns.  Returns false if the file conflicted
0171   // with a file already in the database, in which case an error will have
0172   // been written to ABSL_LOG(ERROR).
0173   bool Add(const FileDescriptorProto& file);
0174 
0175   // Adds the FileDescriptorProto to the database and takes ownership of it.
0176   bool AddAndOwn(const FileDescriptorProto* PROTOBUF_NONNULL file);
0177 
0178   // Adds the FileDescriptorProto to the database and not take ownership of it.
0179   // The owner must ensure file outlives the SimpleDescriptorDatabase.
0180   bool AddUnowned(const FileDescriptorProto* PROTOBUF_NONNULL file);
0181 
0182   // implements DescriptorDatabase -----------------------------------
0183   bool FindFileByName(StringViewArg filename,
0184                       FileDescriptorProto* PROTOBUF_NONNULL output) override;
0185   bool FindFileContainingSymbol(StringViewArg symbol_name,
0186                                 FileDescriptorProto* PROTOBUF_NONNULL
0187                                     output) override;
0188   bool FindFileContainingExtension(
0189       StringViewArg containing_type, int field_number,
0190       FileDescriptorProto* PROTOBUF_NONNULL output) override;
0191   bool FindAllExtensionNumbers(StringViewArg extendee_type,
0192                                std::vector<int>* PROTOBUF_NONNULL
0193                                    output) override;
0194 
0195   bool FindAllFileNames(
0196       std::vector<std::string>* PROTOBUF_NONNULL output) override;
0197 
0198  private:
0199   // An index mapping file names, symbol names, and extension numbers to
0200   // some sort of values.
0201   template <typename Value>
0202   class DescriptorIndex {
0203    public:
0204     // Helpers to recursively add particular descriptors and all their contents
0205     // to the index.
0206     bool AddFile(const FileDescriptorProto& file, Value value);
0207     bool AddSymbol(absl::string_view name, Value value);
0208     bool AddNestedExtensions(StringViewArg filename,
0209                              const DescriptorProto& message_type, Value value);
0210     bool AddExtension(StringViewArg filename, const FieldDescriptorProto& field,
0211                       Value value);
0212 
0213     Value FindFile(StringViewArg filename);
0214     Value FindSymbol(StringViewArg name);
0215     Value FindExtension(StringViewArg containing_type, int field_number);
0216     bool FindAllExtensionNumbers(StringViewArg containing_type,
0217                                  std::vector<int>* PROTOBUF_NONNULL output);
0218     void FindAllFileNames(std::vector<std::string>* PROTOBUF_NONNULL output);
0219 
0220    private:
0221     absl::btree_map<std::string, Value> by_name_;
0222     absl::btree_map<std::string, Value> by_symbol_;
0223     absl::btree_map<std::pair<std::string, int>, Value> by_extension_;
0224 
0225     // Invariant:  The by_symbol_ map does not contain any symbols which are
0226     // prefixes of other symbols in the map.  For example, "foo.bar" is a
0227     // prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz").
0228     //
0229     // This invariant is important because it means that given a symbol name,
0230     // we can find a key in the map which is a prefix of the symbol in O(lg n)
0231     // time, and we know that there is at most one such key.
0232     //
0233     // The prefix lookup algorithm works like so:
0234     // 1) Find the last key in the map which is less than or equal to the
0235     //    search key.
0236     // 2) If the found key is a prefix of the search key, then return it.
0237     //    Otherwise, there is no match.
0238     //
0239     // I am sure this algorithm has been described elsewhere, but since I
0240     // wasn't able to find it quickly I will instead prove that it works
0241     // myself.  The key to the algorithm is that if a match exists, step (1)
0242     // will find it.  Proof:
0243     // 1) Define the "search key" to be the key we are looking for, the "found
0244     //    key" to be the key found in step (1), and the "match key" to be the
0245     //    key which actually matches the search key (i.e. the key we're trying
0246     //    to find).
0247     // 2) The found key must be less than or equal to the search key by
0248     //    definition.
0249     // 3) The match key must also be less than or equal to the search key
0250     //    (because it is a prefix).
0251     // 4) The match key cannot be greater than the found key, because if it
0252     //    were, then step (1) of the algorithm would have returned the match
0253     //    key instead (since it finds the *greatest* key which is less than or
0254     //    equal to the search key).
0255     // 5) Therefore, the found key must be between the match key and the search
0256     //    key, inclusive.
0257     // 6) Since the search key must be a sub-symbol of the match key, if it is
0258     //    not equal to the match key, then search_key[match_key.size()] must
0259     //    be '.'.
0260     // 7) Since '.' sorts before any other character that is valid in a symbol
0261     //    name, then if the found key is not equal to the match key, then
0262     //    found_key[match_key.size()] must also be '.', because any other value
0263     //    would make it sort after the search key.
0264     // 8) Therefore, if the found key is not equal to the match key, then the
0265     //    found key must be a sub-symbol of the match key.  However, this would
0266     //    contradict our map invariant which says that no symbol in the map is
0267     //    a sub-symbol of any other.
0268     // 9) Therefore, the found key must match the match key.
0269     //
0270     // The above proof assumes the match key exists.  In the case that the
0271     // match key does not exist, then step (1) will return some other symbol.
0272     // That symbol cannot be a super-symbol of the search key since if it were,
0273     // then it would be a match, and we're assuming the match key doesn't exist.
0274     // Therefore, step 2 will correctly return no match.
0275   };
0276 
0277   DescriptorIndex<const FileDescriptorProto*> index_;
0278   std::vector<std::unique_ptr<const FileDescriptorProto>> files_to_delete_;
0279 
0280   // If file is non-nullptr, copy it into *output and return true, otherwise
0281   // return false.
0282   bool MaybeCopy(const FileDescriptorProto* PROTOBUF_NULLABLE file,
0283                  FileDescriptorProto* PROTOBUF_NONNULL output);
0284 };
0285 
0286 // Very similar to SimpleDescriptorDatabase, but stores all the descriptors
0287 // as raw bytes and generally tries to use as little memory as possible.
0288 //
0289 // The same caveats regarding FindFileContainingExtension() apply as with
0290 // SimpleDescriptorDatabase.
0291 class PROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
0292  public:
0293   EncodedDescriptorDatabase();
0294   EncodedDescriptorDatabase(const EncodedDescriptorDatabase&) = delete;
0295   EncodedDescriptorDatabase& operator=(const EncodedDescriptorDatabase&) =
0296       delete;
0297   ~EncodedDescriptorDatabase() override;
0298 
0299   // Adds the FileDescriptorProto to the database.  The descriptor is provided
0300   // in encoded form.  The database does not make a copy of the bytes, nor
0301   // does it take ownership; it's up to the caller to make sure the bytes
0302   // remain valid for the life of the database.  Returns false and logs an error
0303   // if the bytes are not a valid FileDescriptorProto or if the file conflicted
0304   // with a file already in the database.
0305   bool Add(const void* PROTOBUF_NONNULL encoded_file_descriptor, int size);
0306 
0307   // Like Add(), but makes a copy of the data, so that the caller does not
0308   // need to keep it around.
0309   bool AddCopy(const void* PROTOBUF_NONNULL encoded_file_descriptor, int size);
0310 
0311   // Like FindFileContainingSymbol but returns only the name of the file.
0312   bool FindNameOfFileContainingSymbol(StringViewArg symbol_name,
0313                                       std::string* PROTOBUF_NONNULL output);
0314 
0315   // implements DescriptorDatabase -----------------------------------
0316   bool FindFileByName(StringViewArg filename,
0317                       FileDescriptorProto* PROTOBUF_NONNULL output) override;
0318   bool FindFileContainingSymbol(StringViewArg symbol_name,
0319                                 FileDescriptorProto* PROTOBUF_NONNULL
0320                                     output) override;
0321   bool FindFileContainingExtension(
0322       StringViewArg containing_type, int field_number,
0323       FileDescriptorProto* PROTOBUF_NONNULL output) override;
0324   bool FindAllExtensionNumbers(StringViewArg extendee_type,
0325                                std::vector<int>* PROTOBUF_NONNULL
0326                                    output) override;
0327   bool FindAllFileNames(
0328       std::vector<std::string>* PROTOBUF_NONNULL output) override;
0329 
0330  private:
0331   class DescriptorIndex;
0332   // Keep DescriptorIndex by pointer to hide the implementation to keep a
0333   // cleaner header.
0334   std::unique_ptr<DescriptorIndex> index_;
0335   std::vector<void*> files_to_delete_;
0336 
0337   // If encoded_file.first is non-nullptr, parse the data into *output and
0338   // return true, otherwise return false.
0339   bool MaybeParse(std::pair<const void * PROTOBUF_NULLABLE, int> encoded_file,
0340                   FileDescriptorProto* PROTOBUF_NONNULL output);
0341 };
0342 
0343 struct PROTOBUF_EXPORT DescriptorPoolDatabaseOptions {
0344   // If true, the database will preserve source code info when returning
0345   // descriptors.
0346   bool preserve_source_code_info = false;
0347 };
0348 
0349 // A DescriptorDatabase that fetches files from a given pool.
0350 class PROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
0351  public:
0352   explicit DescriptorPoolDatabase(const DescriptorPool& pool,
0353                                   DescriptorPoolDatabaseOptions options = {});
0354   DescriptorPoolDatabase(const DescriptorPoolDatabase&) = delete;
0355   DescriptorPoolDatabase& operator=(const DescriptorPoolDatabase&) = delete;
0356   ~DescriptorPoolDatabase() override;
0357 
0358   // implements DescriptorDatabase -----------------------------------
0359   bool FindFileByName(StringViewArg filename,
0360                       FileDescriptorProto* PROTOBUF_NONNULL output) override;
0361   bool FindFileContainingSymbol(StringViewArg symbol_name,
0362                                 FileDescriptorProto* PROTOBUF_NONNULL
0363                                     output) override;
0364   bool FindFileContainingExtension(
0365       StringViewArg containing_type, int field_number,
0366       FileDescriptorProto* PROTOBUF_NONNULL output) override;
0367   bool FindAllExtensionNumbers(StringViewArg extendee_type,
0368                                std::vector<int>* PROTOBUF_NONNULL
0369                                    output) override;
0370 
0371  private:
0372   const DescriptorPool& pool_;
0373   DescriptorPoolDatabaseOptions options_;
0374 };
0375 
0376 // A DescriptorDatabase that wraps two or more others.  It first searches the
0377 // first database and, if that fails, tries the second, and so on.
0378 class PROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
0379  public:
0380   // Merge just two databases.  The sources remain property of the caller.
0381   MergedDescriptorDatabase(DescriptorDatabase* PROTOBUF_NONNULL source1,
0382                            DescriptorDatabase* PROTOBUF_NONNULL source2);
0383   // Merge more than two databases.  The sources remain property of the caller.
0384   // The vector may be deleted after the constructor returns but the
0385   // DescriptorDatabases need to stick around.
0386   explicit MergedDescriptorDatabase(
0387       const std::vector<DescriptorDatabase*>& sources);
0388   MergedDescriptorDatabase(const MergedDescriptorDatabase&) = delete;
0389   MergedDescriptorDatabase& operator=(const MergedDescriptorDatabase&) = delete;
0390   ~MergedDescriptorDatabase() override;
0391 
0392   // implements DescriptorDatabase -----------------------------------
0393   bool FindFileByName(StringViewArg filename,
0394                       FileDescriptorProto* PROTOBUF_NONNULL output) override;
0395   bool FindFileContainingSymbol(StringViewArg symbol_name,
0396                                 FileDescriptorProto* PROTOBUF_NONNULL
0397                                     output) override;
0398   bool FindFileContainingExtension(
0399       StringViewArg containing_type, int field_number,
0400       FileDescriptorProto* PROTOBUF_NONNULL output) override;
0401   // Merges the results of calling all databases. Returns true iff any
0402   // of the databases returned true.
0403   bool FindAllExtensionNumbers(StringViewArg extendee_type,
0404                                std::vector<int>* PROTOBUF_NONNULL
0405                                    output) override;
0406 
0407 
0408   // This function is best-effort. Returns true if at least one underlying
0409   // DescriptorDatabase returns true.
0410   bool FindAllFileNames(
0411       std::vector<std::string>* PROTOBUF_NONNULL output) override;
0412 
0413  private:
0414   std::vector<DescriptorDatabase*> sources_;
0415 };
0416 
0417 }  // namespace protobuf
0418 }  // namespace google
0419 
0420 #include "google/protobuf/port_undef.inc"
0421 
0422 #endif  // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__