| 301 | } |
| 302 | |
| 303 | bool extractZip(ByteReader& in, uint64_t limit, ExtractSink& sink, const CancelFn& cancelled, const ProgressFn& onBytes, std::string& outError) |
| 304 | { |
| 305 | uint64_t consumed = 0; |
| 306 | // Reads through the raw source but never past the file part's limit; the |
| 307 | // adapter's ByteReader knows nothing about framing, so the bound lives here. |
| 308 | auto readInto = [&](void* dst, size_t n) -> size_t { |
| 309 | if (consumed + n > limit) { |
| 310 | n = (size_t)(limit - consumed); |
| 311 | } |
| 312 | if (n == 0) { |
| 313 | return 0; |
| 314 | } |
| 315 | size_t rd = in.read(dst, n); |
| 316 | consumed += rd; |
| 317 | return rd; |
| 318 | }; |
| 319 | |
| 320 | static const size_t kBuf = 0x40000; |
| 321 | std::unique_ptr<uint8_t[]> buf(new uint8_t[kBuf]); |
| 322 | |
| 323 | bool ok = true; |
| 324 | while (consumed + 4 <= limit) { |
| 325 | uint8_t sigBuf[4]; |
| 326 | if (readInto(sigBuf, 4) != 4) { |
| 327 | break; |
| 328 | } |
| 329 | uint32_t sig = (uint32_t)(sigBuf[0] | (sigBuf[1] << 8) | (sigBuf[2] << 16) | ((uint32_t)sigBuf[3] << 24)); |
| 330 | if (sig != 0x04034b50) { |
| 331 | break; |
| 332 | } |
| 333 | uint8_t hdr[26]; |
| 334 | if (readInto(hdr, 26) != 26) { |
| 335 | outError = "Corrupted ZIP header."; |
| 336 | ok = false; |
| 337 | break; |
| 338 | } |
| 339 | uint16_t flags = (uint16_t)(hdr[2] | (hdr[3] << 8)); |
| 340 | uint16_t compression = (uint16_t)(hdr[4] | (hdr[5] << 8)); |
| 341 | uint32_t crc = (uint32_t)(hdr[10] | (hdr[11] << 8) | (hdr[12] << 16) | ((uint32_t)hdr[13] << 24)); |
| 342 | uint32_t compSize = (uint32_t)(hdr[14] | (hdr[15] << 8) | (hdr[16] << 16) | ((uint32_t)hdr[17] << 24)); |
| 343 | uint32_t uncompSize = (uint32_t)(hdr[18] | (hdr[19] << 8) | (hdr[20] << 16) | ((uint32_t)hdr[21] << 24)); |
| 344 | uint16_t nameLen = (uint16_t)(hdr[22] | (hdr[23] << 8)); |
| 345 | uint16_t extraLen = (uint16_t)(hdr[24] | (hdr[25] << 8)); |
| 346 | |
| 347 | std::string name; |
| 348 | name.resize(nameLen); |
| 349 | if (nameLen > 0 && readInto(&name[0], nameLen) != nameLen) { |
| 350 | outError = "Corrupted ZIP header."; |
| 351 | ok = false; |
| 352 | break; |
| 353 | } |
| 354 | if (extraLen > 0) { |
| 355 | std::unique_ptr<uint8_t[]> extra(new uint8_t[extraLen]); |
| 356 | if (readInto(extra.get(), extraLen) != extraLen) { |
| 357 | outError = "Corrupted ZIP header."; |
| 358 | ok = false; |
| 359 | break; |
| 360 | } |