Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -879,10 +879,14 @@ 4BA4846215CC9F1E00D75360 /* OFUnsupportedVersionException.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BA4846015CC9F1E00D75360 /* OFUnsupportedVersionException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BA4846315CC9F1E00D75360 /* OFUnsupportedVersionException.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA4846115CC9F1E00D75360 /* OFUnsupportedVersionException.m */; }; 4BA4846615CC9FAD00D75360 /* ForwardingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA4846515CC9FAD00D75360 /* ForwardingTests.m */; }; 4BA49D9013DB113B00381CDB /* OFIntrospection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BA49D8E13DB113B00381CDB /* OFIntrospection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BA49D9113DB113B00381CDB /* OFIntrospection.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA49D8F13DB113B00381CDB /* OFIntrospection.m */; }; + 4BA842E61F35E53800292FC6 /* OFMutableTarArchiveEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BA842E41F35E53800292FC6 /* OFMutableTarArchiveEntry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4BA842E71F35E53800292FC6 /* OFMutableTarArchiveEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BA842E41F35E53800292FC6 /* OFMutableTarArchiveEntry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4BA842E81F35E53800292FC6 /* OFMutableTarArchiveEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA842E51F35E53800292FC6 /* OFMutableTarArchiveEntry.m */; }; + 4BA842E91F35E53800292FC6 /* OFMutableTarArchiveEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA842E51F35E53800292FC6 /* OFMutableTarArchiveEntry.m */; }; 4BA85BCA140ECCE800E91D51 /* OFCountedSet_hashtable.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BA85BC4140ECCE800E91D51 /* OFCountedSet_hashtable.h */; }; 4BA85BCB140ECCE800E91D51 /* OFCountedSet_hashtable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA85BC5140ECCE800E91D51 /* OFCountedSet_hashtable.m */; }; 4BA85BCC140ECCE800E91D51 /* OFMutableSet_hashtable.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BA85BC6140ECCE800E91D51 /* OFMutableSet_hashtable.h */; }; 4BA85BCD140ECCE800E91D51 /* OFMutableSet_hashtable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA85BC7140ECCE800E91D51 /* OFMutableSet_hashtable.m */; }; 4BA85BCE140ECCE800E91D51 /* OFSet_hashtable.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BA85BC8140ECCE800E91D51 /* OFSet_hashtable.h */; }; @@ -1564,10 +1568,12 @@ 4BA4846015CC9F1E00D75360 /* OFUnsupportedVersionException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFUnsupportedVersionException.h; path = src/exceptions/OFUnsupportedVersionException.h; sourceTree = ""; }; 4BA4846115CC9F1E00D75360 /* OFUnsupportedVersionException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFUnsupportedVersionException.m; path = src/exceptions/OFUnsupportedVersionException.m; sourceTree = ""; }; 4BA4846515CC9FAD00D75360 /* ForwardingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ForwardingTests.m; path = tests/ForwardingTests.m; sourceTree = ""; }; 4BA49D8E13DB113B00381CDB /* OFIntrospection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFIntrospection.h; path = src/OFIntrospection.h; sourceTree = ""; }; 4BA49D8F13DB113B00381CDB /* OFIntrospection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFIntrospection.m; path = src/OFIntrospection.m; sourceTree = ""; }; + 4BA842E41F35E53800292FC6 /* OFMutableTarArchiveEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMutableTarArchiveEntry.h; path = src/OFMutableTarArchiveEntry.h; sourceTree = ""; }; + 4BA842E51F35E53800292FC6 /* OFMutableTarArchiveEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFMutableTarArchiveEntry.m; path = src/OFMutableTarArchiveEntry.m; sourceTree = ""; }; 4BA85BC4140ECCE800E91D51 /* OFCountedSet_hashtable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFCountedSet_hashtable.h; path = src/OFCountedSet_hashtable.h; sourceTree = ""; }; 4BA85BC5140ECCE800E91D51 /* OFCountedSet_hashtable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFCountedSet_hashtable.m; path = src/OFCountedSet_hashtable.m; sourceTree = ""; }; 4BA85BC6140ECCE800E91D51 /* OFMutableSet_hashtable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFMutableSet_hashtable.h; path = src/OFMutableSet_hashtable.h; sourceTree = ""; }; 4BA85BC7140ECCE800E91D51 /* OFMutableSet_hashtable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFMutableSet_hashtable.m; path = src/OFMutableSet_hashtable.m; sourceTree = ""; }; 4BA85BC8140ECCE800E91D51 /* OFSet_hashtable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFSet_hashtable.h; path = src/OFSet_hashtable.h; sourceTree = ""; }; @@ -2119,10 +2125,12 @@ 4BA85BC7140ECCE800E91D51 /* OFMutableSet_hashtable.m */, 4B6799731099E7C50041064A /* OFMutableString.h */, 4B6799741099E7C50041064A /* OFMutableString.m */, 4B55254E147AA5DB0003BF47 /* OFMutableString_UTF8.h */, 4B55254F147AA5DB0003BF47 /* OFMutableString_UTF8.m */, + 4BA842E41F35E53800292FC6 /* OFMutableTarArchiveEntry.h */, + 4BA842E51F35E53800292FC6 /* OFMutableTarArchiveEntry.m */, 4B4116CD1F21654200E78916 /* OFMutableURL.h */, 4B4116CE1F21654200E78916 /* OFMutableURL.m */, 4B92FDDC1F35DFAC000D541D /* OFMutableZIPArchiveEntry.h */, 4B92FDDD1F35DFAC000D541D /* OFMutableZIPArchiveEntry.m */, 4B6743FA163C395900EB1E59 /* OFMutex.h */, @@ -2484,10 +2492,11 @@ 4B2C22001DA292BE00735907 /* OFMutableArray.h in Headers */, 4B1223181F23E6C100D9F8FF /* OFMutableData.h in Headers */, 4B2C22011DA292BE00735907 /* OFMutableDictionary.h in Headers */, 4B2C22021DA292BE00735907 /* OFMutableSet.h in Headers */, 4B2C22031DA292BE00735907 /* OFMutableString.h in Headers */, + 4BA842E71F35E53800292FC6 /* OFMutableTarArchiveEntry.h in Headers */, 4B4116D11F21654200E78916 /* OFMutableURL.h in Headers */, 4B92FDE01F35DFB5000D541D /* OFMutableZIPArchiveEntry.h in Headers */, 4B2C22041DA292BE00735907 /* OFMutex.h in Headers */, 4B2C22051DA292BE00735907 /* OFNull.h in Headers */, 4B2C22061DA292BE00735907 /* OFNumber.h in Headers */, @@ -2712,10 +2721,11 @@ 4B3D23CD1337FCB000DD29B8 /* OFMutableArray.h in Headers */, 4B1223151F23E6C000D9F8FF /* OFMutableData.h in Headers */, 4B3D23CE1337FCB000DD29B8 /* OFMutableDictionary.h in Headers */, 4B39844713D3AFB400E6F825 /* OFMutableSet.h in Headers */, 4B3D23CF1337FCB000DD29B8 /* OFMutableString.h in Headers */, + 4BA842E61F35E53800292FC6 /* OFMutableTarArchiveEntry.h in Headers */, 4B4116D01F21654200E78916 /* OFMutableURL.h in Headers */, 4B92FDDF1F35DFB5000D541D /* OFMutableZIPArchiveEntry.h in Headers */, 4B674403163C395900EB1E59 /* OFMutex.h in Headers */, 4B511B7C139C0A34003764A5 /* OFNull.h in Headers */, 4B3D23D01337FCB000DD29B8 /* OFNumber.h in Headers */, @@ -3277,10 +3287,11 @@ 4B2C214B1DA292BE00735907 /* OFMutableDictionary_hashtable.m in Sources */, 4B2C214C1DA292BE00735907 /* OFMutableSet.m in Sources */, 4B2C214D1DA292BE00735907 /* OFMutableSet_hashtable.m in Sources */, 4B2C214E1DA292BE00735907 /* OFMutableString.m in Sources */, 4B2C214F1DA292BE00735907 /* OFMutableString_UTF8.m in Sources */, + 4BA842E91F35E53800292FC6 /* OFMutableTarArchiveEntry.m in Sources */, 4B4116D31F21654200E78916 /* OFMutableURL.m in Sources */, 4B92FDE21F35DFBC000D541D /* OFMutableZIPArchiveEntry.m in Sources */, 4B2C21501DA292BE00735907 /* OFMutex.m in Sources */, 4B2C21511DA292BE00735907 /* OFNull.m in Sources */, 4B2C21521DA292BE00735907 /* OFNumber.m in Sources */, @@ -3478,10 +3489,11 @@ 4B2B3E84140D430500EC2F7C /* OFMutableDictionary_hashtable.m in Sources */, 4B39844813D3AFB400E6F825 /* OFMutableSet.m in Sources */, 4BA85BCD140ECCE800E91D51 /* OFMutableSet_hashtable.m in Sources */, 4B3D239D1337FC0D00DD29B8 /* OFMutableString.m in Sources */, 4B552553147AA5DB0003BF47 /* OFMutableString_UTF8.m in Sources */, + 4BA842E81F35E53800292FC6 /* OFMutableTarArchiveEntry.m in Sources */, 4B4116D21F21654200E78916 /* OFMutableURL.m in Sources */, 4B92FDE11F35DFBB000D541D /* OFMutableZIPArchiveEntry.m in Sources */, 4B674404163C395900EB1E59 /* OFMutex.m in Sources */, 4B511B7D139C0A34003764A5 /* OFNull.m in Sources */, 4B3D239E1337FC0D00DD29B8 /* OFNumber.m in Sources */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -38,10 +38,11 @@ OFMutableArray.m \ OFMutableData.m \ OFMutableDictionary.m \ OFMutableSet.m \ OFMutableString.m \ + OFMutableTarArchiveEntry.m \ OFMutableURL.m \ OFMutableZIPArchiveEntry.m \ OFNull.m \ OFNumber.m \ OFObject.m \ ADDED src/OFMutableTarArchiveEntry.h Index: src/OFMutableTarArchiveEntry.h ================================================================== --- src/OFMutableTarArchiveEntry.h +++ src/OFMutableTarArchiveEntry.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + * 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 "OFTarArchiveEntry.h" + +OF_ASSUME_NONNULL_BEGIN + +/*! + * @class OFMutableTarArchiveEntry \ + * OFMutableTarArchiveEntry.h ObjFW/OFMutableTarArchiveEntry.h + * + * @brief A class which represents a mutable entry of a tar archive. + */ +@interface OFMutableTarArchiveEntry: OFTarArchiveEntry + +/*! + * The file name of the entry. + */ +@property (readwrite, nonatomic, copy) OFString *fileName; + +/*! + * The mode of the entry. + */ +@property (readwrite, nonatomic) uint32_t mode; + +/*! + * The size of the file. + */ +@property (readwrite, nonatomic) uint64_t size; + +/*! + * The date of the last modification of the file. + */ +@property (readwrite, nonatomic, retain) OFDate *modificationDate; + +/*! + * The type of the archive entry. + * + * See @ref of_tar_archive_entry_type_t. + */ +@property (readwrite, nonatomic) of_tar_archive_entry_type_t type; + +/*! + * The file name of the target (for a hard link or symbolic link). + */ +@property OF_NULLABLE_PROPERTY (readwrite, nonatomic, copy) + OFString *targetFileName; + +/*! + * The owner of the file. + */ +@property OF_NULLABLE_PROPERTY (readwrite, nonatomic, copy) OFString *owner; + +/*! + * The group of the file. + */ +@property OF_NULLABLE_PROPERTY (readwrite, nonatomic, copy) OFString *group; + +/*! + * The device major (if the file is a device). + */ +@property (readwrite, nonatomic) uint32_t deviceMajor; + +/*! + * The device major (if the file is a device). + */ +@property (readwrite, nonatomic) uint32_t deviceMinor; + +/*! + * @brief Converts the OFMutableTarArchiveEntry to an immutable + * OFTarArchiveEntry. + */ +- (void)makeImmutable; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFMutableTarArchiveEntry.m Index: src/OFMutableTarArchiveEntry.m ================================================================== --- src/OFMutableTarArchiveEntry.m +++ src/OFMutableTarArchiveEntry.m @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 + * 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 "OFMutableTarArchiveEntry.h" + +@implementation OFMutableTarArchiveEntry +@dynamic fileName, mode, size, modificationDate, type, targetFileName; +@dynamic owner, group, deviceMajor, deviceMinor; + +- copy +{ + OFMutableTarArchiveEntry *copy = [self mutableCopy]; + + [copy makeImmutable]; + + return copy; +} + +- (void)setFileName: (OFString *)fileName +{ + OFString *old = _fileName; + _fileName = [fileName copy]; + [old release]; +} + +- (void)setMode: (uint32_t)mode +{ + _mode = mode; +} + +- (void)setSize: (uint64_t)size +{ + _size = size; +} + +- (void)setDate: (OFDate *)modificationDate +{ + OFDate *old = _modificationDate; + _modificationDate = [modificationDate retain]; + [old release]; +} + +- (void)setType: (of_tar_archive_entry_type_t)type +{ + _type = type; +} + +- (void)setTargetFileName: (OFString *)targetFileName +{ + OFString *old = _targetFileName; + _targetFileName = [targetFileName copy]; + [old release]; +} + +- (void)setOwner: (OFString *)owner +{ + OFString *old = _owner; + _owner = [owner copy]; + [old release]; +} + +- (void)setGroup: (OFString *)group +{ + OFString *old = _group; + _group = [group copy]; + [old release]; +} + +- (void)setDeviceMajor: (uint32_t)deviceMajor +{ + _deviceMajor = deviceMajor; +} + +- (void)setDeviceMinor: (uint32_t)deviceMinor +{ + _deviceMinor = deviceMinor; +} + +- (void)makeImmutable +{ + object_setClass(self, [OFTarArchiveEntry class]); +} +@end Index: src/OFMutableZIPArchiveEntry.h ================================================================== --- src/OFMutableZIPArchiveEntry.h +++ src/OFMutableZIPArchiveEntry.h @@ -111,11 +111,12 @@ * See the ZIP specification for details. */ @property (readwrite, nonatomic) uint16_t generalPurposeBitFlag; /*! - * @brief Converts the OFMutableZIPArchive to an immutable OFZIPArchive. + * @brief Converts the OFMutableZIPArchiveEntry to an immutable + * OFZIPArchiveEntry. */ - (void)makeImmutable; @end OF_ASSUME_NONNULL_END Index: src/OFTarArchive.h ================================================================== --- src/OFTarArchive.h +++ src/OFTarArchive.h @@ -19,29 +19,26 @@ OF_ASSUME_NONNULL_BEGIN @class OFString; @class OFStream; +@class OFTarArchive_FileReadStream; /*! * @class OFTarArchive OFTarArchive.h ObjFW/OFTarArchive.h * * @brief A class for accessing and manipulating tar archives. */ @interface OFTarArchive: OFObject { -#ifdef OF_TAR_ARCHIVE_ENTRY_M -@public -#endif OFStream *_stream; -@protected enum { OF_TAR_ARCHIVE_MODE_READ, OF_TAR_ARCHIVE_MODE_WRITE, OF_TAR_ARCHIVE_MODE_APPEND } _mode; - OFTarArchiveEntry *_lastReturnedEntry; + OFTarArchive_FileReadStream *_lastReturnedStream; } /*! * @brief Creates a new OFTarArchive object with the specified stream. * @@ -100,16 +97,23 @@ * @brief Returns the next entry from the tar archive or `nil` if all entries * have been read. * * This is only available in read mode. * - * @warning Calling @ref nextEntry will invalidate all streams returned by the - * previous entry! Reading from an invalidated stream will throw an - * @ref OFReadFailedException! + * @warning Calling @ref nextEntry will invalidate all streams returned by + * @ref streamForReadingCurrentEntry entry! Reading from an + * invalidated stream will throw an @ref OFReadFailedException! * * @return The next entry from the tar archive or `nil` if all entries have * been read */ - (OFTarArchiveEntry *)nextEntry; + +/*! + * @brief Returns a stream for reading the current entry. + * + * @return A stream for reading the current entry + */ +- (OFStream *)streamForReadingCurrentEntry; @end OF_ASSUME_NONNULL_END Index: src/OFTarArchive.m ================================================================== --- src/OFTarArchive.m +++ src/OFTarArchive.m @@ -24,10 +24,24 @@ # import "OFFile.h" #endif #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" +#import "OFNotOpenException.h" + +@interface OFTarArchive_FileReadStream: OFStream +{ + OFStream *_stream; + OFTarArchiveEntry *_entry; + size_t _toRead; + bool _atEndOfStream; +} + +- initWithEntry: (OFTarArchiveEntry *)entry + stream: (OFStream *)stream; +- (void)of_skip; +@end @implementation OFTarArchive: OFObject + (instancetype)archiveWithStream: (OFStream *)stream mode: (OFString *)mode { @@ -82,30 +96,31 @@ #endif - (void)dealloc { [_stream release]; - [_lastReturnedEntry release]; + [_lastReturnedStream release]; [super dealloc]; } - (OFTarArchiveEntry *)nextEntry { + OFTarArchiveEntry *entry; union { char c[512]; uint32_t u32[512 / sizeof(uint32_t)]; } buffer; bool empty = true; if (_mode != OF_TAR_ARCHIVE_MODE_READ) @throw [OFInvalidArgumentException exception]; - [_lastReturnedEntry of_skip]; - [_lastReturnedEntry close]; - [_lastReturnedEntry release]; - _lastReturnedEntry = nil; + [_lastReturnedStream of_skip]; + [_lastReturnedStream close]; + [_lastReturnedStream release]; + _lastReturnedStream = nil; if ([_stream isAtEndOfStream]) return nil; [_stream readIntoBuffer: buffer.c @@ -124,12 +139,118 @@ @throw [OFInvalidFormatException exception]; return nil; } - _lastReturnedEntry = [[OFTarArchiveEntry alloc] - of_initWithHeader: buffer.c - stream: _stream]; + entry = [[[OFTarArchiveEntry alloc] + of_initWithHeader: buffer.c] autorelease]; + + _lastReturnedStream = [[OFTarArchive_FileReadStream alloc] + initWithEntry: entry + stream: _stream]; + + return entry; +} + +- (OFStream *)streamForReadingCurrentEntry +{ + return [[_lastReturnedStream retain] autorelease]; +} +@end + +@implementation OFTarArchive_FileReadStream +- initWithEntry: (OFTarArchiveEntry *)entry + stream: (OFStream *)stream +{ + self = [super init]; + + @try { + _entry = [entry copy]; + _stream = [stream retain]; + _toRead = [entry size]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [self close]; + + [_entry release]; + + [super dealloc]; +} + +- (size_t)lowlevelReadIntoBuffer: (void *)buffer + length: (size_t)length +{ + size_t ret; + + if (_stream == nil) + @throw [OFNotOpenException exceptionWithObject: self]; + + if (_atEndOfStream) + return 0; + + if ((uint64_t)length > _toRead) + length = (size_t)_toRead; + + ret = [_stream readIntoBuffer: buffer + length: length]; + + if (ret == 0) + _atEndOfStream = true; + + _toRead -= ret; + + return ret; +} + +- (bool)lowlevelIsAtEndOfStream +{ + if (_stream == nil) + @throw [OFNotOpenException exceptionWithObject: self]; + + return _atEndOfStream; +} + +- (bool)hasDataInReadBuffer +{ + return ([super hasDataInReadBuffer] || [_stream hasDataInReadBuffer]); +} + +- (void)close +{ + [_stream release]; + _stream = nil; + + [super close]; +} + +- (void)of_skip +{ + char buffer[512]; + uint64_t size; + + while (_toRead >= 512) { + [_stream readIntoBuffer: buffer + exactLength: 512]; + _toRead -= 512; + } + + if (_toRead > 0) { + [_stream readIntoBuffer: buffer + exactLength: (size_t)_toRead]; + _toRead = 0; + } + + size = [_entry size]; - return _lastReturnedEntry; + if (size % 512 != 0) + [_stream readIntoBuffer: buffer + exactLength: 512 - ((size_t)size % 512)]; } @end Index: src/OFTarArchiveEntry+Private.h ================================================================== --- src/OFTarArchiveEntry+Private.h +++ src/OFTarArchiveEntry+Private.h @@ -18,10 +18,9 @@ OF_ASSUME_NONNULL_BEGIN @interface OFTarArchiveEntry () - (instancetype)of_initWithHeader: (char [_Nonnull 512])header - stream: (OFStream *)stream OF_METHOD_FAMILY(init); -- (void)of_skip; + OF_METHOD_FAMILY(init); @end OF_ASSUME_NONNULL_END Index: src/OFTarArchiveEntry.h ================================================================== --- src/OFTarArchiveEntry.h +++ src/OFTarArchiveEntry.h @@ -13,11 +13,10 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" -#import "OFStream.h" OF_ASSUME_NONNULL_BEGIN @class OFDate; @@ -46,17 +45,15 @@ /*! * @class OFTarArchiveEntry OFTarArchiveEntry.h ObjFW/OFTarArchiveEntry.h * * @brief A class which represents an entry of a tar archive. */ -@interface OFTarArchiveEntry: OFStream +@interface OFTarArchiveEntry: OFObject { - OFStream *_stream; - bool _atEndOfStream; OFString *_fileName; uint32_t _mode; - uint64_t _size, _toRead; + uint64_t _size; OFDate *_modificationDate; of_tar_archive_entry_type_t _type; OFString *_targetFileName; OFString *_owner, *_group; uint32_t _deviceMajor, _deviceMinor; @@ -90,21 +87,21 @@ @property (readonly, nonatomic) of_tar_archive_entry_type_t type; /*! * The file name of the target (for a hard link or symbolic link). */ -@property (readonly, nonatomic) OFString *targetFileName; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *targetFileName; /*! * The owner of the file. */ -@property (readonly, nonatomic) OFString *owner; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *owner; /*! * The group of the file. */ -@property (readonly, nonatomic) OFString *group; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *group; /*! * The device major (if the file is a device). */ @property (readonly, nonatomic) uint32_t deviceMajor; @@ -112,9 +109,28 @@ /*! * The device major (if the file is a device). */ @property (readonly, nonatomic) uint32_t deviceMinor; +/*! + * @brief Creates a new OFTarArchiveEntry with the specified file name. + * + * @param fileName The file name for the OFTarArchiveEntry + * @return A new, autoreleased OFTarArchiveEntry + */ ++ (instancetype)entryWithFileName: (OFString *)fileName; + - init OF_UNAVAILABLE; + +/*! + * @brief Initializes an already allocated OFTarArchiveEntry with the specified + * file name. + * + * @param fileName The file name for the OFTarArchiveEntry + * @return An initialized OFTarArchiveEntry + */ +- initWithFileName: (OFString *)fileName; @end OF_ASSUME_NONNULL_END + +#import "OFMutableTarArchiveEntry.h" Index: src/OFTarArchiveEntry.m ================================================================== --- src/OFTarArchiveEntry.m +++ src/OFTarArchiveEntry.m @@ -12,22 +12,19 @@ * 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. */ -#define OF_TAR_ARCHIVE_ENTRY_M - #include "config.h" #include #import "OFTarArchiveEntry.h" #import "OFTarArchiveEntry+Private.h" #import "OFStream.h" #import "OFDate.h" -#import "OFNotOpenException.h" #import "OFOutOfRangeException.h" static OFString * stringFromBuffer(const char *buffer, size_t length) { @@ -49,42 +46,42 @@ return value; } @implementation OFTarArchiveEntry -@synthesize fileName = _fileName, mode = _mode, size = _size; -@synthesize modificationDate = _modificationDate, type = _type; -@synthesize targetFileName = _targetFileName; -@synthesize owner = _owner, group = _group; -@synthesize deviceMajor = _deviceMajor, deviceMinor = _deviceMinor; ++ (instancetype)entryWithFileName: (OFString *)fileName +{ + return [[[self alloc] initWithFileName: fileName] autorelease]; +} - init { OF_INVALID_INIT_METHOD } - (instancetype)of_initWithHeader: (char [512])header - stream: (OFStream *)stream { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); - - _stream = [stream retain]; + OFString *targetFileName; _fileName = [stringFromBuffer(header, 100) copy]; _mode = (uint32_t)octalValueFromBuffer( header + 100, 8, UINT32_MAX); - _size = _toRead = (uint64_t)octalValueFromBuffer( + _size = (uint64_t)octalValueFromBuffer( header + 124, 12, UINT64_MAX); _modificationDate = [[OFDate alloc] initWithTimeIntervalSince1970: (of_time_interval_t)octalValueFromBuffer( header + 136, 12, UINTMAX_MAX)]; _type = header[156]; - _targetFileName = [stringFromBuffer(header + 157, 100) copy]; + + targetFileName = stringFromBuffer(header + 157, 100); + if ([targetFileName length] > 0) + _targetFileName = [targetFileName copy]; if (_type == '\0') _type = OF_TAR_ARCHIVE_ENTRY_TYPE_FILE; if (memcmp(header + 257, "ustar\0" "00", 8) == 0) { @@ -110,89 +107,112 @@ @throw e; } return self; } + +- initWithFileName: (OFString *)fileName +{ + self = [super init]; + + @try { + _fileName = [fileName copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} - (void)dealloc { - [self close]; - [_fileName release]; [_modificationDate release]; [_targetFileName release]; [_owner release]; [_group release]; [super dealloc]; } -- (size_t)lowlevelReadIntoBuffer: (void *)buffer - length: (size_t)length -{ - size_t ret; - - if (_stream == nil) - @throw [OFNotOpenException exceptionWithObject: self]; - - if (_atEndOfStream) - return 0; - - if ((uint64_t)length > _toRead) - length = (size_t)_toRead; - - ret = [_stream readIntoBuffer: buffer - length: length]; - - if (ret == 0) - _atEndOfStream = true; - - _toRead -= ret; - - return ret; -} - -- (bool)lowlevelIsAtEndOfStream -{ - if (_stream == nil) - @throw [OFNotOpenException exceptionWithObject: self]; - - return _atEndOfStream; -} - -- (bool)hasDataInReadBuffer -{ - return ([super hasDataInReadBuffer] || [_stream hasDataInReadBuffer]); -} - -- (void)close -{ - [_stream release]; - _stream = nil; - - [super close]; -} - -- (void)of_skip -{ - char buffer[512]; - - while (_toRead >= 512) { - [_stream readIntoBuffer: buffer - exactLength: 512]; - _toRead -= 512; - } - - if (_toRead > 0) { - [_stream readIntoBuffer: buffer - exactLength: (size_t)_toRead]; - _toRead = 0; - } - - if (_size % 512 != 0) - [_stream readIntoBuffer: buffer - exactLength: 512 - ((size_t)_size % 512)]; +- copy +{ + return [self retain]; +} + +- mutableCopy +{ + OFTarArchiveEntry *copy = [[OFMutableTarArchiveEntry alloc] + initWithFileName: _fileName]; + + @try { + copy->_mode = _mode; + copy->_size = _size; + copy->_modificationDate = [_modificationDate copy]; + copy->_type = _type; + copy->_targetFileName = [_targetFileName copy]; + copy->_owner = [_owner copy]; + copy->_group = [_group copy]; + copy->_deviceMajor = _deviceMajor; + copy->_deviceMinor = _deviceMinor; + } @catch (id e) { + [copy release]; + @throw e; + } + + return copy; +} + +- (OFString *)fileName +{ + return _fileName; +} + +- (uint32_t)mode +{ + return _mode; +} + +- (uint64_t)size +{ + return _size; +} + +- (OFDate *)modificationDate +{ + return _modificationDate; +} + +- (of_tar_archive_entry_type_t)type +{ + return _type; +} + +- (OFString *)targetFileName +{ + return _targetFileName; +} + +- (OFString *)owner +{ + return _owner; +} + +- (OFString *)group +{ + return _group; +} + +- (uint32_t)deviceMajor +{ + return _deviceMajor; +} + +- (uint32_t)deviceMinor +{ + return _deviceMinor; } - (OFString *)description { void *pool = objc_autoreleasePoolPush(); Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -378,11 +378,11 @@ initWithStream: _stream localFileHeader: localFileHeader]; objc_autoreleasePoolPop(pool); - return _lastReturnedStream; + return [[_lastReturnedStream retain] autorelease]; } @end @implementation OFZIPArchive_LocalFileHeader - initWithStream: (OFStream *)stream Index: utils/ofzip/TarArchive.m ================================================================== --- utils/ofzip/TarArchive.m +++ utils/ofzip/TarArchive.m @@ -237,10 +237,11 @@ OFString *fileName = [entry fileName]; OFString *outFileName = [fileName stringByStandardizingPath]; OFArray OF_GENERIC(OFString *) *pathComponents; OFString *directory; OFFile *output; + OFStream *stream; uint64_t written = 0, size = [entry size]; int8_t percent = -1, newPercent; if (!all && ![files containsObject: fileName]) continue; @@ -317,12 +318,14 @@ output = [OFFile fileWithPath: outFileName mode: @"w"]; setPermissions(outFileName, entry); - while (![entry isAtEndOfStream]) { - ssize_t length = [app copyBlockFromStream: entry + stream = [_archive streamForReadingCurrentEntry]; + + while (![stream isAtEndOfStream]) { + ssize_t length = [app copyBlockFromStream: stream toStream: output fileName: fileName]; if (length < 0) { app->_exitStatus = 1; @@ -386,16 +389,19 @@ files = [OFMutableSet setWithArray: files_]; while ((entry = [_archive nextEntry]) != nil) { OFString *fileName = [entry fileName]; + OFStream *stream; if (![files containsObject: fileName]) continue; - while (![entry isAtEndOfStream]) { - ssize_t length = [app copyBlockFromStream: entry + stream = [_archive streamForReadingCurrentEntry]; + + while (![stream isAtEndOfStream]) { + ssize_t length = [app copyBlockFromStream: stream toStream: of_stdout fileName: fileName]; if (length < 0) { app->_exitStatus = 1; @@ -402,11 +408,11 @@ return; } } [files removeObject: fileName]; - [entry close]; + [stream close]; if ([files count] == 0) break; }