Index: src/OFZooArchive.h ================================================================== --- src/OFZooArchive.h +++ src/OFZooArchive.h @@ -31,10 +31,11 @@ OF_KINDOF(OFStream *) _stream; uint_least8_t _mode; OFStringEncoding _encoding; uint16_t _minVersionNeeded; uint8_t _headerType; + OFString *_Nullable _archiveComment; OFZooArchiveEntry *_Nullable _currentEntry; #ifdef OF_ZOO_ARCHIVE_M @public #endif OFStream *_Nullable _lastReturnedStream; @@ -46,10 +47,15 @@ /** * @brief The encoding to use for the archive. Defaults to UTF-8. */ @property (nonatomic) OFStringEncoding encoding; +/** + * @brief The archive comment. + */ +@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *archiveComment; + /** * @brief Creates a new OFZooArchive object with the specified stream. * * @param stream A stream from which the Zoo archive will be read. * This needs to be an OFSeekableStream. For writing, the stream Index: src/OFZooArchive.m ================================================================== --- src/OFZooArchive.m +++ src/OFZooArchive.m @@ -170,19 +170,21 @@ - (void)dealloc { if (_stream != nil) [self close]; + [_archiveComment release]; [_currentEntry release]; [super dealloc]; } - (void)of_readArchiveHeader { char headerText[20]; - uint32_t firstFileOffset; + uint32_t firstFileOffset, commentOffset; + uint16_t commentLength; [_stream readIntoBuffer: headerText exactLength: 20]; if ([_stream readLittleEndianInt32] != 0xFDC4A7DC) @throw [OFInvalidFormatException exception]; @@ -199,13 +201,42 @@ _minVersionNeeded & 0xFF]]; if ((_headerType = [_stream readInt8]) > 1) @throw [OFUnsupportedVersionException exceptionWithVersion: [OFString stringWithFormat: @"%" PRIu8, _headerType]]; + + commentOffset = [_stream readLittleEndianInt32]; + commentLength = [_stream readLittleEndianInt16]; + + if (commentOffset > 0) { + [_stream seekToOffset: commentOffset whence: OFSeekSet]; + _archiveComment = [_stream readStringWithLength: commentLength + encoding: _encoding]; + } [_stream seekToOffset: firstFileOffset whence: OFSeekSet]; } + +- (OFString *)archiveComment +{ + return _archiveComment; +} + +- (void)setArchiveComment: (OFString *)comment +{ + void *pool = objc_autoreleasePoolPush(); + OFString *old; + + if ([comment cStringLengthWithEncoding: _encoding] > UINT16_MAX) + @throw [OFOutOfRangeException exception]; + + old = _archiveComment; + _archiveComment = [comment copy]; + [old release]; + + objc_autoreleasePoolPop(pool); +} - (OFZooArchiveEntry *)nextEntry { if (_mode != modeRead) @throw [OFInvalidArgumentException exception]; @@ -294,25 +325,37 @@ if (entry.compressionMethod != 0) @throw [OFNotImplementedException exceptionWithSelector: _cmd object: self]; if (_lastHeaderOffset == 0) { + uint16_t commentLength = + [_archiveComment cStringLengthWithEncoding: _encoding]; + /* First file - write header. */ [_stream writeBuffer: "ObjFW Zoo Archive.\x1F" length: 20]; [_stream writeLittleEndianInt32: 0xFDC4A7DC]; - [_stream writeLittleEndianInt32: 42]; - [_stream writeLittleEndianInt32: -42]; + [_stream writeLittleEndianInt32: 42 + commentLength]; + [_stream writeLittleEndianInt32: -(42 + commentLength)]; /* TODO: Increase to 0x201 once we add compressed files. */ [_stream writeBigEndianInt16: 0x200]; /* Header type */ [_stream writeInt8: 1]; - /* Archive comment offset */ - [_stream writeLittleEndianInt32: 0]; - /* Archive comment length */ - [_stream writeLittleEndianInt16: 0]; + + if (_archiveComment != nil) { + [_stream writeLittleEndianInt32: 42]; + [_stream writeLittleEndianInt16: commentLength]; + } else { + [_stream writeLittleEndianInt32: 0]; + [_stream writeLittleEndianInt16: 0]; + } + /* Version flag */ [_stream writeInt8: 0]; + + if (_archiveComment != nil) + [_stream writeString: _archiveComment + encoding: _encoding]; } else [self of_fixUpLastHeader]; @try { [_lastReturnedStream close];