X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=sope-core%2FNGExtensions%2FFdExt.subproj%2FNSURL%2Bmisc.m;h=e7dad368f5085557e47f7e68ab9cf7b3304c5802;hb=16c3f13b75515189351744501af0dd27b477d79a;hp=fca96e8d898d6c1d7d3fd7eb5142de6fd13e8061;hpb=7eadc020be39163d31271943ebe303a97725794e;p=sope diff --git a/sope-core/NGExtensions/FdExt.subproj/NSURL+misc.m b/sope-core/NGExtensions/FdExt.subproj/NSURL+misc.m index fca96e8d..e7dad368 100644 --- a/sope-core/NGExtensions/FdExt.subproj/NSURL+misc.m +++ b/sope-core/NGExtensions/FdExt.subproj/NSURL+misc.m @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #include "NSURL+misc.h" #include "common.h" @@ -86,8 +85,8 @@ static BOOL debugURLProcessing = NO; - (NSString *)stringValueRelativeToURL:(NSURL *)_base { /* Sample: - base: http://localhost:20000/dbd.woa/so/localhost/ self: http://localhost:20000/dbd.woa/so/localhost/Databases/A + base: http://localhost:20000/dbd.woa/so/localhost/ => Databases/A Note: on Panther Foundation the -path misses the trailing slash! @@ -95,7 +94,8 @@ static BOOL debugURLProcessing = NO; NSString *relPath; if (_base == self || _base == nil) { - relPath = [[self pathWithCorrectTrailingSlash] urlPathRelativeToSelf]; + relPath = [self pathWithCorrectTrailingSlash]; + relPath = [relPath urlPathRelativeToSelf]; relPath = [self stringByAddingFragmentAndQueryToPath:relPath]; if (debugURLProcessing) { NSLog(@"%s: no base or base is self => '%@'", @@ -145,7 +145,8 @@ static BOOL debugURLProcessing = NO; if (debugURLProcessing) { NSLog(@"%s: same namespace, but no direct relative (%@, base %@) => '%@'", - __PRETTY_FUNCTION__, self, _base, relPath); + __PRETTY_FUNCTION__, + [self absoluteString], [_base absoluteString], relPath); } return relPath; } @@ -192,14 +193,18 @@ static BOOL isEqual(id o1, id o2) { */ NSString *p; NSString *lp; + + /* + /SOGo/so/X/Mail/Y/INBOX/withsubdirs/ + ..//SOGo/so/X/Mail/Y/INBOX/withsubdirs// + */ p = self; lp = [p lastPathComponent]; + if (![p hasSuffix:@"/"]) + return lp; - p = ([p hasSuffix:@"/"]) - ? [NSString stringWithFormat:@"../%@/", p] - : lp; - return p; + return [[@"../" stringByAppendingString:lp] stringByAppendingString:@"/"]; } - (NSString *)urlPathRelativeToRoot { @@ -217,32 +222,12 @@ static BOOL isEqual(id o1, id o2) { return @"/"; } - /* this is the same like the absoltute path, only without a leading "/" .. */ - return [p substringFromIndex:1]; + /* this is the same like the absolute path, only without a leading "/" .. */ + return [p characterAtIndex:0] == '/' ? [p substringFromIndex:1] : p; } -- (NSString *)urlPathRelativeToPath:(NSString *)_base { +static NSString *calcRelativePathOfChildURL(NSString *self, NSString *_base) { /* - This can be used for URLs in the same namespace. It should - never return an absolute path (it only does in error conditions). - */ - - if (_base == nil || [_base length] == 0) { - NSLog(@"%s: invalid base (nil or length 0), using absolute path '%@' ...", - __PRETTY_FUNCTION__, self); - return self; - } - - if ([_base isEqualToString:@"/"]) - return [self urlPathRelativeToRoot]; - if ([_base isEqualToString:self]) - return [self urlPathRelativeToSelf]; - - if (debugURLProcessing) - NSLog(@"%s: %@ relative to %@ ...", __PRETTY_FUNCTION__, self, _base); - - if ([self hasPrefix:_base]) { - /* the whole base URI is prefix of our URI: case a) b: "/a/b/c" @@ -259,19 +244,19 @@ static BOOL isEqual(id o1, id o2) { b=s is already catched above and s is guaranteed to be longer than b. - */ - unsigned blen; - NSString *result; + */ + unsigned blen; + NSString *result; - if (debugURLProcessing) + if (debugURLProcessing) NSLog(@"%s: has base as prefix ...", __PRETTY_FUNCTION__); - blen = [_base length]; + blen = [_base length]; - if ([_base characterAtIndex:(blen - 1)] == '/') { + if ([_base characterAtIndex:(blen - 1)] == '/') { /* last char of 'b' is '/' => case b) */ result = [self substringFromIndex:blen]; - } - else { + } + else { /* last char of 'b' is not a slash (either case a) or case c)), both are handled in the same way (search last / ...) @@ -288,23 +273,62 @@ static BOOL isEqual(id o1, id o2) { /* no we have case b) ... */ result = [self substringFromIndex:(r.location + 1)]; } - } - return result; } - else { - NSString *prefix; - unsigned plen; + return result; +} + +- (NSString *)commonDirPathPrefixWithString:(NSString *)_other { + // TODO: the implementation can probably be optimized a _LOT_ + /* eg "/home/images/" vs "/home/index.html" => "/home/", _not_ "/home/i" ! */ + NSString *s; + unsigned len; + NSRange r; + + if (_other == self) + return self; + + s = [self commonPrefixWithString:_other options:0]; + len = [s length]; + if (len == 0) + return s; + if ([s characterAtIndex:(len - 1)] == '/') + return s; + + r = [s rangeOfString:@"/" options:NSBackwardsSearch]; + if (r.length == 0) /* hm, can't happen? */ + return nil; + + return [s substringToIndex:(r.location + r.length)];; +} + +static +NSString *calcRelativePathOfNonChildURL(NSString *self, NSString *_base) { + unsigned numSlashes; + NSString *result; + NSString *prefix; + NSString *suffix; + unsigned plen; + + prefix = [self commonDirPathPrefixWithString:_base]; + plen = [prefix length]; + suffix = [self substringFromIndex:plen]; + numSlashes = 0; - prefix = [self commonPrefixWithString:_base options:0]; - plen = [prefix length]; + if (debugURLProcessing) { + NSLog(@"%s: does not have base as prefix, common '%@'\n" + @" self='%@'\n" + @" base='%@'\n" + @" suffix='%@'", + __PRETTY_FUNCTION__, prefix, self, _base, suffix); + } - if (plen == 0) { + if (plen == 0) { NSLog(@"%s: invalid strings, no common prefix ...: '%@' and '%@' !", __PRETTY_FUNCTION__, self, _base); return self; - } + } - if (plen == 1) { + if (plen == 1) { /* common prefix is root. That is, nothing in common: b: "/a/b" @@ -314,7 +338,11 @@ static BOOL isEqual(id o1, id o2) { b: "/a/b/" s: "/l" >: "../../l" + (number of slashes without root * "..", then the trailer?) */ + unsigned i, len; + + len = [_base length]; if ([prefix characterAtIndex:0] != '/') { NSLog(@"%s: invalid strings, common prefix '%@' is not '/': " @@ -322,14 +350,86 @@ static BOOL isEqual(id o1, id o2) { __PRETTY_FUNCTION__, self, _base, prefix); } - /* TODO: to be completed ... */ - return self; - } + for (i = 1 /* skip root */; i < len; i++) { + if ([_base characterAtIndex:i] == '/') + numSlashes++; + } + } + else { + /* + base: /dev/en/projects/bsd/index.html + self: /dev/en/macosx/ + => ../../macosx/ + */ + NSString *basesuffix; + unsigned i, len; + + basesuffix = [_base substringFromIndex:plen]; + len = [basesuffix length]; + + for (i = 0; i < len; i++) { + if ([basesuffix characterAtIndex:i] == '/') + numSlashes++; + } + } + + if (debugURLProcessing) + NSLog(@"%s: slashes: %d", __PRETTY_FUNCTION__, numSlashes); - /* TODO: to be completed ... */ + /* optimization for some depths */ + switch (numSlashes) { + case 0: /* no slashes in base: b:/a, s:/images/a => images/a */ + result = suffix; + break; + case 1: /* one slash in base: b:/a/, s:/images/a => ../images/a, etc */ + result = [@"../" stringByAppendingString:suffix]; + break; + case 2: result = [@"../../" stringByAppendingString:suffix]; break; + case 3: result = [@"../../../" stringByAppendingString:suffix]; break; + case 4: result = [@"../../../../" stringByAppendingString:suffix]; break; + case 5: result = [@"../../../../../" stringByAppendingString:suffix];break; + default: { + NSMutableString *ms; + unsigned i; + + ms = [NSMutableString stringWithCapacity:(numSlashes * 3)]; + for (i = 0; i < numSlashes; i++) + [ms appendString:@"../"]; + [ms appendString:suffix]; + result = ms; + break; + } + } + if (debugURLProcessing) + NSLog(@"%s: => '%@'", __PRETTY_FUNCTION__, result); + return result; +} + +- (NSString *)urlPathRelativeToPath:(NSString *)_base { + /* + This can be used for URLs in the same namespace. It should + never return an absolute path (it only does in error conditions). + */ + // TODO: the implementation can probably be optimized a _LOT_ + + if (_base == nil || [_base length] == 0) { + NSLog(@"%s: invalid base (nil or length 0), using absolute path '%@' ...", + __PRETTY_FUNCTION__, self); + return self; } - return self; + if ([_base isEqualToString:@"/"]) + return [self urlPathRelativeToRoot]; + if ([_base isEqualToString:self]) + return [self urlPathRelativeToSelf]; + + if (debugURLProcessing) + NSLog(@"%s: %@ relative to %@ ...", __PRETTY_FUNCTION__, self, _base); + + if ([self hasPrefix:_base]) + return calcRelativePathOfChildURL(self, _base); + + return calcRelativePathOfNonChildURL(self, _base); } @end /* NSString(URLPathProcessing) */