Finalize sandbox file access persistence. Add another cover art filename.

This commit is contained in:
Christopher Snowhill 2021-02-28 02:02:44 -08:00
parent 79fcd4e20a
commit 49d91d5f5f
16 changed files with 452 additions and 16 deletions

View file

@ -15,6 +15,8 @@
#import "PathNode.h"
#import <CogAudio/Status.h>
#import "SandboxBroker.h"
#import "Logging.h"
#import "MiniModeMenuTitleTransformer.h"
#import "DualWindow.h"
@ -72,13 +74,15 @@ void* kAppControllerContext = &kAppControllerContext;
[p setResolvesAliases:YES];
[p beginSheetModalForWindow:mainWindow completionHandler:^(NSInteger result) {
[p close];
[NSApp stopModal];
if ( result == NSModalResponseOK ) {
[self->playlistLoader willInsertURLs:[p URLs] origin:URLOriginInternal];
[self->playlistLoader didInsertURLs:[self->playlistLoader addURLs:[p URLs] sort:YES] origin:URLOriginInternal];
} else {
[p close];
}
}];
[NSApp runModalForWindow:[NSApp mainWindow]];
}
- (IBAction)savePlaylist:(id)sender
@ -143,6 +147,12 @@ void* kAppControllerContext = &kAppControllerContext;
[self registerHotKeys];
(void) [spotlightWindowController init];
SandboxBroker * sandboxBroker = [SandboxBroker sharedSandboxBroker];
if (!sandboxBroker)
{
ALog("sandbox init failed");
}
[[playlistController undoManager] disableUndoRegistration];
NSString *basePath = [@"~/Library/Application Support/Cog/" stringByExpandingTildeInPath];
@ -355,6 +365,9 @@ void* kAppControllerContext = &kAppControllerContext;
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath:[folder stringByAppendingPathComponent:fileName] error:&error];
DLog(@"Saving bookmarks for sandbox access");
[[SandboxBroker sharedSandboxBroker] shutdown];
DLog(@"Saving expanded nodes: %@", [expandedNodes description]);
@ -387,10 +400,11 @@ void* kAppControllerContext = &kAppControllerContext;
{
//Need to convert to urls
NSMutableArray *urls = [NSMutableArray array];
for (NSString *filename in filenames)
{
[urls addObject:[NSURL fileURLWithPath:filename]];
NSURL * fileUrl = [NSURL fileURLWithPath:filename];
[urls addObject:fileUrl];
}
[playlistLoader willInsertURLs:urls origin:URLOriginExternal];
[playlistLoader didInsertURLs:[playlistLoader addURLs:urls sort:YES] origin:URLOriginExternal];

View file

@ -366,6 +366,7 @@
TargetAttributes = {
8DC2EF4F0486A6940098B216 = {
DevelopmentTeam = "";
LastSwiftMigration = 1240;
ProvisioningStyle = Automatic;
};
};
@ -431,10 +432,12 @@
1DEB91AE08733DA50010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -448,12 +451,15 @@
GCC_PREFIX_HEADER = CogAudio_Prefix.pch;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.cogaudio;
PRODUCT_NAME = CogAudio;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
WARNING_LDFLAGS = "";
WRAPPER_EXTENSION = framework;
ZERO_LINK = YES;
@ -463,9 +469,11 @@
1DEB91AF08733DA50010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -477,12 +485,14 @@
GCC_PREFIX_HEADER = CogAudio_Prefix.pch;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.cogaudio;
PRODUCT_NAME = CogAudio;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
WARNING_LDFLAGS = "";
WRAPPER_EXTENSION = framework;
};

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18121" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18121"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -18,7 +18,7 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
<rect key="contentRect" x="331" y="367" width="1000" height="400"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1055"/>
<value key="minSize" type="size" width="750" height="200"/>
<stackView key="contentView" distribution="equalSpacing" orientation="vertical" alignment="centerX" spacing="0.0" detachesHiddenViews="YES" id="2">
<rect key="frame" x="0.0" y="0.0" width="1000" height="400"/>
@ -565,7 +565,7 @@
<window title="Cog" separatorStyle="none" allowsToolTipsWhenApplicationIsInactive="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="Mini Window" animationBehavior="default" toolbarStyle="unified" id="2234" userLabel="Mini Window (Window)" customClass="MiniWindow">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="192" y="547" width="640" height="0.0"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1055"/>
<view key="contentView" hidden="YES" wantsLayer="YES" id="2235">
<rect key="frame" x="0.0" y="0.0" width="640" height="0.0"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@ -1435,7 +1435,6 @@ Gw
<string>status</string>
<mutableString>queued</mutableString>
</declaredKeys>
<classReference key="objectClass" className="PlaylistEntry"/>
<connections>
<outlet property="playbackController" destination="705" id="2121"/>
<outlet property="playlistLoader" destination="1319" id="1321"/>
@ -1755,7 +1754,6 @@ Gw
<mutableString>title</mutableString>
<mutableString>artist</mutableString>
</declaredKeys>
<classReference key="objectClass" className="PlaylistEntry"/>
<connections>
<binding destination="218" name="contentObject" keyPath="currentEntry" id="1902"/>
</connections>
@ -1767,7 +1765,6 @@ Gw
<string>artist</string>
<string>album</string>
</declaredKeys>
<classReference key="objectClass" className="PlaylistEntry"/>
<connections>
<binding destination="218" name="contentArray" keyPath="arrangedObjects" id="2039"/>
<binding destination="218" name="selectionIndexes" keyPath="selectionIndexes" id="2041"/>

