Index: src/OFZIPArchive.h ================================================================== --- src/OFZIPArchive.h +++ src/OFZIPArchive.h @@ -16,11 +16,12 @@ #import "OFObject.h" #import "OFString.h" @class OFFile; -@class OFDictionary; +@class OFArray; +@class OFMutableArray; @class OFMutableDictionary; @class OFStream; /*! * @brief A class for accessing and manipulating ZIP files. @@ -31,16 +32,17 @@ OFString *_path; uint16_t _diskNumber, _centralDirectoryDisk; uint16_t _centralDirectoryEntriesInDisk, _centralDirectoryEntries; uint32_t _centralDirectorySize, _centralDirectoryOffset; OFString *_archiveComment; - OFMutableDictionary *_entries; + OFMutableArray *_entries; + OFMutableDictionary *_pathToEntryMap; } #ifdef OF_HAVE_PROPERTIES @property (readonly, copy) OFString *archiveComment; -@property (readonly, copy) OFDictionary *entries; +@property (readonly, copy) OFArray *entries; #endif /*! * @brief Creates a new OFZIPArchive object for the specified file. * @@ -57,18 +59,20 @@ * @return An initialized OFZIPArchive */ - initWithPath: (OFString*)path; /*! - * @brief Returns the entries in the central directory of the archive as a - * dictionary. - * - * The dictionary maps the file name to an @ref OFZIPArchiveEntry. - * - * @return The entries in the central directory of the archive as a dictionary - */ -- (OFDictionary*)entries; + * @brief Returns the entries of the central directory of the archive as an + * array of objects of class @ref OFZIPArchiveEntry. + * + * The array is sorted by the offset of the local file header, smallest offset + * to largest offset. This way, hard disk seeks are minimized when the array is + * enumerated to extract all files of the archive. + * + * @return The entries of the central directory of the archive as an array + */ +- (OFArray*)entries; /*! * @brief Returns the archive comment. * * @return The archive comment Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -20,10 +20,11 @@ #import "OFZIPArchive.h" #import "OFZIPArchiveEntry.h" #import "OFZIPArchiveEntry+Private.h" #import "OFDataArray.h" +#import "OFArray.h" #import "OFDictionary.h" #import "OFFile.h" #import "OFDeflateStream.h" #import "OFChecksumFailedException.h" @@ -141,10 +142,11 @@ { [_file release]; [_path release]; [_archiveComment release]; [_entries release]; + [_pathToEntryMap release]; [super dealloc]; } - (void)OF_readZIPInfo @@ -190,29 +192,33 @@ size_t i; [_file seekToOffset: _centralDirectoryOffset whence: SEEK_SET]; - _entries = [[OFMutableDictionary alloc] init]; + _entries = [[OFMutableArray alloc] init]; + _pathToEntryMap = [[OFMutableDictionary alloc] init]; for (i = 0; i < _centralDirectoryEntries; i++) { OFZIPArchiveEntry *entry = [[[OFZIPArchiveEntry alloc] OF_initWithFile: _file] autorelease]; - if ([_entries objectForKey: [entry fileName]] != nil) + if ([_pathToEntryMap objectForKey: [entry fileName]] != nil) @throw [OFInvalidFormatException exception]; - [_entries setObject: entry - forKey: [entry fileName]]; + [_entries addObject: entry]; + [_pathToEntryMap setObject: entry + forKey: [entry fileName]]; } + [_entries sort]; [_entries makeImmutable]; + [_pathToEntryMap makeImmutable]; objc_autoreleasePoolPop(pool); } -- (OFDictionary*)entries +- (OFArray*)entries { OF_GETTER(_entries, true) } - (OFString*)archiveComment @@ -222,11 +228,11 @@ - (OFStream*)streamForReadingFile: (OFString*)path { OFStream *ret; void *pool = objc_autoreleasePoolPush(); - OFZIPArchiveEntry *entry = [_entries objectForKey: path]; + OFZIPArchiveEntry *entry = [_pathToEntryMap objectForKey: path]; OFZIPArchive_LocalFileHeader *localFileHeader; if (entry == nil) { errno = ENOENT; @throw [OFOpenFileFailedException exceptionWithPath: path Index: src/OFZIPArchiveEntry.m ================================================================== --- src/OFZIPArchiveEntry.m +++ src/OFZIPArchiveEntry.m @@ -24,10 +24,11 @@ #import "OFDate.h" #import "autorelease.h" #import "macros.h" +#import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" @implementation OFZIPArchiveEntry - (instancetype)OF_initWithFile: (OFFile*)file { @@ -219,6 +220,23 @@ - (uint32_t)OF_localFileHeaderOffset { return _localFileHeaderOffset; } + +- (of_comparison_result_t)compare: (id)object +{ + OFZIPArchiveEntry *entry; + + if (![object isKindOfClass: [OFZIPArchiveEntry class]]) + @throw [OFInvalidArgumentException exception]; + + entry = object; + + if (_localFileHeaderOffset > entry->_localFileHeaderOffset) + return OF_ORDERED_DESCENDING; + if (_localFileHeaderOffset < entry->_localFileHeaderOffset) + return OF_ORDERED_ASCENDING; + + return OF_ORDERED_SAME; +} @end