Index: src/OFString+PathAdditions.h ================================================================== --- src/OFString+PathAdditions.h +++ src/OFString+PathAdditions.h @@ -82,8 +82,15 @@ * * @param component The path component to append * @return A new, autoreleased OFString with the path component appended */ - (OFString *)stringByAppendingPathComponent: (OFString *)component; + +- (bool)of_isDirectoryPath; +- (OFString *)of_pathToURLPathWithURLEncodedHost: + (OFString *__autoreleasing _Nullable *_Nonnull)URLEncodedHost; +- (OFString *)of_URLPathToPathWithURLEncodedHost: + (nullable OFString *)URLEncodedHost; +- (OFString *)of_pathComponentToURLPathComponent; @end OF_ASSUME_NONNULL_END Index: src/OFURL.m ================================================================== --- src/OFURL.m +++ src/OFURL.m @@ -58,89 +58,10 @@ @interface OFURLQueryOrFragmentAllowedCharacterSet: OFURLAllowedCharacterSetBase + (OFCharacterSet *)URLQueryOrFragmentAllowedCharacterSet; @end -#ifdef OF_HAVE_FILES -static OFString * -pathToURLPath(OFString *path) -{ -# if defined(OF_WINDOWS) || defined(OF_MSDOS) - path = [path stringByReplacingOccurrencesOfString: @"\\" - withString: @"/"]; - path = [path stringByPrependingString: @"/"]; - - return path; -# elif defined(OF_AMIGAOS) - OFArray OF_GENERIC(OFString *) *components = path.pathComponents; - OFMutableString *ret = [OFMutableString string]; - - for (OFString *component in components) { - if (component.length == 0) - continue; - - if ([component isEqual: @"/"]) - [ret appendString: @"/.."]; - else { - [ret appendString: @"/"]; - [ret appendString: component]; - } - } - - [ret makeImmutable]; - - return ret; -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) - return [path stringByPrependingString: @"/"]; -# else - return path; -# endif -} - -static OFString * -URLPathToPath(OFString *path) -{ -# if defined(OF_WINDOWS) || defined(OF_MSDOS) - path = [path substringWithRange: of_range(1, path.length - 1)]; - path = [path stringByReplacingOccurrencesOfString: @"/" - withString: @"\\"]; - - return path; -# elif defined(OF_AMIGAOS) - OFMutableArray OF_GENERIC(OFString *) *components; - size_t count; - - path = [path substringWithRange: of_range(1, path.length - 1)]; - components = [[[path - componentsSeparatedByString: @"/"] mutableCopy] autorelease]; - count = components.count; - - for (size_t i = 0; i < count; i++) { - OFString *component = [components objectAtIndex: i]; - - if ([component isEqual: @"."]) { - [components removeObjectAtIndex: i]; - count--; - - i--; - continue; - } - - if ([component isEqual: @".."]) - [components replaceObjectAtIndex: i - withObject: @"/"]; - } - - return [OFString pathWithComponents: components]; -# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) - return [path substringWithRange: of_range(1, path.length - 1)]; -# else - return path; -# endif -} -#endif - @interface OFInvertedCharacterSetWithoutPercent: OFCharacterSet { OFCharacterSet *_characterSet; bool (*_characterIsMember)(id, SEL, of_unichar_t); } @@ -698,22 +619,11 @@ bool isDirectory; @try { void *pool = objc_autoreleasePoolPush(); -#if defined(OF_WINDOWS) || defined(OF_MSDOS) - isDirectory = ([path hasSuffix: @"\\"] || - [path hasSuffix: @"/"] || - [OFFileURLHandler of_directoryExistsAtPath: path]); -#elif defined(OF_AMIGAOS) - isDirectory = ([path hasSuffix: @"/"] || - [path hasSuffix: @":"] || - [OFFileURLHandler of_directoryExistsAtPath: path]); -#else - isDirectory = ([path hasSuffix: @"/"] || - [OFFileURLHandler of_directoryExistsAtPath: path]); -#endif + isDirectory = [path of_isDirectoryPath]; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; @@ -730,10 +640,11 @@ { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); + OFString *URLEncodedHost = nil; if (!path.absolutePath) { OFString *currentDirectoryPath = [OFFileManager defaultManager].currentDirectoryPath; @@ -740,27 +651,13 @@ path = [currentDirectoryPath stringByAppendingPathComponent: path]; path = path.stringByStandardizingPath; } -#ifdef OF_WINDOWS - if ([path hasPrefix: @"\\\\"]) { - OFArray *components = path.pathComponents; - - if (components.count < 2) - @throw [OFInvalidFormatException exception]; - - _URLEncodedHost = [[[components objectAtIndex: 1] - stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLHostAllowedCharacterSet]] copy]; - path = [OFString pathWithComponents: - [components objectsInRange: - of_range(2, components.count - 2)]]; - } -#endif - - path = pathToURLPath(path); + path = [path + of_pathToURLPathWithURLEncodedHost: &URLEncodedHost]; + _URLEncodedHost = [URLEncodedHost copy]; if (isDirectory && ![path hasSuffix: @"/"]) path = [path stringByAppendingString: @"/"]; _URLEncodedScheme = @"file"; @@ -930,24 +827,23 @@ } - (OFArray *)pathComponents { void *pool = objc_autoreleasePoolPush(); + bool isFile = [_URLEncodedScheme isEqual: @"file"]; OFMutableArray *ret; size_t count; -#if defined(OF_WINDOWS) || defined(OF_MSDOS) - if ([_URLEncodedScheme isEqual: @"file"]) { - OFString *path = [_URLEncodedPath substringWithRange: - of_range(1, _URLEncodedPath.length - 1)]; - path = [path stringByReplacingOccurrencesOfString: @"/" - withString: @"\\"]; + if (isFile) { + OFString *path = [_URLEncodedPath + of_URLPathToPathWithURLEncodedHost: nil]; ret = [[path.pathComponents mutableCopy] autorelease]; - [ret insertObject: @"/" - atIndex: 0]; + + if (![ret.firstObject isEqual: @"/"]) + [ret insertObject: @"/" + atIndex: 0]; } else -#endif ret = [[[_URLEncodedPath componentsSeparatedByString: @"/"] mutableCopy] autorelease]; count = ret.count; @@ -955,15 +851,15 @@ [ret replaceObjectAtIndex: 0 withObject: @"/"]; for (size_t i = 0; i < count; i++) { OFString *component = [ret objectAtIndex: i]; -#if defined(OF_WINDOWS) || defined(OF_MSDOS) - component = [component - stringByReplacingOccurrencesOfString: @"\\" - withString: @"/"]; -#endif + + if (isFile) + component = + [component of_pathComponentToURLPathComponent]; + [ret replaceObjectAtIndex: i withObject: component.stringByURLDecoding]; } [ret makeImmutable]; @@ -1106,32 +1002,11 @@ @throw [OFInvalidArgumentException exception]; if (![_URLEncodedPath hasPrefix: @"/"]) @throw [OFInvalidFormatException exception]; - path = self.path; - -#if !defined(OF_WINDOWS) && !defined(OF_MSDOS) - if (path.length > 1 && [path hasSuffix: @"/"]) -#else - if (path.length > 1 && [path hasSuffix: @"/"] && - ![path hasSuffix: @":/"]) -#endif - path = [path substringWithRange: of_range(0, path.length - 1)]; - - path = URLPathToPath(path); - -#ifdef OF_WINDOWS - if (_URLEncodedHost != nil) { - if (path.length == 0) - path = [OFString stringWithFormat: @"\\\\%@", - self.host]; - else - path = [OFString stringWithFormat: @"\\\\%@\\%@", - self.host, path]; - } -#endif + path = [self.path of_URLPathToPathWithURLEncodedHost: _URLEncodedHost]; [path retain]; objc_autoreleasePoolPop(pool); Index: src/platform/amiga/OFString+PathAdditions.m ================================================================== --- src/platform/amiga/OFString+PathAdditions.m +++ src/platform/amiga/OFString+PathAdditions.m @@ -17,10 +17,11 @@ #include "config.h" #import "OFString+PathAdditions.h" #import "OFArray.h" +#import "OFFileURLHandler.h" #import "OFOutOfRangeException.h" int _OFString_PathAdditions_reference; @@ -268,6 +269,73 @@ [ret makeImmutable]; return ret; } } + +- (bool)of_isDirectoryPath +{ + return ([self hasSuffix: @"/"] || [self hasSuffix: @":"] || + [OFFileURLHandler of_directoryExistsAtPath: self]); +} + +- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost +{ + OFArray OF_GENERIC(OFString *) *components = self.pathComponents; + OFMutableString *ret = [OFMutableString string]; + + for (OFString *component in components) { + if (component.length == 0) + continue; + + if ([component isEqual: @"/"]) + [ret appendString: @"/.."]; + else { + [ret appendString: @"/"]; + [ret appendString: component]; + } + } + + [ret makeImmutable]; + + return ret; +} + +- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost +{ + OFString *path = self; + + if (path.length > 1 && [path hasSuffix: @"/"]) + path = [path substringWithRange: of_range(0, path.length - 1)]; + + OFMutableArray OF_GENERIC(OFString *) *components; + size_t count; + + path = [path substringWithRange: of_range(1, path.length - 1)]; + components = [[[path + componentsSeparatedByString: @"/"] mutableCopy] autorelease]; + count = components.count; + + for (size_t i = 0; i < count; i++) { + OFString *component = [components objectAtIndex: i]; + + if ([component isEqual: @"."]) { + [components removeObjectAtIndex: i]; + count--; + + i--; + continue; + } + + if ([component isEqual: @".."]) + [components replaceObjectAtIndex: i + withObject: @"/"]; + } + + return [OFString pathWithComponents: components]; +} + +- (OFString *)of_pathComponentToURLPathComponent +{ + return self; +} @end Index: src/platform/libfat/OFString+PathAdditions.m ================================================================== --- src/platform/libfat/OFString+PathAdditions.m +++ src/platform/libfat/OFString+PathAdditions.m @@ -17,10 +17,11 @@ #include "config.h" #import "OFString+PathAdditions.h" #import "OFArray.h" +#import "OFFileURLHandler.h" #import "OFOutOfRangeException.h" int _OFString_PathAdditions_reference; @@ -314,6 +315,32 @@ [ret makeImmutable]; return ret; } } + +- (bool)of_isDirectoryPath +{ + return ([self hasSuffix: @"/"] || + [OFFileURLHandler of_directoryExistsAtPath: self]); +} + +- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost +{ + return [self stringByPrependingString: @"/"]; +} + +- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost +{ + OFString *path = self; + + if (path.length > 1 && [path hasSuffix: @"/"]) + path = [path substringWithRange: of_range(0, path.length - 1)]; + + return [path substringWithRange: of_range(1, path.length - 1)]; +} + +- (OFString *)of_pathComponentToURLPathComponent +{ + return self; +} @end Index: src/platform/posix/OFString+PathAdditions.m ================================================================== --- src/platform/posix/OFString+PathAdditions.m +++ src/platform/posix/OFString+PathAdditions.m @@ -17,10 +17,11 @@ #include "config.h" #import "OFString+PathAdditions.h" #import "OFArray.h" +#import "OFFileURLHandler.h" #import "OFOutOfRangeException.h" int _OFString_PathAdditions_reference; @@ -314,6 +315,32 @@ [ret makeImmutable]; return ret; } } + +- (bool)of_isDirectoryPath +{ + return ([self hasSuffix: @"/"] || + [OFFileURLHandler of_directoryExistsAtPath: self]); +} + +- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost +{ + return self; +} + +- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost +{ + OFString *path = self; + + if (path.length > 1 && [path hasSuffix: @"/"]) + path = [path substringWithRange: of_range(0, path.length - 1)]; + + return path; +} + +- (OFString *)of_pathComponentToURLPathComponent +{ + return self; +} @end Index: src/platform/windows/OFString+PathAdditions.m ================================================================== --- src/platform/windows/OFString+PathAdditions.m +++ src/platform/windows/OFString+PathAdditions.m @@ -22,11 +22,14 @@ #include "config.h" #import "OFString+PathAdditions.h" #import "OFArray.h" +#import "OFFileURLHandler.h" +#import "OFURL.h" +#import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" int _OFString_PathAdditions_reference; @implementation OFString (PathAdditions) @@ -316,6 +319,67 @@ [ret makeImmutable]; return ret; } } + +- (bool)of_isDirectoryPath +{ + return ([self hasSuffix: @"\\"] || [self hasSuffix: @"/"] || + [OFFileURLHandler of_directoryExistsAtPath: self]); +} + +- (OFString *)of_pathToURLPathWithURLEncodedHost: (OFString **)URLEncodedHost +{ + OFString *path = self; + + if ([path hasPrefix: @"\\\\"]) { + OFArray *components = path.pathComponents; + + if (components.count < 2) + @throw [OFInvalidFormatException exception]; + + *URLEncodedHost = [[components objectAtIndex: 1] + stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLHostAllowedCharacterSet]]; + path = [OFString pathWithComponents: [components + objectsInRange: of_range(2, components.count - 2)]]; + } + + path = [path stringByReplacingOccurrencesOfString: @"\\" + withString: @"/"]; + path = [path stringByPrependingString: @"/"]; + + return path; +} + +- (OFString *)of_URLPathToPathWithURLEncodedHost: (OFString *)URLEncodedHost +{ + OFString *path = self; + + if (path.length > 1 && [path hasSuffix: @"/"] && + ![path hasSuffix: @":/"]) + path = [path substringWithRange: of_range(0, path.length - 1)]; + + path = [path substringWithRange: of_range(1, path.length - 1)]; + path = [path stringByReplacingOccurrencesOfString: @"/" + withString: @"\\"]; + + if (URLEncodedHost != nil) { + OFString *host = [URLEncodedHost stringByURLDecoding]; + + if (path.length == 0) + path = [OFString stringWithFormat: @"\\\\%@", host]; + else + path = [OFString stringWithFormat: @"\\\\%@\\%@", + host, path]; + } + + return path; +} + +- (OFString *)of_pathComponentToURLPathComponent +{ + return [self stringByReplacingOccurrencesOfString: @"\\" + withString: @"/"]; +} @end