View file

@ -10,6 +10,8 @@
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>

View file

@ -153,6 +153,7 @@
83BC5AC320E4CE8D00631CD4 /* SpotlightPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 178456C00F6320B5007E8021 /* SpotlightPanel.xib */; };
83BC5AC420E4CE9000631CD4 /* Feedback.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17D1B1DA0F6330D400694C57 /* Feedback.xib */; };
83BCB8DE17FC971300760340 /* FFMPEG.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = B09E94350D747F7B0064F138 /* FFMPEG.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
83CAEB9125EB3EE100D6ACCC /* SandboxBroker.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CAEB9025EB3EE100D6ACCC /* SandboxBroker.m */; };
83D0380F24A40DFB004CF90F /* CogAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83D0380E24A40DF2004CF90F /* CogAssets.xcassets */; };
83E5E54C18087CA5001F3284 /* miniModeOffTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 83E5E54A18087CA5001F3284 /* miniModeOffTemplate.pdf */; };
83E5E54D18087CA5001F3284 /* miniModeOnTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 83E5E54B18087CA5001F3284 /* miniModeOnTemplate.pdf */; };
@ -899,6 +900,8 @@
83BC5AD820E4D0D900631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/SpotlightPanel.strings; sourceTree = "<group>"; };
83BC5ADA20E4D0E900631CD4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Feedback.strings; sourceTree = "<group>"; };
83BC5ADC20E4D0EC00631CD4 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Feedback.strings; sourceTree = "<group>"; };
83CAEB8D25EB3E8B00D6ACCC /* SandboxBroker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SandboxBroker.h; sourceTree = "<group>"; };
83CAEB9025EB3EE100D6ACCC /* SandboxBroker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SandboxBroker.m; sourceTree = "<group>"; };
83D0380E24A40DF2004CF90F /* CogAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = CogAssets.xcassets; sourceTree = "<group>"; };
83D3C5FC201C674D005564CB /* AdPlug.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AdPlug.xcodeproj; path = Plugins/AdPlug/AdPlug.xcodeproj; sourceTree = "<group>"; };
83E5E54A18087CA5001F3284 /* miniModeOffTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = miniModeOffTemplate.pdf; path = Images/miniModeOffTemplate.pdf; sourceTree = "<group>"; };
@ -1078,6 +1081,8 @@
17FAEBAB0F662985007C8707 /* ToolTipTextField.m */,
8355D6B4180612F300D05687 /* NSData+MD5.h */,
8355D6B5180612F300D05687 /* NSData+MD5.m */,
83CAEB8D25EB3E8B00D6ACCC /* SandboxBroker.h */,
83CAEB9025EB3EE100D6ACCC /* SandboxBroker.m */,
);
path = Utils;
sourceTree = "<group>";
@ -1735,7 +1740,7 @@
LastUpgradeCheck = 1100;
TargetAttributes = {
8D1107260486CEB800E47090 = {
DevelopmentTeam = RXH4D9SUXM;
DevelopmentTeam = 4S876G9VCD;
LastSwiftMigration = 1220;
ProvisioningStyle = Automatic;
};
@ -2242,6 +2247,7 @@
17E0D5EA0F520F02005B6FED /* MainWindow.m in Sources */,
836D28A818086386005B7299 /* MiniModeMenuTitleTransformer.m in Sources */,
17E0D5EB0F520F02005B6FED /* MiniWindow.m in Sources */,
83CAEB9125EB3EE100D6ACCC /* SandboxBroker.m in Sources */,
17E0D5EC0F520F02005B6FED /* PositionSlider.m in Sources */,
17E0D5ED0F520F02005B6FED /* TimeField.m in Sources */,
17E0D6160F520F87005B6FED /* FontSizetoLineHeightTransformer.m in Sources */,

View file

@ -17,6 +17,8 @@
#import "StatusImageTransformer.h"
#import "ToggleQueueTitleTransformer.h"
#import "SandboxBroker.h"
#import "Logging.h"
#define UNDO_STACK_LIMIT 0
@ -264,7 +266,7 @@
NSArray *entries = [playlistLoader insertURLs:acceptedURLs atIndex:row sort:YES];
[self didInsertURLs:entries origin:URLOriginInternal];
}
if ([self shuffle] != ShuffleOff) [self resetShuffleList];
return YES;
@ -347,9 +349,12 @@
DLog(@"Removing indexes: %@", indexes);
DLog(@"Current index: %i", currentEntry.index);
SandboxBroker * sandboxBroker = [SandboxBroker sharedSandboxBroker];
NSMutableIndexSet *unarrangedIndexes = [[NSMutableIndexSet alloc] init];
for (PlaylistEntry *pe in objects) {
[unarrangedIndexes addIndex:[pe index]];
[sandboxBroker removeBookmarkForURL:[pe URL]];
}
if (currentEntry.index >= 0 && [unarrangedIndexes containsIndex:currentEntry.index]) {
@ -964,6 +969,12 @@
if (shouldClear) {
[self clear:self];
}
SandboxBroker * sandboxBroker = [SandboxBroker sharedSandboxBroker];
for (NSURL * url in urls) {
[sandboxBroker addBookmarkToDictionary:url];
}
}
- (void)didInsertURLs:(NSArray *)urls origin:(URLOrigin)origin {

View file

@ -61,6 +61,7 @@
8359FF2617FEF35C0060F3ED /* ArchiveSource-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ArchiveSource-Prefix.pch"; sourceTree = "<group>"; };
8359FF6A17FEF39F0060F3ED /* File_Extractor.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = File_Extractor.xcodeproj; path = ../../Frameworks/File_Extractor/File_Extractor.xcodeproj; sourceTree = "<group>"; };
8384913518081BA000E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../../Utils/Logging.h; sourceTree = "<group>"; };
83CAEB9225EB3F7A00D6ACCC /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../../Utils/SandboxBroker.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -116,6 +117,7 @@
8359FF2017FEF35C0060F3ED /* ArchiveSource */ = {
isa = PBXGroup;
children = (
83CAEB9225EB3F7A00D6ACCC /* SandboxBroker.h */,
8384913518081BA000E7332D /* Logging.h */,
835900A017FF079C0060F3ED /* Plugin.h */,
8359009A17FEFDA80060F3ED /* ArchiveContainer.h */,

View file

@ -10,6 +10,8 @@
#import <File_Extractor/fex.h>
#import "SandboxBroker.h"
#import "Logging.h"
static NSString * path_pack_string(NSString * src)
@ -49,6 +51,11 @@ static NSString * g_make_unpack_path(NSString * archive, NSString * file, NSStri
if (![url isFileURL]) {
return [NSArray array];
}
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker beginFolderAccess:url];
fex_t * fex;
fex_err_t error = fex_open( &fex, [[url path] UTF8String] );
@ -67,6 +74,8 @@ static NSString * g_make_unpack_path(NSString * archive, NSString * file, NSStri
}
fex_close( fex );
[sandboxBroker endFolderAccess:url];
return files;
}

View file

@ -21,6 +21,7 @@
NSUInteger size;
NSURL *_url;
NSURL *fileURL;
}
@end

View file

@ -8,6 +8,8 @@
#import "ArchiveSource.h"
#import "SandboxBroker.h"
#import "Logging.h"
static NSString * path_unpack_string(NSString * src, NSRange * remainder)
@ -87,6 +89,13 @@ static BOOL g_parse_unpack_path(NSString * src, NSString ** archive, NSString **
if (![type isEqualToString:@"fex"])
return NO;
fileURL = [NSURL fileURLWithPath:archive];
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker beginFolderAccess:fileURL];
fex_err_t error;
error = fex_open( &fex, [archive UTF8String] );
@ -161,6 +170,13 @@ static BOOL g_parse_unpack_path(NSString * src, NSString ** archive, NSString **
fex_close( fex );
fex = NULL;
}
if ( fileURL ) {
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker endFolderAccess:fileURL];
}
}
- (NSURL *)url

