Overview
Comment: | OFZIPArchive: Support for writing ZIP64 archives |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
def4cbbba67f874ec79351d63b5e9006 |
User & Date: | js on 2017-08-14 00:31:05 |
Other Links: | manifest | tags |
Context
2017-08-14
| ||
00:45 | OFZIPArchive(Entry): A logic and a typo fix check-in: de6e2319ca user: js tags: trunk | |
00:31 | OFZIPArchive: Support for writing ZIP64 archives check-in: def4cbbba6 user: js tags: trunk | |
2017-08-13
| ||
22:38 | Fix -[OFData description] check-in: 484c7987d2 user: js tags: trunk | |
Changes
Modified src/OFZIPArchive.m from [c1fa8a1f8d] to [db5f1942c0].
︙ | ︙ | |||
43 44 45 46 47 48 49 | #import "OFOutOfRangeException.h" #import "OFSeekFailedException.h" #import "OFUnsupportedVersionException.h" /* * FIXME: Current limitations: * - Split archives are not supported. | < < | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #import "OFOutOfRangeException.h" #import "OFSeekFailedException.h" #import "OFUnsupportedVersionException.h" /* * FIXME: Current limitations: * - Split archives are not supported. * - Encrypted files cannot be read. */ @interface OFZIPArchive () - (void)of_readZIPInfo; - (void)of_readEntries; - (void)of_closeLastReturnedStream; - (void)of_writeCentralDirectory; |
︙ | ︙ | |||
471 472 473 474 475 476 477 478 479 480 481 482 | return [[_lastReturnedStream retain] autorelease]; } - (OFStream *)streamForWritingEntry: (OFZIPArchiveEntry *)entry_ { /* TODO: Avoid data descriptor when _stream is an OFSeekableStream */ void *pool; OFMutableZIPArchiveEntry *entry; OFString *fileName; OFData *extraField; uint16_t fileNameLength, extraFieldLength; | > < | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | return [[_lastReturnedStream retain] autorelease]; } - (OFStream *)streamForWritingEntry: (OFZIPArchiveEntry *)entry_ { /* TODO: Avoid data descriptor when _stream is an OFSeekableStream */ int64_t offsetAdd = 0; void *pool; OFMutableZIPArchiveEntry *entry; OFString *fileName; OFData *extraField; uint16_t fileNameLength, extraFieldLength; if (_mode != OF_ZIP_ARCHIVE_MODE_WRITE && _mode != OF_ZIP_ARCHIVE_MODE_APPEND) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); entry = [[entry_ mutableCopy] autorelease]; |
︙ | ︙ | |||
498 499 500 501 502 503 504 | if ([entry compressionMethod] != OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; [self of_closeLastReturnedStream]; | > > > > | > | | | | > > | | | < < | > | > > > | < | < < < > > > > > > > > > | > | > > > > > > > | | | | | | | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 | if ([entry compressionMethod] != OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; [self of_closeLastReturnedStream]; fileName = [entry fileName]; fileNameLength = [fileName UTF8StringLength]; extraField = [entry extraField]; extraFieldLength = [extraField count]; if (UINT16_MAX - extraFieldLength < 20) @throw [OFOutOfRangeException exception]; [entry setVersionMadeBy: ([entry versionMadeBy] & 0xFF00) | 45]; [entry setMinVersionNeeded: ([entry minVersionNeeded] & 0xFF00) | 45]; [entry setCompressedSize: 0]; [entry setUncompressedSize: 0]; [entry setCRC32: 0]; [entry setGeneralPurposeBitFlag: [entry generalPurposeBitFlag] | (1 << 3) | (1 << 11)]; [entry of_setLocalFileHeaderOffset: _offset]; [_stream writeLittleEndianInt32: 0x04034B50]; [_stream writeLittleEndianInt16: [entry minVersionNeeded]]; [_stream writeLittleEndianInt16: [entry generalPurposeBitFlag]]; [_stream writeLittleEndianInt16: [entry compressionMethod]]; [_stream writeLittleEndianInt16: [entry of_lastModifiedFileTime]]; [_stream writeLittleEndianInt16: [entry of_lastModifiedFileDate]]; /* We use ZIP64 */ [_stream writeLittleEndianInt32: 0xFFFFFFFF]; [_stream writeLittleEndianInt32: 0xFFFFFFFF]; [_stream writeLittleEndianInt32: 0xFFFFFFFF]; [_stream writeLittleEndianInt16: fileNameLength]; [_stream writeLittleEndianInt16: extraFieldLength + 20]; offsetAdd += 4 + (5 * 2) + (3 * 4) + (2 * 2); [_stream writeString: fileName]; offsetAdd += fileNameLength; [_stream writeLittleEndianInt16: OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64]; [_stream writeLittleEndianInt16: 16]; /* We use the data descriptor */ [_stream writeLittleEndianInt64: 0]; [_stream writeLittleEndianInt64: 0]; offsetAdd += (2 * 2) + (2 * 8); if (extraField != nil) [_stream writeData: extraField]; offsetAdd += extraFieldLength; if (INT64_MAX - _offset < offsetAdd) @throw [OFOutOfRangeException exception]; _offset += offsetAdd; _lastReturnedStream = [[OFZIPArchive_FileWriteStream alloc] initWithStream: _stream entry: entry]; objc_autoreleasePoolPop(pool); return [[_lastReturnedStream retain] autorelease]; } - (void)of_writeCentralDirectory { void *pool = objc_autoreleasePoolPush(); _centralDirectoryEntries = 0; _centralDirectoryEntriesInDisk = 0; _centralDirectorySize = 0; _centralDirectoryOffset = _offset; for (OFZIPArchiveEntry *entry in _entries) { _centralDirectorySize += [entry of_writeToStream: _stream]; _centralDirectoryEntries++; _centralDirectoryEntriesInDisk++; } /* ZIP64 end of central directory */ [_stream writeLittleEndianInt32: 0x06064B50]; [_stream writeLittleEndianInt64: 44]; /* Remaining size */ [_stream writeLittleEndianInt16: 45]; /* Version made by */ [_stream writeLittleEndianInt16: 45]; /* Version required */ [_stream writeLittleEndianInt32: _diskNumber]; [_stream writeLittleEndianInt32: _centralDirectoryDisk]; [_stream writeLittleEndianInt64: _centralDirectoryEntriesInDisk]; [_stream writeLittleEndianInt64: _centralDirectoryEntries]; [_stream writeLittleEndianInt64: _centralDirectorySize]; [_stream writeLittleEndianInt64: _centralDirectoryOffset]; /* ZIP64 end of central directory locator */ [_stream writeLittleEndianInt32: 0x07064B50]; [_stream writeLittleEndianInt32: _diskNumber]; [_stream writeLittleEndianInt64: _centralDirectoryOffset + _centralDirectorySize]; [_stream writeLittleEndianInt32: 1]; /* Total number of disks */ /* End of central directory */ [_stream writeLittleEndianInt32: 0x06054B50]; [_stream writeLittleEndianInt16: 0xFFFF]; /* Disk number */ [_stream writeLittleEndianInt16: 0xFFFF]; /* CD disk */ [_stream writeLittleEndianInt16: 0xFFFF]; /* CD entries in disk */ [_stream writeLittleEndianInt16: 0xFFFF]; /* CD entries */ [_stream writeLittleEndianInt32: 0xFFFFFFFF]; /* CD size */ [_stream writeLittleEndianInt32: 0xFFFFFFFF]; /* CD offset */ [_stream writeLittleEndianInt16: [_archiveComment UTF8StringLength]]; if (_archiveComment != nil) [_stream writeString: _archiveComment]; objc_autoreleasePoolPop(pool); } |
︙ | ︙ | |||
833 834 835 836 837 838 839 | _bytesWritten += (int64_t)length; _CRC32 = of_crc32(_CRC32, buffer, length); } - (void)close { | < < < < < < < | | < | | | > > | 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | _bytesWritten += (int64_t)length; _CRC32 = of_crc32(_CRC32, buffer, length); } - (void)close { if (_stream == nil) return; [_stream writeLittleEndianInt32: 0x08074B50]; [_stream writeLittleEndianInt32: _CRC32]; [_stream writeLittleEndianInt64: _bytesWritten]; [_stream writeLittleEndianInt64: _bytesWritten]; [_stream release]; _stream = nil; [_entry setCRC32: ~_CRC32]; [_entry setCompressedSize: _bytesWritten]; [_entry setUncompressedSize: _bytesWritten]; [_entry makeImmutable]; _bytesWritten += (2 * 4 + 2 * 8); } @end |
Modified src/OFZIPArchiveEntry.m from [1983c233dd] to [fef61c95a7].
︙ | ︙ | |||
420 421 422 423 424 425 426 | objc_autoreleasePoolPop(pool); return [ret autorelease]; } - (uint64_t)of_writeToStream: (OFStream *)stream { | | | < < < < | | | | | > > > > > > > > > > > > < < | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 | objc_autoreleasePoolPop(pool); return [ret autorelease]; } - (uint64_t)of_writeToStream: (OFStream *)stream { void *pool = objc_autoreleasePoolPush(); uint64_t size = 0; if (UINT16_MAX - [_extraField count] < 32) @throw [OFOutOfRangeException exception]; [stream writeLittleEndianInt32: 0x02014B50]; [stream writeLittleEndianInt16: _versionMadeBy]; [stream writeLittleEndianInt16: _minVersionNeeded]; [stream writeLittleEndianInt16: _generalPurposeBitFlag]; [stream writeLittleEndianInt16: _compressionMethod]; [stream writeLittleEndianInt16: _lastModifiedFileTime]; [stream writeLittleEndianInt16: _lastModifiedFileDate]; [stream writeLittleEndianInt32: _CRC32]; [stream writeLittleEndianInt32: 0xFFFFFFFF]; [stream writeLittleEndianInt32: 0xFFFFFFFF]; [stream writeLittleEndianInt16: (uint16_t)[_fileName UTF8StringLength]]; [stream writeLittleEndianInt16: (uint16_t)[_extraField count] + 32]; [stream writeLittleEndianInt16: (uint16_t)[_fileComment UTF8StringLength]]; [stream writeLittleEndianInt16: 0xFFFF]; [stream writeLittleEndianInt16: _internalAttributes]; [stream writeLittleEndianInt32: _versionSpecificAttributes]; [stream writeLittleEndianInt32: 0xFFFFFFFF]; size += (4 + (6 * 2) + (3 * 4) + (5 * 2) + (2 * 4)); [stream writeString: _fileName]; size += (uint64_t)[_fileName UTF8StringLength]; [stream writeLittleEndianInt16: OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64]; [stream writeLittleEndianInt16: 28]; [stream writeLittleEndianInt64: _uncompressedSize]; [stream writeLittleEndianInt64: _compressedSize]; [stream writeLittleEndianInt64: _localFileHeaderOffset]; [stream writeLittleEndianInt32: _startDiskNumber]; size += (2 * 2) + (3 * 8) + 4; if (_extraField != nil) [stream writeData: _extraField]; size += (uint64_t)[_extraField count]; if (_fileComment != nil) [stream writeString: _fileComment]; size += (uint64_t)[_fileComment UTF8StringLength]; objc_autoreleasePoolPop(pool); return size; } @end |