| 57 | } // namespace |
| 58 | |
| 59 | bool ZipFile::loadAllFileStatSlims() { |
| 60 | const ScopedOpenClose zip{*this}; |
| 61 | if (!zip) return false; |
| 62 | |
| 63 | if (!loadZipDetails()) return false; |
| 64 | |
| 65 | file.seek(zipDetails.centralDirOffset); |
| 66 | |
| 67 | uint32_t sig; |
| 68 | char itemName[256]; |
| 69 | fileStatSlimCache.clear(); |
| 70 | fileStatSlimCache.reserve(zipDetails.totalEntries); |
| 71 | |
| 72 | while (file.available()) { |
| 73 | file.read(&sig, 4); |
| 74 | if (sig != 0x02014b50) break; // End of list |
| 75 | |
| 76 | FileStatSlim fileStat = {}; |
| 77 | |
| 78 | file.seekCur(6); |
| 79 | file.read(&fileStat.method, 2); |
| 80 | file.seekCur(8); |
| 81 | file.read(&fileStat.compressedSize, 4); |
| 82 | file.read(&fileStat.uncompressedSize, 4); |
| 83 | uint16_t nameLen, m, k; |
| 84 | file.read(&nameLen, 2); |
| 85 | file.read(&m, 2); |
| 86 | file.read(&k, 2); |
| 87 | file.seekCur(8); |
| 88 | file.read(&fileStat.localHeaderOffset, 4); |
| 89 | |
| 90 | if (nameLen < sizeof(itemName)) { |
| 91 | file.read(itemName, nameLen); |
| 92 | itemName[nameLen] = '\0'; |
| 93 | fileStatSlimCache.emplace(itemName, fileStat); |
| 94 | } else { |
| 95 | // Skip over oversized entry names to avoid writing past fixed buffer. |
| 96 | file.seekCur(nameLen); |
| 97 | } |
| 98 | |
| 99 | // Skip the rest of this entry (extra field + comment) |
| 100 | file.seekCur(m + k); |
| 101 | } |
| 102 | |
| 103 | // Set cursor to start of central directory for sequential access |
| 104 | lastCentralDirPos = zipDetails.centralDirOffset; |
| 105 | lastCentralDirPosValid = true; |
| 106 | |
| 107 | return true; |
| 108 | } |
| 109 | |
| 110 | bool ZipFile::loadFileStatSlim(const char* filename, FileStatSlim* fileStat) { |
| 111 | if (!fileStatSlimCache.empty()) { |