ObjFW  Artifact [2297e4dbb2]

Artifact 2297e4dbb2f8f5e1850c9498924912cc8ace0f38542594ecdf99dbae91df9a7f:

  • File src/OFZIPArchive.h — part of check-in [6527c97d03] at 2022-10-09 16:19:17 on branch trunk — OFZIPArchive: Make returned streams retain archive

    In order to not create a retain cycle, this changes the reference to the
    last returned stream to an unsafe unretained one that the stream itself
    needs to reset to nil in its dealloc.

    Since when closing a stream for writing the archive needs to be updated,
    the code for that was moved out of OFZIPArchive and into the stream
    writer, since it now has a reference to the archive anyway. (user: js, size: 6505) [annotate] [blame] [check-ins using]


/*
 * Copyright (c) 2008-2022 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFObject.h"
#import "OFString.h"
#import "OFZIPArchiveEntry.h"

OF_ASSUME_NONNULL_BEGIN

@class OFArray OF_GENERIC(ObjectType);
@class OFMutableArray OF_GENERIC(ObjectType);
@class OFMutableDictionary OF_GENERIC(KeyType, ObjectType);
@class OFStream;

/**
 * @class OFZIPArchive OFZIPArchive.h ObjFW/OFZIPArchive.h
 *
 * @brief A class for accessing and manipulating ZIP files.
 */
OF_SUBCLASSING_RESTRICTED
@interface OFZIPArchive: OFObject
{
	OFStream *_stream;
#ifdef OF_ZIP_ARCHIVE_M
@public
#endif
	int64_t _offset;
@protected
	uint_least8_t _mode;
	uint32_t _diskNumber, _centralDirectoryDisk;
	uint64_t _centralDirectoryEntriesInDisk, _centralDirectoryEntries;
	uint64_t _centralDirectorySize;
	int64_t _centralDirectoryOffset;
	OFString *_Nullable _archiveComment;
#ifdef OF_ZIP_ARCHIVE_M
@public
#endif
	OFMutableArray OF_GENERIC(OFZIPArchiveEntry *) *_entries;
	OFMutableDictionary OF_GENERIC(OFString *, OFZIPArchiveEntry *)
	    *_pathToEntryMap;
	OFStream *_Nullable _lastReturnedStream;
}

/**
 * @brief The archive comment.
 */
@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *archiveComment;

/**
 * @brief The entries in the central directory of the archive as an array of
 *	  objects of class @ref OFZIPArchiveEntry.
 *
 * The objects of the array have the same order as the entries in the central
 * directory, which does not need to be the order in which the actual files are
 * stored.
 */
@property (readonly, nonatomic)
    OFArray OF_GENERIC(OFZIPArchiveEntry *) *entries;

/**
 * @brief Creates a new OFZIPArchive object with the specified stream.
 *
 * @param stream A stream from which the ZIP archive will be read.
 *		 For read and append mode, this needs to be an OFSeekableStream.
 * @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
 *	       archive.
 * @return A new, autoreleased OFZIPArchive
 */
+ (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode;

/**
 * @brief Creates a new OFZIPArchive object with the specified file.
 *
 * @param URI The URI 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
 *	       archive.
 * @return A new, autoreleased OFZIPArchive
 */
+ (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode;

/**
 * @brief Creates a URI for accessing a the specified file within the specified
 *	  ZIP archive.
 *
 * @param path The path of the file within the archive
 * @param archive The URI of the archive
 * @return A URI for accessing the specified file within the specified ZIP
 *	   archive
 */
+ (OFURI *)URIForFile: (OFString *)path inArchive: (OFURI *)archive;

- (instancetype)init OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated OFZIPArchive object with the
 *	  specified stream.
 *
 * @param stream A stream from which the ZIP archive will be read.
 *		 For read and append mode, this needs to be an OFSeekableStream.
 * @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
 *	       archive.
 * @return An initialized OFZIPArchive
 */
- (instancetype)initWithStream: (OFStream *)stream
			  mode: (OFString *)mode OF_DESIGNATED_INITIALIZER;

/**
 * @brief Initializes an already allocated OFZIPArchive object with the
 *	  specified file.
 *
 * @param URI The URI 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
 *	       archive.
 * @return An initialized OFZIPArchive
 */
- (instancetype)initWithURI: (OFURI *)URI mode: (OFString *)mode;

/**
 * @brief Returns a stream for reading the specified file from the archive.
 *
 * @note This method is only available in read mode.
 *
 * @note The returned stream conforms to @ref OFReadyForReadingObserving if the
 *	 underlying stream does so, too.
 *
 * @warning Calling @ref streamForReadingFile: will invalidate all streams
 *	    previously returned by @ref streamForReadingFile: or
 *	    @ref streamForWritingEntry:! Reading from or writing to an
 *	    invalidated stream will throw an @ref OFReadFailedException or
 *	    @ref OFWriteFailedException!
 *
 * @param path The path to the file inside the archive
 * @return A stream for reading the specified file form the archive
 */
- (OFStream *)streamForReadingFile: (OFString *)path;

/**
 * @brief Returns a stream for writing the specified entry to the archive.
 *
 * @note This method is only available in write and append mode.
 *
 * @note The returned stream conforms to @ref OFReadyForWritingObserving if the
 *	 underlying stream does so, too.
 *
 * @warning Calling @ref streamForWritingEntry: will invalidate all streams
 *	    previously returned by @ref streamForReadingFile: or
 *	    @ref streamForWritingEntry:! Reading from or writing to an
 *	    invalidated stream will throw an @ref OFReadFailedException or
 *	    @ref OFWriteFailedException!
 *
 * @param entry The entry to write to the archive.@n
 *		The following parts of the specified entry will be ignored:
 *		  * The lower 8 bits of the version made by.
 *		  * The lower 8 bits of the minimum version needed.
 *		  * The compressed size.
 *		  * The uncompressed size.
 *		  * The CRC32.
 *		  * Bit 3 and 11 of the general purpose bit flag.
 * @return A stream for writing the specified entry to the archive
 */
- (OFStream *)streamForWritingEntry: (OFZIPArchiveEntry *)entry;

/**
 * @brief Closes the OFZIPArchive.
 */
- (void)close;
@end

#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t OFZIPArchiveReadField32(const uint8_t *_Nonnull *_Nonnull,
    uint16_t *_Nonnull);
extern uint64_t OFZIPArchiveReadField64(const uint8_t *_Nonnull *_Nonnull,
    uint16_t *_Nonnull);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END