View file

@ -8,6 +8,7 @@
#import "FileSource.h"
#import "SandboxBroker.h"
@implementation FileSource
@ -30,6 +31,11 @@
{
[self setURL:url];
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker beginFolderAccess:url];
NSString * path = [url path];
fex_type_t type;
@ -132,6 +138,11 @@
fex_close( fex );
fex = NULL;
}
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker endFolderAccess:_url];
}
- (NSURL *)url

View file

@ -52,6 +52,7 @@
17ADB4190B979AEB00257CA2 /* FileSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileSource.m; sourceTree = "<group>"; };
32DBCF630370AF2F00C91783 /* FileSource_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileSource_Prefix.pch; sourceTree = "<group>"; };
8335FF6817FF765A002D8DD2 /* File_Extractor.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = File_Extractor.xcodeproj; path = ../../Frameworks/File_Extractor/File_Extractor.xcodeproj; sourceTree = "<group>"; };
83CAEB9325EB402B00D6ACCC /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../Utils/SandboxBroker.h; sourceTree = "<group>"; };
8D5B49B6048680CD000E48DA /* FileSource.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FileSource.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
@ -102,6 +103,7 @@
08FB77AFFE84173DC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
83CAEB9325EB402B00D6ACCC /* SandboxBroker.h */,
17ADB4080B979A8A00257CA2 /* Plugin.h */,
17ADB4180B979AEB00257CA2 /* FileSource.h */,
17ADB4190B979AEB00257CA2 /* FileSource.m */,

