@@ -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];