Home | History | Annotate | Download | only in flatbuffers
      1 /*
      2  * Copyright 2017 Google Inc. All rights reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef FLATBUFFERS_REGISTRY_H_
     18 #define FLATBUFFERS_REGISTRY_H_
     19 
     20 #include "flatbuffers/idl.h"
     21 
     22 namespace flatbuffers {
     23 
     24 // Convenience class to easily parse or generate text for arbitrary FlatBuffers.
     25 // Simply pre-populate it with all schema filenames that may be in use, and
     26 // This class will look them up using the file_identifier declared in the
     27 // schema.
     28 class Registry {
     29  public:
     30   // Call this for all schemas that may be in use. The identifier has
     31   // a function in the generated code, e.g. MonsterIdentifier().
     32   void Register(const char *file_identifier, const char *schema_path) {
     33     Schema schema;
     34     schema.path_ = schema_path;
     35     schemas_[file_identifier] = schema;
     36   }
     37 
     38   // Generate text from an arbitrary FlatBuffer by looking up its
     39   // file_identifier in the registry.
     40   bool FlatBufferToText(const uint8_t *flatbuf, size_t len,
     41                         std::string *dest) {
     42     // Get the identifier out of the buffer.
     43     // If the buffer is truncated, exit.
     44     if (len < sizeof(uoffset_t) +
     45               FlatBufferBuilder::kFileIdentifierLength) {
     46       lasterror_ = "buffer truncated";
     47       return false;
     48     }
     49     std::string ident(reinterpret_cast<const char *>(flatbuf) +
     50                         sizeof(uoffset_t),
     51                       FlatBufferBuilder::kFileIdentifierLength);
     52     // Load and parse the schema.
     53     Parser parser;
     54     if (!LoadSchema(ident, &parser)) return false;
     55     // Now we're ready to generate text.
     56     if (!GenerateText(parser, flatbuf, dest)) {
     57       lasterror_ = "unable to generate text for FlatBuffer binary";
     58       return false;
     59     }
     60     return true;
     61   }
     62 
     63   // Converts a binary buffer to text using one of the schemas in the registry,
     64   // use the file_identifier to indicate which.
     65   // If DetachedBuffer::data() is null then parsing failed.
     66   DetachedBuffer TextToFlatBuffer(const char *text,
     67                                   const char *file_identifier) {
     68     // Load and parse the schema.
     69     Parser parser;
     70     if (!LoadSchema(file_identifier, &parser)) return DetachedBuffer();
     71     // Parse the text.
     72     if (!parser.Parse(text)) {
     73       lasterror_ = parser.error_;
     74       return DetachedBuffer();
     75     }
     76     // We have a valid FlatBuffer. Detach it from the builder and return.
     77     return parser.builder_.ReleaseBufferPointer();
     78   }
     79 
     80   // Modify any parsing / output options used by the other functions.
     81   void SetOptions(const IDLOptions &opts) { opts_ = opts; }
     82 
     83   // If schemas used contain include statements, call this function for every
     84   // directory the parser should search them for.
     85   void AddIncludeDirectory(const char *path) {
     86     include_paths_.push_back(path);
     87   }
     88 
     89   // Returns a human readable error if any of the above functions fail.
     90   const std::string &GetLastError() { return lasterror_; }
     91 
     92  private:
     93    bool LoadSchema(const std::string &ident, Parser *parser) {
     94      // Find the schema, if not, exit.
     95      auto it = schemas_.find(ident);
     96      if (it == schemas_.end()) {
     97        // Don't attach the identifier, since it may not be human readable.
     98        lasterror_ = "identifier for this buffer not in the registry";
     99        return false;
    100      }
    101      auto &schema = it->second;
    102      // Load the schema from disk. If not, exit.
    103      std::string schematext;
    104      if (!LoadFile(schema.path_.c_str(), false, &schematext)) {
    105        lasterror_ = "could not load schema: " + schema.path_;
    106        return false;
    107      }
    108      // Parse schema.
    109      parser->opts = opts_;
    110      if (!parser->Parse(schematext.c_str(), vector_data(include_paths_),
    111                         schema.path_.c_str())) {
    112        lasterror_ = parser->error_;
    113        return false;
    114      }
    115      return true;
    116    }
    117 
    118   struct Schema {
    119     std::string path_;
    120     // TODO(wvo) optionally cache schema file or parsed schema here.
    121   };
    122 
    123   std::string lasterror_;
    124   IDLOptions opts_;
    125   std::vector<const char *> include_paths_;
    126   std::map<std::string, Schema> schemas_;
    127 };
    128 
    129 }  // namespace flatbuffers
    130 
    131 #endif  // FLATBUFFERS_REGISTRY_H_
    132