View file

@ -12,6 +12,7 @@
17F563B40C3BDBB30019975C /* TagLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17F563A60C3BDB8F0019975C /* TagLib.framework */; };
17F563B60C3BDBB50019975C /* TagLib.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 17F563A60C3BDB8F0019975C /* TagLib.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
8384913A18081FFC00E7332D /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 8384913918081FFC00E7332D /* Logging.h */; };
83B5CB9825EB9688000B0F8B /* SandboxBroker.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B5CB9725EB9688000B0F8B /* SandboxBroker.h */; };
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; };
/* End PBXBuildFile section */
@ -57,6 +58,7 @@
17F563A00C3BDB8F0019975C /* TagLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = TagLib.xcodeproj; path = ../../Frameworks/TagLib/TagLib.xcodeproj; sourceTree = SOURCE_ROOT; };
32DBCF630370AF2F00C91783 /* TagLib_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TagLib_Prefix.pch; sourceTree = "<group>"; };
8384913918081FFC00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
83B5CB9725EB9688000B0F8B /* SandboxBroker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SandboxBroker.h; path = ../../Utils/SandboxBroker.h; sourceTree = "<group>"; };
8D5B49B6048680CD000E48DA /* TagLib.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TagLib.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
@ -107,6 +109,7 @@
08FB77AFFE84173DC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
83B5CB9725EB9688000B0F8B /* SandboxBroker.h */,
8384913918081FFC00E7332D /* Logging.h */,
07CACE890ED1AD1000C0F1E8 /* TagLibMetadataWriter.h */,
07CACE8A0ED1AD1000C0F1E8 /* TagLibMetadataWriter.m */,
@ -168,6 +171,7 @@
buildActionMask = 2147483647;
files = (
8384913A18081FFC00E7332D /* Logging.h in Headers */,
83B5CB9825EB9688000B0F8B /* SandboxBroker.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View file

@ -18,6 +18,8 @@
#import <taglib/mpeg/id3v2/id3v2tag.h>
#import <taglib/mpeg/id3v2/frames/attachedpictureframe.h>
#import "SandboxBroker.h"
@implementation TagLibMetadataReader
+ (NSDictionary *)metadataForURL:(NSURL *)url
@ -27,7 +29,13 @@
}
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
// Open sandbox access, may already be granted
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker beginFolderAccess:url];
// if ( !*TagLib::ascii_encoding ) {
// NSStringEncoding enc = [NSString defaultCStringEncoding];
// CFStringEncoding cfenc = CFStringConvertNSStringEncodingToEncoding(enc);
@ -164,7 +172,6 @@
if (nil == image) {
// Try to load image from external file
NSString *path = [[url path] stringByDeletingLastPathComponent];
// Gather list of candidate image files
@ -185,6 +192,8 @@
[dict setObject:image forKey:@"albumArt"];
}
}
[sandboxBroker endFolderAccess:url];
return dict;
}
@ -202,7 +211,7 @@
+ (NSArray *)coverNames
{
return [NSArray arrayWithObjects:@"cover", @"folder", @"album", @"front", nil];
return [NSArray arrayWithObjects:@"cover", @"folder", @"album", @"albumart", @"front", nil];
}
+ (NSArray *)fileTypes

28
Utils/SandboxBroker.h Normal file
View file

@ -0,0 +1,28 @@
//
// SandboxBroker.h
// Cog
//
// Created by Christopher Snowhill on 2/27/21.
//
#ifndef SandboxBroker_h
#define SandboxBroker_h
@interface SandboxBroker : NSObject {
NSMutableDictionary *storage;
NSError *errorState;
}
+ (id) sharedSandboxBroker;
- (id) init;
- (void) shutdown;
- (void) addBookmarkToDictionary:(NSURL *)fileUrl;
- (void) removeBookmarkForURL:(NSURL *)fileUrl;
- (void) beginFolderAccess:(NSURL *)fileUrl;
- (void) endFolderAccess:(NSURL *)fileUrl;
@end
#endif /* SandboxBroker_h */

314
Utils/SandboxBroker.m Normal file
View file

@ -0,0 +1,314 @@
//
// SandboxBroker.m
// CogAudio Framework
//
// Created by Christopher Snowhill on 2/27/21.
//
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "SandboxBroker.h"
#import "Logging.h"
static NSURL * urlWithoutFragment(NSURL * u) {
NSString * s = [u path];
NSString* lastComponent = [u lastPathComponent];
// Find that last component in the string from the end to make sure
// to get the last one
NSRange fragmentRange = [s rangeOfString:lastComponent
options:NSBackwardsSearch];
// Chop the fragment.
NSString* newURLString = [s substringToIndex:fragmentRange.location + fragmentRange.length];
return [NSURL fileURLWithPath:newURLString];
}
@interface SandboxEntry : NSObject <NSSecureCoding> {
NSInteger _pathRefCount;
NSInteger _secRefCount;
NSData *_bookmark;
NSURL *_secureUrl;
};
@property(class, readonly) BOOL supportsSecureCoding;
@property(readonly) NSData * bookmark;
@property NSURL * secureUrl;
@property NSInteger pathRefCount;
@property NSInteger secRefCount;
- (id) initWithCoder:(NSCoder *)coder;
- (void) encodeWithCoder:(NSCoder *)coder;
- (id) initWithBookmark:(NSData *)bookmark;
@end
@implementation SandboxEntry
- (id) initWithCoder:(NSCoder *)coder {
SandboxEntry * obj = [super init];
if (obj) {
obj->_pathRefCount = [coder decodeIntegerForKey:@"refCount"];
obj->_bookmark = [coder decodeObjectForKey:@"bookmark"];
obj->_secRefCount = 0;
obj->_secureUrl = nil;
}
return obj;
}
- (void) encodeWithCoder:(NSCoder *)coder {
[coder encodeInteger:_pathRefCount forKey:@"refCount"];
[coder encodeObject:_bookmark forKey:@"bookmark"];
}
- (id) initWithBookmark:(NSData *)bookmark {
SandboxEntry * obj = [super init];
if (obj) {
obj->_pathRefCount = 1;
obj->_secRefCount = 0;
obj->_secureUrl = nil;
obj->_bookmark = bookmark;
}
return obj;
}
+ (BOOL) supportsSecureCoding {
return YES;
}
- (NSInteger) pathRefCount {
return _pathRefCount;
}
- (void) setPathRefCount:(NSInteger)pathRefCount {
_pathRefCount = pathRefCount;
}
- (NSInteger) secRefCount {
return _secRefCount;
}
- (void) setSecRefCount:(NSInteger)secRefCount {
_secRefCount = secRefCount;
}
- (NSURL *) secureUrl {
return _secureUrl;
}
- (void) setSecureUrl:(NSURL *)url {
_secureUrl = url;
}
- (NSData *) bookmark {
return _bookmark;
}
@end
@implementation SandboxBroker
+ (id) sharedSandboxBroker {
static SandboxBroker *theSharedSandboxBroker = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
theSharedSandboxBroker = [[self alloc] init];
});
return theSharedSandboxBroker;
}
- (id) init {
id _self = [super init];
if (_self) {
NSData *archiveData = [[NSUserDefaults standardUserDefaults] valueForKey:@"fileBookmarks"];
if (archiveData) {
NSError * err = nil;
// It's an NSDictionary, containing SandboxEntry objects, referenced by NSURL keys
NSSet * classes = [NSSet setWithObjects:[NSDictionary class], [SandboxEntry class], [NSURL class], nil];
NSDictionary * _storage = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:archiveData error:&err];
if (err) {
ALog("bookmark archive error - %@", err);
}
if (_storage) {
storage = [_storage mutableCopy];
return _self;
}
}
storage = [[NSMutableDictionary alloc] init];
}
return _self;
}
- (void) shutdown {
NSError * err = nil;
NSArray * allKeys = [[storage allKeys] copy];
for (NSURL * folderUrl in allKeys) {
SandboxEntry * obj = [storage objectForKey:folderUrl];
if ([obj secureUrl]) {
[[obj secureUrl] stopAccessingSecurityScopedResource];
}
}
NSData * archiveData = [NSKeyedArchiver archivedDataWithRootObject:storage requiringSecureCoding:YES error:&err];
if (err) {
ALog("error archiving bookmarks - %@", err);
} else {
[[NSUserDefaults standardUserDefaults] setObject:archiveData forKey:@"fileBookmarks"];
}
}
- (void) addBookmarkToDictionary:(NSURL *)fileUrl {
__block NSURL * folderUrl = [urlWithoutFragment(fileUrl) URLByDeletingLastPathComponent];
@synchronized(self) {
__block SandboxEntry * obj = [storage objectForKey:folderUrl];
if (!obj) {
NSOpenPanel *p;
p = [NSOpenPanel openPanel];
[p setCanChooseFiles:NO];
[p setCanChooseDirectories:YES];
[p setAllowsMultipleSelection:YES];
[p setResolvesAliases:YES];
[p setDirectoryURL:folderUrl];
[p setTitle:@"Press OK to grant access to this folder"];
errorState = nil;
[p beginSheetModalForWindow:[NSApp mainWindow] completionHandler:^(NSInteger result) {
if ( result == NSModalResponseOK ) {
folderUrl = [[p URLs] objectAtIndex:0];
NSError * err = nil;
NSData * bookmark = [folderUrl bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&err];
if (!bookmark && err) {
ALog("failed to bookmark path %@ with error %@", folderUrl, err);
self->errorState = err;
[NSApp stopModal];
return;
}
obj = [[SandboxEntry alloc] initWithBookmark:bookmark];
[self->storage setObject:obj forKey:folderUrl];
[NSApp stopModal];
} else {
ALog("user rejected file access prompt");
self->errorState = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadNoPermissionError userInfo:nil];
[NSApp stopModal];
return;
}
}];
[NSApp runModalForWindow:[NSApp mainWindow]];
} else {
[obj setPathRefCount:[obj pathRefCount] + 1];
[storage setObject:obj forKey:folderUrl];
}
}
}
- (void) removeBookmarkForURL:(NSURL *)fileUrl {
NSURL * folderUrl = [urlWithoutFragment(fileUrl) URLByDeletingLastPathComponent];
@synchronized (self) {
SandboxEntry * obj = [storage objectForKey:folderUrl];
if (obj) {
NSInteger refCount = [obj pathRefCount];
if (refCount > 1) {
[obj setPathRefCount:refCount - 1];
[storage setObject:obj forKey:folderUrl];
} else {
if ([obj secureUrl]) {
[[obj secureUrl] stopAccessingSecurityScopedResource];
}
[storage removeObjectForKey:folderUrl];
}
}
}
}
- (void) beginFolderAccess:(NSURL *)fileUrl {
NSURL * folderUrl = [urlWithoutFragment(fileUrl) URLByDeletingLastPathComponent];
@synchronized (self) {
SandboxEntry * obj = [storage objectForKey:folderUrl];
if (!obj) {
errorState = nil;
[self addBookmarkToDictionary:fileUrl];
obj = [storage objectForKey:folderUrl];
if (errorState) {
ALog(@"error granting permission to folder - %@", errorState);
return;
}
}
if (obj) {
NSInteger refCount = [obj secRefCount];
if (refCount > 0) {
[obj setSecRefCount:refCount + 1];
[storage setObject:obj forKey:folderUrl];
} else {
NSError * err = nil;
BOOL isStale = NO;
NSURL * secureUrl = [NSURL URLByResolvingBookmarkData:[obj bookmark] options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&err];
if (!secureUrl && err)
{
ALog("failed to access bookmark for %@ with error %@", folderUrl, err);
return;
}
[secureUrl startAccessingSecurityScopedResource];
[obj setSecureUrl:secureUrl];
[obj setSecRefCount:1];
[storage setObject:obj forKey:folderUrl];
}
}
}
}
- (void) endFolderAccess:(NSURL *)fileUrl {
NSURL * folderUrl = [urlWithoutFragment(fileUrl) URLByDeletingLastPathComponent];
@synchronized (self) {
SandboxEntry * obj = [storage objectForKey:folderUrl];
if (obj) {
NSInteger refCount = [obj secRefCount];
if (refCount > 1) {
[obj setSecRefCount:refCount - 1];
[storage setObject:obj forKey:folderUrl];
} else {
if ([obj secureUrl]) {
[[obj secureUrl] stopAccessingSecurityScopedResource];
[obj setSecureUrl:nil];
}
[obj setSecRefCount:0];
[storage setObject:obj forKey:folderUrl];
}
}
}
}
@end