@@ -13,58 +13,111 @@ * file. */ #include "config.h" -#import "OFZIPURIHandler.h" +#include + +#import "OFArchiveURIHandler.h" +#import "OFGZIPStream.h" +#import "OFLHAArchive.h" #import "OFStream.h" +#import "OFTarArchive.h" #import "OFURI.h" #import "OFZIPArchive.h" #import "OFInvalidArgumentException.h" +#import "OFOpenItemFailedException.h" -@implementation OFZIPURIHandler +@implementation OFArchiveURIHandler - (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode { void *pool = objc_autoreleasePoolPush(); - OFString *percentEncodedPath, *archiveURI, *path; + OFString *scheme = URI.scheme; + OFString *percentEncodedPath, *path; size_t pos; - OFZIPArchive *archive; + OFURI *archiveURI; OFStream *stream; - if (![URI.scheme isEqual: @"of-zip"] || URI.host != nil || - URI.port != nil || URI.user != nil || URI.password != nil || - URI.query != nil || URI.fragment != nil) + if (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]; + + /* + * GZIP only compresses one file and thus has no path inside an + * archive. + */ + if ([scheme isEqual: @"of-gzip"]) { + stream = [OFURIHandler openItemAtURI: [OFURI URIWithString: + URI.path] + mode: @"r"]; + stream = [OFGZIPStream streamWithStream: stream mode: @"r"]; + goto end; + } percentEncodedPath = URI.percentEncodedPath; pos = [percentEncodedPath rangeOfString: @"!"].location; if (pos == OFNotFound) @throw [OFInvalidArgumentException exception]; - archiveURI = [percentEncodedPath substringWithRange: - OFMakeRange(0, pos)].stringByRemovingPercentEncoding; + archiveURI = [OFURI URIWithString: + [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"]; - stream = [archive streamForReadingFile: path]; + if ([scheme isEqual: @"of-lha"]) { + OFLHAArchive *archive = [OFLHAArchive archiveWithURI: archiveURI + mode: @"r"]; + OFLHAArchiveEntry *entry; + + while ((entry = [archive nextEntry]) != nil) { + if ([entry.fileName isEqual: path]) { + stream = [archive streamForReadingCurrentEntry]; + goto end; + } + } + + @throw [OFOpenItemFailedException exceptionWithURI: URI + mode: mode + errNo: ENOENT]; + } else if ([scheme isEqual: @"of-tar"]) { + OFTarArchive *archive = [OFTarArchive archiveWithURI: archiveURI + mode: @"r"]; + OFTarArchiveEntry *entry; + + while ((entry = [archive nextEntry]) != nil) { + if ([entry.fileName isEqual: path]) { + stream = [archive streamForReadingCurrentEntry]; + goto end; + } + } + + @throw [OFOpenItemFailedException exceptionWithURI: URI + mode: mode + errNo: ENOENT]; + } else if ([scheme isEqual: @"of-zip"]) { + OFZIPArchive *archive = [OFZIPArchive archiveWithURI: archiveURI + mode: @"r"]; + + stream = [archive streamForReadingFile: path]; + } else + @throw [OFInvalidArgumentException exception]; - [stream retain]; +end: + stream = [stream retain]; objc_autoreleasePoolPop(pool); return [stream autorelease]; } @end