Index: src/OFZIPArchive.h ================================================================== --- src/OFZIPArchive.h +++ src/OFZIPArchive.h @@ -32,10 +32,15 @@ * @brief A class for accessing and manipulating ZIP files. */ @interface OFZIPArchive: OFObject { OFSeekableStream *_stream; + enum { + OF_ZIP_ARCHIVE_MODE_READ, + OF_ZIP_ARCHIVE_MODE_WRITE, + OF_ZIP_ARCHIVE_MODE_APPEND + } _mode; uint32_t _diskNumber, _centralDirectoryDisk; uint64_t _centralDirectoryEntriesInDisk, _centralDirectoryEntries; uint64_t _centralDirectorySize; int64_t _centralDirectoryOffset; OFString *_archiveComment; @@ -52,44 +57,60 @@ /*! * @brief Creates a new OFZIPArchive object with the specified seekable stream. * * @param stream A seekable stream from which the ZIP archive will be read + * @param mode The mode for the ZIP file. Valid modes are "r" for reading, + * "w" for creating a new file and "a" for appending to an existing + * file. * @return A new, autoreleased OFZIPArchive */ -+ (instancetype)archiveWithSeekableStream: (OFSeekableStream *)stream; ++ (instancetype)archiveWithSeekableStream: (OFSeekableStream *)stream + mode: (OFString *)mode; #ifdef OF_HAVE_FILES /*! * @brief Creates a new OFZIPArchive object with the specified file. * * @param path The path to the ZIP file + * @param mode The mode for the ZIP file. Valid modes are "r" for reading, + * "w" for creating a new file and "a" for appending to an existing + * file. * @return A new, autoreleased OFZIPArchive */ -+ (instancetype)archiveWithPath: (OFString *)path; ++ (instancetype)archiveWithPath: (OFString *)path + mode: (OFString *)mode; #endif - init OF_UNAVAILABLE; /*! * @brief Initializes an already allocated OFZIPArchive object with the * specified seekable stream. * * @param stream A seekable stream from which the ZIP archive will be read + * @param mode The mode for the ZIP file. Valid modes are "r" for reading, + * "w" for creating a new file and "a" for appending to an existing + * file. * @return An initialized OFZIPArchive */ -- initWithSeekableStream: (OFSeekableStream *)stream OF_DESIGNATED_INITIALIZER; +- initWithSeekableStream: (OFSeekableStream *)stream + mode: (OFString *)mode OF_DESIGNATED_INITIALIZER; #ifdef OF_HAVE_FILES /*! * @brief Initializes an already allocated OFZIPArchive object with the * specified file. * * @param path The path to the ZIP file + * @param mode The mode for the ZIP file. Valid modes are "r" for reading, + * "w" for creating a new file and "a" for appending to an existing + * file. * @return An initialized OFZIPArchive */ -- initWithPath: (OFString *)path; +- initWithPath: (OFString *)path + mode: (OFString *)mode; #endif /*! * @brief Returns the entries of the central directory of the archive as an * array of objects of class @ref OFZIPArchiveEntry. @@ -102,10 +123,12 @@ */ - (OFArray OF_GENERIC(OFZIPArchiveEntry *) *)entries; /*! * @brief Returns a stream for reading the specified file from the archive. + * + * This method is only available in read and append mode. * * @warning Calling @ref streamForReadingFile: will invalidate all streams * previously returned by @ref streamForReadingFile:! Reading from an * invalidated stream will throw an @ref OFReadFailedException! * Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -135,35 +135,45 @@ @implementation OFZIPArchive @synthesize archiveComment = _archiveComment; + (instancetype)archiveWithSeekableStream: (OFSeekableStream *)stream + mode: (OFString *)mode { - return [[[self alloc] initWithSeekableStream: stream] autorelease]; + return [[[self alloc] initWithSeekableStream: stream + mode: mode] autorelease]; } #ifdef OF_HAVE_FILES + (instancetype)archiveWithPath: (OFString *)path + mode: (OFString *)mode { - return [[[self alloc] initWithPath: path] autorelease]; + return [[[self alloc] initWithPath: path + mode: mode] autorelease]; } #endif - init { OF_INVALID_INIT_METHOD } - initWithSeekableStream: (OFSeekableStream *)stream + mode: (OFString *)mode { self = [super init]; @try { _stream = [stream retain]; - [self of_readZIPInfo]; - [self of_readEntries]; + if ([mode isEqual: @"r"]) { + _mode = OF_ZIP_ARCHIVE_MODE_READ; + + [self of_readZIPInfo]; + [self of_readEntries]; + } else + @throw [OFInvalidArgumentException exception]; } @catch (id e) { [self release]; @throw e; } @@ -170,15 +180,17 @@ return self; } #ifdef OF_HAVE_FILES - initWithPath: (OFString *)path + mode: (OFString *)mode { OFFile *file = [[OFFile alloc] initWithPath: path - mode: @"r"]; + mode: mode]; @try { - self = [self initWithSeekableStream: file]; + self = [self initWithSeekableStream: file + mode: mode]; } @finally { [file release]; } return self; @@ -327,11 +339,15 @@ void *pool = objc_autoreleasePoolPush(); OFZIPArchiveEntry *entry = [_pathToEntryMap objectForKey: path]; OFZIPArchive_LocalFileHeader *localFileHeader; int64_t offset64; - if (entry == nil) + if (_mode != OF_ZIP_ARCHIVE_MODE_READ && + _mode != OF_ZIP_ARCHIVE_MODE_APPEND) + @throw [OFInvalidArgumentException exception]; + + if ((entry = [_pathToEntryMap objectForKey: path]) == nil) @throw [OFOpenItemFailedException exceptionWithPath: path mode: @"r" errNo: ENOENT]; [_lastReturnedStream close]; Index: utils/ofzip/ZIPArchive.m ================================================================== --- utils/ofzip/ZIPArchive.m +++ utils/ofzip/ZIPArchive.m @@ -65,11 +65,12 @@ { self = [super init]; @try { _archive = [[OFZIPArchive alloc] - initWithSeekableStream: stream]; + initWithSeekableStream: stream + mode: @"r"]; } @catch (id e) { [self release]; @throw e; }