Index: src/OFMutableZIPArchiveEntry.m ================================================================== --- src/OFMutableZIPArchiveEntry.m +++ src/OFMutableZIPArchiveEntry.m @@ -26,11 +26,11 @@ @implementation OFMutableZIPArchiveEntry @dynamic fileName, fileComment, extraField, versionMadeBy, minVersionNeeded; @dynamic modificationDate, compressionMethod, compressedSize, uncompressedSize; @dynamic CRC32, versionSpecificAttributes, generalPurposeBitFlag; -@dynamic of_localFileHeaderOffset; +@dynamic of_startDiskNumber, of_localFileHeaderOffset; /* * The following are optional in OFMutableArchiveEntry, but Apple GCC 4.0.1 is * buggy and needs this to stop complaining. */ @dynamic POSIXPermissions, ownerAccountID, groupOwnerAccountID; @@ -170,10 +170,15 @@ - (void)setGeneralPurposeBitFlag: (uint16_t)generalPurposeBitFlag { _generalPurposeBitFlag = generalPurposeBitFlag; } + +- (void)of_setStartDiskNumber: (uint32_t)startDiskNumber +{ + _startDiskNumber = startDiskNumber; +} - (void)of_setLocalFileHeaderOffset: (int64_t)localFileHeaderOffset { if (localFileHeaderOffset < 0) @throw [OFInvalidArgumentException exception]; Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -152,29 +152,38 @@ @implementation OFZIPArchive @synthesize delegate = _delegate, archiveComment = _archiveComment; static void -seekOrThrowInvalidFormat(OFZIPArchive *archive, const uint32_t *diskNumber, +seekOrThrowInvalidFormat(OFZIPArchive *archive, const uint32_t *diskNumberPtr, OFStreamOffset offset, OFSeekWhence whence) { - if (diskNumber != NULL && *diskNumber != archive->_diskNumber) { + uint32_t diskNumber = 1; + + if (diskNumberPtr != NULL) { + diskNumber = *diskNumberPtr; + + if (diskNumber == 0) + diskNumber = 1; + } + + if (diskNumberPtr != NULL && diskNumber != archive->_diskNumber) { OFStream *oldStream = archive->_stream; OFSeekableStream *stream; if (archive->_mode != modeRead || - *diskNumber > archive->_lastDiskNumber) + diskNumber > archive->_lastDiskNumber) @throw [OFInvalidFormatException exception]; stream = [archive->_delegate archive: archive - wantsPartNumbered: *diskNumber + wantsPartNumbered: diskNumber lastPartNumber: archive->_lastDiskNumber]; if (stream == nil) @throw [OFInvalidFormatException exception]; - archive->_diskNumber = *diskNumber; + archive->_diskNumber = diskNumber; archive->_stream = [stream retain]; [oldStream release]; } @try { @@ -229,10 +238,14 @@ if (![stream isKindOfClass: [OFSeekableStream class]]) @throw [OFInvalidArgumentException exception]; [self of_readZIPInfo]; [self of_readEntries]; + } else if (_mode == modeWrite) { + _diskNumber = 1; + _lastDiskNumber = 1; + _centralDirectoryDisk = 1; } if (_mode == modeAppend) { _offset = _centralDirectoryOffset; seekOrThrowInvalidFormat(self, NULL, @@ -341,14 +354,14 @@ * FIXME: Handle number of the disk containing ZIP64 end of * central directory record. */ diskNumber = [_stream readLittleEndianInt32]; offset64 = [_stream readLittleEndianInt64]; - _lastDiskNumber = [_stream readLittleEndianInt32]; + _diskNumber = _lastDiskNumber = [_stream readLittleEndianInt32]; + if (_lastDiskNumber == 0) @throw [OFInvalidFormatException exception]; - _lastDiskNumber--; if (offset64 < 0 || (OFStreamOffset)offset64 != offset64) @throw [OFOutOfRangeException exception]; seekOrThrowInvalidFormat(self, &diskNumber, @@ -364,11 +377,14 @@ /* version made by */ [_stream readLittleEndianInt16]; /* version needed to extract */ [_stream readLittleEndianInt16]; - if ([_stream readLittleEndianInt32] != _diskNumber) + diskNumber = [_stream readLittleEndianInt32]; + if (diskNumber == 0) + diskNumber = 1; + if (diskNumber != _diskNumber) @throw [OFInvalidFormatException exception]; _centralDirectoryDisk = [_stream readLittleEndianInt32]; _centralDirectoryEntriesInDisk = [_stream readLittleEndianInt64]; @@ -577,10 +593,11 @@ entry.minVersionNeeded = (entry.minVersionNeeded & 0xFF00) | 45; entry.compressedSize = 0; entry.uncompressedSize = 0; entry.CRC32 = 0; entry.generalPurposeBitFlag |= (seekable ? 0 : (1u << 3)) | (1u << 11); + entry.of_startDiskNumber = _diskNumber; entry.of_localFileHeaderOffset = _offset; [_stream writeLittleEndianInt32: 0x04034B50]; [_stream writeLittleEndianInt16: entry.minVersionNeeded]; [_stream writeLittleEndianInt16: entry.generalPurposeBitFlag]; Index: src/OFZIPArchiveEntry+Private.h ================================================================== --- src/OFZIPArchiveEntry+Private.h +++ src/OFZIPArchiveEntry+Private.h @@ -28,10 +28,12 @@ OF_METHOD_FAMILY(init) OF_DIRECT; - (uint64_t)of_writeToStream: (OFStream *)stream OF_DIRECT; @end @interface OFMutableZIPArchiveEntry () +@property (readwrite, nonatomic, setter=of_setStartDiskNumber:) + uint32_t of_startDiskNumber; @property (readwrite, nonatomic, setter=of_setLocalFileHeaderOffset:) int64_t of_localFileHeaderOffset; @end OF_ASSUME_NONNULL_END