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(). Register(const char * file_identifier,const char * schema_path)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. FlatBufferToText(const uint8_t * flatbuf,size_t len,std::string * dest)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. TextToFlatBuffer(const char * text,const char * file_identifier)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. SetOptions(const IDLOptions & opts)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. AddIncludeDirectory(const char * path)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. GetLastError()90 const std::string &GetLastError() { return lasterror_; } 91 92 private: LoadSchema(const std::string & ident,Parser * parser)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