| 40 | } |
| 41 | |
| 42 | void Archive::create(std::map<std::filesystem::path, std::filesystem::path> modules, std::filesystem::path prefix){ |
| 43 | // Open file |
| 44 | std::ofstream output(path, std::ios::binary | std::ios::out); |
| 45 | |
| 46 | // Write magic & version. `magic` is declared char[5] with a trailing |
| 47 | // '\0' for C-string convenience; the on-disk header is 4 magic bytes |
| 48 | // (matching check_magic_version's `stream.read(..., 4)`) followed by |
| 49 | // 4 version bytes. Writing sizeof(magic)=5 would shift every later |
| 50 | // field by one byte and `extract`/`list` would fail to recognize the |
| 51 | // archive. |
| 52 | output.write(magic, 4); |
| 53 | output.write(version, sizeof(version)); |
| 54 | |
| 55 | // Write paths section |
| 56 | std::vector<PathEntry> path_entries; |
| 57 | auto paths_start = output.tellp(); |
| 58 | write_data(output, (uint64_t) 0); // len(paths): Update later |
| 59 | write_data(output, (uint32_t) modules.size()); |
| 60 | for(auto module_pair : modules){ |
| 61 | std::string name = (prefix / module_pair.second).lexically_normal().string(); |
| 62 | write_data(output, (uint32_t)name.size()) << name; |
| 63 | write_data(output, (uint64_t) 0); // address: Update later |
| 64 | PathEntry& entry = path_entries.emplace_back(); |
| 65 | entry.path = module_pair.first; |
| 66 | entry.name_size = name.size(); |
| 67 | } |
| 68 | uint64_t paths_size = output.tellp() - paths_start; |
| 69 | |
| 70 | // Write module |
| 71 | for(PathEntry& path_entry : path_entries){ |
| 72 | path_entry.address = output.tellp(); // Fill module position |
| 73 | write_data(output, (uint64_t) 0); // len(module): Update later |
| 74 | std::filesystem::path module_path = path_entry.path; |
| 75 | if(!std::filesystem::exists(module_path)){ |
| 76 | throw Exception::Exception(std::string("module '") + module_path.string() + "' not found"); |
| 77 | } |
| 78 | std::ifstream module_file(module_path, std::ios::in | std::ios::binary); |
| 79 | char buf[1024]; |
| 80 | uint64_t module_size = 0; |
| 81 | while(!module_file.eof()){ |
| 82 | module_file.read(buf, 1024); |
| 83 | std::streamsize extracted = module_file.gcount(); |
| 84 | output.write(buf, extracted); |
| 85 | module_size += extracted; |
| 86 | } |
| 87 | module_file.close(); |
| 88 | path_entry.module_size = module_size; // Fill module size |
| 89 | } |
| 90 | |
| 91 | // Update paths |
| 92 | output.seekp(paths_start); |
| 93 | write_data(output, paths_size); // len(paths) |
| 94 | output.seekp(sizeof(uint32_t), std::ios::cur); // skip path count |
| 95 | for(PathEntry& path_entry : path_entries){ |
| 96 | output.seekp(path_entry.name_size + sizeof(uint32_t), std::ios::cur); |
| 97 | write_data(output, (uint64_t)path_entry.address); |
| 98 | } |
| 99 | |