Revision: 25202 http://sourceforge.net/p/bibdesk/svn/25202 Author: hofman Date: 2020-12-16 17:03:00 +0000 (Wed, 16 Dec 2020) Log Message: ----------- Use union for alias handle or bookmark data of linked file, we should only have one or the other
Modified Paths: -------------- trunk/bibdesk/BDSKLinkedFile.m Modified: trunk/bibdesk/BDSKLinkedFile.m =================================================================== --- trunk/bibdesk/BDSKLinkedFile.m 2020-12-16 07:30:24 UTC (rev 25201) +++ trunk/bibdesk/BDSKLinkedFile.m 2020-12-16 17:03:00 UTC (rev 25202) @@ -49,6 +49,7 @@ #define ENCODED_PLIST_PREFIX @"YnBsaXN0" #define ALIASDATA_KEY @"aliasData" +#define BOOKMARK_KEY @"bookmark" #define RELATIVEPATH_KEY @"relativePath" static CFURLRef BDSKCreateURLFromFSRef(const FSRef *inRef); @@ -71,12 +72,17 @@ // Private concrete subclasses @interface BDSKLinkedAliasFile : BDSKLinkedFile { - AliasHandle alias; + union _BDSKLocator { + AliasHandle handle; + NSData *bookmark; + } alias; const FSRef *fileRef; NSString *relativePath; NSURL *fileURL; + BOOL isBookmark; BOOL isInitial; - char hasSkimNotes; + BOOL hasSkimNotes; + BOOL hasSkimNotesNeedsUpdate; id delegate; } @@ -268,34 +274,74 @@ @implementation BDSKLinkedAliasFile -// takes possession of anAlias, even if it fails -- (id)initWithAlias:(AliasHandle)anAlias relativePath:(NSString *)relPath delegate:(id<BDSKLinkedFileDelegate>)aDelegate; +- (id)initWithURL:(NSURL *)aURL delegate:(id<BDSKLinkedFileDelegate>)aDelegate; { - BDSKASSERT(nil != anAlias || nil != relPath); + BDSKASSERT([aURL isFileURL]); + + NSString *aPath = [aURL path]; + + BDSKASSERT(nil != aPath); BDSKASSERT(nil == aDelegate || [aDelegate respondsToSelector:@selector(basePathForLinkedFile:)]); - self = [super init]; - if (anAlias == nil && relPath == nil) { + NSString *basePath = [aDelegate basePathForLinkedFile:self]; + NSString *relPath = basePath ? [aPath relativePathFromPath:basePath] : nil; + AliasHandle anAlias = BDSKPathToAliasHandle((CFStringRef)aPath, (CFStringRef)basePath); + + if (anAlias == NULL) { [self release]; self = nil; - } else if (self == nil) { - BDSKDisposeAliasHandle(anAlias); } else { - fileRef = NULL; // this is updated lazily, as we don't know the base path at this point - alias = anAlias; - relativePath = [relPath copy]; - delegate = aDelegate; - fileURL = nil; - isInitial = YES; - hasSkimNotes = -1; + self = [super init]; + if (self) { + fileRef = NULL; // this is updated below if we know the base pat + alias.handle = anAlias; + isBookmark = NO; + relativePath = [relPath copy]; + delegate = aDelegate; + fileURL = nil; + isInitial = YES; + hasSkimNotes = NO; + hasSkimNotesNeedsUpdate = YES; + if (basePath) + // this initalizes the FSRef and update the alias + [self updateFileRef]; + } } - return self; + return self; } -- (id)initWithAliasData:(NSData *)data relativePath:(NSString *)relPath delegate:(id<BDSKLinkedFileDelegate>)aDelegate; +- (id)initWithData:(NSData *)data isBookmark:(BOOL)isBookmarkData relativePath:(NSString *)relPath delegate:(id<BDSKLinkedFileDelegate>)aDelegate; { - AliasHandle anAlias = BDSKDataToAliasHandle((CFDataRef)data); - return [self initWithAlias:anAlias relativePath:relPath delegate:aDelegate]; + BDSKASSERT(nil != data || nil != relPath); + BDSKASSERT(nil == aDelegate || [aDelegate respondsToSelector:@selector(basePathForLinkedFile:)]); + + AliasHandle anAlias = NULL; + if (isBookmarkData == NO) { + anAlias = BDSKDataToAliasHandle((CFDataRef)data); + if (anAlias == NULL) data = nil; + } + + if (data == nil && relPath == nil) { + [self release]; + self = nil; + } else { + self = [super init]; + if (self) { + fileRef = NULL; // this is updated lazily, as we don't know the base path at this point + if (isBookmarkData) + alias.bookmark = [data copy]; + else + alias.handle = anAlias; + isBookmark = isBookmarkData; + relativePath = [relPath copy]; + delegate = aDelegate; + fileURL = nil; + isInitial = YES; + hasSkimNotes = NO; + hasSkimNotesNeedsUpdate = YES; + } + } + return self; } - (id)initWithBase64String:(NSString *)base64String delegate:(id<BDSKLinkedFileDelegate>)aDelegate; @@ -315,7 +361,8 @@ } NSString *relPath = nil; - NSData *aliasData = nil; + NSData *fileData = nil; + BOOL isBookmarkData = NO; if ([base64String hasPrefix:ENCODED_PLIST_PREFIX]) { if (([base64String length] % 4) != 0) { @@ -342,7 +389,11 @@ dictionary = BDSKDictionaryFromArchivedData(data) ?: BDSKDictionaryFromPlistData(data); else dictionary = BDSKDictionaryFromPlistData(data) ?: BDSKDictionaryFromArchivedData(data); - aliasData = [dictionary objectForKey:ALIASDATA_KEY]; + fileData = [dictionary objectForKey:ALIASDATA_KEY]; + if (fileData == nil) { + fileData = [dictionary objectForKey:BOOKMARK_KEY]; + isBookmarkData = (fileData != nil); + } relPath = [dictionary objectForKey:RELATIVEPATH_KEY]; [data release]; } @@ -350,37 +401,9 @@ relPath = base64String; } - return [self initWithAliasData:aliasData relativePath:relPath delegate:aDelegate]; + return [self initWithData:fileData isBookmark:isBookmarkData relativePath:relPath delegate:aDelegate]; } - -- (id)initWithURL:(NSURL *)aURL delegate:(id<BDSKLinkedFileDelegate>)aDelegate; -{ - BDSKASSERT([aURL isFileURL]); - - NSString *aPath = [aURL path]; - - BDSKASSERT(nil != aPath); - BDSKASSERT(nil == aDelegate || [aDelegate respondsToSelector:@selector(basePathForLinkedFile:)]); - - NSString *basePath = [aDelegate basePathForLinkedFile:self]; - NSString *relPath = basePath ? [aPath relativePathFromPath:basePath] : nil; - AliasHandle anAlias = BDSKPathToAliasHandle((CFStringRef)aPath, (CFStringRef)basePath); - - if (anAlias == NULL) { - [self release]; - self = nil; - } else { - self = [self initWithAlias:anAlias relativePath:relPath delegate:aDelegate]; - if (self) { - if (basePath) - // this initalizes the FSRef and update the alias - [self updateFileRef]; - } - } - return self; -} - - (id)initWithURLString:(NSString *)aString; { BDSKASSERT_NOT_REACHED("Attempt to initialize BDSKLinkedAliasFile with a URL string"); @@ -390,24 +413,32 @@ - (id)initWithCoder:(NSCoder *)coder { NSData *data = nil; + BOOL isBookmarkData = NO; NSString *relPath = nil; if ([coder allowsKeyedCoding]) { data = [coder decodeObjectForKey:ALIASDATA_KEY]; + if (data == nil) { + data = [coder decodeObjectForKey:BOOKMARK_KEY]; + isBookmarkData = (data != nil); + } relPath = [coder decodeObjectForKey:RELATIVEPATH_KEY]; } else { data = [coder decodeObject]; relPath = [coder decodeObject]; } - return [self initWithAliasData:data relativePath:relPath delegate:nil]; + return [self initWithData:data isBookmark:isBookmarkData relativePath:relPath delegate:nil]; } - (void)encodeWithCoder:(NSCoder *)coder { + NSData *data = [self aliasDataRelativeToPath:[delegate basePathForLinkedFile:self]]; if ([coder allowsKeyedCoding]) { - [coder encodeObject:[self aliasDataRelativeToPath:[delegate basePathForLinkedFile:self]] forKey:ALIASDATA_KEY]; + [coder encodeObject:data forKey:ALIASDATA_KEY]; + if (data == nil && isBookmark && alias.bookmark) + [coder encodeObject:alias.bookmark forKey:BOOKMARK_KEY]; [coder encodeObject:relativePath forKey:RELATIVEPATH_KEY]; } else { - [coder encodeObject:[self aliasDataRelativeToPath:[delegate basePathForLinkedFile:self]]]; + [coder encodeObject:data]; [coder encodeObject:relativePath]; } } @@ -415,7 +446,11 @@ - (void)dealloc { BDSKZONEDESTROY(fileRef); - BDSKDisposeAliasHandle(alias); alias = NULL; + if (isBookmark) { + BDSKDESTROY(alias.bookmark); + } else { + BDSKDisposeAliasHandle(alias.handle); alias.handle = NULL; + } BDSKDESTROY(relativePath); BDSKDESTROY(fileURL); [super dealloc]; @@ -423,7 +458,13 @@ - (id)copyWithZone:(NSZone *)aZone { - return [[[self class] allocWithZone:aZone] initWithAliasData:[self aliasDataRelativeToPath:[delegate basePathForLinkedFile:self]] relativePath:relativePath delegate:delegate]; + NSData *data = [self aliasDataRelativeToPath:[delegate basePathForLinkedFile:self]]; + BOOL isBookmarkData = NO; + if (data == nil && isBookmark && alias.bookmark){ + data = alias.bookmark; + isBookmarkData = YES; + } + return [[[self class] allocWithZone:aZone] initWithData:data isBookmark:isBookmarkData relativePath:relativePath delegate:delegate]; } // Should we implement -isEqual: and -hash? @@ -466,7 +507,7 @@ if (aURL != fileURL) { [fileURL release]; fileURL = [aURL retain]; - hasSkimNotes = -1; + hasSkimNotesNeedsUpdate = YES; if (isInitial == NO) [delegate performSelector:@selector(linkedFileURLChanged:) withObject:self afterDelay:0.0]; } @@ -493,10 +534,15 @@ shouldUpdate = hasRef = BDSKPathToFSRef((CFStringRef)path, &aRef); } - if (hasRef == false && alias != NULL) { - hasRef = BDSKAliasHandleToFSRef(alias, hasBaseRef ? &baseRef : NULL, &aRef, &shouldUpdate); + if (hasRef == false && isBookmark == NO && alias.handle != NULL) { + hasRef = BDSKAliasHandleToFSRef(alias.handle, hasBaseRef ? &baseRef : NULL, &aRef, &shouldUpdate); shouldUpdate = (shouldUpdate || relativePath == nil) && hasBaseRef && hasRef; } + if (hasRef == false && isBookmark && alias.bookmark != nil) { + NSURL *aURL = [NSURL URLByResolvingBookmarkData:alias.bookmark options:NSURLBookmarkResolutionWithoutUI | NSURLBookmarkResolutionWithoutMounting relativeToURL:(basePath ? [NSURL fileURLWithPath:basePath] : nil) bookmarkDataIsStale:NULL error:NULL]; + hasRef = BDSKPathToFSRef((CFStringRef)[aURL path], &aRef); + shouldUpdate = hasBaseRef && hasRef; + } if (hasRef) [self setFileRef:&aRef]; @@ -564,9 +610,11 @@ } - (BOOL)hasSkimNotes { - if (hasSkimNotes == -1) + if (hasSkimNotesNeedsUpdate) { hasSkimNotes = [[fileURL SkimNotes] count] > 0; - return hasSkimNotes == 1; + hasSkimNotesNeedsUpdate = NO; + } + return hasSkimNotes; } - (NSData *)aliasDataRelativeToPath:(NSString *)basePath; @@ -589,8 +637,8 @@ if (anAlias != NULL) { data = BDSKCopyAliasHandleToData(anAlias); BDSKDisposeAliasHandle(anAlias); - } else if (alias != NULL) { - data = BDSKCopyAliasHandleToData(alias); + } else if (isBookmark == NO && alias.handle != NULL) { + data = BDSKCopyAliasHandleToData(alias.handle); } return [(NSData *)data autorelease]; @@ -603,10 +651,15 @@ newBasePath = [delegate basePathForLinkedFile:self]; NSData *data = noAlias ? nil : [self aliasDataRelativeToPath:newBasePath]; NSString *path = [self path]; + NSString *dataKey = ALIASDATA_KEY; path = path && newBasePath ? [path relativePathFromPath:newBasePath] : relativePath; if (path == nil && noAlias) data = [self aliasDataRelativeToPath:newBasePath]; - NSDictionary *dictionary = data ? [NSDictionary dictionaryWithObjectsAndKeys:data, ALIASDATA_KEY, path, RELATIVEPATH_KEY, nil] : [NSDictionary dictionaryWithObjectsAndKeys:path, RELATIVEPATH_KEY, nil]; + if (data == nil && (noAlias == NO || path == nil) && isBookmark) { + data = alias.bookmark; + dataKey = BOOKMARK_KEY; + } + NSDictionary *dictionary = data ? [NSDictionary dictionaryWithObjectsAndKeys:data, dataKey, path, RELATIVEPATH_KEY, nil] : [NSDictionary dictionaryWithObjectsAndKeys:path, RELATIVEPATH_KEY, nil]; if (saveArchivedData) return [[NSKeyedArchiver archivedDataWithRootObject:dictionary] base64String]; else @@ -616,15 +669,20 @@ - (void)updateAliasWithPath:(NSString *)aPath basePath:(NSString *)basePath { AliasHandle anAlias = BDSKPathToAliasHandle((CFStringRef)aPath, (CFStringRef)basePath); if (anAlias != NULL) { - AliasHandle saveAlias = alias; - alias = anAlias; + BOOL saveIsBookmark = isBookmark; + union _BDSKLocator saveAlias = alias; + alias.handle = anAlias; + isBookmark = NO; [self updateFileRef]; if (fileRef == NULL) { BDSKDisposeAliasHandle(anAlias); alias = saveAlias; + isBookmark = saveIsBookmark; [self updateFileRef]; + } else if (saveIsBookmark) { + [saveAlias.bookmark release]; } else { - BDSKDisposeAliasHandle(saveAlias); + BDSKDisposeAliasHandle(saveAlias.handle); } } } @@ -686,13 +744,21 @@ Boolean didUpdate; // update the alias - if (alias != NULL) + if (isBookmark == NO && alias.handle != NULL) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - FSUpdateAlias(BDSKBaseRefIfOnSameVolume(baseRef, fileRef), fileRef, alias, &didUpdate); + FSUpdateAlias(BDSKBaseRefIfOnSameVolume(baseRef, fileRef), fileRef, alias.handle, &didUpdate); #pragma clang diagnostic pop - else - alias = BDSKFSRefToAliasHandle(fileRef, baseRef); + } else { + AliasHandle anAlias = BDSKFSRefToAliasHandle(fileRef, baseRef); + if (anAlias) { + if (isBookmark) { + BDSKDESTROY(alias.bookmark); + isBookmark = NO; + } + alias.handle = anAlias; + } + } // update the relative path [relativePath autorelease]; @@ -700,7 +766,7 @@ } - (void)updateHasSkimNotes { - hasSkimNotes = -1; + hasSkimNotesNeedsUpdate = YES; if (isInitial == NO) [delegate performSelector:@selector(linkedFileURLChanged:) withObject:self afterDelay:0.0]; } 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