@@ -11,25 +11,27 @@ * 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_LHA_ARCHIVE_M + #include "config.h" #include #import "OFLHAArchive.h" #import "OFLHAArchiveEntry.h" #import "OFLHAArchiveEntry+Private.h" +#import "OFArchiveURIHandler.h" #import "OFCRC16.h" -#ifdef OF_HAVE_FILES -# import "OFFile.h" -#endif #import "OFLHADecompressingStream.h" -#import "OFStream.h" #import "OFSeekableStream.h" +#import "OFStream.h" #import "OFString.h" +#import "OFURI.h" +#import "OFURIHandler.h" #import "OFChecksumMismatchException.h" #import "OFInvalidArgumentException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" @@ -44,36 +46,40 @@ }; OF_DIRECT_MEMBERS @interface OFLHAArchiveFileReadStream: OFStream { + OFLHAArchive *_archive; OFStream *_stream, *_decompressedStream; OFLHAArchiveEntry *_entry; - uint32_t _toRead, _bytesConsumed; + unsigned long long _toRead; uint16_t _CRC16; bool _atEndOfStream, _skipped; } -- (instancetype)of_initWithStream: (OFStream *)stream - entry: (OFLHAArchiveEntry *)entry; +- (instancetype)of_initWithArchive: (OFLHAArchive *)archive + stream: (OFStream *)stream + entry: (OFLHAArchiveEntry *)entry; - (void)of_skip; @end OF_DIRECT_MEMBERS @interface OFLHAArchiveFileWriteStream: OFStream { + OFLHAArchive *_archive; OFMutableLHAArchiveEntry *_entry; OFStringEncoding _encoding; OFSeekableStream *_stream; - OFFileOffset _headerOffset; + OFStreamOffset _headerOffset; uint32_t _bytesWritten; uint16_t _CRC16; } -- (instancetype)of_initWithStream: (OFSeekableStream *)stream - entry: (OFLHAArchiveEntry *)entry - encoding: (OFStringEncoding)encoding; +- (instancetype)of_initWithArchive: (OFLHAArchive *)archive + stream: (OFSeekableStream *)stream + entry: (OFLHAArchiveEntry *)entry + encoding: (OFStringEncoding)encoding; @end @implementation OFLHAArchive @synthesize encoding = _encoding; @@ -80,16 +86,19 @@ + (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode { return [[[self alloc] initWithStream: stream mode: mode] autorelease]; } -#ifdef OF_HAVE_FILES -+ (instancetype)archiveWithPath: (OFString *)path mode: (OFString *)mode ++ (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode { - return [[[self alloc] initWithPath: path mode: mode] autorelease]; + return [[[self alloc] initWithURI: URI mode: mode] autorelease]; } -#endif + ++ (OFURI *)URIForFilePath: (OFString *)path inArchiveWithURI: (OFURI *)URI +{ + return OFArchiveURIHandlerURIForFileInArchive(@"lha", path, URI); +} - (instancetype)init { OF_INVALID_INIT_METHOD } @@ -114,11 +123,11 @@ ![_stream isKindOfClass: [OFSeekableStream class]]) @throw [OFInvalidArgumentException exception]; if (_mode == modeAppend) [(OFSeekableStream *)_stream seekToOffset: 0 - whence: SEEK_END]; + whence: OFSeekEnd]; _encoding = OFStringEncodingISO8859_1; } @catch (id e) { [self release]; @throw e; @@ -125,54 +134,59 @@ } return self; } -#ifdef OF_HAVE_FILES -- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode -{ - OFFile *file; - - if ([mode isEqual: @"a"]) - file = [[OFFile alloc] initWithPath: path mode: @"r+"]; - else - file = [[OFFile alloc] initWithPath: path mode: mode]; +- (instancetype)initWithURI: (OFURI *)URI mode: (OFString *)mode +{ + void *pool = objc_autoreleasePoolPush(); + OFStream *stream; @try { - self = [self initWithStream: file mode: mode]; - } @finally { - [file release]; + if ([mode isEqual: @"a"]) + stream = [OFURIHandler openItemAtURI: URI mode: @"r+"]; + else + stream = [OFURIHandler openItemAtURI: URI mode: mode]; + } @catch (id e) { + [self release]; + @throw e; } + + self = [self initWithStream: stream mode: mode]; + + objc_autoreleasePoolPop(pool); return self; } -#endif - (void)dealloc { if (_stream != nil) [self close]; + [_currentEntry release]; + [super dealloc]; } - (OFLHAArchiveEntry *)nextEntry { - OFLHAArchiveEntry *entry; char header[21]; size_t headerLen; if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; + + [_currentEntry release]; + _currentEntry = nil; [(OFLHAArchiveFileReadStream *)_lastReturnedStream of_skip]; @try { [_lastReturnedStream close]; } @catch (OFNotOpenException *e) { /* Might have already been closed by the user - that's fine. */ } - [_lastReturnedStream release]; _lastReturnedStream = nil; for (headerLen = 0; headerLen < 21;) { if (_stream.atEndOfStream) { if (headerLen == 0) @@ -186,32 +200,34 @@ headerLen += [_stream readIntoBuffer: header + headerLen length: 21 - headerLen]; } - entry = [[[OFLHAArchiveEntry alloc] + _currentEntry= [[OFLHAArchiveEntry alloc] of_initWithHeader: header stream: _stream - encoding: _encoding] autorelease]; + encoding: _encoding]; - _lastReturnedStream = [[OFLHAArchiveFileReadStream alloc] - of_initWithStream: _stream - entry: entry]; - - return entry; + return _currentEntry; } - (OFStream *)streamForReadingCurrentEntry { if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; - if (_lastReturnedStream == nil) + if (_currentEntry == nil) @throw [OFInvalidArgumentException exception]; - return [[(OFLHAArchiveFileReadStream *)_lastReturnedStream - retain] autorelease]; + _lastReturnedStream = [[[OFLHAArchiveFileReadStream alloc] + of_initWithArchive: self + stream: _stream + entry: _currentEntry] autorelease]; + [_currentEntry release]; + _currentEntry = nil; + + return _lastReturnedStream; } - (OFStream *)streamForWritingEntry: (OFLHAArchiveEntry *)entry { OFString *compressionMethod; @@ -229,20 +245,19 @@ @try { [_lastReturnedStream close]; } @catch (OFNotOpenException *e) { /* Might have already been closed by the user - that's fine. */ } - [_lastReturnedStream release]; _lastReturnedStream = nil; - _lastReturnedStream = [[OFLHAArchiveFileWriteStream alloc] - of_initWithStream: (OFSeekableStream *)_stream - entry: entry - encoding: _encoding]; + _lastReturnedStream = [[[OFLHAArchiveFileWriteStream alloc] + of_initWithArchive: self + stream: (OFSeekableStream *)_stream + entry: entry + encoding: _encoding] autorelease]; - return [[(OFLHAArchiveFileWriteStream *)_lastReturnedStream - retain] autorelease]; + return _lastReturnedStream; } - (void)close { if (_stream == nil) @@ -251,27 +266,28 @@ @try { [_lastReturnedStream close]; } @catch (OFNotOpenException *e) { /* Might have already been closed by the user - that's fine. */ } - [_lastReturnedStream release]; _lastReturnedStream = nil; [_stream release]; _stream = nil; } @end @implementation OFLHAArchiveFileReadStream -- (instancetype)of_initWithStream: (OFStream *)stream - entry: (OFLHAArchiveEntry *)entry +- (instancetype)of_initWithArchive: (OFLHAArchive *)archive + stream: (OFStream *)stream + entry: (OFLHAArchiveEntry *)entry { self = [super init]; @try { OFString *compressionMethod; + _archive = [archive retain]; _stream = [stream retain]; compressionMethod = entry.compressionMethod; if ([compressionMethod isEqual: @"-lh4-"] || @@ -308,10 +324,15 @@ if (_stream != nil || _decompressedStream != nil) [self close]; [_entry release]; + if (_archive->_lastReturnedStream == self) + _archive->_lastReturnedStream = nil; + + [_archive release]; + [super dealloc]; } - (bool)lowlevelIsAtEndOfStream { @@ -333,11 +354,11 @@ if (_stream.atEndOfStream && !_decompressedStream.hasDataInReadBuffer) @throw [OFTruncatedDataException exception]; if (length > _toRead) - length = _toRead; + length = (size_t)_toRead; ret = [_decompressedStream readIntoBuffer: buffer length: length]; _toRead -= ret; _CRC16 = OFCRC16(_CRC16, buffer, ret); @@ -373,11 +394,11 @@ } - (void)of_skip { OFStream *stream; - uint32_t toRead; + unsigned long long toRead; if (_stream == nil || _skipped) return; stream = _stream; @@ -398,22 +419,23 @@ stream = _stream; } if ([stream isKindOfClass: [OFSeekableStream class]] && - (sizeof(OFFileOffset) > 4 || toRead < INT32_MAX)) - [(OFSeekableStream *)stream seekToOffset: (OFFileOffset)toRead - whence: SEEK_CUR]; + toRead < LLONG_MAX && (long long)toRead == (OFStreamOffset)toRead) + [(OFSeekableStream *)stream seekToOffset: (OFStreamOffset)toRead + whence: OFSeekCurrent]; else { while (toRead > 0) { char buffer[512]; - size_t min = toRead; + unsigned long long min = toRead; if (min > 512) min = 512; - toRead -= [stream readIntoBuffer: buffer length: min]; + toRead -= [stream readIntoBuffer: buffer + length: (size_t)min]; } } _toRead = 0; _skipped = true; @@ -435,21 +457,23 @@ [super close]; } @end @implementation OFLHAArchiveFileWriteStream -- (instancetype)of_initWithStream: (OFSeekableStream *)stream - entry: (OFLHAArchiveEntry *)entry - encoding: (OFStringEncoding)encoding +- (instancetype)of_initWithArchive: (OFLHAArchive *)archive + stream: (OFSeekableStream *)stream + entry: (OFLHAArchiveEntry *)entry + encoding: (OFStringEncoding)encoding { self = [super init]; @try { + _archive = [archive retain]; _entry = [entry mutableCopy]; _encoding = encoding; - _headerOffset = [stream seekToOffset: 0 whence: SEEK_CUR]; + _headerOffset = [stream seekToOffset: 0 whence: OFSeekCurrent]; [_entry of_writeToStream: stream encoding: _encoding]; /* * Retain stream last, so that -[close] called by -[dealloc] * doesn't write in case of an error. @@ -467,10 +491,15 @@ { 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 @@ -515,25 +544,25 @@ .fileDescriptorForWriting; } - (void)close { - OFFileOffset offset; + OFStreamOffset offset; if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; _entry.uncompressedSize = _bytesWritten; _entry.compressedSize = _bytesWritten; _entry.CRC16 = _CRC16; - offset = [_stream seekToOffset: 0 whence: SEEK_CUR]; - [_stream seekToOffset: _headerOffset whence: SEEK_SET]; + offset = [_stream seekToOffset: 0 whence: OFSeekCurrent]; + [_stream seekToOffset: _headerOffset whence: OFSeekSet]; [_entry of_writeToStream: _stream encoding: _encoding]; - [_stream seekToOffset: offset whence: SEEK_SET]; + [_stream seekToOffset: offset whence: OFSeekSet]; [_stream release]; _stream = nil; [super close]; } @end