| 297 | } |
| 298 | |
| 299 | int ZipFile::fillUncompressedSizes(std::deque<SizeTarget>& targets, std::deque<uint32_t>& sizes) { |
| 300 | if (targets.empty()) { |
| 301 | return 0; |
| 302 | } |
| 303 | |
| 304 | const ScopedOpenClose zip{*this}; |
| 305 | if (!zip) return 0; |
| 306 | |
| 307 | if (!loadZipDetails()) return 0; |
| 308 | |
| 309 | file.seek(zipDetails.centralDirOffset); |
| 310 | |
| 311 | int matched = 0; |
| 312 | const int targetCount = static_cast<int>(targets.size()); |
| 313 | uint32_t sig; |
| 314 | char itemName[256]; |
| 315 | |
| 316 | while (file.available()) { |
| 317 | file.read(&sig, 4); |
| 318 | if (sig != 0x02014b50) break; |
| 319 | |
| 320 | file.seekCur(6); |
| 321 | uint16_t method; |
| 322 | file.read(&method, 2); |
| 323 | file.seekCur(8); |
| 324 | uint32_t compressedSize, uncompressedSize; |
| 325 | file.read(&compressedSize, 4); |
| 326 | file.read(&uncompressedSize, 4); |
| 327 | uint16_t nameLen, m, k; |
| 328 | file.read(&nameLen, 2); |
| 329 | file.read(&m, 2); |
| 330 | file.read(&k, 2); |
| 331 | file.seekCur(8); |
| 332 | uint32_t localHeaderOffset; |
| 333 | file.read(&localHeaderOffset, 4); |
| 334 | |
| 335 | if (nameLen < 256) { |
| 336 | file.read(itemName, nameLen); |
| 337 | itemName[nameLen] = '\0'; |
| 338 | |
| 339 | uint64_t hash = fnvHash64(itemName, nameLen); |
| 340 | SizeTarget key = {hash, nameLen, 0}; |
| 341 | |
| 342 | auto it = std::lower_bound(targets.begin(), targets.end(), key, [](const SizeTarget& a, const SizeTarget& b) { |
| 343 | return a.hash < b.hash || (a.hash == b.hash && a.len < b.len); |
| 344 | }); |
| 345 | |
| 346 | while (it != targets.end() && it->hash == hash && it->len == nameLen) { |
| 347 | if (it->index < sizes.size()) { |
| 348 | sizes[it->index] = uncompressedSize; |
| 349 | matched++; |
| 350 | } |
| 351 | ++it; |
| 352 | } |
| 353 | |
| 354 | if (matched >= targetCount) { |
| 355 | break; |
| 356 | } |