@@ -18,10 +18,11 @@ #include #import "OFZIPArchive.h" #import "OFZIPArchiveEntry.h" #import "OFZIPArchiveEntry+Private.h" +#import "OFCRC32.h" #import "OFData.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFStream.h" #import "OFSeekableStream.h" @@ -29,12 +30,10 @@ # import "OFFile.h" #endif #import "OFInflateStream.h" #import "OFInflate64Stream.h" -#import "crc32.h" - #import "OFChecksumMismatchException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFNotImplementedException.h" #import "OFNotOpenException.h" @@ -47,10 +46,16 @@ /* * FIXME: Current limitations: * - Split archives are not supported. * - Encrypted files cannot be read. */ + +enum { + modeRead, + modeWrite, + modeAppend +}; OF_DIRECT_MEMBERS @interface OFZIPArchive () - (void)of_readZIPInfo; - (void)of_readEntries; @@ -101,11 +106,11 @@ - (instancetype)initWithStream: (OFStream *)stream entry: (OFMutableZIPArchiveEntry *)entry; @end uint32_t -of_zip_archive_read_field32(const uint8_t **data, uint16_t *size) +OFZIPArchiveReadField32(const uint8_t **data, uint16_t *size) { uint32_t field = 0; if (*size < 4) @throw [OFInvalidFormatException exception]; @@ -118,11 +123,11 @@ return field; } uint64_t -of_zip_archive_read_field64(const uint8_t **data, uint16_t *size) +OFZIPArchiveReadField64(const uint8_t **data, uint16_t *size) { uint64_t field = 0; if (*size < 8) @throw [OFInvalidFormatException exception]; @@ -136,15 +141,14 @@ return field; } static void seekOrThrowInvalidFormat(OFSeekableStream *stream, - of_offset_t offset, int whence) + OFFileOffset offset, int whence) { @try { - [stream seekToOffset: offset - whence: whence]; + [stream seekToOffset: offset whence: whence]; } @catch (OFSeekFailedException *e) { if (e.errNo == EINVAL) @throw [OFInvalidFormatException exception]; @throw e; @@ -152,63 +156,57 @@ } @implementation OFZIPArchive @synthesize archiveComment = _archiveComment; -+ (instancetype)archiveWithStream: (OFStream *)stream - mode: (OFString *)mode ++ (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode { - return [[[self alloc] initWithStream: stream - mode: mode] autorelease]; + return [[[self alloc] initWithStream: stream mode: mode] autorelease]; } #ifdef OF_HAVE_FILES -+ (instancetype)archiveWithPath: (OFString *)path - mode: (OFString *)mode ++ (instancetype)archiveWithPath: (OFString *)path mode: (OFString *)mode { - return [[[self alloc] initWithPath: path - mode: mode] autorelease]; + return [[[self alloc] initWithPath: path mode: mode] autorelease]; } #endif - (instancetype)init { OF_INVALID_INIT_METHOD } -- (instancetype)initWithStream: (OFStream *)stream - mode: (OFString *)mode +- (instancetype)initWithStream: (OFStream *)stream mode: (OFString *)mode { self = [super init]; @try { if ([mode isEqual: @"r"]) - _mode = OF_ZIP_ARCHIVE_MODE_READ; + _mode = modeRead; else if ([mode isEqual: @"w"]) - _mode = OF_ZIP_ARCHIVE_MODE_WRITE; + _mode = modeWrite; else if ([mode isEqual: @"a"]) - _mode = OF_ZIP_ARCHIVE_MODE_APPEND; + _mode = modeAppend; else @throw [OFInvalidArgumentException exception]; _stream = [stream retain]; _entries = [[OFMutableArray alloc] init]; _pathToEntryMap = [[OFMutableDictionary alloc] init]; - if (_mode == OF_ZIP_ARCHIVE_MODE_READ || - _mode == OF_ZIP_ARCHIVE_MODE_APPEND) { + if (_mode == modeRead || _mode == modeAppend) { if (![stream isKindOfClass: [OFSeekableStream class]]) @throw [OFInvalidArgumentException exception]; [self of_readZIPInfo]; [self of_readEntries]; } - if (_mode == OF_ZIP_ARCHIVE_MODE_APPEND) { + if (_mode == modeAppend) { _offset = _centralDirectoryOffset; seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - (of_offset_t)_offset, SEEK_SET); + (OFFileOffset)_offset, SEEK_SET); } } @catch (id e) { /* * If we are in write or append mode, we do not want -[close] * to write anything to it on error - after all, it might not @@ -223,25 +221,21 @@ return self; } #ifdef OF_HAVE_FILES -- (instancetype)initWithPath: (OFString *)path - mode: (OFString *)mode +- (instancetype)initWithPath: (OFString *)path mode: (OFString *)mode { OFFile *file; if ([mode isEqual: @"a"]) - file = [[OFFile alloc] initWithPath: path - mode: @"r+"]; + file = [[OFFile alloc] initWithPath: path mode: @"r+"]; else - file = [[OFFile alloc] initWithPath: path - mode: mode]; + file = [[OFFile alloc] initWithPath: path mode: mode]; @try { - self = [self initWithStream: file - mode: mode]; + self = [self initWithStream: file mode: mode]; } @finally { [file release]; } return self; @@ -264,11 +258,11 @@ - (void)of_readZIPInfo { void *pool = objc_autoreleasePoolPush(); uint16_t commentLength; - of_offset_t offset = -22; + OFFileOffset offset = -22; bool valid = false; do { seekOrThrowInvalidFormat((OFSeekableStream *)_stream, offset, SEEK_END); @@ -290,11 +284,11 @@ _centralDirectoryOffset = [_stream readLittleEndianInt32]; commentLength = [_stream readLittleEndianInt16]; _archiveComment = [[_stream readStringWithLength: commentLength - encoding: OF_STRING_ENCODING_CODEPAGE_437] copy]; + encoding: OFStringEncodingCodepage437] copy]; if (_diskNumber == 0xFFFF || _centralDirectoryDisk == 0xFFFF || _centralDirectoryEntriesInDisk == 0xFFFF || _centralDirectoryEntries == 0xFFFF || @@ -316,15 +310,15 @@ * central directory record. */ [_stream readLittleEndianInt32]; offset64 = [_stream readLittleEndianInt64]; - if (offset64 < 0 || (of_offset_t)offset64 != offset64) + if (offset64 < 0 || (OFFileOffset)offset64 != offset64) @throw [OFOutOfRangeException exception]; seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - (of_offset_t)offset64, SEEK_SET); + (OFFileOffset)offset64, SEEK_SET); if ([_stream readLittleEndianInt32] != 0x06064B50) @throw [OFInvalidFormatException exception]; size = [_stream readLittleEndianInt64]; @@ -343,11 +337,11 @@ _centralDirectoryEntries = [_stream readLittleEndianInt64]; _centralDirectorySize = [_stream readLittleEndianInt64]; _centralDirectoryOffset = [_stream readLittleEndianInt64]; if (_centralDirectoryOffset < 0 || - (of_offset_t)_centralDirectoryOffset != + (OFFileOffset)_centralDirectoryOffset != _centralDirectoryOffset) @throw [OFOutOfRangeException exception]; } objc_autoreleasePoolPop(pool); @@ -356,26 +350,25 @@ - (void)of_readEntries { void *pool = objc_autoreleasePoolPush(); if (_centralDirectoryOffset < 0 || - (of_offset_t)_centralDirectoryOffset != _centralDirectoryOffset) + (OFFileOffset)_centralDirectoryOffset != _centralDirectoryOffset) @throw [OFOutOfRangeException exception]; seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - (of_offset_t)_centralDirectoryOffset, SEEK_SET); + (OFFileOffset)_centralDirectoryOffset, SEEK_SET); for (size_t i = 0; i < _centralDirectoryEntries; i++) { OFZIPArchiveEntry *entry = [[[OFZIPArchiveEntry alloc] of_initWithStream: _stream] autorelease]; if ([_pathToEntryMap objectForKey: entry.fileName] != nil) @throw [OFInvalidFormatException exception]; [_entries addObject: entry]; - [_pathToEntryMap setObject: entry - forKey: entry.fileName]; + [_pathToEntryMap setObject: entry forKey: entry.fileName]; } objc_autoreleasePoolPop(pool); } @@ -410,12 +403,11 @@ [_lastReturnedStream close]; } @catch (OFNotOpenException *e) { /* Might have already been closed by the user - that's fine. */ } - if ((_mode == OF_ZIP_ARCHIVE_MODE_WRITE || - _mode == OF_ZIP_ARCHIVE_MODE_APPEND) && + if ((_mode == modeWrite || _mode == modeAppend) && [_lastReturnedStream isKindOfClass: [OFZIPArchiveFileWriteStream class]]) { OFZIPArchiveFileWriteStream *stream = (OFZIPArchiveFileWriteStream *)_lastReturnedStream; @@ -440,11 +432,11 @@ void *pool = objc_autoreleasePoolPush(); OFZIPArchiveEntry *entry; OFZIPArchiveLocalFileHeader *localFileHeader; int64_t offset64; - if (_mode != OF_ZIP_ARCHIVE_MODE_READ) + if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; if ((entry = [_pathToEntryMap objectForKey: path]) == nil) @throw [OFOpenItemFailedException exceptionWithPath: path mode: @"r" @@ -451,15 +443,15 @@ errNo: ENOENT]; [self of_closeLastReturnedStream]; offset64 = entry.of_localFileHeaderOffset; - if (offset64 < 0 || (of_offset_t)offset64 != offset64) + if (offset64 < 0 || (OFFileOffset)offset64 != offset64) @throw [OFOutOfRangeException exception]; seekOrThrowInvalidFormat((OFSeekableStream *)_stream, - (of_offset_t)offset64, SEEK_SET); + (OFFileOffset)offset64, SEEK_SET); localFileHeader = [[[OFZIPArchiveLocalFileHeader alloc] initWithStream: _stream] autorelease]; if (![localFileHeader matchesEntry: entry]) @throw [OFInvalidFormatException exception]; @@ -490,12 +482,11 @@ OFMutableZIPArchiveEntry *entry; OFString *fileName; OFData *extraField; uint16_t fileNameLength, extraFieldLength; - if (_mode != OF_ZIP_ARCHIVE_MODE_WRITE && - _mode != OF_ZIP_ARCHIVE_MODE_APPEND) + if (_mode != modeWrite && _mode != modeAppend) @throw [OFInvalidArgumentException exception]; pool = objc_autoreleasePoolPush(); entry = [[entry_ mutableCopy] autorelease]; @@ -503,12 +494,11 @@ @throw [OFOpenItemFailedException exceptionWithPath: entry.fileName mode: @"w" errNo: EEXIST]; - if (entry.compressionMethod != - OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE) + if (entry.compressionMethod != OFZIPArchiveEntryCompressionMethodNone) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; [self of_closeLastReturnedStream]; @@ -544,12 +534,11 @@ offsetAdd += 4 + (5 * 2) + (3 * 4) + (2 * 2); [_stream writeString: fileName]; offsetAdd += fileNameLength; - [_stream writeLittleEndianInt16: - OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64]; + [_stream writeLittleEndianInt16: OFZIPArchiveEntryExtraFieldTagZIP64]; [_stream writeLittleEndianInt16: 16]; /* We use the data descriptor */ [_stream writeLittleEndianInt64: 0]; [_stream writeLittleEndianInt64: 0]; offsetAdd += (2 * 2) + (2 * 8); @@ -626,12 +615,11 @@ if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; [self of_closeLastReturnedStream]; - if (_mode == OF_ZIP_ARCHIVE_MODE_WRITE || - _mode == OF_ZIP_ARCHIVE_MODE_APPEND) + if (_mode == modeWrite || _mode == modeAppend) [self of_writeCentralDirectory]; [_stream release]; _stream = nil; } @@ -644,11 +632,11 @@ @try { void *pool = objc_autoreleasePoolPush(); OFMutableData *extraField = nil; uint16_t fileNameLength, extraFieldLength; - of_string_encoding_t encoding; + OFStringEncoding encoding; size_t ZIP64Index; uint16_t ZIP64Size; if ([stream readLittleEndianInt32] != 0x04034B50) @throw [OFInvalidFormatException exception]; @@ -662,33 +650,32 @@ _compressedSize = [stream readLittleEndianInt32]; _uncompressedSize = [stream readLittleEndianInt32]; fileNameLength = [stream readLittleEndianInt16]; extraFieldLength = [stream readLittleEndianInt16]; encoding = (_generalPurposeBitFlag & (1u << 11) - ? OF_STRING_ENCODING_UTF_8 - : OF_STRING_ENCODING_CODEPAGE_437); + ? OFStringEncodingUTF8 : OFStringEncodingCodepage437); _fileName = [[stream readStringWithLength: fileNameLength encoding: encoding] copy]; if (extraFieldLength > 0) extraField = [[[stream readDataWithCount: extraFieldLength] mutableCopy] autorelease]; - ZIP64Index = of_zip_archive_entry_extra_field_find(extraField, - OF_ZIP_ARCHIVE_ENTRY_EXTRA_FIELD_ZIP64, &ZIP64Size); + ZIP64Index = OFZIPArchiveEntryExtraFieldFind(extraField, + OFZIPArchiveEntryExtraFieldTagZIP64, &ZIP64Size); - if (ZIP64Index != OF_NOT_FOUND) { + if (ZIP64Index != OFNotFound) { const uint8_t *ZIP64 = [extraField itemAtIndex: ZIP64Index]; - of_range_t range = - of_range(ZIP64Index - 4, ZIP64Size + 4); + OFRange range = + OFRangeMake(ZIP64Index - 4, ZIP64Size + 4); if (_uncompressedSize == 0xFFFFFFFF) - _uncompressedSize = of_zip_archive_read_field64( + _uncompressedSize = OFZIPArchiveReadField64( &ZIP64, &ZIP64Size); if (_compressedSize == 0xFFFFFFFF) - _compressedSize = of_zip_archive_read_field64( + _compressedSize = OFZIPArchiveReadField64( &ZIP64, &ZIP64Size); if (ZIP64Size > 0) @throw [OFInvalidFormatException exception]; @@ -745,18 +732,18 @@ @try { _stream = [stream retain]; switch (entry.compressionMethod) { - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_NONE: + case OFZIPArchiveEntryCompressionMethodNone: _decompressedStream = [stream retain]; break; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE: + case OFZIPArchiveEntryCompressionMethodDeflate: _decompressedStream = [[OFInflateStream alloc] initWithStream: stream]; break; - case OF_ZIP_ARCHIVE_ENTRY_COMPRESSION_METHOD_DEFLATE64: + case OFZIPArchiveEntryCompressionMethodDeflate64: _decompressedStream = [[OFInflate64Stream alloc] initWithStream: stream]; break; default: @throw [OFNotImplementedException @@ -791,12 +778,11 @@ @throw [OFNotOpenException exceptionWithObject: self]; return _atEndOfStream; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length +- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length { size_t ret; if (_stream == nil) @throw [OFNotOpenException exceptionWithObject: self]; @@ -813,15 +799,14 @@ #endif if ((uint64_t)length > _toRead) length = (size_t)_toRead; - ret = [_decompressedStream readIntoBuffer: buffer - length: length]; + ret = [_decompressedStream readIntoBuffer: buffer length: length]; _toRead -= ret; - _CRC32 = of_crc32(_CRC32, buffer, ret); + _CRC32 = OFCRC32(_CRC32, buffer, ret); if (_toRead == 0) { _atEndOfStream = true; if (~_CRC32 != _entry.CRC32) { @@ -887,12 +872,11 @@ [_entry release]; [super dealloc]; } -- (size_t)lowlevelWriteBuffer: (const void *)buffer - length: (size_t)length +- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length { size_t bytesWritten; #if SIZE_MAX >= INT64_MAX if (length > INT64_MAX) @@ -900,15 +884,14 @@ #endif if (INT64_MAX - _bytesWritten < (int64_t)length) @throw [OFOutOfRangeException exception]; - bytesWritten = [_stream writeBuffer: buffer - length: length]; + bytesWritten = [_stream writeBuffer: buffer length: length]; _bytesWritten += (int64_t)bytesWritten; - _CRC32 = of_crc32(_CRC32, buffer, length); + _CRC32 = OFCRC32(_CRC32, buffer, length); return bytesWritten; } - (void)close