| 41 | static constexpr const uint32_t min_required_toolchain_version_v2 { 140000u }; |
| 42 | |
| 43 | unique_ptr<archive> load_archive(const string& file_name) { |
| 44 | string data; |
| 45 | if (!file_io::file_to_string(file_name, data)) { |
| 46 | return {}; |
| 47 | } |
| 48 | const auto data_size = data.size(); |
| 49 | auto cur_size = (decltype(data_size))0; |
| 50 | const uint8_t* data_ptr = (const uint8_t*)data.data(); |
| 51 | |
| 52 | auto ar = make_unique<archive>(); |
| 53 | |
| 54 | // parse header |
| 55 | cur_size += sizeof(header_v2); |
| 56 | if (cur_size > data_size) { |
| 57 | log_error("universal binary $: invalid header size, expected $, got $", |
| 58 | file_name, cur_size, data_size); |
| 59 | return {}; |
| 60 | } |
| 61 | const header_v2& header = *(const header_v2*)data_ptr; |
| 62 | data_ptr += sizeof(header_v2); |
| 63 | |
| 64 | if (memcmp(header.magic, "FUBA", 4) != 0) { |
| 65 | log_error("universal binary $: invalid header magic", file_name); |
| 66 | return {}; |
| 67 | } |
| 68 | if (header.binary_format_version != binary_format_version) { |
| 69 | log_error("universal binary $: unsupported binary version $", file_name, header.binary_format_version); |
| 70 | return {}; |
| 71 | } |
| 72 | memcpy(&ar->header.static_header, &header, sizeof(header_v2)); |
| 73 | |
| 74 | const auto& bin_count = ar->header.static_header.binary_count; |
| 75 | if (bin_count == 0) { |
| 76 | // no binaries -> return early |
| 77 | return ar; |
| 78 | } |
| 79 | |
| 80 | // parse dynamic header |
| 81 | ar->header.targets.resize(bin_count); |
| 82 | ar->header.offsets.resize(bin_count); |
| 83 | ar->header.toolchain_versions.resize(bin_count); |
| 84 | ar->header.hashes.resize(bin_count); |
| 85 | |
| 86 | const auto targets_size = sizeof(target_v2) * bin_count; |
| 87 | const auto offsets_size = sizeof(typename decltype(header_dynamic_v2::offsets)::value_type) * bin_count; |
| 88 | const auto toolchain_versions_size = sizeof(typename decltype(header_dynamic_v2::toolchain_versions)::value_type) * bin_count; |
| 89 | const auto hashes_size = sizeof(typename decltype(header_dynamic_v2::hashes)::value_type) * bin_count; |
| 90 | const auto dyn_header_size = targets_size + offsets_size + toolchain_versions_size + hashes_size; |
| 91 | cur_size += dyn_header_size; |
| 92 | if (cur_size > data_size) { |
| 93 | log_error("universal binary $: invalid dynamic header size, expected $, got $", |
| 94 | file_name, cur_size, data_size); |
| 95 | return {}; |
| 96 | } |
| 97 | |
| 98 | memcpy(ar->header.targets.data(), data_ptr, targets_size); |
| 99 | data_ptr += targets_size; |
| 100 |
no test coverage detected