| 1 | #include <nanogui/serializer/core.h> | 
|---|
| 2 | #include <iostream> | 
|---|
| 3 |  | 
|---|
| 4 | NAMESPACE_BEGIN(nanogui) | 
|---|
| 5 |  | 
|---|
| 6 | static const char * = "SER_V1"; | 
|---|
| 7 | static const int  = 6; | 
|---|
| 8 | static const int  = | 
|---|
| 9 | serialized_header_id_length + sizeof(uint64_t) + sizeof(uint32_t); | 
|---|
| 10 |  | 
|---|
| 11 | Serializer::Serializer(const std::string &filename, bool write_) | 
|---|
| 12 | : mFilename(filename), mWrite(write_), mCompatibility(false) { | 
|---|
| 13 | mFile.open(filename, write_ ? (std::ios::out | std::ios::trunc | std::ios::binary) | 
|---|
| 14 | : (std::ios::in  | std::ios::binary)); | 
|---|
| 15 | if (!mFile.is_open()) | 
|---|
| 16 | throw std::runtime_error( "Could not open \""+ filename + "\"!"); | 
|---|
| 17 |  | 
|---|
| 18 | if (!mWrite) | 
|---|
| 19 | readTOC(); | 
|---|
| 20 | seek(serialized_header_size); | 
|---|
| 21 | mPrefixStack.push_back( ""); | 
|---|
| 22 | } | 
|---|
| 23 |  | 
|---|
| 24 | Serializer::~Serializer() { | 
|---|
| 25 | if (mWrite) | 
|---|
| 26 | writeTOC(); | 
|---|
| 27 | } | 
|---|
| 28 |  | 
|---|
| 29 | bool Serializer::isSerializedFile(const std::string &filename) { | 
|---|
| 30 | try { | 
|---|
| 31 | Serializer s(filename, false); | 
|---|
| 32 | return true; | 
|---|
| 33 | } catch (const std::exception &) { | 
|---|
| 34 | return false; | 
|---|
| 35 | } | 
|---|
| 36 | } | 
|---|
| 37 |  | 
|---|
| 38 | size_t Serializer::size() { | 
|---|
| 39 | mFile.seekg(0, std::ios_base::end); | 
|---|
| 40 | return (uint64_t) mFile.tellg(); | 
|---|
| 41 | } | 
|---|
| 42 |  | 
|---|
| 43 | void Serializer::push(const std::string &name) { | 
|---|
| 44 | mPrefixStack.push_back(mPrefixStack.back() + name + "."); | 
|---|
| 45 | } | 
|---|
| 46 |  | 
|---|
| 47 | void Serializer::pop() { | 
|---|
| 48 | mPrefixStack.pop_back(); | 
|---|
| 49 | } | 
|---|
| 50 |  | 
|---|
| 51 | std::vector<std::string> Serializer::keys() const { | 
|---|
| 52 | const std::string &prefix = mPrefixStack.back(); | 
|---|
| 53 | std::vector<std::string> result; | 
|---|
| 54 | for (auto const &kv : mTOC) { | 
|---|
| 55 | if (kv.first.substr(0, prefix.length()) == prefix) | 
|---|
| 56 | result.push_back(kv.first.substr(prefix.length())); | 
|---|
| 57 | } | 
|---|
| 58 | return result; | 
|---|
| 59 | } | 
|---|
| 60 |  | 
|---|
| 61 | bool Serializer::get_base(const std::string &name, | 
|---|
| 62 | const std::string &type_id) { | 
|---|
| 63 | if (mWrite) | 
|---|
| 64 | throw std::runtime_error( "\""+ mFilename + | 
|---|
| 65 | "\": not open for reading!"); | 
|---|
| 66 |  | 
|---|
| 67 | std::string fullName = mPrefixStack.back() + name; | 
|---|
| 68 |  | 
|---|
| 69 | auto it = mTOC.find(fullName); | 
|---|
| 70 | if (it == mTOC.end()) { | 
|---|
| 71 | std::string message = "\""+ mFilename + | 
|---|
| 72 | "\": unable to find field named \""+ | 
|---|
| 73 | fullName + "\"!"; | 
|---|
| 74 | if (!mCompatibility) | 
|---|
| 75 | throw std::runtime_error(message); | 
|---|
| 76 | else | 
|---|
| 77 | std::cerr << "Warning: "<< message << std::endl; | 
|---|
| 78 |  | 
|---|
| 79 | return false; | 
|---|
| 80 | } | 
|---|
| 81 |  | 
|---|
| 82 | const auto &record = it->second; | 
|---|
| 83 | if (record.first != type_id) | 
|---|
| 84 | throw std::runtime_error( | 
|---|
| 85 | "\""+ mFilename + "\": field named \""+ fullName + | 
|---|
| 86 | "\" has an incompatible type (expected \""+ type_id + | 
|---|
| 87 | "\", got \""+ record.first + "\")!"); | 
|---|
| 88 |  | 
|---|
| 89 | seek((size_t) record.second); | 
|---|
| 90 |  | 
|---|
| 91 | return true; | 
|---|
| 92 | } | 
|---|
| 93 |  | 
|---|
| 94 | void Serializer::set_base(const std::string &name, | 
|---|
| 95 | const std::string &type_id) { | 
|---|
| 96 | if (!mWrite) | 
|---|
| 97 | throw std::runtime_error( "\""+ mFilename + "\": not open for writing!"); | 
|---|
| 98 |  | 
|---|
| 99 | std::string fullName = mPrefixStack.back() + name; | 
|---|
| 100 | auto it = mTOC.find(fullName); | 
|---|
| 101 | if (it != mTOC.end()) | 
|---|
| 102 | throw std::runtime_error( "\""+ mFilename + "\": field named \""+ | 
|---|
| 103 | fullName + "\" already exists!"); | 
|---|
| 104 |  | 
|---|
| 105 | mTOC[fullName] = std::make_pair(type_id, (uint64_t) mFile.tellp()); | 
|---|
| 106 | } | 
|---|
| 107 |  | 
|---|
| 108 | void Serializer::writeTOC() { | 
|---|
| 109 | uint64_t trailer_offset = (uint64_t) mFile.tellp(); | 
|---|
| 110 | uint32_t nItems = (uint32_t) mTOC.size(); | 
|---|
| 111 |  | 
|---|
| 112 | seek(0); | 
|---|
| 113 | write(serialized_header_id, serialized_header_id_length); | 
|---|
| 114 | write(&trailer_offset, sizeof(uint64_t)); | 
|---|
| 115 | write(&nItems, sizeof(uint32_t)); | 
|---|
| 116 | seek((size_t) trailer_offset); | 
|---|
| 117 |  | 
|---|
| 118 | for (auto item : mTOC) { | 
|---|
| 119 | uint16_t size = (uint16_t) item.first.length(); | 
|---|
| 120 | write(&size, sizeof(uint16_t)); | 
|---|
| 121 | write(item.first.c_str(), size); | 
|---|
| 122 | size = (uint16_t) item.second.first.length(); | 
|---|
| 123 | write(&size, sizeof(uint16_t)); | 
|---|
| 124 | write(item.second.first.c_str(), size); | 
|---|
| 125 |  | 
|---|
| 126 | write(&item.second.second, sizeof(uint64_t)); | 
|---|
| 127 | } | 
|---|
| 128 | } | 
|---|
| 129 |  | 
|---|
| 130 | void Serializer::readTOC() { | 
|---|
| 131 | uint64_t trailer_offset = 0; | 
|---|
| 132 | uint32_t nItems = 0; | 
|---|
| 133 | char [serialized_header_id_length]; | 
|---|
| 134 |  | 
|---|
| 135 | read(header, serialized_header_id_length); | 
|---|
| 136 | if (memcmp(header, serialized_header_id, serialized_header_id_length) != 0) | 
|---|
| 137 | throw std::runtime_error( "\""+ mFilename + "\": invalid file format!"); | 
|---|
| 138 | read(&trailer_offset, sizeof(uint64_t)); | 
|---|
| 139 | read(&nItems, sizeof(uint32_t)); | 
|---|
| 140 | mFile.seekg(trailer_offset); | 
|---|
| 141 |  | 
|---|
| 142 | for (uint32_t i = 0; i < nItems; ++i) { | 
|---|
| 143 | std::string field_name, type_id; | 
|---|
| 144 | uint16_t size; | 
|---|
| 145 | uint64_t offset; | 
|---|
| 146 |  | 
|---|
| 147 | read(&size, sizeof(uint16_t)); field_name.resize(size); | 
|---|
| 148 | read((char *) field_name.data(), size); | 
|---|
| 149 | read(&size, sizeof(uint16_t)); type_id.resize(size); | 
|---|
| 150 | read((char *) type_id.data(), size); | 
|---|
| 151 | read(&offset, sizeof(uint64_t)); | 
|---|
| 152 |  | 
|---|
| 153 | mTOC[field_name] = std::make_pair(type_id, offset); | 
|---|
| 154 | } | 
|---|
| 155 | } | 
|---|
| 156 |  | 
|---|
| 157 | void Serializer::read(void *p, size_t size) { | 
|---|
| 158 | mFile.read((char *) p, size); | 
|---|
| 159 | if (!mFile.good()) | 
|---|
| 160 | throw std::runtime_error( "\""+ mFilename + | 
|---|
| 161 | "\": I/O error while attempting to read "+ | 
|---|
| 162 | std::to_string(size) + " bytes."); | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | void Serializer::write(const void *p, size_t size) { | 
|---|
| 166 | mFile.write((char *) p, size); | 
|---|
| 167 | if (!mFile.good()) | 
|---|
| 168 | throw std::runtime_error( | 
|---|
| 169 | "\""+ mFilename + "\": I/O error while attempting to write "+ | 
|---|
| 170 | std::to_string(size) + " bytes."); | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | void Serializer::seek(size_t pos) { | 
|---|
| 174 | if (mWrite) | 
|---|
| 175 | mFile.seekp(pos); | 
|---|
| 176 | else | 
|---|
| 177 | mFile.seekg(pos); | 
|---|
| 178 |  | 
|---|
| 179 | if (!mFile.good()) | 
|---|
| 180 | throw std::runtime_error( | 
|---|
| 181 | "\""+ mFilename + | 
|---|
| 182 | "\": I/O error while attempting to seek to offset "+ | 
|---|
| 183 | std::to_string(pos) + "."); | 
|---|
| 184 | } | 
|---|
| 185 |  | 
|---|
| 186 | NAMESPACE_END(nanogui) | 
|---|
| 187 |  | 
|---|