Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -292,10 +292,12 @@ 4B83F0F4142FDEFD00E4A821 /* OFStreamObserver_kqueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B83F0F2142FDEFD00E4A821 /* OFStreamObserver_kqueue.h */; }; 4B83F0F5142FDEFD00E4A821 /* OFStreamObserver_kqueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B83F0F3142FDEFD00E4A821 /* OFStreamObserver_kqueue.m */; }; 4B879A8C177231F000EBCEA4 /* OFDataArray+MessagePackValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B879A89177231F000EBCEA4 /* OFDataArray+MessagePackValue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B879A8D177231F000EBCEA4 /* OFDataArray+MessagePackValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B879A8A177231F000EBCEA4 /* OFDataArray+MessagePackValue.m */; }; 4B879A8E177231F000EBCEA4 /* OFMessagePackRepresentation.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B879A8B177231F000EBCEA4 /* OFMessagePackRepresentation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B8B025917BBA7C7009ED983 /* OFZIPArchiveEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B8B025717BBA7C7009ED983 /* OFZIPArchiveEntry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B8B025A17BBA7C7009ED983 /* OFZIPArchiveEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8B025817BBA7C7009ED983 /* OFZIPArchiveEntry.m */; }; 4B8B16FE133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B8B16FC133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4B8B16FF133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8B16FD133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.m */; }; 4B8B170D133A3C11007CD8B3 /* OFConditionBroadcastFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8B1702133A3B8E007CD8B3 /* OFConditionBroadcastFailedException.m */; }; 4B8B170E133A3C11007CD8B3 /* OFConditionSignalFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8B1704133A3B8E007CD8B3 /* OFConditionSignalFailedException.m */; }; 4B8B170F133A3C11007CD8B3 /* OFConditionWaitFailedException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8B1706133A3B8E007CD8B3 /* OFConditionWaitFailedException.m */; }; @@ -707,10 +709,12 @@ 4B83F0F2142FDEFD00E4A821 /* OFStreamObserver_kqueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamObserver_kqueue.h; path = src/OFStreamObserver_kqueue.h; sourceTree = ""; }; 4B83F0F3142FDEFD00E4A821 /* OFStreamObserver_kqueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamObserver_kqueue.m; path = src/OFStreamObserver_kqueue.m; sourceTree = ""; }; 4B879A89177231F000EBCEA4 /* OFDataArray+MessagePackValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFDataArray+MessagePackValue.h"; path = "src/OFDataArray+MessagePackValue.h"; sourceTree = ""; }; 4B879A8A177231F000EBCEA4 /* OFDataArray+MessagePackValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFDataArray+MessagePackValue.m"; path = "src/OFDataArray+MessagePackValue.m"; sourceTree = ""; }; 4B879A8B177231F000EBCEA4 /* OFMessagePackRepresentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMessagePackRepresentation.h; path = src/OFMessagePackRepresentation.h; sourceTree = ""; }; + 4B8B025717BBA7C7009ED983 /* OFZIPArchiveEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFZIPArchiveEntry.h; path = src/OFZIPArchiveEntry.h; sourceTree = ""; }; + 4B8B025817BBA7C7009ED983 /* OFZIPArchiveEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFZIPArchiveEntry.m; path = src/OFZIPArchiveEntry.m; sourceTree = ""; }; 4B8B16FC133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFHashAlreadyCalculatedException.h; path = src/exceptions/OFHashAlreadyCalculatedException.h; sourceTree = ""; }; 4B8B16FD133A3B84007CD8B3 /* OFHashAlreadyCalculatedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFHashAlreadyCalculatedException.m; path = src/exceptions/OFHashAlreadyCalculatedException.m; sourceTree = ""; }; 4B8B1701133A3B8E007CD8B3 /* OFConditionBroadcastFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFConditionBroadcastFailedException.h; path = src/exceptions/OFConditionBroadcastFailedException.h; sourceTree = ""; }; 4B8B1702133A3B8E007CD8B3 /* OFConditionBroadcastFailedException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFConditionBroadcastFailedException.m; path = src/exceptions/OFConditionBroadcastFailedException.m; sourceTree = ""; }; 4B8B1703133A3B8E007CD8B3 /* OFConditionSignalFailedException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFConditionSignalFailedException.h; path = src/exceptions/OFConditionSignalFailedException.h; sourceTree = ""; }; @@ -1254,10 +1258,12 @@ 4B67998A1099E7C50041064A /* OFXMLParser.m */, 4B48B95214DC23B100546D39 /* OFXMLProcessingInstructions.h */, 4B48B95314DC23B100546D39 /* OFXMLProcessingInstructions.m */, 4BE52D1F17B990B4005958D1 /* OFZIPArchive.h */, 4BE52D2017B990B4005958D1 /* OFZIPArchive.m */, + 4B8B025717BBA7C7009ED983 /* OFZIPArchiveEntry.h */, + 4B8B025817BBA7C7009ED983 /* OFZIPArchiveEntry.m */, 4B6AF97310A8D4450003FB0A /* ObjFW.h */, 4BB52CC817B8EA8E00B7EBF5 /* apple-forwarding-arm.S */, 4BB52CC917B8EA8E00B7EBF5 /* apple-forwarding-i386.S */, 4BB52CCA17B8EA8E00B7EBF5 /* apple-forwarding-ppc.S */, 4BB52CCB17B8EA8E00B7EBF5 /* apple-forwarding-x86_64.S */, @@ -1469,10 +1475,11 @@ 4B3D23E21337FCB000DD29B8 /* OFXMLElementBuilder.h in Headers */, 4B11005C14329B9A003A45D8 /* OFXMLNode.h in Headers */, 4B3D23E31337FCB000DD29B8 /* OFXMLParser.h in Headers */, 4B48B95414DC23B100546D39 /* OFXMLProcessingInstructions.h in Headers */, 4BE52D2117B990B4005958D1 /* OFZIPArchive.h in Headers */, + 4B8B025917BBA7C7009ED983 /* OFZIPArchiveEntry.h in Headers */, 4B3D23E41337FCB000DD29B8 /* ObjFW.h in Headers */, 4B3D23E51337FCB000DD29B8 /* asprintf.h in Headers */, 4B3D23E61337FCB000DD29B8 /* atomic.h in Headers */, 4BA9CFA415E129D30076DC74 /* autorelease.h in Headers */, 4B3D23E71337FCB000DD29B8 /* base64.h in Headers */, @@ -1827,10 +1834,11 @@ 4B3D23B01337FC0D00DD29B8 /* OFXMLElementBuilder.m in Sources */, 4B11005D14329B9A003A45D8 /* OFXMLNode.m in Sources */, 4B3D23B11337FC0D00DD29B8 /* OFXMLParser.m in Sources */, 4B48B95514DC23B100546D39 /* OFXMLProcessingInstructions.m in Sources */, 4BE52D2217B990B4005958D1 /* OFZIPArchive.m in Sources */, + 4B8B025A17BBA7C7009ED983 /* OFZIPArchiveEntry.m in Sources */, 4B3D23B31337FC0D00DD29B8 /* base64.m in Sources */, 4BB52CC717B8EA7F00B7EBF5 /* codepage_437.m in Sources */, 4B3D23B41337FC0D00DD29B8 /* iso_8859_15.m in Sources */, 4BEF2D3117A5BF5200BB8BA3 /* forwarding.S in Sources */, 4B3D23B51337FC0D00DD29B8 /* foundation-compat.m in Sources */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -62,10 +62,11 @@ OFXMLElementBuilder.m \ OFXMLNode.m \ OFXMLParser.m \ OFXMLProcessingInstructions.m \ OFZIPArchive.m \ + OFZIPArchiveEntry.m \ base64.m \ of_asprintf.m \ of_strptime.m \ unicode.m \ ${USE_SRCS_PLUGINS} \ Index: src/OFZIPArchive.h ================================================================== --- src/OFZIPArchive.h +++ src/OFZIPArchive.h @@ -16,11 +16,11 @@ #import "OFObject.h" #import "OFString.h" @class OFFile; -@class OFMutableArray; +@class OFDictionary; @class OFMutableDictionary; @class OFStream; /*! * @brief A class for accessing and manipulating ZIP files. @@ -31,17 +31,16 @@ OFString *_path; uint16_t _diskNumber, _centralDirectoryDisk; uint16_t _centralDirectoryEntriesInDisk, _centralDirectoryEntries; uint32_t _centralDirectorySize, _centralDirectoryOffset; OFString *_archiveComment; - OFMutableArray *_filesInArchive; - OFMutableDictionary *_fileHeaders; + OFMutableDictionary *_entries; } #ifdef OF_HAVE_PROPERTIES @property (readonly, copy) OFString *archiveComment; -@property (readonly, copy) OFArray *filesInArchive; +@property (readonly, copy) OFDictionary *entries; #endif /*! * @brief Creates a new OFZIPArchive object for the specified file. * @@ -58,15 +57,18 @@ * @return An Initialized OFZIPArchive */ - initWithFile: (OFString*)path; /*! - * @brief Returns an array with the names of all files in the archive. + * @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 An array with the names of all files in the archive + * @return The entries in the central directory of the archive as a dictionary */ -- (OFArray*)filesInArchive; +- (OFDictionary*)entries; /*! * @brief Returns the archive comment. * * @return The archive comment @@ -80,7 +82,7 @@ * @return A stream for reading the specified file form the archive */ - (OFStream*)streamForReadingFile: (OFString*)path; - (void)OF_readZIPInfo; -- (void)OF_readFileHeaders; +- (void)OF_readEntries; @end Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -17,11 +17,11 @@ #include "config.h" #include #import "OFZIPArchive.h" -#import "OFArray.h" +#import "OFZIPArchiveEntry.h" #import "OFDictionary.h" #import "OFFile.h" #import "OFChecksumFailedException.h" #import "OFInvalidArgumentException.h" @@ -44,27 +44,10 @@ * - Write support is missing. * - The ZIP has to be a file on the local file system. * - No support for ZIP64. */ -@interface OFZIPArchive_FileHeader: OFObject -{ -@public - uint16_t _madeWithVersion, _minVersion, _generalPurposeBitFlag; - uint16_t _compressionMethod, _lastModifiedFileTime; - uint16_t _lastModifiedFileDate; - uint32_t _CRC32, _compressedSize, _uncompressedSize; - OFString *_fileName; - OFDataArray *_extraField; - OFString *_fileComment; - uint16_t _startDiskNumber, _internalAttributes; - uint32_t _externalAttributes, _localFileHeaderOffset; -} - -- initWithFile: (OFFile*)file; -@end - @interface OFZIPArchive_LocalFileHeader: OFObject { @public uint16_t _minVersion, _generalPurposeBitFlag, _compressionMethod; uint16_t _lastModifiedFileTime, _lastModifiedFileDate; @@ -72,11 +55,11 @@ OFString *_fileName; OFDataArray *_extraField; } - initWithFile: (OFFile*)file; -- (bool)matchesFileHeader: (OFZIPArchive_FileHeader*)fileHeader; +- (bool)matchesEntry: (OFZIPArchiveEntry*)entry; @end @interface OFZIPArchive_FileStream: OFStream { OFFile *_file; @@ -122,11 +105,11 @@ _file = [[OFFile alloc] initWithPath: path mode: @"rb"]; _path = [path copy]; [self OF_readZIPInfo]; - [self OF_readFileHeaders]; + [self OF_readEntries]; } @catch (id e) { [self release]; @throw e; } @@ -136,12 +119,11 @@ - (void)dealloc { [_file release]; [_path release]; [_archiveComment release]; - [_filesInArchive release]; - [_fileHeaders release]; + [_entries release]; [super dealloc]; } - (void)OF_readZIPInfo @@ -168,40 +150,39 @@ encoding: OF_STRING_ENCODING_CODEPAGE_437] copy]; objc_autoreleasePoolPop(pool); } -- (void)OF_readFileHeaders +- (void)OF_readEntries { void *pool = objc_autoreleasePoolPush(); size_t i; [_file seekToOffset: _centralDirectoryOffset whence: SEEK_SET]; - _filesInArchive = [[OFMutableArray alloc] init]; - _fileHeaders = [[OFMutableDictionary alloc] init]; + _entries = [[OFMutableDictionary alloc] init]; for (i = 0; i < _centralDirectoryEntries; i++) { - OFZIPArchive_FileHeader *fileHeader = - [[[OFZIPArchive_FileHeader alloc] - initWithFile: _file] autorelease]; + OFZIPArchiveEntry *entry = [[[OFZIPArchiveEntry alloc] + OF_initWithFile: _file] autorelease]; + + if ([_entries objectForKey: [entry fileName]] != nil) + @throw [OFInvalidFormatException exception]; - [_filesInArchive addObject: fileHeader->_fileName]; - [_fileHeaders setObject: fileHeader - forKey: fileHeader->_fileName]; + [_entries setObject: entry + forKey: [entry fileName]]; } - [_filesInArchive makeImmutable]; - [_fileHeaders makeImmutable]; + [_entries makeImmutable]; objc_autoreleasePoolPop(pool); } -- (OFArray*)filesInArchive +- (OFDictionary*)entries { - OF_GETTER(_filesInArchive, true) + OF_GETTER(_entries, true) } - (OFString*)archiveComment { OF_GETTER(_archiveComment, true) @@ -209,25 +190,25 @@ - (OFStream*)streamForReadingFile: (OFString*)path { OFStream *ret; void *pool = objc_autoreleasePoolPush(); - OFZIPArchive_FileHeader *fileHeader = [_fileHeaders objectForKey: path]; + OFZIPArchiveEntry *entry = [_entries objectForKey: path]; OFZIPArchive_LocalFileHeader *localFileHeader; - if (fileHeader == nil) { + if (entry == nil) { errno = ENOENT; @throw [OFOpenFileFailedException exceptionWithPath: path mode: @"rb"]; } - [_file seekToOffset: fileHeader->_localFileHeaderOffset + [_file seekToOffset: [entry OF_localFileHeaderOffset] whence: SEEK_SET]; localFileHeader = [[[OFZIPArchive_LocalFileHeader alloc] initWithFile: _file] autorelease]; - if (![localFileHeader matchesFileHeader: fileHeader]) + if (![localFileHeader matchesEntry: entry]) @throw [OFInvalidFormatException exception]; if (localFileHeader->_minVersion > 10) { OFString *version = [OFString stringWithFormat: @"%u.%u", localFileHeader->_minVersion / 10, @@ -250,70 +231,10 @@ objc_autoreleasePoolPop(pool); return [ret autorelease]; } -@end - -@implementation OFZIPArchive_FileHeader -- initWithFile: (OFFile*)file -{ - self = [super init]; - - @try { - void *pool = objc_autoreleasePoolPush(); - uint16_t fileNameLength, extraFieldLength, fileCommentLength; - of_string_encoding_t encoding; - - if ([file readLittleEndianInt32] != 0x02014B50) - @throw [OFInvalidFormatException exception]; - - _madeWithVersion = [file readLittleEndianInt16]; - _minVersion = [file readLittleEndianInt16]; - _generalPurposeBitFlag = [file readLittleEndianInt16]; - _compressionMethod = [file readLittleEndianInt16]; - _lastModifiedFileTime = [file readLittleEndianInt16]; - _lastModifiedFileDate = [file readLittleEndianInt16]; - _CRC32 = [file readLittleEndianInt32]; - _compressedSize = [file readLittleEndianInt32]; - _uncompressedSize = [file readLittleEndianInt32]; - fileNameLength = [file readLittleEndianInt16]; - extraFieldLength = [file readLittleEndianInt16]; - fileCommentLength = [file readLittleEndianInt16]; - _startDiskNumber = [file readLittleEndianInt16]; - _internalAttributes = [file readLittleEndianInt16]; - _externalAttributes = [file readLittleEndianInt32]; - _localFileHeaderOffset = [file readLittleEndianInt32]; - - encoding = (_generalPurposeBitFlag & (1 << 11) - ? OF_STRING_ENCODING_UTF_8 - : OF_STRING_ENCODING_CODEPAGE_437); - - _fileName = [[file readStringWithLength: fileNameLength - encoding: encoding] copy]; - _extraField = [[file - readDataArrayWithCount: extraFieldLength] retain]; - _fileComment = [[file readStringWithLength: fileCommentLength - encoding: encoding] copy]; - - objc_autoreleasePoolPop(pool); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_fileName release]; - [_extraField release]; - [_fileComment release]; - - [super dealloc]; -} @end @implementation OFZIPArchive_LocalFileHeader - initWithFile: (OFFile*)file { @@ -358,21 +279,21 @@ [_extraField release]; [super dealloc]; } -- (bool)matchesFileHeader: (OFZIPArchive_FileHeader*)fileHeader -{ - if (_minVersion != fileHeader->_minVersion || - _generalPurposeBitFlag != fileHeader->_generalPurposeBitFlag || - _compressionMethod != fileHeader->_compressionMethod || - _lastModifiedFileTime != fileHeader->_lastModifiedFileTime || - _lastModifiedFileDate != fileHeader->_lastModifiedFileDate || - _CRC32 != fileHeader->_CRC32 || - _compressedSize != fileHeader->_compressedSize || - _uncompressedSize != fileHeader->_uncompressedSize || - ![_fileName isEqual: fileHeader->_fileName]) +- (bool)matchesEntry: (OFZIPArchiveEntry*)entry +{ + if (_minVersion != [entry OF_minVersion] || + _generalPurposeBitFlag != [entry OF_generalPurposeBitFlag] || + _compressionMethod != [entry OF_compressionMethod] || + _lastModifiedFileTime != [entry OF_lastModifiedFileTime] || + _lastModifiedFileDate != [entry OF_lastModifiedFileDate] || + _CRC32 != [entry CRC32] || + _compressedSize != [entry compressedSize] || + _uncompressedSize != [entry uncompressedSize] || + ![_fileName isEqual: [entry fileName]]) return false; return true; } ADDED src/OFZIPArchiveEntry.h Index: src/OFZIPArchiveEntry.h ================================================================== --- src/OFZIPArchiveEntry.h +++ src/OFZIPArchiveEntry.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 + * Jonathan Schleifer + * + * 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" + +#include + +@class OFString; +@class OFDataArray; +@class OFFile; +@class OFDate; + +/*! + * @brief This class represents an entry in the central directory of a ZIP + * archive. + */ +@interface OFZIPArchiveEntry: OFObject +{ + uint16_t _madeWithVersion, _minVersion, _generalPurposeBitFlag; + uint16_t _compressionMethod, _lastModifiedFileTime; + uint16_t _lastModifiedFileDate; + uint32_t _CRC32, _compressedSize, _uncompressedSize; + OFString *_fileName; + OFDataArray *_extraField; + OFString *_fileComment; + uint16_t _startDiskNumber, _internalAttributes; + uint32_t _externalAttributes, _localFileHeaderOffset; +} + +#ifdef OF_HAVE_PROPERTIES +@property (readonly, copy) OFString *fileName, *fileComment; +@property (readonly, retain) OFDate *modificationDate; +@property (readonly) off_t uncompressedSize, compressedSize; +@property (readonly) uint32_t CRC32; +#endif + +- (instancetype)OF_initWithFile: (OFFile*)file; + +/*! + * @brief Returns the file name of the entry. + * + * @return The file name of the entry + */ +- (OFString*)fileName; + +/*! + * @brief Returns the comment of the entry's file. + * + * @return The comment of the entry's file + */ +- (OFString*)fileComment; + +/*! + * @brief Returns the last modification date of the entry's file. + * + * @return The last modification date of the entry's file + */ +- (OFDate*)modificationDate; + +/*! + * @brief Returns the uncompressed size of the entry's file. + * + * @return The uncompressed size of the entry's file + */ +- (off_t)uncompressedSize; + +/*! + * @brief Returns the compressed size of the entry's file. + * + * @return The compressed size of the entry's file + */ +- (off_t)compressedSize; + +/*! + * @brief Returns the CRC32 checksum of the entry's file. + * + * @return The CRC32 checksum of the entry's file + */ +- (uint32_t)CRC32; + +- (uint16_t)OF_madeWithVersion; +- (uint16_t)OF_minVersion; +- (uint16_t)OF_generalPurposeBitFlag; +- (uint16_t)OF_compressionMethod; +- (uint16_t)OF_lastModifiedFileTime; +- (uint16_t)OF_lastModifiedFileDate; +- (OFDataArray*)OF_extraField; +- (uint16_t)OF_startDiskNumber; +- (uint16_t)OF_internalAttributes; +- (uint32_t)OF_externalAttributes; +- (uint32_t)OF_localFileHeaderOffset; +@end ADDED src/OFZIPArchiveEntry.m Index: src/OFZIPArchiveEntry.m ================================================================== --- src/OFZIPArchiveEntry.m +++ src/OFZIPArchiveEntry.m @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 + * Jonathan Schleifer + * + * 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. + */ + +#include "config.h" + +#import "OFZIPArchiveEntry.h" +#import "OFString.h" +#import "OFDataArray.h" +#import "OFFile.h" +#import "OFDate.h" + +#import "autorelease.h" +#import "macros.h" + +#import "OFInvalidFormatException.h" + +@implementation OFZIPArchiveEntry +- (instancetype)OF_initWithFile: (OFFile*)file +{ + self = [super init]; + + @try { + void *pool = objc_autoreleasePoolPush(); + uint16_t fileNameLength, extraFieldLength, fileCommentLength; + of_string_encoding_t encoding; + + if ([file readLittleEndianInt32] != 0x02014B50) + @throw [OFInvalidFormatException exception]; + + _madeWithVersion = [file readLittleEndianInt16]; + _minVersion = [file readLittleEndianInt16]; + _generalPurposeBitFlag = [file readLittleEndianInt16]; + _compressionMethod = [file readLittleEndianInt16]; + _lastModifiedFileTime = [file readLittleEndianInt16]; + _lastModifiedFileDate = [file readLittleEndianInt16]; + _CRC32 = [file readLittleEndianInt32]; + _compressedSize = [file readLittleEndianInt32]; + _uncompressedSize = [file readLittleEndianInt32]; + fileNameLength = [file readLittleEndianInt16]; + extraFieldLength = [file readLittleEndianInt16]; + fileCommentLength = [file readLittleEndianInt16]; + _startDiskNumber = [file readLittleEndianInt16]; + _internalAttributes = [file readLittleEndianInt16]; + _externalAttributes = [file readLittleEndianInt32]; + _localFileHeaderOffset = [file readLittleEndianInt32]; + + encoding = (_generalPurposeBitFlag & (1 << 11) + ? OF_STRING_ENCODING_UTF_8 + : OF_STRING_ENCODING_CODEPAGE_437); + + _fileName = [[file readStringWithLength: fileNameLength + encoding: encoding] copy]; + _extraField = [[file + readDataArrayWithCount: extraFieldLength] retain]; + _fileComment = [[file readStringWithLength: fileCommentLength + encoding: encoding] copy]; + + objc_autoreleasePoolPop(pool); + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_fileName release]; + [_extraField release]; + [_fileComment release]; + + [super dealloc]; +} + +- (OFString*)fileName +{ + OF_GETTER(_fileName, true) +} + +- (OFString*)fileComment +{ + OF_GETTER(_fileComment, true) +} + +- (OFDate*)modificationDate +{ + void *pool = objc_autoreleasePoolPush(); + uint_fast16_t year = ((_lastModifiedFileDate & 0xFE00) >> 9) + 1980; + uint_fast8_t month = (_lastModifiedFileDate & 0x1E0) >> 5; + uint_fast8_t day = (_lastModifiedFileDate & 0x1F); + uint_fast8_t hour = (_lastModifiedFileTime & 0xF800) >> 11; + uint_fast8_t minute = (_lastModifiedFileTime & 0x7E0) >> 5; + uint_fast8_t second = (_lastModifiedFileTime & 0x1F) << 1; + OFDate *date; + OFString *dateString; + + dateString = [OFString + stringWithFormat: @"%04u-%02u-%02u %02u:%02u:%02u", + year, month, day, hour, minute, second]; + + date = [[OFDate alloc] initWithLocalDateString: dateString + format: @"%Y-%m-%d %H:%M:%S"]; + + objc_autoreleasePoolPop(pool); + + return [date autorelease]; +} + +- (off_t)uncompressedSize +{ + return _uncompressedSize; +} + +- (off_t)compressedSize +{ + return _compressedSize; +} + +- (uint32_t)CRC32 +{ + return _CRC32; +} + +- (uint16_t)OF_madeWithVersion +{ + return _madeWithVersion; +} + +- (uint16_t)OF_minVersion +{ + return _minVersion; +} + +- (uint16_t)OF_generalPurposeBitFlag +{ + return _generalPurposeBitFlag; +} + +- (uint16_t)OF_compressionMethod +{ + return _compressionMethod; +} + +- (uint16_t)OF_lastModifiedFileTime +{ + return _lastModifiedFileTime; +} + +- (uint16_t)OF_lastModifiedFileDate +{ + return _lastModifiedFileDate; +} + +- (OFDataArray*)OF_extraField +{ + OF_GETTER(_extraField, true) +} + +- (uint16_t)OF_startDiskNumber +{ + return _startDiskNumber; +} + +- (uint16_t)OF_internalAttributes +{ + return _internalAttributes; +} + +- (uint32_t)OF_externalAttributes +{ + return _externalAttributes; +} + +- (uint32_t)OF_localFileHeaderOffset +{ + return _localFileHeaderOffset; +} +@end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -46,10 +46,11 @@ #import "OFStream.h" #import "OFStdIOStream.h" #import "OFFile.h" #import "OFZIPArchive.h" +#import "OFZIPArchiveEntry.h" #ifdef OF_HAVE_SOCKETS # import "OFStreamSocket.h" # import "OFTCPSocket.h" # import "OFTLSSocket.h" # import "OFStreamObserver.h"