Revision: 12191 http://bibdesk.svn.sourceforge.net/bibdesk/?rev=12191&view=rev Author: hofman Date: 2008-01-02 04:01:32 -0800 (Wed, 02 Jan 2008)
Log Message: ----------- Resolve FSRefs for linked files without resolving final symlinks and links. We can't use BDAlias, so we wrap our own AliasHandle related functions. Every step should still be tested. Use path based conversion to FSRef. Modified Paths: -------------- trunk/bibdesk/BDSKLinkedFile.h trunk/bibdesk/BDSKLinkedFile.m trunk/bibdesk/BibItem.m Modified: trunk/bibdesk/BDSKLinkedFile.h =================================================================== --- trunk/bibdesk/BDSKLinkedFile.h 2008-01-02 07:00:56 UTC (rev 12190) +++ trunk/bibdesk/BDSKLinkedFile.h 2008-01-02 12:01:32 UTC (rev 12191) @@ -52,6 +52,7 @@ - (NSURL *)URL; - (NSURL *)displayURL; +- (NSString *)path; // string value to be saved as a field value, base64 encoded data for a local file or an absolute URL string for a remote URL - (NSString *)stringRelativeToPath:(NSString *)newBasePath; @@ -70,5 +71,5 @@ @interface NSObject (BDSKLinkedFileDelegate) -- (NSURL *)baseURLForLinkedFile:(BDSKLinkedFile *)file; +- (NSString *)basePathForLinkedFile:(BDSKLinkedFile *)file; @end Modified: trunk/bibdesk/BDSKLinkedFile.m =================================================================== --- trunk/bibdesk/BDSKLinkedFile.m 2008-01-02 07:00:56 UTC (rev 12190) +++ trunk/bibdesk/BDSKLinkedFile.m 2008-01-02 12:01:32 UTC (rev 12191) @@ -40,11 +40,115 @@ #import "BDAlias.h" #import <OmniFoundation/NSData-OFExtensions.h> +static AliasHandle BDSKDataToAliasHandle(CFDataRef inData) +{ + CFIndex len; + Handle handle = NULL; + + if (inData != NULL) { + len = CFDataGetLength(inData); + handle = NewHandle(len); + + if ((handle != NULL) && (len > 0)) { + HLock(handle); + BlockMoveData(CFDataGetBytePtr(inData), *handle, len); + HUnlock(handle); + } + } + return (AliasHandle)handle; +} + +static CFDataRef BDSKAliasHandleToData(AliasHandle inAlias) +{ + Handle inHandle = (Handle)inAlias; + CFDataRef data = NULL; + CFIndex len; + SInt8 handleState; + + if (inHandle != NULL) { + len = GetHandleSize(inHandle); + handleState = HGetState(inHandle); + + HLock(inHandle); + + data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *) *inHandle, len); + + HSetState(inHandle, handleState); + } + return data; +} + +static OSStatus BDSKPathToFSRef(CFStringRef inPath, FSRef *outRef) +{ + OSStatus err = noErr; + + if (inPath == NULL) + err = fnfErr; + else + err = FSPathMakeRefWithOptions((UInt8 *)[(NSString *)inPath fileSystemRepresentation], kFSPathMakeRefDoNotFollowLeafSymlink, outRef, NULL); + + return err; +} + +static CFStringRef BDSKFSRefToPathCopy(const FSRef *inRef) +{ + CFURLRef tmpURL = NULL; + CFStringRef result = NULL; + + if (inRef != NULL) { + tmpURL = CFURLCreateFromFSRef(kCFAllocatorDefault, inRef); + + if (tmpURL != NULL) { + result = CFURLCopyFileSystemPath(tmpURL, kCFURLPOSIXPathStyle); + CFRelease(tmpURL); + } + } + + return result; +} + +static AliasHandle BDSKFSRefToAliasHandle(const FSRef *inRef, const FSRef *inBaseRef) +{ + OSStatus err = noErr; + AliasHandle alias = NULL; + + err = FSNewAlias(inBaseRef, inRef, &alias); + + if (err != noErr && alias != NULL) { + DisposeHandle((Handle)alias); + alias = NULL; + } + + return alias; +} + +static AliasHandle BDSKPathToAliasHandle(CFStringRef inPath, CFStringRef inBasePath) +{ + OSStatus err = noErr; + FSRef ref, baseRef; + AliasHandle alias = NULL; + + err = BDSKPathToFSRef(inPath, &ref); + + if (err == noErr) { + if (inBasePath != NULL) { + err = BDSKPathToFSRef(inBasePath, &baseRef); + + if (err != noErr) + alias = BDSKFSRefToAliasHandle(&ref, &baseRef); + } else { + alias = BDSKFSRefToAliasHandle(&ref, NULL); + } + } + + return alias; +} + // Private concrete subclasses @interface BDSKLinkedAliasFile : BDSKLinkedFile { - BDAlias *alias; + AliasHandle alias; const FSRef *fileRef; NSString *relativePath; id delegate; @@ -53,9 +157,9 @@ - (id)initWithPath:(NSString *)aPath delegate:(id)aDelegate; - (void)setRelativePath:(NSString *)newRelativePath; +- (void)updateRelativePathWithBasePath:(NSString *)basePath; - (const FSRef *)fileRef; -- (NSString *)path; - (NSData *)aliasDataRelativeToPath:(NSString *)newBasePath; @@ -154,6 +258,11 @@ return [self URL]; } +- (NSString *)path; +{ + return [[self URL] path]; +} + - (NSString *)stringRelativeToPath:(NSString *)newBasePath; { OBRequestConcreteImplementation(self, _cmd); @@ -184,13 +293,13 @@ @implementation BDSKLinkedAliasFile // guaranteed to be called with a non-nil alias -- (id)initWithAlias:(BDAlias *)anAlias relativePath:(NSString *)relPath delegate:(id)aDelegate; +- (id)initWithAlias:(AliasHandle)anAlias relativePath:(NSString *)relPath delegate:(id)aDelegate; { - NSParameterAssert(nil == aDelegate || [aDelegate respondsToSelector:@selector(baseURLForLinkedFile:)]); - NSParameterAssert(nil != anAlias); + NSParameterAssert(nil == aDelegate || [aDelegate respondsToSelector:@selector(basePathForLinkedFile:)]); + NSParameterAssert(NULL != anAlias); if (self = [super init]) { fileRef = NULL; // this is updated lazily, as we don't know the base path at this point - alias = [anAlias retain]; + alias = anAlias; relativePath = [relPath copy]; delegate = aDelegate; } @@ -200,9 +309,15 @@ - (id)initWithAliasData:(NSData *)data relativePath:(NSString *)relPath delegate:(id)aDelegate; { NSParameterAssert(nil != data); - BDAlias *anAlias = [[BDAlias alloc] initWithData:data]; - self = [self initWithAlias:anAlias relativePath:relPath delegate:aDelegate]; - [anAlias release]; + AliasHandle anAlias = BDSKDataToAliasHandle((CFDataRef)data); + if (anAlias == NULL) { + [[super init] release]; + self = nil; + } else { + self = [self initWithAlias:anAlias relativePath:relPath delegate:aDelegate]; + if (self == nil) + DisposeHandle((Handle)anAlias); + } return self; } @@ -218,25 +333,18 @@ - (id)initWithPath:(NSString *)aPath delegate:(id)aDelegate; { NSParameterAssert(nil != aPath); - NSParameterAssert(nil == aDelegate || [aDelegate respondsToSelector:@selector(baseURLForLinkedFile:)]); - BDAlias *anAlias = nil; - NSURL *baseURL = [aDelegate baseURLForLinkedFile:self]; - NSString *basePath = [baseURL path]; - NSString *relPath = nil; - // BDAlias has a different interpretation of aPath, which is inconsistent with the way it handles FSRef - if (basePath) { - relPath = [basePath relativePathToFilename:aPath]; - anAlias = [[BDAlias alloc] initWithPath:relPath relativeToPath:basePath]; - } else { - anAlias = [[BDAlias alloc] initWithPath:aPath]; - } - if (anAlias) { + NSParameterAssert(nil == aDelegate || [aDelegate respondsToSelector:@selector(basePathForLinkedFile:)]); + NSString *basePath = [aDelegate basePathForLinkedFile:self]; + NSString *relPath = [basePath relativePathToFilename:aPath]; + AliasHandle anAlias = BDSKPathToAliasHandle((CFStringRef)aPath, (CFStringRef)basePath); + + if (anAlias != NULL) { if ((self = [self initWithAlias:anAlias relativePath:relPath delegate:aDelegate])) { - if (baseURL) + if (basePath) // this initalizes the FSRef and update the alias [self fileRef]; - } - [anAlias release]; + } else + DisposeHandle((Handle)anAlias); } else { [[super init] release]; self = nil; @@ -246,6 +354,7 @@ - (id)initWithURL:(NSURL *)aURL delegate:(id)aDelegate; { + OBASSERT([aURL isFileURL]); return [self initWithPath:[aURL path] delegate:aDelegate]; } @@ -257,7 +366,6 @@ - (id)initWithCoder:(NSCoder *)coder { - OBASSERT_NOT_REACHED("BDSKLinkedAliasFile needs a base path for encoding"); NSData *data = nil; NSString *relPath = nil; if ([coder allowsKeyedCoding]) { @@ -272,12 +380,11 @@ - (void)encodeWithCoder:(NSCoder *)coder { - OBASSERT_NOT_REACHED("BDSKLinkedAliasFile needs a base path for encoding"); if ([coder allowsKeyedCoding]) { - [coder encodeObject:[self aliasDataRelativeToPath:[[delegate baseURLForLinkedFile:self] path]] forKey:@"aliasData"]; + [coder encodeObject:[self aliasDataRelativeToPath:[delegate basePathForLinkedFile:self]] forKey:@"aliasData"]; [coder encodeObject:relativePath forKey:@"relativePath"]; } else { - [coder encodeObject:[self aliasDataRelativeToPath:[[delegate baseURLForLinkedFile:self] path]]]; + [coder encodeObject:[self aliasDataRelativeToPath:[delegate basePathForLinkedFile:self]]]; [coder encodeObject:relativePath]; } } @@ -285,7 +392,8 @@ - (void)dealloc { NSZoneFree([self zone], (void *)fileRef); - [alias release]; + if (alias != NULL) + DisposeHandle((Handle)alias); [relativePath release]; [super dealloc]; } @@ -312,7 +420,7 @@ } - (void)setDelegate:(id)newDelegate { - NSParameterAssert(nil == newDelegate || [newDelegate respondsToSelector:@selector(baseURLForLinkedFile:)]); + NSParameterAssert(nil == newDelegate || [newDelegate respondsToSelector:@selector(basePathForLinkedFile:)]); delegate = newDelegate; } @@ -344,9 +452,9 @@ - (const FSRef *)fileRef; { - NSURL *baseURL = [delegate baseURLForLinkedFile:self]; + NSString *basePath = [delegate basePathForLinkedFile:self]; FSRef baseRef; - Boolean hasBaseRef = baseURL && CFURLGetFSRef((CFURLRef)baseURL, &baseRef); + Boolean hasBaseRef = basePath && noErr == BDSKPathToFSRef((CFStringRef)basePath, &baseRef); Boolean shouldUpdate = false; if (fileRef == NULL) { @@ -354,21 +462,15 @@ short aliasCount = 1; Boolean hasRef = false; - if (baseURL && relativePath) { - NSString *path = [[baseURL path] stringByAppendingPathComponent:relativePath]; - NSURL *tmpURL = [NSURL fileURLWithPath:path]; + if (basePath && relativePath) { + NSString *path = [basePath stringByAppendingPathComponent:relativePath]; - shouldUpdate = hasRef = hasBaseRef && tmpURL && CFURLGetFSRef((CFURLRef)tmpURL, &aRef); + shouldUpdate = hasRef = (hasBaseRef && noErr == BDSKPathToFSRef((CFStringRef)path, &aRef)); } - if (hasRef == false && alias) { - if (hasBaseRef) { - hasRef = noErr == FSMatchAliasNoUI(&baseRef, kARMNoUI | kARMSearch | kARMSearchRelFirst, [alias alias], &aliasCount, &aRef, &shouldUpdate, NULL, NULL); - shouldUpdate = shouldUpdate && hasRef; - } else { - hasRef = noErr == FSMatchAliasNoUI(NULL, kARMNoUI | kARMSearch | kARMSearchRelFirst, [alias alias], &aliasCount, &aRef, &shouldUpdate, NULL, NULL); - shouldUpdate = false; - } + if (hasRef == false && alias != NULL) { + hasRef = noErr == FSMatchAliasNoUI(hasBaseRef ? &baseRef : NULL, kARMNoUI | kARMSearch | kARMSearchRelFirst, alias, &aliasCount, &aRef, &shouldUpdate, NULL, NULL); + shouldUpdate = shouldUpdate && hasBaseRef && hasRef; } if (hasRef) @@ -378,17 +480,11 @@ } if (shouldUpdate) { - if (alias) - FSUpdateAlias(&baseRef, fileRef, [alias alias], &shouldUpdate); + if (alias != NULL) + FSUpdateAlias(&baseRef, fileRef, alias, &shouldUpdate); else - alias = [[BDAlias alloc] initWithFSRef:(FSRef *)fileRef relativeToFSRef:&baseRef]; - if (baseURL) { - CFURLRef tmpURL = CFURLCreateFromFSRef(CFAllocatorGetDefault(), fileRef); - if (tmpURL) { - [self setRelativePath:[[baseURL path] relativePathToFilename:[(NSURL *)tmpURL path]]]; - CFRelease(tmpURL); - } - } + alias = BDSKFSRefToAliasHandle(fileRef, &baseRef); + [self updateRelativePathWithBasePath:basePath]; } return fileRef; @@ -396,16 +492,8 @@ - (NSURL *)URL; { - BOOL hadFileRef = fileRef != NULL; - const FSRef *aRef = [self fileRef]; - NSURL *aURL = aRef == NULL ? nil : [(id)CFURLCreateFromFSRef(CFAllocatorGetDefault(), aRef) autorelease]; - if (aURL == nil && hadFileRef) { - // apparently fileRef is invalid, try to update it - [self setFileRef:NULL]; - if (aRef = [self fileRef]) - aURL = [(id)CFURLCreateFromFSRef(CFAllocatorGetDefault(), aRef) autorelease]; - } - return aURL; + NSString *path = [self path]; + return path ? [NSURL fileURLWithPath:path] : nil; } - (NSURL *)displayURL; @@ -418,32 +506,44 @@ - (NSString *)path; { - return [[self URL] path]; + BOOL hadFileRef = fileRef != NULL; + const FSRef *ref = [self fileRef]; + NSString *path = ref == NULL ? nil : (NSString *)BDSKFSRefToPathCopy(ref); + + if (path == nil && hadFileRef) { + // apparently fileRef is invalid, try to update it + [self setFileRef:NULL]; + if (ref = [self fileRef]) + path = (NSString *)BDSKFSRefToPathCopy(ref); + } + return [path autorelease]; } - (NSData *)aliasDataRelativeToPath:(NSString *)newBasePath; { // make sure the fileRef is valid - [self URL]; + [self path]; FSRef *fsRef = (FSRef *)[self fileRef]; FSRef baseRef; - NSURL *baseURL; - BDAlias *anAlias = nil; + NSString *basePath; + AliasHandle anAlias = NULL; + CFDataRef data = NULL; if (fsRef) { - baseURL = newBasePath ? [NSURL fileURLWithPath:newBasePath] : nil; - if (baseURL && CFURLGetFSRef((CFURLRef)baseURL, &baseRef)) - anAlias = [[[BDAlias alloc] initWithFSRef:fsRef relativeToFSRef:&baseRef] autorelease]; - else - anAlias = [[[BDAlias alloc] initWithFSRef:fsRef] autorelease]; + BOOL hasBaseRef = (newBasePath && noErr == BDSKPathToFSRef((CFStringRef)newBasePath, &baseRef)); + anAlias = BDSKFSRefToAliasHandle(fsRef, hasBaseRef ? &baseRef : NULL); } else if (relativePath && newBasePath) { - anAlias = [[[BDAlias alloc] initWithPath:relativePath relativeToPath:newBasePath] autorelease]; + anAlias = BDSKPathToAliasHandle((CFStringRef)[basePath stringByAppendingPathComponent:relativePath], (CFStringRef)newBasePath); } - if (anAlias == nil) - anAlias = alias; + if (anAlias != NULL) { + data = BDSKAliasHandleToData(anAlias); + DisposeHandle((Handle)anAlias); + } else if (alias != NULL) { + data = BDSKAliasHandleToData(alias); + } - return [anAlias aliasData]; + return (NSData *)data; } - (NSString *)stringRelativeToPath:(NSString *)newBasePath; @@ -457,59 +557,57 @@ // this could be called when the document fileURL changes - (void)updateWithPath:(NSString *)aPath { - NSURL *baseURL = [delegate baseURLForLinkedFile:self]; + NSString *basePath = [delegate basePathForLinkedFile:self]; FSRef baseRef; if (fileRef == NULL) { // this does the updating if possible [self fileRef]; } else { - CFURLRef aURL = CFURLCreateFromFSRef(CFAllocatorGetDefault(), fileRef); - if (aURL == NULL) { + CFStringRef path = BDSKFSRefToPathCopy(fileRef); + if (path == NULL) { // the fileRef was invalid, reset it and update [self setFileRef:NULL]; [self fileRef]; if (fileRef == NULL) { // this can happen after an auto file to a volume, as the file is actually not moved but copied - BDAlias *anAlias; - NSString *basePath = [baseURL path]; - if (basePath) - anAlias = [[BDAlias alloc] initWithPath:[basePath relativePathToFilename:aPath] relativeToPath:basePath]; - else - anAlias = [[BDAlias alloc] initWithPath:aPath]; - if (anAlias) { - BDAlias *saveAlias = alias; - alias = [anAlias retain]; + AliasHandle anAlias = BDSKPathToAliasHandle((CFStringRef)aPath, (CFStringRef)basePath); + if (anAlias != NULL) { + AliasHandle saveAlias = alias; + alias = anAlias; [self fileRef]; if (fileRef == NULL) { - [alias release]; alias = saveAlias; [self fileRef]; - } else { - [saveAlias release]; + } else if (saveAlias != NULL) { + DisposeHandle((Handle)saveAlias); } } } } else { - CFRelease(aURL); - if (baseURL && CFURLGetFSRef((CFURLRef)baseURL, &baseRef)) { + CFRelease(path); + if (basePath && noErr == BDSKPathToFSRef((CFStringRef)basePath, &baseRef)) { Boolean didUpdate; - if (alias) - FSUpdateAlias(&baseRef, fileRef, [alias alias], &didUpdate); + if (alias != NULL) + FSUpdateAlias(&baseRef, fileRef, alias, &didUpdate); else - alias = [[BDAlias alloc] initWithFSRef:(FSRef *)fileRef relativeToFSRef:&baseRef]; - if (baseURL) { - CFURLRef tmpURL = CFURLCreateFromFSRef(CFAllocatorGetDefault(), fileRef); - if (tmpURL) { - [self setRelativePath:[[baseURL path] relativePathToFilename:[(NSURL *)tmpURL path]]]; - CFRelease(tmpURL); - } - } + alias = BDSKFSRefToAliasHandle(fileRef, &baseRef); + [self updateRelativePathWithBasePath:basePath]; } } } } +- (void)updateRelativePathWithBasePath:(NSString *)basePath { + if (basePath && fileRef != NULL) { + CFStringRef path = BDSKFSRefToPathCopy(fileRef); + if (path) { + [self setRelativePath:[basePath relativePathToFilename:(NSString *)path]]; + CFRelease(path); + } + } +} + @end #pragma mark - Modified: trunk/bibdesk/BibItem.m =================================================================== --- trunk/bibdesk/BibItem.m 2008-01-02 07:00:56 UTC (rev 12190) +++ trunk/bibdesk/BibItem.m 2008-01-02 12:01:32 UTC (rev 12191) @@ -2534,9 +2534,8 @@ return [[[[self owner] fileURL] path] stringByDeletingLastPathComponent]; } -- (NSURL *)baseURLForLinkedFile:(BDSKLinkedFile *)file { - NSString *basePath = [self basePath]; - return basePath ? [NSURL fileURLWithPath:basePath] : nil; +- (NSString *)basePathForLinkedFile:(BDSKLinkedFile *)file { + return [self basePath]; } // for main tableview sort descriptor This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ Bibdesk-commit mailing list Bibdesk-commit@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bibdesk-commit