| 120 | template <typename T> int64_t LE(T x) { return flatbuffers::EndianScalar((int64_t)x); }; |
| 121 | |
| 122 | void BuildPakFile(string &pakfile, string &bytecode, set<string> &files) { |
| 123 | // All offsets in 64bit, just in-case we ever want pakfiles > 4GB :) |
| 124 | // Since we're building this in memory, they can only be created by a 64bit build. |
| 125 | vector<int64_t> filestarts; |
| 126 | vector<int64_t> namestarts; |
| 127 | vector<int64_t> uncompressed; |
| 128 | vector<string> filenames; |
| 129 | auto add_file = [&](string_view buf, string_view filename) { |
| 130 | filestarts.push_back(LE(pakfile.size())); |
| 131 | filenames.push_back(string(filename)); |
| 132 | LOG_INFO("adding to pakfile: ", filename); |
| 133 | if (IsCompressed(filename)) { |
| 134 | string out; |
| 135 | WEntropyCoder<true>((uchar *)buf.data(), buf.length(), buf.length(), out); |
| 136 | pakfile += out; |
| 137 | uncompressed.push_back(buf.length()); |
| 138 | } else { |
| 139 | pakfile += buf; |
| 140 | uncompressed.push_back(-1); |
| 141 | } |
| 142 | }; |
| 143 | // Start with a magic id, just for the hell of it. |
| 144 | pakfile.insert(pakfile.end(), magic, magic + magic_size); |
| 145 | // Bytecode always first entry. |
| 146 | add_file(bytecode, bcname); |
| 147 | // Followed by all files. |
| 148 | files.insert("data/shaders/default.materials"); // If it hadn't already been added. |
| 149 | string buf; |
| 150 | for (auto &filename : files) { |
| 151 | auto l = LoadFile(filename, &buf); |
| 152 | if (l >= 0) { |
| 153 | add_file(buf, filename); |
| 154 | } else { |
| 155 | vector<pair<string, int64_t>> dir; |
| 156 | if (!ScanDir(filename, dir)) |
| 157 | THROW_OR_ABORT("cannot load file/dir for pakfile: " + filename); |
| 158 | for (auto &[name, size] : dir) { |
| 159 | auto fn = filename + name; |
| 160 | if (size >= 0 && LoadFile(fn, &buf) >= 0) |
| 161 | add_file(buf, fn); |
| 162 | } |
| 163 | } |
| 164 | } |
| 165 | // Now we can write the directory, first the names: |
| 166 | auto dirstart = LE(pakfile.size()); |
| 167 | for (auto &filename : filenames) { |
| 168 | namestarts.push_back(LE(pakfile.size())); |
| 169 | pakfile.insert(pakfile.end(), filename.c_str(), filename.c_str() + filename.length() + 1); |
| 170 | } |
| 171 | // Then the starting offsets and other data: |
| 172 | pakfile.insert(pakfile.end(), (uchar *)uncompressed.data(), |
| 173 | (uchar *)(uncompressed.data() + uncompressed.size())); |
| 174 | pakfile.insert(pakfile.end(), (uchar *)filestarts.data(), |
| 175 | (uchar *)(filestarts.data() + filestarts.size())); |
| 176 | pakfile.insert(pakfile.end(), (uchar *)namestarts.data(), |
| 177 | (uchar *)(namestarts.data() + namestarts.size())); |
| 178 | auto num = LE(filestarts.size()); |
| 179 | // Finally the "header" (or do we call this a "tailer" ? ;) |