Changeset View
Changeset View
Standalone View
Standalone View
kzip.cpp
- This file was moved from src/kzip.cpp.
Show First 20 Lines • Show All 305 Lines • ▼ Show 20 Line(s) | |||||
306 | * Checks if a token for a central or local header has been found and resets | 306 | * Checks if a token for a central or local header has been found and resets | ||
307 | * the device to the begin of the token. If a token for the data descriptor is | 307 | * the device to the begin of the token. If a token for the data descriptor is | ||
308 | * found it is assumed there is a central or local header token starting right | 308 | * found it is assumed there is a central or local header token starting right | ||
309 | * behind the data descriptor, and the device is set accordingly to the begin | 309 | * behind the data descriptor, and the device is set accordingly to the begin | ||
310 | * of that token. | 310 | * of that token. | ||
311 | * To be called when a 'P' has been found. | 311 | * To be called when a 'P' has been found. | ||
312 | * @param buffer start of buffer with the 3 bytes behind 'P' | 312 | * @param buffer start of buffer with the 3 bytes behind 'P' | ||
313 | * @param dev device that is read from | 313 | * @param dev device that is read from | ||
314 | * @param dataDescriptor only search for data descriptor | ||||
314 | * @return true if a local or central header begin is or could be reached | 315 | * @return true if a local or central header begin is or could be reached | ||
315 | */ | 316 | */ | ||
316 | static bool handlePossibleHeaderBegin(const char *buffer, QIODevice *dev) | 317 | static bool handlePossibleHeaderBegin(const char *buffer, QIODevice *dev, bool dataDescriptor) | ||
317 | { | 318 | { | ||
318 | // we have to detect three magic tokens here: | 319 | // we have to detect three magic tokens here: | ||
319 | // PK34 for the next local header in case there is no data descriptor | 320 | // PK34 for the next local header in case there is no data descriptor | ||
320 | // PK12 for the central header in case there is no data descriptor | 321 | // PK12 for the central header in case there is no data descriptor | ||
321 | // PK78 for the data descriptor in case it is following the compressed data | 322 | // PK78 for the data descriptor in case it is following the compressed data | ||
322 | // TODO: optimize using 32bit const data for comparison instead of byte-wise, | 323 | // TODO: optimize using 32bit const data for comparison instead of byte-wise, | ||
323 | // given we run at least on 32bit CPUs | 324 | // given we run at least on 32bit CPUs | ||
324 | 325 | | |||
325 | if (buffer[0] == 'K') { | 326 | if (buffer[0] == 'K') { | ||
326 | if (buffer[1] == 7 && buffer[2] == 8) { | 327 | if (buffer[1] == 7 && buffer[2] == 8) { | ||
327 | // data descriptor token found | 328 | // data descriptor token found | ||
328 | dev->seek(dev->pos() + 12); // skip the 'data_descriptor' | 329 | dev->seek(dev->pos() + 12); // skip the 'data_descriptor' | ||
329 | return true; | 330 | return true; | ||
330 | } | 331 | } | ||
331 | 332 | | |||
332 | if ((buffer[1] == 1 && buffer[2] == 2) | 333 | if (!dataDescriptor && ((buffer[1] == 1 && buffer[2] == 2) | ||
333 | || (buffer[1] == 3 && buffer[2] == 4)) { | 334 | || (buffer[1] == 3 && buffer[2] == 4))) { | ||
334 | // central/local header token found | 335 | // central/local header token found | ||
335 | dev->seek(dev->pos() - 4); | 336 | dev->seek(dev->pos() - 4); | ||
336 | // go back 4 bytes, so that the magic bytes can be found | 337 | // go back 4 bytes, so that the magic bytes can be found | ||
337 | // in the next cycle... | 338 | // in the next cycle... | ||
338 | return true; | 339 | return true; | ||
339 | } | 340 | } | ||
340 | } | 341 | } | ||
341 | return false; | 342 | return false; | ||
342 | } | 343 | } | ||
343 | 344 | | |||
344 | /** | 345 | /** | ||
345 | * Reads the device forwards from the current pos until a token for a central or | 346 | * Reads the device forwards from the current pos until a token for a central or | ||
346 | * local header has been found or is to be assumed. | 347 | * local header has been found or is to be assumed. | ||
dfaure: can you document the new boolean param as well? | |||||
347 | * @param dev device that is read from | 348 | * @param dev device that is read from | ||
348 | * @return true if a local or central header token could be reached, false on error | 349 | * @return true if a local or central header token could be reached, false on error | ||
349 | */ | 350 | */ | ||
350 | static bool seekToNextHeaderToken(QIODevice *dev) | 351 | static bool seekToNextHeaderToken(QIODevice *dev, bool dataDescriptor) | ||
351 | { | 352 | { | ||
352 | bool headerTokenFound = false; | 353 | bool headerTokenFound = false; | ||
353 | char buffer[3]; | 354 | char buffer[3]; | ||
354 | 355 | | |||
355 | while (!headerTokenFound) { | 356 | while (!headerTokenFound) { | ||
356 | int n = dev->read(buffer, 1); | 357 | int n = dev->read(buffer, 1); | ||
357 | if (n < 1) { | 358 | if (n < 1) { | ||
358 | //qCWarning(KArchiveLog) << "Invalid ZIP file. Unexpected end of file. (#2)"; | 359 | //qCWarning(KArchiveLog) << "Invalid ZIP file. Unexpected end of file. (#2)"; | ||
359 | return false; | 360 | return false; | ||
360 | } | 361 | } | ||
361 | 362 | | |||
362 | if (buffer[0] != 'P') { | 363 | if (buffer[0] != 'P') { | ||
363 | continue; | 364 | continue; | ||
364 | } | 365 | } | ||
365 | 366 | | |||
366 | n = dev->read(buffer, 3); | 367 | n = dev->read(buffer, 3); | ||
367 | if (n < 3) { | 368 | if (n < 3) { | ||
368 | //qCWarning(KArchiveLog) << "Invalid ZIP file. Unexpected end of file. (#3)"; | 369 | //qCWarning(KArchiveLog) << "Invalid ZIP file. Unexpected end of file. (#3)"; | ||
369 | return false; | 370 | return false; | ||
370 | } | 371 | } | ||
371 | 372 | | |||
372 | if (handlePossibleHeaderBegin(buffer, dev)) { | 373 | if (handlePossibleHeaderBegin(buffer, dev, dataDescriptor)) { | ||
373 | headerTokenFound = true; | 374 | headerTokenFound = true; | ||
374 | } else { | 375 | } else { | ||
375 | for (int i = 0; i < 3; ++i) { | 376 | for (int i = 0; i < 3; ++i) { | ||
376 | if (buffer[i] == 'P') { | 377 | if (buffer[i] == 'P') { | ||
377 | // We have another P character so we must go back a little to check if it is a magic | 378 | // We have another P character so we must go back a little to check if it is a magic | ||
378 | dev->seek(dev->pos() - 3 + i); | 379 | dev->seek(dev->pos() - 3 + i); | ||
379 | break; | 380 | break; | ||
380 | } | 381 | } | ||
▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Line(s) | 478 | if (!memcmp(buffer, "PK\3\4", 4)) { // local file header | |||
538 | dev->seek(extraFieldEnd); | 539 | dev->seek(extraFieldEnd); | ||
539 | 540 | | |||
540 | // we have to take care of the 'general purpose bit flag'. | 541 | // we have to take care of the 'general purpose bit flag'. | ||
541 | // if bit 3 is set, the header doesn't contain the length of | 542 | // if bit 3 is set, the header doesn't contain the length of | ||
542 | // the file and we look for the signature 'PK\7\8'. | 543 | // the file and we look for the signature 'PK\7\8'. | ||
543 | if (gpf & 8) { | 544 | if (gpf & 8) { | ||
544 | // here we have to read through the compressed data to find | 545 | // here we have to read through the compressed data to find | ||
545 | // the next PKxx | 546 | // the next PKxx | ||
546 | if (!seekToNextHeaderToken(dev)) { | 547 | if (!seekToNextHeaderToken(dev, true)) { | ||
547 | setErrorString(tr("Could not seek to next header token")); | 548 | setErrorString(tr("Could not seek to next header token")); | ||
548 | return false; | 549 | return false; | ||
549 | } | 550 | } | ||
550 | } else { | 551 | } else { | ||
551 | // here we skip the compressed data and jump to the next header | 552 | // here we skip the compressed data and jump to the next header | ||
552 | //qCDebug(KArchiveLog) << "general purpose bit flag indicates, that local file header contains valid size"; | 553 | //qCDebug(KArchiveLog) << "general purpose bit flag indicates, that local file header contains valid size"; | ||
553 | bool foundSignature = false; | 554 | bool foundSignature = false; | ||
554 | // check if this could be a symbolic link | 555 | // check if this could be a symbolic link | ||
555 | if (compression_mode == NoCompression | 556 | if (compression_mode == NoCompression | ||
556 | && uncomp_size <= max_path_len | 557 | && uncomp_size <= max_path_len | ||
557 | && uncomp_size > 0) { | 558 | && uncomp_size > 0) { | ||
558 | // read content and store it | 559 | // read content and store it | ||
559 | // If it's not a symlink, then we'll just discard the data for now. | 560 | // If it's not a symlink, then we'll just discard the data for now. | ||
560 | pfi.guessed_symlink = dev->read(uncomp_size); | 561 | pfi.guessed_symlink = dev->read(uncomp_size); | ||
561 | if (pfi.guessed_symlink.size() < uncomp_size) { | 562 | if (pfi.guessed_symlink.size() < uncomp_size) { | ||
562 | setErrorString(tr("Invalid ZIP file. Unexpected end of file. (#5)")); | 563 | setErrorString(tr("Invalid ZIP file. Unexpected end of file. (#5)")); | ||
563 | return false; | 564 | return false; | ||
564 | } | 565 | } | ||
565 | } else { | 566 | } else { | ||
566 | if (compr_size > dev->size()) { | 567 | if (compr_size > dev->size()) { | ||
567 | // here we cannot trust the compressed size, so scan through the compressed | 568 | // here we cannot trust the compressed size, so scan through the compressed | ||
568 | // data to find the next header | 569 | // data to find the next header | ||
569 | if (!seekToNextHeaderToken(dev)) { | 570 | if (!seekToNextHeaderToken(dev, false)) { | ||
570 | setErrorString(tr("Could not seek to next header token")); | 571 | setErrorString(tr("Could not seek to next header token")); | ||
571 | return false; | 572 | return false; | ||
572 | } | 573 | } | ||
573 | foundSignature = true; | 574 | foundSignature = true; | ||
574 | } else { | 575 | } else { | ||
575 | // qCDebug(KArchiveLog) << "before interesting dev->pos(): " << dev->pos(); | 576 | // qCDebug(KArchiveLog) << "before interesting dev->pos(): " << dev->pos(); | ||
576 | bool success = dev->seek(dev->pos() + compr_size); // can this fail ??? | 577 | bool success = dev->seek(dev->pos() + compr_size); // can this fail ??? | ||
577 | Q_UNUSED(success); // prevent warning in release builds. | 578 | Q_UNUSED(success); // prevent warning in release builds. | ||
Show All 11 Lines | |||||
589 | // qCDebug(KArchiveLog) << "Testing for optional data descriptor"; | 590 | // qCDebug(KArchiveLog) << "Testing for optional data descriptor"; | ||
590 | // read static data descriptor | 591 | // read static data descriptor | ||
591 | n = dev->read(buffer, 4); | 592 | n = dev->read(buffer, 4); | ||
592 | if (n < 4) { | 593 | if (n < 4) { | ||
593 | setErrorString(tr("Invalid ZIP file. Unexpected end of file. (#1)")); | 594 | setErrorString(tr("Invalid ZIP file. Unexpected end of file. (#1)")); | ||
594 | return false; | 595 | return false; | ||
595 | } | 596 | } | ||
596 | 597 | | |||
597 | if (buffer[0] != 'P' || !handlePossibleHeaderBegin(buffer + 1, dev)) { | 598 | if (buffer[0] != 'P' || !handlePossibleHeaderBegin(buffer + 1, dev, false)) { | ||
598 | // assume data descriptor without signature | 599 | // assume data descriptor without signature | ||
599 | dev->seek(dev->pos() + 8); // skip rest of the 'data_descriptor' | 600 | dev->seek(dev->pos() + 8); // skip rest of the 'data_descriptor' | ||
600 | } | 601 | } | ||
601 | } | 602 | } | ||
602 | 603 | | |||
603 | // not needed any more | 604 | // not needed any more | ||
604 | /* // here we calculate the length of the file in the zip | 605 | /* // here we calculate the length of the file in the zip | ||
605 | // with headers and jump to the next header. | 606 | // with headers and jump to the next header. | ||
▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Line(s) | 806 | if (buffer[i] == 'P') { | |||
808 | break; | 809 | break; | ||
809 | } | 810 | } | ||
810 | } | 811 | } | ||
811 | } | 812 | } | ||
812 | } | 813 | } | ||
813 | } else { | 814 | } else { | ||
814 | setErrorString( | 815 | setErrorString( | ||
815 | tr("Invalid ZIP file. Unrecognized header at offset %1") | 816 | tr("Invalid ZIP file. Unrecognized header at offset %1") | ||
816 | .arg(offset)); | 817 | .arg(dev->pos() - 4)); | ||
817 | return false; | 818 | return false; | ||
818 | } | 819 | } | ||
819 | } | 820 | } | ||
820 | //qCDebug(KArchiveLog) << "*** done *** "; | 821 | //qCDebug(KArchiveLog) << "*** done *** "; | ||
821 | return true; | 822 | return true; | ||
822 | } | 823 | } | ||
823 | 824 | | |||
824 | bool KZip::closeArchive() | 825 | bool KZip::closeArchive() | ||
▲ Show 20 Lines • Show All 638 Lines • Show Last 20 Lines |
can you document the new boolean param as well?