Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -203,10 +203,11 @@ OFSandbox.m \ OFSizeValue.m \ OFStrPTime.m \ OFSubarray.m \ OFUTF8String.m \ + OFZIPURIHandler.m \ ${LIBBASES_M} \ ${RUNTIME_AUTORELEASE_M} \ ${RUNTIME_INSTANCE_M} \ ${UNICODE_M} SRCS_FILES += OFFileURIHandler.m Index: src/OFURIHandler.m ================================================================== --- src/OFURIHandler.m +++ src/OFURIHandler.m @@ -29,10 +29,11 @@ # import "OFFileURIHandler.h" #endif #if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) # import "OFHTTPURIHandler.h" #endif +#import "OFZIPURIHandler.h" #import "OFUnsupportedProtocolException.h" static OFMutableDictionary OF_GENERIC(OFString *, OFURIHandler *) *handlers; #ifdef OF_HAVE_THREADS @@ -66,10 +67,11 @@ #endif #if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) [self registerClass: [OFHTTPURIHandler class] forScheme: @"http"]; [self registerClass: [OFHTTPURIHandler class] forScheme: @"https"]; #endif + [self registerClass: [OFZIPURIHandler class] forScheme: @"of-zip"]; } + (bool)registerClass: (Class)class forScheme: (OFString *)scheme { #ifdef OF_HAVE_THREADS ADDED src/OFZIPURIHandler.h Index: src/OFZIPURIHandler.h ================================================================== --- src/OFZIPURIHandler.h +++ src/OFZIPURIHandler.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2022 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 "OFURIHandler.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OFZIPURIHandler: OFURIHandler +@end + +OF_ASSUME_NONNULL_END ADDED src/OFZIPURIHandler.m Index: src/OFZIPURIHandler.m ================================================================== --- src/OFZIPURIHandler.m +++ src/OFZIPURIHandler.m @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008-2022 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 "OFZIPURIHandler.h" +#import "OFURI.h" +#import "OFZIPArchive.h" + +#import "OFInvalidArgumentException.h" + +@implementation OFZIPURIHandler +- (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode +{ + OFString *percentEncodedPath, *archiveURI, *path; + size_t pos; + OFZIPArchive *archive; + + if (![URI.scheme isEqual: @"of-zip"] || URI.host != nil || + URI.port != nil || URI.user != nil || URI.password != nil || + URI.query != nil || URI.fragment != nil) + @throw [OFInvalidArgumentException exception]; + + if (![mode isEqual: @"r"]) + /* + * Writing has some implications that are not decided yet: Will + * it always append to an archive? What happens if the file + * already exists? + */ + @throw [OFInvalidArgumentException exception]; + + percentEncodedPath = URI.percentEncodedPath; + pos = [percentEncodedPath rangeOfString: @"!"].location; + + if (pos == OFNotFound) + @throw [OFInvalidArgumentException exception]; + + archiveURI = [percentEncodedPath substringWithRange: + OFMakeRange(0, pos)].stringByRemovingPercentEncoding; + path = [percentEncodedPath substringWithRange: + OFMakeRange(pos + 1, percentEncodedPath.length - pos - 1)] + .stringByRemovingPercentEncoding; + + archive = [OFZIPArchive + archiveWithURI: [OFURI URIWithString: archiveURI] + mode: @"r"]; + + return [archive streamForReadingFile: path]; +} +@end