| 216 | } |
| 217 | |
| 218 | bool ZipFile::loadZipDetails() { |
| 219 | if (zipDetails.isSet) { |
| 220 | return true; |
| 221 | } |
| 222 | |
| 223 | const ScopedOpenClose zip{*this}; |
| 224 | if (!zip) return false; |
| 225 | |
| 226 | const size_t fileSize = file.size(); |
| 227 | if (fileSize < 22) { |
| 228 | LOG_ERR("ZIP", "File too small to be a valid zip"); |
| 229 | return false; // Minimum EOCD size is 22 bytes |
| 230 | } |
| 231 | |
| 232 | // We scan the last 1KB (or the whole file if smaller) for the EOCD signature |
| 233 | // 0x06054b50 is stored as 0x50, 0x4b, 0x05, 0x06 in little-endian |
| 234 | const int scanRange = fileSize > 1024 ? 1024 : fileSize; |
| 235 | const auto buffer = static_cast<uint8_t*>(malloc(scanRange)); |
| 236 | if (!buffer) { |
| 237 | LOG_ERR("ZIP", "Failed to allocate memory for EOCD scan buffer"); |
| 238 | return false; |
| 239 | } |
| 240 | |
| 241 | file.seek(fileSize - scanRange); |
| 242 | file.read(buffer, scanRange); |
| 243 | |
| 244 | // Scan backwards for the signature |
| 245 | int foundOffset = -1; |
| 246 | for (int i = scanRange - 22; i >= 0; i--) { |
| 247 | constexpr uint32_t signature = 0x06054b50; |
| 248 | if (*reinterpret_cast<uint32_t*>(&buffer[i]) == signature) { |
| 249 | foundOffset = i; |
| 250 | break; |
| 251 | } |
| 252 | } |
| 253 | |
| 254 | if (foundOffset == -1) { |
| 255 | LOG_ERR("ZIP", "EOCD signature not found in zip file"); |
| 256 | free(buffer); |
| 257 | return false; |
| 258 | } |
| 259 | |
| 260 | // Now extract the values we need from the EOCD record |
| 261 | // Relative positions within EOCD: |
| 262 | // Offset 10: Total number of entries (2 bytes) |
| 263 | // Offset 16: Offset of start of central directory with respect to the starting disk number (4 bytes) |
| 264 | zipDetails.totalEntries = *reinterpret_cast<uint16_t*>(&buffer[foundOffset + 10]); |
| 265 | zipDetails.centralDirOffset = *reinterpret_cast<uint32_t*>(&buffer[foundOffset + 16]); |
| 266 | zipDetails.isSet = true; |
| 267 | |
| 268 | free(buffer); |
| 269 | return true; |
| 270 | } |
| 271 | |
| 272 | bool ZipFile::open() { |
| 273 | if (!Storage.openFileForRead("ZIP", filePath, file)) { |