Finalize sandbox file access persistence. Add another cover art filename.
This commit is contained in:
parent
79fcd4e20a
commit
49d91d5f5f
16 changed files with 452 additions and 16 deletions
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 */,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
NSUInteger size;
|
||||
|
||||
NSURL *_url;
|
||||
NSURL *fileURL;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */,
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
28
Utils/SandboxBroker.h
Normal 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
314
Utils/SandboxBroker.m
Normal 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
|
Loading…
Reference in a new issue