Index: utils/ofarc/Archive.h ================================================================== --- utils/ofarc/Archive.h +++ utils/ofarc/Archive.h @@ -12,27 +12,30 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #import "OFObject.h" -#import "OFFile.h" -#import "OFArray.h" +#import "OFString.h" OF_ASSUME_NONNULL_BEGIN + +@class OFArray OF_GENERIC(ObjectType); +@class OFIRI; +@class OFStream; @protocol Archive -+ (instancetype)archiveWithPath: (nullable OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding; -- (instancetype)initWithPath: (nullable OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding; ++ (instancetype)archiveWithIRI: (nullable OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding; +- (instancetype)initWithIRI: (nullable OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding; - (void)listFiles; - (void)extractFiles: (OFArray OF_GENERIC(OFString *) *)files; - (void)printFiles: (OFArray OF_GENERIC(OFString *) *)files; @optional - (void)addFiles: (OFArray OF_GENERIC(OFString *) *)files; @end OF_ASSUME_NONNULL_END Index: utils/ofarc/GZIPArchive.h ================================================================== --- utils/ofarc/GZIPArchive.h +++ utils/ofarc/GZIPArchive.h @@ -18,7 +18,8 @@ #import "Archive.h" @interface GZIPArchive: OFObject { OFGZIPStream *_stream; + OFIRI *_archiveIRI; } @end Index: utils/ofarc/GZIPArchive.m ================================================================== --- utils/ofarc/GZIPArchive.m +++ utils/ofarc/GZIPArchive.m @@ -14,26 +14,29 @@ */ #include "config.h" #import "OFApplication.h" +#import "OFArray.h" +#import "OFFile.h" #import "OFFileManager.h" -#import "OFStdIOStream.h" +#import "OFIRI.h" #import "OFLocale.h" +#import "OFStdIOStream.h" #import "GZIPArchive.h" #import "OFArc.h" static OFArc *app; static void -setPermissions(OFString *destination, OFString *source) +setPermissions(OFString *destination, OFIRI *source) { #ifdef OF_FILE_MANAGER_SUPPORTS_PERMISSIONS OFFileManager *fileManager = [OFFileManager defaultManager]; OFFileAttributes attributes = [fileManager - attributesOfItemAtPath: source]; + attributesOfItemAtIRI: source]; OFFileAttributeKey key = OFFilePOSIXPermissions; OFFileAttributes destinationAttributes = [OFDictionary dictionaryWithObject: [attributes objectForKey: key] forKey: key]; @@ -63,31 +66,32 @@ { if (self == [GZIPArchive class]) app = (OFArc *)[OFApplication sharedApplication].delegate; } -+ (instancetype)archiveWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding -{ - return [[[self alloc] initWithPath: path - stream: stream - mode: mode - encoding: encoding] autorelease]; -} - -- (instancetype)initWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding ++ (instancetype)archiveWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding +{ + return [[[self alloc] initWithIRI: IRI + stream: stream + mode: mode + encoding: encoding] autorelease]; +} + +- (instancetype)initWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _stream = [[OFGZIPStream alloc] initWithStream: stream mode: mode]; + _archiveIRI = [IRI copy]; } @catch (id e) { [self release]; @throw e; } @@ -95,10 +99,11 @@ } - (void)dealloc { [_stream release]; + [_archiveIRI release]; [super dealloc]; } - (void)listFiles @@ -119,12 +124,12 @@ @"Cannot extract a specific file of a .gz archive!")]; app->_exitStatus = 1; return; } - fileName = app->_archivePath.lastPathComponent - .stringByDeletingPathExtension; + /* FIXME: Should use IRI-specific path extension deletion. */ + fileName = _archiveIRI.lastPathComponent.stringByDeletingPathExtension; if (app->_outputLevel >= 0) [OFStdOut writeString: OF_LOCALIZED(@"extracting_file", @"Extracting %[file]...", @"file", fileName)]; @@ -131,11 +136,11 @@ if (![app shouldExtractFile: fileName outFileName: fileName]) return; output = [OFFile fileWithPath: fileName mode: @"w"]; - setPermissions(fileName, app->_archivePath); + setPermissions(fileName, _archiveIRI); while (!_stream.atEndOfStream) { ssize_t length = [app copyBlockFromStream: _stream toStream: output fileName: fileName]; @@ -157,11 +162,12 @@ } } - (void)printFiles: (OFArray OF_GENERIC(OFString *) *)files { - OFString *fileName = app->_archivePath.lastPathComponent + /* FIXME: Should use IRI-specific path extension deletion. */ + OFString *fileName = _archiveIRI.lastPathComponent .stringByDeletingPathExtension; if (files.count > 0) { [OFStdErr writeLine: OF_LOCALIZED( @"cannot_print_specific_file_from_gz", Index: utils/ofarc/LHAArchive.m ================================================================== --- utils/ofarc/LHAArchive.m +++ utils/ofarc/LHAArchive.m @@ -18,11 +18,13 @@ #include #import "OFApplication.h" #import "OFArray.h" #import "OFDate.h" +#import "OFFile.h" #import "OFFileManager.h" +#import "OFIRI.h" #import "OFLocale.h" #import "OFNumber.h" #import "OFPair.h" #import "OFSet.h" #import "OFStdIOStream.h" @@ -83,25 +85,25 @@ { if (self == [LHAArchive class]) app = (OFArc *)[OFApplication sharedApplication].delegate; } -+ (instancetype)archiveWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding -{ - return [[[self alloc] initWithPath: path - stream: stream - mode: mode - encoding: encoding] autorelease]; -} - -- (instancetype)initWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding ++ (instancetype)archiveWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding +{ + return [[[self alloc] initWithIRI: IRI + stream: stream + mode: mode + encoding: encoding] autorelease]; +} + +- (instancetype)initWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _archive = [[OFLHAArchive alloc] initWithStream: stream Index: utils/ofarc/OFArc.h ================================================================== --- utils/ofarc/OFArc.h +++ utils/ofarc/OFArc.h @@ -17,10 +17,12 @@ #import "OFString.h" #import "Archive.h" OF_ASSUME_NONNULL_BEGIN + +@class OFIRI; #ifndef S_IRWXG # define S_IRWXG 0 #endif #ifndef S_IRWXO @@ -30,22 +32,21 @@ @interface OFArc: OFObject { int8_t _overwrite; @public int8_t _outputLevel; - OFString *_archivePath; int _exitStatus; } -- (id )openArchiveWithPath: (OFString *)path - type: (OFString *)type - mode: (char)mode - encoding: (OFStringEncoding)encoding; +- (id )openArchiveWithIRI: (nullable OFIRI *)IRI + type: (OFString *)type + mode: (char)mode + encoding: (OFStringEncoding)encoding; - (bool)shouldExtractFile: (OFString *)fileName outFileName: (OFString *)outFileName; - (ssize_t)copyBlockFromStream: (OFStream *)input toStream: (OFStream *)output fileName: (OFString *)fileName; - (nullable OFString *)safeLocalPathForPath: (OFString *)path; @end OF_ASSUME_NONNULL_END Index: utils/ofarc/OFArc.m ================================================================== --- utils/ofarc/OFArc.m +++ utils/ofarc/OFArc.m @@ -20,10 +20,11 @@ #import "OFApplication.h" #import "OFArray.h" #import "OFFile.h" #import "OFFileManager.h" #import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFLocale.h" #import "OFOptionsParser.h" #import "OFSandbox.h" #import "OFStdIOStream.h" @@ -64,10 +65,11 @@ @"directory\n" @" -E --encoding= The encoding used by the archive\n" @" (only tar, lha and zoo files)\n" @" -f --force Force / overwrite files\n" @" -h --help Show this help\n" + @" --iri Use an IRI to access the archive\n" @" -l --list List all files in the archive\n" @" -n --no-clobber Never overwrite files\n" @" -p --print Print one or more files from the " @"archive\n" @" -q --quiet Quiet mode (no output, except " @@ -98,10 +100,22 @@ @"longopt1", longOption1, @"shortopt2", shortOption2Str, @"longopt2", longOption2)]; [OFApplication terminateWithStatus: 1]; } + +static OFIRI * +argumentToIRI(OFString *argument, bool isIRI) +{ + if (isIRI) + return [OFIRI IRIWithString: argument]; + + if ([argument isEqual: @"-"]) + return nil; + + return [OFIRI fileIRIWithPath: argument]; +} static void mutuallyExclusiveError5(OFUnichar shortOption1, OFString *longOption1, OFUnichar shortOption2, OFString *longOption2, OFUnichar shortOption3, OFString *longOption3, @@ -169,17 +183,19 @@ @implementation OFArc - (void)applicationDidFinishLaunching: (OFNotification *)notification { OFString *outputDir, *encodingString, *type; + bool isIRI; const OFOptionsParserOption options[] = { { 'a', @"append", 0, NULL, NULL }, { 'c', @"create", 0, NULL, NULL }, { 'C', @"directory", 1, NULL, &outputDir }, { 'E', @"encoding", 1, NULL, &encodingString }, { 'f', @"force", 0, NULL, NULL }, { 'h', @"help", 0, NULL, NULL }, + { 0, @"iri", 0, &isIRI, NULL }, { 'l', @"list", 0, NULL, NULL }, { 'n', @"no-clobber", 0, NULL, NULL }, { 'p', @"print", 0, NULL, NULL }, { 'q', @"quiet", 0, NULL, NULL }, { 't', @"type", 1, NULL, &type }, @@ -189,10 +205,11 @@ }; OFUnichar option, mode = '\0'; OFStringEncoding encoding = OFStringEncodingAutodetect; OFOptionsParser *optionsParser; OFArray OF_GENERIC(OFString *) *remainingArguments, *files; + OFIRI *IRI; id archive; #ifdef OF_HAVE_SANDBOX OFSandbox *sandbox = [OFSandbox sandbox]; sandbox.allowsStdIO = true; @@ -337,88 +354,90 @@ case 'a': case 'c': if (remainingArguments.count < 1) help(OFStdErr, false, 1); + IRI = argumentToIRI(remainingArguments.firstObject, isIRI); files = [remainingArguments objectsInRange: OFMakeRange(1, remainingArguments.count - 1)]; #ifdef OF_HAVE_SANDBOX - if (![remainingArguments.firstObject isEqual: @"-"]) - [sandbox unveilPath: remainingArguments.firstObject + if ([IRI.scheme isEqual: @"file"]) + [sandbox unveilPath: IRI.path permissions: (mode == 'a' ? @"rwc" : @"wc")]; for (OFString *path in files) [sandbox unveilPath: path permissions: @"r"]; sandbox.allowsUnveil = false; [OFApplication of_activateSandbox: sandbox]; #endif - archive = [self - openArchiveWithPath: remainingArguments.firstObject - type: type - mode: mode - encoding: encoding]; + archive = [self openArchiveWithIRI: IRI + type: type + mode: mode + encoding: encoding]; addFiles(archive, files); break; case 'l': if (remainingArguments.count != 1) help(OFStdErr, false, 1); + IRI = argumentToIRI(remainingArguments.firstObject, isIRI); + #ifdef OF_HAVE_SANDBOX - if (![remainingArguments.firstObject isEqual: @"-"]) - [sandbox unveilPath: remainingArguments.firstObject + if ([IRI.scheme isEqual: @"file"]) + [sandbox unveilPath: IRI.path permissions: @"r"]; sandbox.allowsUnveil = false; [OFApplication of_activateSandbox: sandbox]; #endif - archive = [self - openArchiveWithPath: remainingArguments.firstObject - type: type - mode: mode - encoding: encoding]; + archive = [self openArchiveWithIRI: IRI + type: type + mode: mode + encoding: encoding]; [archive listFiles]; break; case 'p': if (remainingArguments.count < 1) help(OFStdErr, false, 1); + IRI = argumentToIRI(remainingArguments.firstObject, isIRI); + files = [remainingArguments objectsInRange: + OFMakeRange(1, remainingArguments.count - 1)]; + #ifdef OF_HAVE_SANDBOX - if (![remainingArguments.firstObject isEqual: @"-"]) - [sandbox unveilPath: remainingArguments.firstObject + if ([IRI.scheme isEqual: @"file"]) + [sandbox unveilPath: IRI.path permissions: @"r"]; sandbox.allowsUnveil = false; [OFApplication of_activateSandbox: sandbox]; #endif - files = [remainingArguments objectsInRange: - OFMakeRange(1, remainingArguments.count - 1)]; - - archive = [self - openArchiveWithPath: remainingArguments.firstObject - type: type - mode: mode - encoding: encoding]; + archive = [self openArchiveWithIRI: IRI + type: type + mode: mode + encoding: encoding]; [archive printFiles: files]; break; case 'x': if (remainingArguments.count < 1) help(OFStdErr, false, 1); + IRI = argumentToIRI(remainingArguments.firstObject, isIRI); files = [remainingArguments objectsInRange: OFMakeRange(1, remainingArguments.count - 1)]; #ifdef OF_HAVE_SANDBOX - if (![remainingArguments.firstObject isEqual: @"-"]) - [sandbox unveilPath: remainingArguments.firstObject + if ([IRI.scheme isEqual: @"file"]) + [sandbox unveilPath: IRI.path permissions: @"r"]; if (files.count > 0) for (OFString *path in files) [sandbox unveilPath: path permissions: @"wc"]; @@ -435,15 +454,14 @@ sandbox.allowsUnveil = false; [OFApplication of_activateSandbox: sandbox]; #endif - archive = [self - openArchiveWithPath: remainingArguments.firstObject - type: type - mode: mode - encoding: encoding]; + archive = [self openArchiveWithIRI: IRI + type: type + mode: mode + encoding: encoding]; if (outputDir != nil) { OFFileManager *fileManager = [OFFileManager defaultManager]; @@ -455,30 +473,24 @@ } @try { [archive extractFiles: files]; } @catch (OFCreateDirectoryFailedException *e) { - OFString *error = [OFString - stringWithCString: strerror(e.errNo) - encoding: [OFLocale encoding]]; [OFStdErr writeString: @"\r"]; [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_create_directory", @"Failed to create directory %[dir]: %[error]", @"dir", e.IRI.fileSystemRepresentation, - @"error", error)]; + @"error", OFStrError(e.errNo))]; _exitStatus = 1; } @catch (OFOpenItemFailedException *e) { - OFString *error = [OFString - stringWithCString: strerror(e.errNo) - encoding: [OFLocale encoding]]; [OFStdErr writeString: @"\r"]; [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_open_file", @"Failed to open file %[file]: %[error]", @"file", e.path, - @"error", error)]; + @"error", OFStrError(e.errNo))]; _exitStatus = 1; } break; default: @@ -487,27 +499,20 @@ } [OFApplication terminateWithStatus: _exitStatus]; } -- (id )openArchiveWithPath: (OFString *)path_ - type: (OFString *)type - mode: (char)mode - encoding: (OFStringEncoding)encoding +- (id )openArchiveWithIRI: (OFIRI *)IRI + type: (OFString *)type + mode: (char)mode + encoding: (OFStringEncoding)encoding { /* To make clang-analyzer happy about assigning nil to path later. */ - OFString *path = path_; OFString *modeString, *fileModeString; OFStream *file = nil; id archive = nil; - [_archivePath release]; - _archivePath = [path copy]; - - if (path == nil) - return nil; - switch (mode) { case 'a': modeString = @"a"; fileModeString = @"r+"; break; @@ -522,11 +527,11 @@ break; default: @throw [OFInvalidArgumentException exception]; } - if ([path isEqual: @"-"]) { + if (IRI == nil) { switch (mode) { case 'a': case 'c': file = OFStdOut; break; @@ -536,31 +541,27 @@ file = OFStdIn; break; default: @throw [OFInvalidArgumentException exception]; } - - path = nil; } else { @try { - file = [OFFile fileWithPath: path mode: fileModeString]; + file = [OFIRIHandler openItemAtIRI: IRI + mode: fileModeString]; } @catch (OFOpenItemFailedException *e) { - OFString *error = [OFString - stringWithCString: strerror(e.errNo) - encoding: [OFLocale encoding]]; [OFStdErr writeString: @"\r"]; [OFStdErr writeLine: OF_LOCALIZED( @"failed_to_open_file", @"Failed to open file %[file]: %[error]", - @"file", e.path, - @"error", error)]; + @"file", e.IRI.string, + @"error", OFStrError(e.errNo))]; [OFApplication terminateWithStatus: 1]; } } if (type == nil || [type isEqual: @"auto"]) { - OFString *lowercasePath = path.lowercaseString; + OFString *lowercasePath = IRI.path.lowercaseString; /* This one has to be first for obvious reasons */ if ([lowercasePath hasSuffix: @".tar.gz"] || [lowercasePath hasSuffix: @".tgz"]) type = @"tgz"; @@ -579,42 +580,42 @@ type = @"zip"; } @try { if ([type isEqual: @"gz"]) - archive = [GZIPArchive archiveWithPath: path - stream: file - mode: modeString - encoding: encoding]; - else if ([type isEqual: @"lha"]) - archive = [LHAArchive archiveWithPath: path - stream: file - mode: modeString - encoding: encoding]; - else if ([type isEqual: @"tar"]) - archive = [TarArchive archiveWithPath: path + archive = [GZIPArchive archiveWithIRI: IRI stream: file mode: modeString encoding: encoding]; + else if ([type isEqual: @"lha"]) + archive = [LHAArchive archiveWithIRI: IRI + stream: file + mode: modeString + encoding: encoding]; + else if ([type isEqual: @"tar"]) + archive = [TarArchive archiveWithIRI: IRI + stream: file + mode: modeString + encoding: encoding]; else if ([type isEqual: @"tgz"]) { OFStream *GZIPStream = [OFGZIPStream streamWithStream: file mode: modeString]; - archive = [TarArchive archiveWithPath: path - stream: GZIPStream - mode: modeString - encoding: encoding]; + archive = [TarArchive archiveWithIRI: IRI + stream: GZIPStream + mode: modeString + encoding: encoding]; } else if ([type isEqual: @"zip"]) - archive = [ZIPArchive archiveWithPath: path - stream: file - mode: modeString - encoding: encoding]; + archive = [ZIPArchive archiveWithIRI: IRI + stream: file + mode: modeString + encoding: encoding]; else if ([type isEqual: @"zoo"]) - archive = [ZooArchive archiveWithPath: path - stream: file - mode: modeString - encoding: encoding]; + archive = [ZooArchive archiveWithIRI: IRI + stream: file + mode: modeString + encoding: encoding]; else { [OFStdErr writeLine: OF_LOCALIZED( @"unknown_archive_type", @"Unknown archive type: %[type]", @"type", type)]; @@ -627,32 +628,26 @@ goto error; } @throw e; } @catch (OFReadFailedException *e) { - OFString *error = [OFString - stringWithCString: strerror(e.errNo) - encoding: [OFLocale encoding]]; [OFStdErr writeLine: OF_LOCALIZED(@"failed_to_read_file", @"Failed to read file %[file]: %[error]", - @"file", path, - @"error", error)]; + @"file", IRI.string, + @"error", OFStrError(e.errNo))]; goto error; } @catch (OFSeekFailedException *e) { - OFString *error = [OFString - stringWithCString: strerror(e.errNo) - encoding: [OFLocale encoding]]; [OFStdErr writeLine: OF_LOCALIZED(@"failed_to_seek_in_file", @"Failed to seek in file %[file]: %[error]", - @"file", path, - @"error", error)]; + @"file", IRI.string, + @"error", OFStrError(e.errNo))]; goto error; } @catch (OFInvalidFormatException *e) { [OFStdErr writeLine: OF_LOCALIZED( @"file_is_not_a_valid_archive", @"File %[file] is not a valid archive!", - @"file", path)]; + @"file", IRI.string)]; goto error; } if ((mode == 'a' || mode == 'c') && ![archive respondsToSelector: @selector(addFiles:)]) { @@ -661,12 +656,12 @@ } return archive; error: - if (mode == 'c' && path != nil) - [[OFFileManager defaultManager] removeItemAtPath: path]; + if (mode == 'c' && IRI != nil) + [[OFFileManager defaultManager] removeItemAtIRI: IRI]; [OFApplication terminateWithStatus: 1]; abort(); } @@ -737,32 +732,26 @@ size_t length; @try { length = [input readIntoBuffer: buffer length: bufferSize]; } @catch (OFReadFailedException *e) { - OFString *error = [OFString - stringWithCString: strerror(e.errNo) - encoding: [OFLocale encoding]]; [OFStdOut writeString: @"\r"]; [OFStdErr writeLine: OF_LOCALIZED(@"failed_to_read_file", @"Failed to read file %[file]: %[error]", @"file", fileName, - @"error", error)]; + @"error", OFStrError(e.errNo))]; return -1; } @try { [output writeBuffer: buffer length: length]; } @catch (OFWriteFailedException *e) { - OFString *error = [OFString - stringWithCString: strerror(e.errNo) - encoding: [OFLocale encoding]]; [OFStdOut writeString: @"\r"]; [OFStdErr writeLine: OF_LOCALIZED(@"failed_to_write_file", @"Failed to write file %[file]: %[error]", @"file", fileName, - @"error", error)]; + @"error", OFStrError(e.errNo))]; return -1; } return length; } Index: utils/ofarc/TarArchive.m ================================================================== --- utils/ofarc/TarArchive.m +++ utils/ofarc/TarArchive.m @@ -18,10 +18,11 @@ #include #import "OFApplication.h" #import "OFArray.h" #import "OFDate.h" +#import "OFFile.h" #import "OFFileManager.h" #import "OFLocale.h" #import "OFNumber.h" #import "OFPair.h" #import "OFSet.h" @@ -76,25 +77,25 @@ { if (self == [TarArchive class]) app = (OFArc *)[OFApplication sharedApplication].delegate; } -+ (instancetype)archiveWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding -{ - return [[[self alloc] initWithPath: path - stream: stream - mode: mode - encoding: encoding] autorelease]; -} - -- (instancetype)initWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding ++ (instancetype)archiveWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding +{ + return [[[self alloc] initWithIRI: IRI + stream: stream + mode: mode + encoding: encoding] autorelease]; +} + +- (instancetype)initWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _archive = [[OFTarArchive alloc] initWithStream: stream Index: utils/ofarc/ZIPArchive.h ================================================================== --- utils/ofarc/ZIPArchive.h +++ utils/ofarc/ZIPArchive.h @@ -17,9 +17,9 @@ #import "Archive.h" @interface ZIPArchive: OFObject { - OFString *_path; + OFIRI *_archiveIRI; OFZIPArchive *_archive; } @end Index: utils/ofarc/ZIPArchive.m ================================================================== --- utils/ofarc/ZIPArchive.m +++ utils/ofarc/ZIPArchive.m @@ -19,11 +19,14 @@ #import "OFApplication.h" #import "OFArray.h" #import "OFData.h" #import "OFDate.h" +#import "OFFile.h" #import "OFFileManager.h" +#import "OFIRI.h" +#import "OFIRIHandler.h" #import "OFLocale.h" #import "OFNumber.h" #import "OFPair.h" #import "OFSet.h" #import "OFStdIOStream.h" @@ -83,30 +86,30 @@ { if (self == [ZIPArchive class]) app = (OFArc *)[OFApplication sharedApplication].delegate; } -+ (instancetype)archiveWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding -{ - return [[[self alloc] initWithPath: path - stream: stream - mode: mode - encoding: encoding] autorelease]; -} - -- (instancetype)initWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding ++ (instancetype)archiveWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding +{ + return [[[self alloc] initWithIRI: IRI + stream: stream + mode: mode + encoding: encoding] autorelease]; +} + +- (instancetype)initWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding { self = [super init]; @try { - _path = [path copy]; + _archiveIRI = [IRI copy]; _archive = [[OFZIPArchive alloc] initWithStream: stream mode: mode]; _archive.delegate = self; } @catch (id e) { [self release]; @@ -116,36 +119,40 @@ return self; } - (void)dealloc { - [_path release]; + [_archiveIRI release]; [_archive release]; [super dealloc]; } - (OFSeekableStream *)archive: (OFZIPArchive *)archive wantsPartNumbered: (unsigned int)partNumber lastPartNumber: (unsigned int)lastPartNumber { - OFString *path; + OFIRI *IRI; - if ([_path.pathExtension caseInsensitiveCompare: @"zip"] != + if ([_archiveIRI.path.pathExtension caseInsensitiveCompare: @"zip"] != OFOrderedSame) return nil; if (partNumber > 98) return nil; if (partNumber == lastPartNumber) - path = _path; - else - path = [_path.stringByDeletingPathExtension + IRI = _archiveIRI; + else { + OFMutableIRI *copy = [[_archiveIRI mutableCopy] autorelease]; + copy.path = [_archiveIRI.path.stringByDeletingPathExtension stringByAppendingFormat: @".z%02u", partNumber + 1]; + [copy makeImmutable]; + IRI = copy; + } - return [OFFile fileWithPath: path mode: @"r"]; + return (OFSeekableStream *)[OFIRIHandler openItemAtIRI: IRI mode: @"r"]; } - (void)listFiles { for (OFZIPArchiveEntry *entry in _archive.entries) { Index: utils/ofarc/ZooArchive.m ================================================================== --- utils/ofarc/ZooArchive.m +++ utils/ofarc/ZooArchive.m @@ -16,11 +16,13 @@ #include "config.h" #include #import "OFApplication.h" +#import "OFArray.h" #import "OFDate.h" +#import "OFFile.h" #import "OFFileManager.h" #import "OFLocale.h" #import "OFNumber.h" #import "OFSet.h" #import "OFStdIOStream.h" @@ -74,25 +76,25 @@ { if (self == [ZooArchive class]) app = (OFArc *)[OFApplication sharedApplication].delegate; } -+ (instancetype)archiveWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding -{ - return [[[self alloc] initWithPath: path - stream: stream - mode: mode - encoding: encoding] autorelease]; -} - -- (instancetype)initWithPath: (OFString *)path - stream: (OF_KINDOF(OFStream *))stream - mode: (OFString *)mode - encoding: (OFStringEncoding)encoding ++ (instancetype)archiveWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding +{ + return [[[self alloc] initWithIRI: IRI + stream: stream + mode: mode + encoding: encoding] autorelease]; +} + +- (instancetype)initWithIRI: (OFIRI *)IRI + stream: (OF_KINDOF(OFStream *))stream + mode: (OFString *)mode + encoding: (OFStringEncoding)encoding { self = [super init]; @try { _archive = [[OFZooArchive alloc] initWithStream: stream Index: utils/ofarc/localization/de.json ================================================================== --- utils/ofarc/localization/de.json +++ utils/ofarc/localization/de.json @@ -20,10 +20,12 @@ " -C --directory= In angegebenes Verzeichnis entpacken\n", " -E --encoding= Das Encoding des Archivs (nur tar-, ", "lha- und zoo-Dateien)\n", " -f --force Existierende Dateien überschreiben\n", " -h --help Diese Hilfe anzeigen\n", + " --iri Eine IRI benutzen um auf das Archiv zuzugreifen", + "\n", " -l --list Alle Dateien im Archiv auflisten\n", " -n --no-clobber Dateien niemals überschreiben\n", " -p --print Eine oder mehr Dateien aus dem Archiv ausgeben", "\n", " -q --quiet Ruhiger Modus (keine Ausgabe außer Fehler)\n",