Revision: 26844 http://sourceforge.net/p/bibdesk/svn/26844 Author: hofman Date: 2021-09-11 09:40:06 +0000 (Sat, 11 Sep 2021) Log Message: ----------- Revert part of r26842 which hiked along
Modified Paths: -------------- trunk/bibdesk/BDSKLinkedFile.m Modified: trunk/bibdesk/BDSKLinkedFile.m =================================================================== --- trunk/bibdesk/BDSKLinkedFile.m 2021-09-11 09:13:44 UTC (rev 26843) +++ trunk/bibdesk/BDSKLinkedFile.m 2021-09-11 09:40:06 UTC (rev 26844) @@ -94,6 +94,7 @@ @interface BDSKLinkedAliasFile : BDSKLinkedFile { id alias; // can be a BDSKAlias or bookmark NSData + id fileRef; // can be a BDSKFileRef or a file reference NSURL NSString *relativePath; NSURL *fileURL; BOOL isInitial; @@ -101,25 +102,13 @@ BOOL hasSkimNotesNeedsUpdate; id delegate; } -- (void)updateFileURL; -- (NSData *)copyAliasDataRelativeToPath:(NSString *)newBasePath; -@end -#pragma mark - - -@interface BDSKAliasLinkedFile : BDSKLinkedAliasFile { - const FSRef *fileRef; -} - (void)updateFileRef; -@end +- (void)updateFileURL; -#pragma mark - +- (NSData *)copyAliasDataRelativeToPath:(NSString *)newBasePath; +- (NSData *)copyBookmarkDataRelativeToPath:(NSString *)newBasePath; -@interface BDSKBookmarkLinkedFile : BDSKLinkedAliasFile { - NSURL *fileRefURL; -} -- (void)updateFileRefURL; -- (NSData *)copyBookmarkDataRelativeToPath:(NSString *)newBasePath; @end #pragma mark - @@ -150,10 +139,6 @@ saveRelativePathOnly = [[NSUserDefaults standardUserDefaults] boolForKey:BDSKSaveLinkedFilesAsRelativePathOnlyKey]; saveArchivedData = [[NSUserDefaults standardUserDefaults] boolForKey:BDSKSaveLinkedFilesAsArchivedDataKey]; wantsBookmark = saveArchivedData == NO && [[NSUserDefaults standardUserDefaults] boolForKey:BDSKSaveLinkedFilesAsBookmarkDataKey]; - - NSString *fileClassName = wantsBookmark ? @"BDSKBookmarkLinkedFile" : @"BDSKAliasLinkedFile"; - [NSKeyedUnarchiver setClass:NSClassFromString(fileClassName) forClassName:@"BDSKLinkedAliasFile"]; - [NSUnarchiver decodeClassName:@"BDSKLinkedAliasFile" asClassName:fileClassName]; } + (id)allocWithZone:(NSZone *)aZone { @@ -261,7 +246,7 @@ - (id)initWithURL:(NSURL *)aURL delegate:(id<BDSKLinkedFileDelegate>)aDelegate { if([aURL isFileURL]) - return (id)[(wantsBookmark ? [BDSKBookmarkLinkedFile alloc] : [BDSKAliasLinkedFile alloc]) initWithURL:aURL delegate:aDelegate]; + return (id)[[BDSKLinkedAliasFile alloc] initWithURL:aURL delegate:aDelegate]; else if (aURL) return (id)[[BDSKLinkedURL alloc] initWithURL:aURL delegate:aDelegate]; else @@ -269,7 +254,7 @@ } - (id)initWithBase64String:(NSString *)base64String delegate:(id<BDSKLinkedFileDelegate>)aDelegate { - return (id)[(wantsBookmark ? [BDSKBookmarkLinkedFile alloc] : [BDSKAliasLinkedFile alloc]) initWithBase64String:base64String delegate:aDelegate]; + return (id)[[BDSKLinkedAliasFile alloc] initWithBase64String:base64String delegate:aDelegate]; } - (id)initWithURLString:(NSString *)aString { @@ -302,6 +287,7 @@ } else { self = [super init]; if (self) { + fileRef = nil; // this is updated lazily, as we don't know the base path at this point alias = [anAlias retain]; relativePath = [relPath copy]; delegate = aDelegate; @@ -315,8 +301,24 @@ } - (id)initWithURL:(NSURL *)aURL delegate:(id<BDSKLinkedFileDelegate>)aDelegate { - BDSKASSERT_NOT_REACHED("Attempt to initialize BDSKLinkedAliasFile directly with a URL"); - return nil; + BDSKASSERT([aURL isFileURL]); + + NSString *aPath = [aURL path]; + + BDSKASSERT(nil != aPath); + + NSString *basePath = [aDelegate basePathForLinkedFile:self]; + NSString *relPath = basePath ? [aPath relativePathFromPath:basePath] : nil; + id anAlias; + if (wantsBookmark) + anAlias = BDSKCreateBookmarkDataFromURL(aURL); + else + anAlias = [BDSKAlias newWithPath:aPath basePath:basePath]; + self = [self initWithAlias:anAlias relativePath:relPath delegate:aDelegate]; + [anAlias release]; + if (self && basePath) + [self updateFileRef]; + return self; } - (id)initWithBase64String:(NSString *)base64String delegate:(id<BDSKLinkedFileDelegate>)aDelegate { @@ -383,11 +385,6 @@ } - (id)initWithCoder:(NSCoder *)coder { - if ([self isMemberOfClass:[BDSKLinkedAliasFile class]]) { - BDSKASSERT_NOT_REACHED("Attempt to decode a BDSKLinkedAliasFile instance"); - [self release]; - self = wantsBookmark ? [BDSKBookmarkLinkedFile alloc] : [BDSKAliasLinkedFile alloc]; - } id anAlias = nil; NSString *relPath = nil; if ([coder allowsKeyedCoding]) { @@ -407,23 +404,33 @@ - (void)encodeWithCoder:(NSCoder *)coder { // make sure the fileRef is valid [self updateFileURL]; + NSData *data = nil; + NSString *basePath = [delegate basePathForLinkedFile:self]; if ([coder allowsKeyedCoding]) { - // the alias or bookmark data is set by the subclasses + if (wantsBookmark) { + data = [self copyBookmarkDataRelativeToPath:basePath]; + if (data) + [coder encodeObject:alias forKey:BOOKMARK_KEY]; + else if ([alias isKindOfClass:[BDSKAlias class]] && (data = [alias copyData])) + [coder encodeObject:data forKey:ALIASDATA_KEY]; + } else { + data = [self copyAliasDataRelativeToPath:basePath]; + if (data) + [coder encodeObject:data forKey:ALIASDATA_KEY]; + else if ([alias isKindOfClass:[NSData class]]) + [coder encodeObject:alias forKey:BOOKMARK_KEY]; + } [coder encodeObject:relativePath forKey:RELATIVEPATH_KEY]; } else { - NSData *data = [self copyAliasDataRelativeToPath:[delegate basePathForLinkedFile:self]]; + data = [self copyAliasDataRelativeToPath:basePath]; [coder encodeObject:data]; [coder encodeObject:relativePath]; - [data release]; } + [data release]; } -// always encode subclasses as BDSKLinkedAliasFile -- (Class)classForKeyedArchiver { return [BDSKLinkedAliasFile class]; } -- (Class)classForArchiver { return [BDSKLinkedAliasFile class]; } -- (Class)classForPortCoder { return [BDSKLinkedAliasFile class]; } - - (void)dealloc { + BDSKDESTROY(fileRef); BDSKDESTROY(alias); BDSKDESTROY(relativePath); BDSKDESTROY(fileURL); @@ -433,11 +440,21 @@ - (id)copyWithZone:(NSZone *)aZone { // make sure the fileRef is valid [self updateFileURL]; - NSData *data = [self copyAliasDataRelativeToPath:[delegate basePathForLinkedFile:self]]; - id anAlias = [BDSKAlias newWithData:data]; - [data release]; - if (anAlias == nil && [alias isKindOfClass:[NSData class]]) - anAlias = [alias copy]; + id anAlias = nil; + if (wantsBookmark) { + anAlias = [self copyBookmarkDataRelativeToPath:[delegate basePathForLinkedFile:self]]; + if (anAlias == nil && [alias isKindOfClass:[BDSKAlias class]]) { + NSData *data = [alias copyData]; + anAlias = [BDSKAlias newWithData:data]; + [data release]; + } + } else { + NSData *data = [self copyAliasDataRelativeToPath:[delegate basePathForLinkedFile:self]]; + anAlias = [BDSKAlias newWithData:data]; + [data release]; + if (anAlias == nil && [alias isKindOfClass:[NSData class]]) + anAlias = [alias copy]; + } self = [[[self class] allocWithZone:aZone] initWithAlias:anAlias relativePath:relativePath delegate:delegate]; [anAlias release]; return self; @@ -482,179 +499,25 @@ } } -// this is really implemented by the subclasses -- (void)updateFileURL { - if (fileURL == nil && relativePath) { - NSString *basePath = [delegate basePathForLinkedFile:self]; - if (basePath) - fileURL = [[NSURL alloc] initFileURLWithPath:[relativePath isAbsolutePath] ? relativePath : [[basePath stringByAppendingPathComponent:relativePath] stringByStandardizingPath]]; - } -} - -- (NSURL *)URL { - [self updateFileURL]; - return fileURL; -} - -- (NSURL *)displayURL { - NSURL *displayURL = [self URL]; - if (displayURL == nil && relativePath) { - NSString *basePath = [delegate basePathForLinkedFile:self]; - displayURL = basePath ? [NSURL URLWithString:[relativePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]] relativeToURL:[NSURL fileURLWithPath:basePath isDirectory:YES]] : [NSURL fileURLWithPath:relativePath isDirectory:NO]; - } - return displayURL; -} - -- (BOOL)hasSkimNotes { - if (hasSkimNotesNeedsUpdate) { - hasSkimNotes = [[fileURL SkimNotes] count] > 0; - hasSkimNotesNeedsUpdate = NO; - } - return hasSkimNotes; -} - -- (NSData *)copyAliasDataRelativeToPath:(NSString *)basePath { - BDSKAlias *anAlias = NULL; - NSData *data = nil; - - if (fileURL) { - anAlias = [BDSKAlias newWithPath:[fileURL path] basePath:basePath]; - } else if (relativePath && basePath) { - NSString *path = [relativePath isAbsolutePath] ? relativePath : [[basePath stringByAppendingPathComponent:relativePath] stringByStandardizingPath]; - anAlias = [BDSKAlias newWithPath:path basePath:basePath]; - } - if (anAlias != NULL) { - data = [anAlias copyData]; - [anAlias release]; - } else if ([alias isKindOfClass:[BDSKAlias class]]) { - data = [alias copyData]; - } - - return data; -} - -- (NSData *)copyDataRelativeToPath:(NSString *)newBasePath isBookmark:(BOOL *)isBookmark { - NSData *data = [self copyAliasDataRelativeToPath:newBasePath]; - if (data) { - *isBookmark = NO; - } else if ([alias isKindOfClass:[NSData class]]) { - data = [alias retain]; - *isBookmark = YES; - } - return data; -} - -- (NSString *)stringRelativeToPath:(NSString *)newBasePath { - BOOL noAlias = saveRelativePathOnly && newBasePath != nil; - if (newBasePath == nil) - newBasePath = [delegate basePathForLinkedFile:self]; - NSDictionary *dictionary = nil; - // this will make sure the fileURL is valid - NSString *path = [self path]; - path = path && newBasePath ? [path relativePathFromPath:newBasePath] : relativePath; - if (noAlias == NO || path == nil) { - BOOL isBookmark = NO; - NSData *data = [self copyDataRelativeToPath:newBasePath isBookmark:&isBookmark]; - if (data) { - dictionary = [NSDictionary dictionaryWithObjectsAndKeys:data, (isBookmark ? BOOKMARK_KEY : ALIASDATA_KEY), path, RELATIVEPATH_KEY, nil]; - [data release]; - } - } - if (dictionary == nil) - dictionary = [NSDictionary dictionaryWithObjectsAndKeys:path, RELATIVEPATH_KEY, nil]; - if (saveArchivedData) - return [[NSKeyedArchiver archivedDataWithRootObject:dictionary] base64String]; +- (NSURL *)newPathURL { + if (fileRef == nil) + return nil; + else if (wantsBookmark) + return (NSURL *)CFURLCreateFilePathURL(kCFAllocatorDefault, (CFURLRef)fileRef, NULL); else - return [[NSPropertyListSerialization dataWithPropertyList:dictionary format:NSPropertyListBinaryFormat_v1_0 options:0 error:NULL] base64String]; + return BDSKCreateURLFromFSRef([fileRef fsRef]); } -// This is called when the file is added (new or initially), -// the document URL changes, or with aPath != nil after an autofile -// implemented by the subclasses -- (void)updateWithPath:(NSString *)aPath {} - -- (void)updateHasSkimNotes { - hasSkimNotesNeedsUpdate = YES; - if (isInitial == NO) - [delegate performSelector:@selector(linkedFileURLChanged:) withObject:self afterDelay:0.0]; -} - -@end - -#pragma mark - - -@implementation BDSKAliasLinkedFile - -- (id)initWithURL:(NSURL *)aURL delegate:(id<BDSKLinkedFileDelegate>)aDelegate { - BDSKASSERT([aURL isFileURL]); - - NSString *aPath = [aURL path]; - - BDSKASSERT(nil != aPath); - - NSString *basePath = [aDelegate basePathForLinkedFile:self]; - NSString *relPath = basePath ? [aPath relativePathFromPath:basePath] : nil; - id anAlias = [BDSKAlias newWithPath:aPath basePath:basePath]; - self = [self initWithAlias:anAlias relativePath:relPath delegate:aDelegate]; - [anAlias release]; - if (self && basePath) - [self updateFileRef]; - return self; -} - -- (void)encodeWithCoder:(NSCoder *)coder { - [super encodeWithCoder:coder]; - if ([coder allowsKeyedCoding]) { - NSData *data = [self copyAliasDataRelativeToPath:[delegate basePathForLinkedFile:self]]; - if (data) - [coder encodeObject:data forKey:ALIASDATA_KEY]; - else if ([alias isKindOfClass:[NSData class]]) - [coder encodeObject:alias forKey:BOOKMARK_KEY]; - [data release]; - } -} - -- (void)dealloc { - BDSKZONEDESTROY(fileRef); - [super dealloc]; -} - -- (id)copyWithZone:(NSZone *)aZone { - // make sure the fileRef is valid - [self updateFileURL]; - NSData *data = [self copyAliasDataRelativeToPath:[delegate basePathForLinkedFile:self]]; - id anAlias = [BDSKAlias newWithData:data]; - [data release]; - if (anAlias == nil && [alias isKindOfClass:[NSData class]]) - anAlias = [alias copy]; - self = [[[self class] allocWithZone:aZone] initWithAlias:anAlias relativePath:relativePath delegate:delegate]; - [anAlias release]; - return self; -} - -- (void)setFileRef:(FSRef *)aRef { - BDSKZONEDESTROY(fileRef); - if (aRef != NULL) { - FSRef *newRef = (FSRef *)NSZoneMalloc([self zone], sizeof(FSRef)); - if (newRef) { - bcopy(aRef, newRef, sizeof(FSRef)); - fileRef = newRef; - } else { - [self release]; - self = nil; - } - } -} - - (void)updateAliasWithBaseRef:(FSRef *)baseRef { BDSKASSERT(fileRef != nil); BDSKASSERT(baseRef != NULL); + BDSKASSERT(wantsBookmark == NO); // update the alias if ([alias isKindOfClass:[BDSKAlias class]]) { - [alias updateWithFSRef:fileRef baseRef:baseRef]; + [alias updateWithFSRef:[fileRef fsRef] baseRef:baseRef]; } else { - BDSKAlias *anAlias = [BDSKAlias newWithFSRef:fileRef baseRef:baseRef]; + BDSKAlias *anAlias = [BDSKAlias newWithFSRef:[fileRef fsRef] baseRef:baseRef]; if (anAlias) { BDSKDESTROY(alias); alias = anAlias; @@ -662,55 +525,130 @@ } } +- (void)updateBookmark { + BDSKASSERT(fileURL != nil); + BDSKASSERT(wantsBookmark); + + // update the bookmark + NSData *data = BDSKCreateBookmarkDataFromURL(fileURL ?: [fileRef filePathURL]); + if (data) { + [alias release]; + alias = data; + } +} + - (void)updateFileRef { NSString *basePath = [delegate basePathForLinkedFile:self]; BOOL shouldUpdate = NO; - FSRef baseRef; - BOOL hasBaseRef = BDSKPathToFSRef(basePath, &baseRef); - - if (fileRef == nil) { - FSRef aRef; - BOOL hasRef = NO; - - if (fileURL) { - hasRef = BDSKPathToFSRef([fileURL path], &aRef); - shouldUpdate = hasBaseRef && hasRef; + if (wantsBookmark) { + // using bookmark and NSURL + if (fileRef == nil) { + NSURL *refURL = nil; + + if (fileURL) { + refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)fileURL, NULL); + shouldUpdate = basePath != nil && refURL != nil; + } + + if (refURL == nil && basePath && relativePath) { + NSURL *aURL = [NSURL fileURLWithPath:[relativePath isAbsolutePath] ? relativePath : [basePath stringByAppendingPathComponent:relativePath] isDirectory:NO]; + refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)aURL, NULL); + shouldUpdate = refURL != nil; + } + + if (refURL == nil) { + if ([alias isKindOfClass:[NSData class]]) { + NSURL *aURL = (NSURL *)CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, (CFDataRef)alias, kCFURLBookmarkResolutionWithoutUIMask | kCFURLBookmarkResolutionWithoutMountingMask, NULL, NULL, (Boolean *)&shouldUpdate, NULL); + if (aURL) { + refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)aURL, NULL); + [aURL release]; + } + shouldUpdate = shouldUpdate && basePath != nil && refURL != nil; + } else if ([alias isKindOfClass:[BDSKAlias class]]) { + FSRef aRef, baseRef; + BOOL ignored, hasBaseRef = BDSKPathToFSRef(basePath, &baseRef); + if ([alias getFSRef:&aRef baseRef:hasBaseRef ? &baseRef : NULL shouldUpdate:&ignored]){ + NSURL *aURL = BDSKCreateURLFromFSRef(&aRef); + if (aURL) { + refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)aURL, NULL); + [aURL release]; + } + } + shouldUpdate = hasBaseRef && refURL != nil; + } + } + + if (refURL != nil) { + [fileRef release]; + fileRef = refURL; + } + } else if (relativePath == nil) { + shouldUpdate = basePath != nil; } - if (hasRef == NO && hasBaseRef && relativePath) { - NSString *path = [relativePath isAbsolutePath] ? relativePath : [basePath stringByAppendingPathComponent:relativePath]; - shouldUpdate = hasRef = BDSKPathToFSRef(path, &aRef); + if ((shouldUpdate || fileURL == nil) && fileRef != nil) { + NSURL *aURL = [self newPathURL]; + if (aURL != nil) { + if (fileURL == nil) + fileURL = [aURL retain]; + if (shouldUpdate) { + [self updateBookmark]; + [self setRelativePath:[aURL path] fromPath:basePath]; + } + [aURL release]; + } } - if (hasRef == NO) { - if ([alias isKindOfClass:[BDSKAlias class]]) { - hasRef = [alias getFSRef:&aRef baseRef:hasBaseRef ? &baseRef : NULL shouldUpdate:&shouldUpdate]; - shouldUpdate = (shouldUpdate || relativePath == nil) && hasBaseRef && hasRef; - } else if ([alias isKindOfClass:[NSData class]]) { - NSURL *aURL = [NSURL URLByResolvingBookmarkData:alias options:NSURLBookmarkResolutionWithoutUI relativeToURL:nil bookmarkDataIsStale:NULL error:NULL]; - hasRef = BDSKPathToFSRef([aURL path], &aRef); + } else { + // using AliasHandle and FSRef + FSRef baseRef; + BOOL hasBaseRef = BDSKPathToFSRef(basePath, &baseRef); + + if (fileRef == nil) { + FSRef aRef; + BOOL hasRef = NO; + + if (fileURL) { + hasRef = BDSKPathToFSRef([fileURL path], &aRef); shouldUpdate = hasBaseRef && hasRef; } + + if (hasRef == NO && hasBaseRef && relativePath) { + NSString *path = [relativePath isAbsolutePath] ? relativePath : [basePath stringByAppendingPathComponent:relativePath]; + shouldUpdate = hasRef = BDSKPathToFSRef(path, &aRef); + } + + if (hasRef == NO) { + if ([alias isKindOfClass:[BDSKAlias class]]) { + hasRef = [alias getFSRef:&aRef baseRef:hasBaseRef ? &baseRef : NULL shouldUpdate:&shouldUpdate]; + shouldUpdate = (shouldUpdate || relativePath == nil) && hasBaseRef && hasRef; + } else if ([alias isKindOfClass:[NSData class]]) { + NSURL *aURL = [NSURL URLByResolvingBookmarkData:alias options:NSURLBookmarkResolutionWithoutUI relativeToURL:nil bookmarkDataIsStale:NULL error:NULL]; + hasRef = BDSKPathToFSRef([aURL path], &aRef); + shouldUpdate = hasBaseRef && hasRef; + } + } + + if (hasRef) { + [fileRef release]; + fileRef = [[BDSKFileRef alloc] initWithFSRef:&aRef]; + } + } else if (relativePath == nil) { + shouldUpdate = hasBaseRef; } - if (hasRef) { - [self setFileRef:&aRef]; - } - } else if (relativePath == nil) { - shouldUpdate = hasBaseRef; - } - - if ((shouldUpdate || fileURL == nil) && fileRef != nil) { - NSURL *aURL = BDSKCreateURLFromFSRef(fileRef); - if (aURL != nil) { - if (fileURL == nil) - fileURL = [aURL retain]; - if (shouldUpdate) { - [self updateAliasWithBaseRef:&baseRef]; - [self setRelativePath:[aURL path] fromPath:basePath]; + if ((shouldUpdate || fileURL == nil) && fileRef != nil) { + NSURL *aURL = [self newPathURL]; + if (aURL != nil) { + if (fileURL == nil) + fileURL = [aURL retain]; + if (shouldUpdate) { + [self updateAliasWithBaseRef:&baseRef]; + [self setRelativePath:[aURL path] fromPath:basePath]; + } + [aURL release]; } - [aURL release]; } } } @@ -720,301 +658,102 @@ NSURL *aURL = nil; if (fileRef != nil) { - aURL = BDSKCreateURLFromFSRef(fileRef); + aURL = [self newPathURL]; if (aURL == nil) // fileRef was invalid, try to update it - BDSKZONEDESTROY(fileRef); + BDSKDESTROY(fileRef); } if (aURL == nil) { // fileRef was nil or invalid [self updateFileRef]; - aURL = BDSKCreateURLFromFSRef(fileRef); + aURL = [self newPathURL]; } if ([aURL isEqual:fileURL] == NO && (aURL != nil || hadFileURL)) { - FSRef aRef; - if (BDSKPathToFSRef([fileURL path], &aRef)) { - // the file was replaced, reference the replacement rather than the moved file - // this is what Dropbox does with file updates - [self setFileRef:&aRef]; - [aURL release]; - aURL =BDSKCreateURLFromFSRef(fileRef); - NSString *basePath = [delegate basePathForLinkedFile:self]; - FSRef baseRef; - if (BDSKPathToFSRef(basePath, &baseRef)) { - [self updateAliasWithBaseRef:&baseRef]; - [self setRelativePath:[aURL path] fromPath:basePath]; - } - } - [self setFileURL:aURL]; - } - [aURL release]; - isInitial = NO; -} - -- (NSData *)copyAliasDataRelativeToPath:(NSString *)basePath { - BDSKAlias *anAlias = NULL; - NSData *data = nil; - - if (fileRef) { - FSRef baseRef; - BOOL hasBaseRef = BDSKPathToFSRef(basePath, &baseRef); - anAlias = [BDSKAlias newWithFSRef:fileRef baseRef:hasBaseRef ? &baseRef : NULL]; - } else if (relativePath && basePath) { - NSString *path = [relativePath isAbsolutePath] ? relativePath : [[basePath stringByAppendingPathComponent:relativePath] stringByStandardizingPath]; - anAlias = [BDSKAlias newWithPath:path basePath:basePath]; - } - if (anAlias != NULL) { - data = [anAlias copyData]; - [anAlias release]; - } else if ([alias isKindOfClass:[BDSKAlias class]]) { - data = [alias copyData]; - } - - return data; -} - -- (void)setAliasWithPath:(NSString *)aPath basePath:(NSString *)basePath { - id anAlias = [BDSKAlias newWithPath:aPath basePath:basePath]; - if (anAlias != nil) { - id saveAlias = alias; - alias = anAlias; - [self updateFileRef]; - if (fileRef == nil) { - [anAlias release]; - alias = saveAlias; - [self updateFileRef]; - } else { - [saveAlias release]; - } - } -} - -// This is called when the file is added (new or initially), -// the document URL changes, or with aPath != nil after an autofile -- (void)updateWithPath:(NSString *)aPath { - NSString *basePath = [delegate basePathForLinkedFile:self]; - - if (fileRef == nil) { - // this does the updating if possible - [self updateFileRef]; - } else { - NSURL *aURL = BDSKCreateURLFromFSRef(fileRef); - if (aURL != nil) { - // if the path has changed, updating will be done below - if (basePath && (aPath == nil || [[aURL path] isEqualToString:aPath])) { - FSRef baseRef; - if (BDSKPathToFSRef(basePath, &baseRef)) { - [self updateAliasWithBaseRef:&baseRef]; + if (wantsBookmark) { + // using bookmark and NSURL + NSURL *refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)fileURL, NULL); + if (refURL) { + // the file was replaced, reference the replacement rather than the moved file + // this is what Dropbox does with file updates + [fileRef release]; + fileRef = refURL; + [aURL release]; + aURL = [self newPathURL]; + NSString *basePath = [delegate basePathForLinkedFile:self]; + if (basePath) { + [self updateBookmark]; [self setRelativePath:[aURL path] fromPath:basePath]; } } - [aURL release]; } else { - // the fileRef was invalid, reset it and update - BDSKZONEDESTROY(fileRef); - [self updateFileRef]; - if (fileRef == nil && aPath) { - // this can happen after an auto file to a volume, as the file is actually not moved but copied - [self setAliasWithPath:aPath basePath:basePath]; - if (basePath) - [self setRelativePath:aPath fromPath:basePath]; - } - } - } - if (aPath) { - NSString *path = [self path]; - if ([path isEqualToString:aPath] == NO) { - BOOL needsUpdate = YES; + // using AliasHandle and FSRef FSRef aRef; - if (BDSKPathToFSRef(aPath, &aRef)) { - NSURL *aURL = BDSKCreateURLFromFSRef(&aRef); - if ([path isEqualToString:[aURL path]]) { - needsUpdate = NO; - } else { - [self setFileRef:&aRef]; - [self setFileURL:aURL]; - } + if (BDSKPathToFSRef([fileURL path], &aRef)) { + // the file was replaced, reference the replacement rather than the moved file + // this is what Dropbox does with file updates + [fileRef release]; + fileRef = [[BDSKFileRef alloc] initWithFSRef:&aRef]; [aURL release]; - } - if (needsUpdate) { + aURL = [self newPathURL]; + NSString *basePath = [delegate basePathForLinkedFile:self]; FSRef baseRef; if (BDSKPathToFSRef(basePath, &baseRef)) { [self updateAliasWithBaseRef:&baseRef]; - [self setRelativePath:aPath fromPath:basePath]; - } else { - [self setAliasWithPath:aPath basePath:basePath]; + [self setRelativePath:[aURL path] fromPath:basePath]; } } } + [self setFileURL:aURL]; } + [aURL release]; + isInitial = NO; } -@end - -#pragma mark - - -@implementation BDSKBookmarkLinkedFile - -- (id)initWithURL:(NSURL *)aURL delegate:(id<BDSKLinkedFileDelegate>)aDelegate { - BDSKASSERT([aURL isFileURL]); - - NSString *aPath = [aURL path]; - - BDSKASSERT(nil != aPath); - - NSString *basePath = [aDelegate basePathForLinkedFile:self]; - NSString *relPath = basePath ? [aPath relativePathFromPath:basePath] : nil; - id anAlias = BDSKCreateBookmarkDataFromURL(aURL); - self = [self initWithAlias:anAlias relativePath:relPath delegate:aDelegate]; - [anAlias release]; - if (self && basePath) - [self updateFileRefURL]; - return self; -} - -- (void)encodeWithCoder:(NSCoder *)coder { - [super encodeWithCoder:coder]; - if ([coder allowsKeyedCoding]) { - NSData *data = [self copyBookmarkDataRelativeToPath:[delegate basePathForLinkedFile:self]]; - if (data) - [coder encodeObject:alias forKey:BOOKMARK_KEY]; - else if ([alias isKindOfClass:[BDSKAlias class]] && (data = [alias copyData])) - [coder encodeObject:data forKey:ALIASDATA_KEY]; - [data release]; - } -} - -- (void)dealloc { - BDSKDESTROY(fileRefURL); - [super dealloc]; -} - -- (id)copyWithZone:(NSZone *)aZone { - // make sure the fileRef is valid +- (NSURL *)URL { [self updateFileURL]; - id anAlias = [self copyBookmarkDataRelativeToPath:[delegate basePathForLinkedFile:self]]; - if (anAlias == nil && [alias isKindOfClass:[BDSKAlias class]]) { - NSData *data = [alias copyData]; - anAlias = [BDSKAlias newWithData:data]; - [data release]; - } - self = [[[self class] allocWithZone:aZone] initWithAlias:anAlias relativePath:relativePath delegate:delegate]; - [anAlias release]; - return self; + return fileURL; } -- (void)updateBookmark { - BDSKASSERT(fileURL != nil); - - // update the bookmark - NSData *data = BDSKCreateBookmarkDataFromURL(fileURL ?: [fileRefURL filePathURL]); - if (data) { - [alias release]; - alias = data; +- (NSURL *)displayURL { + NSURL *displayURL = [self URL]; + if (displayURL == nil && relativePath) { + NSString *basePath = [delegate basePathForLinkedFile:self]; + displayURL = basePath ? [NSURL URLWithString:[relativePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]] relativeToURL:[NSURL fileURLWithPath:basePath isDirectory:YES]] : [NSURL fileURLWithPath:relativePath isDirectory:NO]; } + return displayURL; } -- (void)updateFileRefURL { - NSString *basePath = [delegate basePathForLinkedFile:self]; - BOOL shouldUpdate = NO; - - // using bookmark and NSURL - if (fileRefURL == nil) { - NSURL *refURL = nil; - - if (fileURL) { - refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)fileURL, NULL); - shouldUpdate = basePath != nil && refURL != nil; - } - - if (refURL == nil && basePath && relativePath) { - NSURL *aURL = [NSURL fileURLWithPath:[relativePath isAbsolutePath] ? relativePath : [basePath stringByAppendingPathComponent:relativePath] isDirectory:NO]; - refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)aURL, NULL); - shouldUpdate = refURL != nil; - } - - if (refURL == nil) { - if ([alias isKindOfClass:[NSData class]]) { - NSURL *aURL = (NSURL *)CFURLCreateByResolvingBookmarkData(kCFAllocatorDefault, (CFDataRef)alias, kCFURLBookmarkResolutionWithoutUIMask | kCFURLBookmarkResolutionWithoutMountingMask, NULL, NULL, (Boolean *)&shouldUpdate, NULL); - if (aURL) { - refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)aURL, NULL); - [aURL release]; - } - shouldUpdate = shouldUpdate && basePath != nil && refURL != nil; - } else if ([alias isKindOfClass:[BDSKAlias class]]) { - FSRef aRef, baseRef; - BOOL ignored, hasBaseRef = BDSKPathToFSRef(basePath, &baseRef); - if ([alias getFSRef:&aRef baseRef:hasBaseRef ? &baseRef : NULL shouldUpdate:&ignored]){ - NSURL *aURL = BDSKCreateURLFromFSRef(&aRef); - if (aURL) { - refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)aURL, NULL); - [aURL release]; - } - } - shouldUpdate = hasBaseRef && refURL != nil; - } - } - - if (refURL != nil) { - [fileRefURL release]; - fileRefURL = refURL; - } - } else if (relativePath == nil) { - shouldUpdate = basePath != nil; +- (BOOL)hasSkimNotes { + if (hasSkimNotesNeedsUpdate) { + hasSkimNotes = [[fileURL SkimNotes] count] > 0; + hasSkimNotesNeedsUpdate = NO; } - - if ((shouldUpdate || fileURL == nil) && fileRefURL != nil) { - NSURL *aURL = (NSURL *)CFURLCreateFilePathURL(kCFAllocatorDefault, (CFURLRef)fileRefURL, NULL); - if (aURL != nil) { - if (fileURL == nil) - fileURL = [aURL retain]; - if (shouldUpdate) { - [self updateBookmark]; - [self setRelativePath:[aURL path] fromPath:basePath]; - } - [aURL release]; - } - } + return hasSkimNotes; } -- (void)updateFileURL { - BOOL hadFileURL = fileURL != nil; - NSURL *aURL = nil; +- (NSData *)copyAliasDataRelativeToPath:(NSString *)basePath { + BDSKAlias *anAlias = NULL; + NSData *data = nil; - if (fileRefURL != nil) { - aURL = (NSURL *)CFURLCreateFilePathURL(kCFAllocatorDefault, (CFURLRef)fileRefURL, NULL); - if (aURL == nil) - // fileRefURL was invalid, try to update it - BDSKDESTROY(fileRefURL); + if (wantsBookmark && fileURL) { + anAlias = [BDSKAlias newWithPath:[fileURL path] basePath:basePath]; + } else if (wantsBookmark == NO && fileRef) { + FSRef baseRef; + BOOL hasBaseRef = BDSKPathToFSRef(basePath, &baseRef); + anAlias = [BDSKAlias newWithFSRef:[fileRef fsRef] baseRef:hasBaseRef ? &baseRef : NULL]; + } else if (relativePath && basePath) { + NSString *path = [relativePath isAbsolutePath] ? relativePath : [[basePath stringByAppendingPathComponent:relativePath] stringByStandardizingPath]; + anAlias = [BDSKAlias newWithPath:path basePath:basePath]; } - if (aURL == nil) { - // fileRefURL was nil or invalid - [self updateFileRefURL]; - if (fileRefURL != nil) - aURL = (NSURL *)CFURLCreateFilePathURL(kCFAllocatorDefault, (CFURLRef)fileRefURL, NULL); + if (anAlias != NULL) { + data = [anAlias copyData]; + [anAlias release]; + } else if ([alias isKindOfClass:[BDSKAlias class]]) { + data = [alias copyData]; } - if ([aURL isEqual:fileURL] == NO && (aURL != nil || hadFileURL)) { - // using bookmark and NSURL - NSURL *refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)fileURL, NULL); - if (refURL) { - // the file was replaced, reference the replacement rather than the moved file - // this is what Dropbox does with file updates - [fileRefURL release]; - fileRefURL = refURL; - [aURL release]; - aURL = (NSURL *)CFURLCreateFilePathURL(kCFAllocatorDefault, (CFURLRef)fileRefURL, NULL); - NSString *basePath = [delegate basePathForLinkedFile:self]; - if (basePath) { - [self updateBookmark]; - [self setRelativePath:[aURL path] fromPath:basePath]; - } - } - [self setFileURL:aURL]; - } - [aURL release]; - isInitial = NO; + return data; } - (NSData *)copyBookmarkDataRelativeToPath:(NSString *)basePath { @@ -1032,27 +771,52 @@ return data; } -- (NSData *)copyDataRelativeToPath:(NSString *)newBasePath isBookmark:(BOOL *)isBookmark { - NSData *data = [self copyBookmarkDataRelativeToPath:newBasePath]; - if (data) { - *isBookmark = YES; - } else if ([alias isKindOfClass:[BDSKAlias class]]) { - data = [alias copyData]; - *isBookmark = NO; +- (NSString *)stringRelativeToPath:(NSString *)newBasePath { + BOOL noAlias = saveRelativePathOnly && newBasePath != nil; + if (newBasePath == nil) + newBasePath = [delegate basePathForLinkedFile:self]; + // this will make sure the fileRef is valid + NSString *path = [self path]; + NSData *data = nil; + NSString *dataKey = ALIASDATA_KEY; + path = path && newBasePath ? [path relativePathFromPath:newBasePath] : relativePath; + if (noAlias == NO || path == nil) { + if (wantsBookmark) { + data = [self copyBookmarkDataRelativeToPath:newBasePath]; + if (data) + dataKey = BOOKMARK_KEY; + else if ([alias isKindOfClass:[BDSKAlias class]]) + data = [alias copyData]; + } else { + data = [self copyAliasDataRelativeToPath:newBasePath]; + if (data == nil && [alias isKindOfClass:[NSData class]]) { + data = [alias retain]; + dataKey = BOOKMARK_KEY; + } + } } - return data; + NSDictionary *dictionary = data ? [NSDictionary dictionaryWithObjectsAndKeys:data, dataKey, path, RELATIVEPATH_KEY, nil] : [NSDictionary dictionaryWithObjectsAndKeys:path, RELATIVEPATH_KEY, nil]; + [data release]; + if (saveArchivedData) + return [[NSKeyedArchiver archivedDataWithRootObject:dictionary] base64String]; + else + return [[NSPropertyListSerialization dataWithPropertyList:dictionary format:NSPropertyListBinaryFormat_v1_0 options:0 error:NULL] base64String]; } -- (void)setBookmarkWithPath:(NSString *)aPath { - id anAlias = BDSKCreateBookmarkDataFromURL([NSURL fileURLWithPath:aPath]); +- (void)setAliasOrBookmarkWithPath:(NSString *)aPath basePath:(NSString *)basePath { + id anAlias = nil; + if (wantsBookmark) + anAlias = BDSKCreateBookmarkDataFromURL([NSURL fileURLWithPath:aPath]); + else + anAlias = [BDSKAlias newWithPath:aPath basePath:basePath]; if (anAlias != nil) { id saveAlias = alias; alias = anAlias; - [self updateFileRefURL]; - if (fileRefURL == nil) { + [self updateFileRef]; + if (fileRef == nil) { [anAlias release]; alias = saveAlias; - [self updateFileRefURL]; + [self updateFileRef]; } else { [saveAlias release]; } @@ -1064,25 +828,33 @@ - (void)updateWithPath:(NSString *)aPath { NSString *basePath = [delegate basePathForLinkedFile:self]; - if (fileRefURL == nil) { + if (fileRef == nil) { // this does the updating if possible - [self updateFileRefURL]; + [self updateFileRef]; } else { - NSURL *aURL = (NSURL *)CFURLCreateFilePathURL(kCFAllocatorDefault, (CFURLRef)fileRefURL, NULL); + NSURL *aURL = [self newPathURL]; if (aURL != nil) { // if the path has changed, updating will be done below if (basePath && (aPath == nil || [[aURL path] isEqualToString:aPath])) { - [self updateBookmark]; - [self setRelativePath:[aURL path] fromPath:basePath]; + if (wantsBookmark) { + [self updateBookmark]; + [self setRelativePath:[aURL path] fromPath:basePath]; + } else { + FSRef baseRef; + if (BDSKPathToFSRef(basePath, &baseRef)) { + [self updateAliasWithBaseRef:&baseRef]; + [self setRelativePath:[aURL path] fromPath:basePath]; + } + } } [aURL release]; } else { - // the fileRefURL was invalid, reset it and update - BDSKDESTROY(fileRefURL); - [self updateFileRefURL]; - if (fileRefURL == nil && aPath) { + // the fileRef was invalid, reset it and update + BDSKDESTROY(fileRef); + [self updateFileRef]; + if (fileRef == nil && aPath) { // this can happen after an auto file to a volume, as the file is actually not moved but copied - [self setBookmarkWithPath:aPath]; + [self setAliasOrBookmarkWithPath:aPath basePath:basePath]; if (basePath) [self setRelativePath:aPath fromPath:basePath]; } @@ -1092,31 +864,63 @@ NSString *path = [self path]; if ([path isEqualToString:aPath] == NO) { BOOL needsUpdate = YES; - NSURL *refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)[NSURL fileURLWithPath:aPath], NULL); - if (refURL) { - NSURL *aURL = (NSURL *)CFURLCreateFilePathURL(kCFAllocatorDefault, (CFURLRef)refURL, NULL); - if ([path isEqualToString:[aURL path]]) { - [refURL release]; - needsUpdate = NO; - } else { - [fileRefURL release]; - fileRefURL = refURL; - [self setFileURL:aURL]; + if (wantsBookmark) { + // using bookmark and NSURL + NSURL *refURL = (NSURL *)CFURLCreateFileReferenceURL(kCFAllocatorDefault, (CFURLRef)[NSURL fileURLWithPath:aPath], NULL); + if (refURL) { + NSURL *aURL = (NSURL *)CFURLCreateFilePathURL(kCFAllocatorDefault, (CFURLRef)refURL, NULL); + if ([path isEqualToString:[aURL path]]) { + [refURL release]; + needsUpdate = NO; + } else { + [fileRef release]; + fileRef = refURL; + [self setFileURL:aURL]; + } + [aURL release]; } - [aURL release]; - } - if (needsUpdate) { - if (basePath) { - [self updateBookmark]; - [self setRelativePath:aPath fromPath:basePath]; - } else { - [self setBookmarkWithPath:aPath]; + if (needsUpdate) { + if (basePath) { + [self updateBookmark]; + [self setRelativePath:aPath fromPath:basePath]; + } else { + [self setAliasOrBookmarkWithPath:aPath basePath:basePath]; + } } + } else { + // using AliasHandle and FSRef + FSRef aRef; + if (BDSKPathToFSRef(aPath, &aRef)) { + NSURL *aURL = BDSKCreateURLFromFSRef(&aRef); + if ([path isEqualToString:[aURL path]]) { + needsUpdate = NO; + } else { + [fileRef release]; + fileRef = [[BDSKFileRef alloc] initWithFSRef:&aRef]; + [self setFileURL:aURL]; + } + [aURL release]; + } + if (needsUpdate) { + FSRef baseRef; + if (BDSKPathToFSRef(basePath, &baseRef)) { + [self updateAliasWithBaseRef:&baseRef]; + [self setRelativePath:aPath fromPath:basePath]; + } else { + [self setAliasOrBookmarkWithPath:aPath basePath:basePath]; + } + } } } } } +- (void)updateHasSkimNotes { + hasSkimNotesNeedsUpdate = YES; + if (isInitial == NO) + [delegate performSelector:@selector(linkedFileURLChanged:) withObject:self afterDelay:0.0]; +} + @end #pragma mark - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. _______________________________________________ Bibdesk-commit mailing list Bibdesk-commit@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bibdesk-commit