Overview
Comment: | OFZIPArchive: Make returned streams retain archive
In order to not create a retain cycle, this changes the reference to the Since when closing a stream for writing the archive needs to be updated, |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
6527c97d03ed80fc1cffc2e6a9842229 |
User & Date: | js on 2022-10-09 16:19:17 |
Other Links: | manifest | tags |
Context
2022-10-09
| ||
16:33 | Drop of- prefix from URI schemes check-in: 9b3cae6cba user: js tags: trunk | |
16:19 | OFZIPArchive: Make returned streams retain archive check-in: 6527c97d03 user: js tags: trunk | |
2022-10-08
| ||
23:47 | Move all archive URI handling to a single file check-in: 55858a10bb user: js tags: trunk | |
Changes
Modified src/OFZIPArchive.h from [e88e9d721e] to [2297e4dbb2].
︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | * * @brief A class for accessing and manipulating ZIP files. */ OF_SUBCLASSING_RESTRICTED @interface OFZIPArchive: OFObject { OFStream *_stream; int64_t _offset; uint_least8_t _mode; uint32_t _diskNumber, _centralDirectoryDisk; uint64_t _centralDirectoryEntriesInDisk, _centralDirectoryEntries; uint64_t _centralDirectorySize; int64_t _centralDirectoryOffset; OFString *_Nullable _archiveComment; OFMutableArray OF_GENERIC(OFZIPArchiveEntry *) *_entries; OFMutableDictionary OF_GENERIC(OFString *, OFZIPArchiveEntry *) *_pathToEntryMap; OFStream *_Nullable _lastReturnedStream; } /** | > > > > > > > | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | * * @brief A class for accessing and manipulating ZIP files. */ OF_SUBCLASSING_RESTRICTED @interface OFZIPArchive: OFObject { OFStream *_stream; #ifdef OF_ZIP_ARCHIVE_M @public #endif int64_t _offset; @protected uint_least8_t _mode; uint32_t _diskNumber, _centralDirectoryDisk; uint64_t _centralDirectoryEntriesInDisk, _centralDirectoryEntries; uint64_t _centralDirectorySize; int64_t _centralDirectoryOffset; OFString *_Nullable _archiveComment; #ifdef OF_ZIP_ARCHIVE_M @public #endif OFMutableArray OF_GENERIC(OFZIPArchiveEntry *) *_entries; OFMutableDictionary OF_GENERIC(OFString *, OFZIPArchiveEntry *) *_pathToEntryMap; OFStream *_Nullable _lastReturnedStream; } /** |
︙ | ︙ |
Modified src/OFZIPArchive.m from [4d14cd8ba2] to [9d548c4f33].
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #include <errno.h> #import "OFZIPArchive.h" #import "OFZIPArchiveEntry.h" #import "OFZIPArchiveEntry+Private.h" | > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #define OF_ZIP_ARCHIVE_M #include "config.h" #include <errno.h> #import "OFZIPArchive.h" #import "OFZIPArchiveEntry.h" #import "OFZIPArchiveEntry+Private.h" |
︙ | ︙ | |||
56 57 58 59 60 61 62 | modeAppend }; OF_DIRECT_MEMBERS @interface OFZIPArchive () - (void)of_readZIPInfo; - (void)of_readEntries; | < | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | modeAppend }; OF_DIRECT_MEMBERS @interface OFZIPArchive () - (void)of_readZIPInfo; - (void)of_readEntries; - (void)of_writeCentralDirectory; @end OF_DIRECT_MEMBERS @interface OFZIPArchiveLocalFileHeader: OFObject { @public |
︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 88 89 90 91 92 | - (instancetype)initWithStream: (OFStream *)stream; - (bool)matchesEntry: (OFZIPArchiveEntry *)entry; @end OF_DIRECT_MEMBERS @interface OFZIPArchiveFileReadStream: OFStream { OFStream *_stream, *_decompressedStream; OFZIPArchiveEntry *_entry; unsigned long long _toRead; uint32_t _CRC32; bool _atEndOfStream; } | > | > | > > | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | - (instancetype)initWithStream: (OFStream *)stream; - (bool)matchesEntry: (OFZIPArchiveEntry *)entry; @end OF_DIRECT_MEMBERS @interface OFZIPArchiveFileReadStream: OFStream { OFZIPArchive *_archive; OFStream *_stream, *_decompressedStream; OFZIPArchiveEntry *_entry; unsigned long long _toRead; uint32_t _CRC32; bool _atEndOfStream; } - (instancetype)of_initWithArchive: (OFZIPArchive *)archive stream: (OFStream *)stream entry: (OFZIPArchiveEntry *)entry; @end OF_DIRECT_MEMBERS @interface OFZIPArchiveFileWriteStream: OFStream { OFZIPArchive *_archive; OFStream *_stream; uint32_t _CRC32; @public unsigned long long _bytesWritten; OFMutableZIPArchiveEntry *_entry; } - (instancetype)of_initWithArchive: (OFZIPArchive *)archive stream: (OFStream *)stream entry: (OFMutableZIPArchiveEntry *)entry; @end uint32_t OFZIPArchiveReadField32(const uint8_t **data, uint16_t *size) { uint32_t field = 0; |
︙ | ︙ | |||
253 254 255 256 257 258 259 | if (_stream != nil) [self close]; [_stream release]; [_archiveComment release]; [_entries release]; [_pathToEntryMap release]; | < | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | if (_stream != nil) [self close]; [_stream release]; [_archiveComment release]; [_entries release]; [_pathToEntryMap release]; [super dealloc]; } - (void)of_readZIPInfo { void *pool = objc_autoreleasePoolPush(); |
︙ | ︙ | |||
399 400 401 402 403 404 405 | old = _archiveComment; _archiveComment = [comment copy]; [old release]; objc_autoreleasePoolPop(pool); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > | | 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | old = _archiveComment; _archiveComment = [comment copy]; [old release]; objc_autoreleasePoolPop(pool); } - (OFStream *)streamForReadingFile: (OFString *)path { void *pool = objc_autoreleasePoolPush(); OFZIPArchiveEntry *entry; OFZIPArchiveLocalFileHeader *localFileHeader; int64_t offset64; if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; if ((entry = [_pathToEntryMap objectForKey: path]) == nil) @throw [OFOpenItemFailedException exceptionWithPath: path mode: @"r" errNo: ENOENT]; @try { [_lastReturnedStream close]; } @catch (OFNotOpenException *e) { /* Might have already been closed by the user - that's fine. */ } _lastReturnedStream = nil; offset64 = entry.of_localFileHeaderOffset; if (offset64 < 0 || (OFStreamOffset)offset64 != offset64) @throw [OFOutOfRangeException exception]; seekOrThrowInvalidFormat((OFSeekableStream *)_stream, (OFStreamOffset)offset64, OFSeekSet); |
︙ | ︙ | |||
470 471 472 473 474 475 476 | (localFileHeader->_minVersionNeeded & 0xFF) / 10, (localFileHeader->_minVersionNeeded & 0xFF) % 10]; @throw [OFUnsupportedVersionException exceptionWithVersion: version]; } | > > | > | | < < | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | (localFileHeader->_minVersionNeeded & 0xFF) / 10, (localFileHeader->_minVersionNeeded & 0xFF) % 10]; @throw [OFUnsupportedVersionException exceptionWithVersion: version]; } objc_autoreleasePoolPop(pool); _lastReturnedStream = [[[OFZIPArchiveFileReadStream alloc] of_initWithArchive: self stream: _stream entry: entry] autorelease]; return _lastReturnedStream; } - (OFStream *)streamForWritingEntry: (OFZIPArchiveEntry *)entry_ { /* TODO: Avoid data descriptor when _stream is an OFSeekableStream */ int64_t offsetAdd = 0; void *pool; |
︙ | ︙ | |||
508 509 510 511 512 513 514 | mode: @"w" errNo: EEXIST]; if (entry.compressionMethod != OFZIPArchiveEntryCompressionMethodNone) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; | > > > > > | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | mode: @"w" errNo: EEXIST]; if (entry.compressionMethod != OFZIPArchiveEntryCompressionMethodNone) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; @try { [_lastReturnedStream close]; } @catch (OFNotOpenException *e) { /* Might have already been closed by the user - that's fine. */ } _lastReturnedStream = nil; fileName = entry.fileName; fileNameLength = fileName.UTF8StringLength; extraField = entry.extraField; extraFieldLength = extraField.count; if (UINT16_MAX - extraFieldLength < 20) |
︙ | ︙ | |||
561 562 563 564 565 566 567 | if (INT64_MAX - _offset < offsetAdd) @throw [OFOutOfRangeException exception]; _offset += offsetAdd; _lastReturnedStream = [[OFZIPArchiveFileWriteStream alloc] | > | | | | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | if (INT64_MAX - _offset < offsetAdd) @throw [OFOutOfRangeException exception]; _offset += offsetAdd; _lastReturnedStream = [[OFZIPArchiveFileWriteStream alloc] of_initWithArchive: self stream: _stream entry: entry]; objc_autoreleasePoolPop(pool); return [_lastReturnedStream autorelease]; } - (void)of_writeCentralDirectory { void *pool = objc_autoreleasePoolPush(); _centralDirectoryEntries = 0; |
︙ | ︙ | |||
623 624 625 626 627 628 629 | } - (void)close { if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; | > > > > > | | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 | } - (void)close { if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; @try { [_lastReturnedStream close]; } @catch (OFNotOpenException *e) { /* Might have already been closed by the user - that's fine. */ } _lastReturnedStream = nil; if (_mode == modeWrite || _mode == modeAppend) [self of_writeCentralDirectory]; [_stream release]; _stream = nil; } |
︙ | ︙ | |||
733 734 735 736 737 738 739 | return false; return true; } @end @implementation OFZIPArchiveFileReadStream | | > | > | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | return false; return true; } @end @implementation OFZIPArchiveFileReadStream - (instancetype)of_initWithArchive: (OFZIPArchive *)archive stream: (OFStream *)stream entry: (OFZIPArchiveEntry *)entry { self = [super init]; @try { _archive = [archive retain]; _stream = [stream retain]; switch (entry.compressionMethod) { case OFZIPArchiveEntryCompressionMethodNone: _decompressedStream = [stream retain]; break; case OFZIPArchiveEntryCompressionMethodDeflate: |
︙ | ︙ | |||
776 777 778 779 780 781 782 783 784 785 786 787 788 789 | - (void)dealloc { if (_stream != nil || _decompressedStream != nil) [self close]; [_entry release]; [super dealloc]; } - (bool)lowlevelIsAtEndOfStream { if (_stream == nil) | > > > > > | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 | - (void)dealloc { if (_stream != nil || _decompressedStream != nil) [self close]; [_entry release]; if (_archive->_lastReturnedStream == self) _archive->_lastReturnedStream = nil; [_archive release]; [super dealloc]; } - (bool)lowlevelIsAtEndOfStream { if (_stream == nil) |
︙ | ︙ | |||
860 861 862 863 864 865 866 | _decompressedStream = nil; [super close]; } @end @implementation OFZIPArchiveFileWriteStream | > | | > > > > > > | 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 | _decompressedStream = nil; [super close]; } @end @implementation OFZIPArchiveFileWriteStream - (instancetype)of_initWithArchive: (OFZIPArchive *)archive stream: (OFStream *)stream entry: (OFMutableZIPArchiveEntry *)entry { self = [super init]; _archive = [archive retain]; _stream = [stream retain]; _entry = [entry retain]; _CRC32 = ~0; return self; } - (void)dealloc { if (_stream != nil) [self close]; [_entry release]; if (_archive->_lastReturnedStream == self) _archive->_lastReturnedStream = nil; [_archive release]; [super dealloc]; } - (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { #if SIZE_MAX >= INT64_MAX |
︙ | ︙ | |||
934 935 936 937 938 939 940 941 942 943 944 | _entry.CRC32 = ~_CRC32; _entry.compressedSize = _bytesWritten; _entry.uncompressedSize = _bytesWritten; [_entry makeImmutable]; _bytesWritten += (2 * 4 + 2 * 8); [super close]; } @end | > > > > > > > > | 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 | _entry.CRC32 = ~_CRC32; _entry.compressedSize = _bytesWritten; _entry.uncompressedSize = _bytesWritten; [_entry makeImmutable]; _bytesWritten += (2 * 4 + 2 * 8); [_archive->_entries addObject: _entry]; [_archive->_pathToEntryMap setObject: _entry forKey: _entry.fileName]; if (ULLONG_MAX - _archive->_offset < _bytesWritten) @throw [OFOutOfRangeException exception]; _archive->_offset += _bytesWritten; [super close]; } @end |