Procházet zdrojové kódy

【编辑工具】对比 - 获取文件权限

lizhe před 1 rokem
rodič
revize
8683c59b23

+ 38 - 0
PDF Office/PDF Master.xcodeproj/project.pbxproj

@@ -1911,6 +1911,15 @@
 		ADD5AE592A64DD2600C14249 /* KMPurchaseAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = ADD5AE582A64DD2600C14249 /* KMPurchaseAlertView.xib */; };
 		ADD5AE5A2A64DD2600C14249 /* KMPurchaseAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = ADD5AE582A64DD2600C14249 /* KMPurchaseAlertView.xib */; };
 		ADD5AE5B2A64DD2600C14249 /* KMPurchaseAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = ADD5AE582A64DD2600C14249 /* KMPurchaseAlertView.xib */; };
+		ADDDCE212B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDDCE1C2B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m */; };
+		ADDDCE222B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDDCE1C2B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m */; };
+		ADDDCE232B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDDCE1C2B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m */; };
+		ADDDCE242B43A32A005B4AB5 /* AppSandboxFileAccess.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDDCE1E2B43A32A005B4AB5 /* AppSandboxFileAccess.m */; };
+		ADDDCE252B43A32A005B4AB5 /* AppSandboxFileAccess.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDDCE1E2B43A32A005B4AB5 /* AppSandboxFileAccess.m */; };
+		ADDDCE262B43A32A005B4AB5 /* AppSandboxFileAccess.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDDCE1E2B43A32A005B4AB5 /* AppSandboxFileAccess.m */; };
+		ADDDCE272B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDDCE202B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m */; };
+		ADDDCE282B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDDCE202B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m */; };
+		ADDDCE292B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDDCE202B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m */; };
 		ADDEEA492AD38BDB00EF675D /* KMSignatureHelpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADDEEA482AD38BDB00EF675D /* KMSignatureHelpViewController.swift */; };
 		ADDEEA4A2AD38BDB00EF675D /* KMSignatureHelpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADDEEA482AD38BDB00EF675D /* KMSignatureHelpViewController.swift */; };
 		ADDEEA4B2AD38BDB00EF675D /* KMSignatureHelpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADDEEA482AD38BDB00EF675D /* KMSignatureHelpViewController.swift */; };
@@ -5171,6 +5180,12 @@
 		ADD272D329B9CFE20032B5D6 /* KMLightNoNetworkView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KMLightNoNetworkView.xib; sourceTree = "<group>"; };
 		ADD5AE542A64D31200C14249 /* KMPurchaseAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMPurchaseAlertView.swift; sourceTree = "<group>"; };
 		ADD5AE582A64DD2600C14249 /* KMPurchaseAlertView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KMPurchaseAlertView.xib; sourceTree = "<group>"; };
+		ADDDCE1B2B43A32A005B4AB5 /* AppSandboxFileAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppSandboxFileAccess.h; sourceTree = "<group>"; };
+		ADDDCE1C2B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppSandboxFileAccessPersist.m; sourceTree = "<group>"; };
+		ADDDCE1D2B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppSandboxFileAccessOpenSavePanelDelegate.h; sourceTree = "<group>"; };
+		ADDDCE1E2B43A32A005B4AB5 /* AppSandboxFileAccess.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppSandboxFileAccess.m; sourceTree = "<group>"; };
+		ADDDCE1F2B43A32A005B4AB5 /* AppSandboxFileAccessPersist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppSandboxFileAccessPersist.h; sourceTree = "<group>"; };
+		ADDDCE202B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppSandboxFileAccessOpenSavePanelDelegate.m; sourceTree = "<group>"; };
 		ADDEEA482AD38BDB00EF675D /* KMSignatureHelpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMSignatureHelpViewController.swift; sourceTree = "<group>"; };
 		ADDEEA592AD399BB00EF675D /* KMSignature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMSignature.swift; sourceTree = "<group>"; };
 		ADDEEA5D2AD39DC500EF675D /* KMSignatureManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMSignatureManager.swift; sourceTree = "<group>"; };
@@ -6376,6 +6391,7 @@
 		89752DA22936ECD5003FF08E /* Third Pard Library */ = {
 			isa = PBXGroup;
 			children = (
+				ADDDCE1A2B43A32A005B4AB5 /* AppSandboxFileAccess */,
 				9FC444F82AA5F7D600D7187C /* ZipArchive.framework */,
 				AD032CB62A4E6A7E00F1D745 /* Starscream.framework */,
 				9F00CF4A2A38655300AC462E /* FirebaseAnalytics */,
@@ -8508,6 +8524,19 @@
 			path = Alert;
 			sourceTree = "<group>";
 		};
+		ADDDCE1A2B43A32A005B4AB5 /* AppSandboxFileAccess */ = {
+			isa = PBXGroup;
+			children = (
+				ADDDCE1B2B43A32A005B4AB5 /* AppSandboxFileAccess.h */,
+				ADDDCE1C2B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m */,
+				ADDDCE1D2B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.h */,
+				ADDDCE1E2B43A32A005B4AB5 /* AppSandboxFileAccess.m */,
+				ADDDCE1F2B43A32A005B4AB5 /* AppSandboxFileAccessPersist.h */,
+				ADDDCE202B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m */,
+			);
+			path = AppSandboxFileAccess;
+			sourceTree = "<group>";
+		};
 		ADDF82E02B391A5C00A81A4E /* DigtalSignature */ = {
 			isa = PBXGroup;
 			children = (
@@ -13116,6 +13145,7 @@
 				BB74DA7B2AC41DE9006EDFE7 /* NSString+KMExtension.swift in Sources */,
 				ADE86ADD2B0AF4B600414DFA /* KMCompareContentSettingWindowController.swift in Sources */,
 				AD1CA4112A061CCD0070541F /* KMAnnotationScreenColorViewItem.swift in Sources */,
+				ADDDCE242B43A32A005B4AB5 /* AppSandboxFileAccess.m in Sources */,
 				BBF8A4012AE8B4E200788BAC /* KMBatchBaseParameter.swift in Sources */,
 				AD867FC129DFC39400F00440 /* KMBOTAAnnotationItem.swift in Sources */,
 				BB9EA1572B1EEAAC00EAFD9B /* KMImageModel.swift in Sources */,
@@ -13408,6 +13438,7 @@
 				9FD0D2AF2AD51BCC00DA3FF8 /* CPDFListEditAnnotationViewController.swift in Sources */,
 				ADAFDA422AE8F3C400F084BC /* KMAdvertisementTimeStampConversion.swift in Sources */,
 				9F0CB4E92986559400007028 /* KMDesignToken+PaddingBottom.swift in Sources */,
+				ADDDCE272B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m in Sources */,
 				ADD1B6E82946C02600C3FFF7 /* KMPrintChoosePageSizeMultipageView.swift in Sources */,
 				AD58F40E2B1DAAA800299EE0 /* KMPrintDefaultView.swift in Sources */,
 				9F1FE4ED29406E4700E952CA /* ThrobberView.m in Sources */,
@@ -13763,6 +13794,7 @@
 				BB147011299DC0D100784A6A /* OIDError.m in Sources */,
 				89752DEA293875FC003FF08E /* KMMainToolbarController.swift in Sources */,
 				BBA93D2D29BEBAA60044E0DD /* KMPreferenceEnum.swift in Sources */,
+				ADDDCE212B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m in Sources */,
 				BBF729A72B19627500576AC5 /* KMRemoveBackgroundOperationQueue.swift in Sources */,
 				AD0E8AB02A31B76300DBFD3C /* KMInAppPurchaseManager.swift in Sources */,
 				BB89DD7E2953F863007C3FFA /* KMWatermarkFileOutsideView.swift in Sources */,
@@ -14138,6 +14170,8 @@
 				AD0E8AB12A31B76300DBFD3C /* KMInAppPurchaseManager.swift in Sources */,
 				BB1BFF8B2AEA4725003EB179 /* KMTableHeaderCell.swift in Sources */,
 				BBB9B314299A5D6D004F3235 /* DropboxModel.m in Sources */,
+				ADDDCE222B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m in Sources */,
+				ADDDCE252B43A32A005B4AB5 /* AppSandboxFileAccess.m in Sources */,
 				BBB9B323299A5D6D004F3235 /* KMServicesCloudFile.m in Sources */,
 				ADAFDA3A2AE8EEFF00F084BC /* KMAdvertisementRequestServer.swift in Sources */,
 				BBC745EB295F067B0072C2ED /* KMCropSettingWindowController.swift in Sources */,
@@ -14712,6 +14746,7 @@
 				BB4F7E822B0C4E140077EC8C /* KMNoteFilterCollevtionViewItem.swift in Sources */,
 				BB146FEB299DC0D100784A6A /* GTLRDuration.m in Sources */,
 				BB89726E294DB67D0045787C /* KMWatermarkAdjectiveBaseView.swift in Sources */,
+				ADDDCE282B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m in Sources */,
 				BB853C9A2AF8E39D009C20C1 /* KMRemovePasswordOperationQueue.swift in Sources */,
 				89D2D2C6294972B900BFF5FE /* KMFormCellView.swift in Sources */,
 				ADAFDA432AE8F3C400F084BC /* KMAdvertisementTimeStampConversion.swift in Sources */,
@@ -15282,6 +15317,7 @@
 				BB2C6ACF28F41BA000478A33 /* CPDFListView.m in Sources */,
 				BB6013822AD38E0100A76FB2 /* CPDFTextAnnotation+PDFListView.swift in Sources */,
 				BB1331502AD78DC0008F6791 /* KMPDFMergeSizeTabelViewCell.swift in Sources */,
+				ADDDCE232B43A32A005B4AB5 /* AppSandboxFileAccessPersist.m in Sources */,
 				AD199DFA2B26A36500D56FEE /* KMPrintPosterPreviewView.swift in Sources */,
 				BB2EDF6C296ECE17003BCF58 /* KMPageEditInsertTypeItemView.swift in Sources */,
 				BBD7FE052A1323A400F96075 /* KMEditImagePropertyViewController.swift in Sources */,
@@ -15612,6 +15648,7 @@
 				ADE86AD32B04BAEA00414DFA /* KMCompareFilesView.swift in Sources */,
 				ADA9102C2A272CE2003352F0 /* KMEditPDFTextManager.swift in Sources */,
 				BB146FD4299DC0D100784A6A /* GTLRDateTime.m in Sources */,
+				ADDDCE262B43A32A005B4AB5 /* AppSandboxFileAccess.m in Sources */,
 				BB5F8A2129BB15AD00365ADB /* KMEmailSubWindowController.m in Sources */,
 				BB6CA4CE298BB0D000A13864 /* KMPreferenceWindowController.swift in Sources */,
 				BB2EDF48296E4618003BCF58 /* KMPageEditTools.swift in Sources */,
@@ -15772,6 +15809,7 @@
 				BB4F7E762B0C42160077EC8C /* KMPopupMenuObject.swift in Sources */,
 				AD85D1AF2AF09C79000F4D28 /* KMHomeQuickToolsWindowCollectionViewItem.swift in Sources */,
 				BBB7B48B2A033F6200B58A5A /* KMThumbnailView.swift in Sources */,
+				ADDDCE292B43A32A005B4AB5 /* AppSandboxFileAccessOpenSavePanelDelegate.m in Sources */,
 				BBE9D0942AF0A85C002E83CE /* KMBatchOperation.swift in Sources */,
 				9FBA0EF728FFC8A0001117AF /* KMCollectionView.swift in Sources */,
 				BB897226294B07960045787C /* KMWatermarkAdjectiveTopBarItemView.swift in Sources */,

+ 68 - 27
PDF Office/PDF Master/Class/PDFTools/Compare/View/KMCompareView.swift

@@ -456,35 +456,44 @@ extension KMCompareView {
     }
     
     func updateDocument(filePath: String, isNew: Bool = false, completion: @escaping (_ fileAttitude: KMFileAttribute?) -> Void) {
-        var pdfDocument = CPDFDocument()
-        if isNew {
-            pdfDocument = KMCompareFilesConfig.defaultConfig.fileNewAttribute.pdfDocument
-        } else {
-            pdfDocument = KMCompareFilesConfig.defaultConfig.fileOldAttribute.pdfDocument
+        let isAccessFilePath = AppSandboxFileAccess().accessFileURL(NSURL(fileURLWithPath: filePath) as URL, persistPermission: true) {
+            
         }
         
-        guard let pdfDocument = pdfDocument else {
-            completion(nil)
-            return
-        }
-        if (pdfDocument.documentURL.path == filePath) {
-            let alert = NSAlert()
-            alert.alertStyle = NSAlert.Style.critical
-            alert.messageText = NSLocalizedString("There is no difference between the two documents.", comment: "")
-            alert.runModal()
-            completion(nil)
-            return
-        } else {
-            KMBaseWindowController.checkPassword(url: NSURL(fileURLWithPath: filePath) as URL) { success, resultPassword in
-                if success {
-                    let file = KMFileAttribute()
-                    file.pdfDocument = pdfDocument
-                    file.password = resultPassword
-                    completion(file)
-                } else {
-                    completion(nil)
+        if isAccessFilePath {
+            print("有权限")
+            var pdfDocument = CPDFDocument()
+            if isNew {
+                pdfDocument = KMCompareFilesConfig.defaultConfig.fileNewAttribute.pdfDocument
+            } else {
+                pdfDocument = KMCompareFilesConfig.defaultConfig.fileOldAttribute.pdfDocument
+            }
+            
+            guard let pdfDocument = pdfDocument else {
+                completion(nil)
+                return
+            }
+            if (pdfDocument.documentURL.path == filePath) {
+                let alert = NSAlert()
+                alert.alertStyle = NSAlert.Style.critical
+                alert.messageText = NSLocalizedString("There is no difference between the two documents.", comment: "")
+                alert.runModal()
+                completion(nil)
+                return
+            } else {
+                KMBaseWindowController.checkPassword(url: NSURL(fileURLWithPath: filePath) as URL) { success, resultPassword in
+                    if success {
+                        let file = KMFileAttribute()
+                        file.pdfDocument = pdfDocument
+                        file.password = resultPassword
+                        completion(file)
+                    } else {
+                        completion(nil)
+                    }
                 }
             }
+        } else {
+            print("无权限")
         }
     }
     
@@ -582,7 +591,7 @@ extension KMCompareView {
     
     @IBAction func oldFilesSelectBoxAction(_ sender: Any) {
         let selectIndex = self.oldFileQKSelectedBox.indexOfSelectedItem
-        if selectIndex > 0 {
+        if selectIndex >= 0 {
             let selectItem = self.oldFileQKSelectedBox.itemObjectValue(at: selectIndex)
             self.updateDocument(filePath: selectItem as! String) { fileAttitude in
                 self.addFilePath(filePath: self.oldFilePaths[selectIndex] , isNew: false)
@@ -592,7 +601,7 @@ extension KMCompareView {
     
     @IBAction func newFilesSelectBoxAction(_ sender: Any) {
         let selectIndex = self.fileQKNewSelectedBox.indexOfSelectedItem
-        if selectIndex > 0 {
+        if selectIndex >= 0 {
             let selectItem = self.fileQKNewSelectedBox.itemObjectValue(at: selectIndex)
             self.updateDocument(filePath: selectItem as! String) { fileAttitude in
                 self.addFilePath(filePath: self.newFilePaths[selectIndex] , isNew: true)
@@ -700,6 +709,38 @@ extension KMCompareView {
                 #endif
 
                 if let filePath = openPanel.url?.path {
+                    let url = NSURL(fileURLWithPath: filePath)
+                    AppSandboxFileAccess().persistPermissionURL(url as URL)
+                    let bookmarkData = try?url.bookmarkData(options: NSURL.BookmarkCreationOptions.withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
+                    if bookmarkData != nil {
+                        AppSandboxFileAccess().bookmarkPersistanceDelegate.setBookmarkData(bookmarkData! as Data, for: url as URL)
+                        AppSandboxFileAccess().bookmarkPersistanceDelegate.setBookmarkData(bookmarkData! as Data, for: NSURL(fileURLWithPath: url.path!) as URL)
+                    }
+                    
+//                    let isAccessFilePath = AppSandboxFileAccess().accessFileURL(url as URL, persistPermission: true) {
+//                        
+//                    }
+//    
+//                    if (isAccessFilePath) {
+//                        print("获取权限成功")
+//                        let url = NSURL(fileURLWithPath: filePath)
+//                        let bookmarkData = try?url.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
+//                        if bookmarkData != nil {
+//                            AppSandboxFileAccess().bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, for: url as URL)
+//                            AppSandboxFileAccess().bookmarkPersistanceDelegate.setBookmarkData(bookmarkData, for: NSURL(fileURLWithPath: url.path!) as URL)
+//                        }
+//                    } else {
+//                        print("获取权限失败")
+//                    }
+                    
+//                    NSURL *url = [NSURL fileURLWithPath:folderPath];
+//                    [[AppSandboxFileAccess fileAccess] persistPermissionURL:url];
+//                    NSData *bookmarkData = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:NULL];
+//                    if (bookmarkData) {
+//                        [[AppSandboxFileAccess fileAccess].bookmarkPersistanceDelegate setBookmarkData:bookmarkData forURL:url];
+//                        [[AppSandboxFileAccess fileAccess].bookmarkPersistanceDelegate setBookmarkData:bookmarkData forURL:[NSURL fileURLWithPath:(url.path?:url.absoluteString)]];
+//                    }
+                    
                     self.updateDocument(filePath: filePath, isNew: isNew) { [unowned self] file in
                         self.addFilePath(filePath: filePath, isNew: isNew)
                     }

+ 3 - 3
PDF Office/PDF Master/Class/PDFTools/Print/View/Preview/KMPrintPreviewView.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22155" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
     <dependencies>
         <deployment identifier="macosx"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22155"/>
-        <plugIn identifier="com.apple.pdfkit.ibplugin" version="22155"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
+        <plugIn identifier="com.apple.pdfkit.ibplugin" version="22505"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>

+ 3 - 0
PDF Office/PDF Master/PDF_Master DMG-Bridging-Header.h

@@ -74,3 +74,6 @@
 #import "CPDFDigtalView.h"
 #import "CDSDrawView.h"
 #import "CPDFSignatureWidgetAnnotation+PDFListView.h"
+
+//文件权限
+#import "AppSandboxFileAccess.h"

+ 3 - 0
PDF Office/PDF Master/PDF_Master Pro-Bridging-Header.h

@@ -58,3 +58,6 @@
 #import "CPDFDigtalView.h"
 #import "CDSDrawView.h"
 #import "CPDFSignatureWidgetAnnotation+PDFListView.h"
+
+//文件权限
+#import "AppSandboxFileAccess.h"

+ 3 - 0
PDF Office/PDF Master/PDF_Master-Bridging-Header.h

@@ -70,3 +70,6 @@
 #import "CPDFDigtalView.h"
 #import "CDSDrawView.h"
 #import "CPDFSignatureWidgetAnnotation+PDFListView.h"
+
+//文件权限
+#import "AppSandboxFileAccess.h"

+ 196 - 0
PDF Office/PDF Master/Third Pard Library/AppSandboxFileAccess/AppSandboxFileAccess.h

@@ -0,0 +1,196 @@
+//
+//  AppSandboxFileAccess.h
+//  AppSandboxFileAccess
+//
+//  Created by Leigh McCulloch on 23/11/2013.
+//
+//  Copyright (c) 2013, Leigh McCulloch
+//  All rights reserved.
+//
+//  BSD-2-Clause License: http://opensource.org/licenses/BSD-2-Clause
+//
+//  Redistribution and use in source and binary forms, with or without
+//  modification, are permitted provided that the following conditions are
+//  met:
+//
+//  1. Redistributions of source code must retain the above copyright
+//  notice, this list of conditions and the following disclaimer.
+//
+//  2. Redistributions in binary form must reproduce the above copyright
+//  notice, this list of conditions and the following disclaimer in the
+//  documentation and/or other materials provided with the distribution.
+//
+//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+//  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+//  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+//  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+//  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <Foundation/Foundation.h>
+#import <AppKit/AppKit.h>
+//@import AppKit;
+
+#pragma mark -
+#pragma mark AppSandboxFileAccessProtocol
+
+@protocol AppSandboxFileAccessProtocol<NSObject>
+
+@required
+- (NSData *)bookmarkDataForURL:(NSURL *)url;
+- (void)setBookmarkData:(NSData *)data forURL:(NSURL *)url;
+- (void)clearBookmarkDataForURL:(NSURL *)url;
+
+@end
+
+#pragma mark -
+#pragma mark AppSandboxFileAccess
+
+typedef void (^AppSandboxFileAccessBlock)(void);
+typedef void (^AppSandboxFileSecurityScopeBlock)(NSURL *securityScopedFileURL, NSData *bookmarkData);
+
+@interface AppSandboxFileAccess : NSObject
+
+/*! @brief The title of the NSOpenPanel displayed when asking permission to access a file.
+ Default: "Allow Access"
+ */
+@property (readwrite, copy, nonatomic) NSString *title;
+/*! @brief The message contained on the the NSOpenPanel displayed when asking permission to access a file.
+ Default: "[Application Name] needs to access this path to continue. Click Allow to continue."
+ */
+@property (readwrite, copy, nonatomic) NSString *message;
+/*! @brief The prompt button on the the NSOpenPanel displayed when asking permission to access a file. 
+ Default: "Allow"
+ */
+@property (readwrite, copy, nonatomic) NSString *prompt;
+
+/*! @brief This is an optional delegate object that can be provided to customize the persistance of bookmark data (e.g. in a Core Data database).
+ Default: nil (Default uses the AppSandboxFileAccessPersist class.)
+ */
+@property (nonatomic, weak) id <AppSandboxFileAccessProtocol> bookmarkPersistanceDelegate;
+
+/*! @brief Create the object with the default values. */
++ (AppSandboxFileAccess *)fileAccess;
+
+/*! @brief Initialise the object with the default values. */
+- (instancetype)init;
+
+/*! @brief Access a file path to read or write, automatically gaining permission from the user with NSOpenPanel if required
+ and using persisted permissions if possible.
+ 
+ @see accessFile:persistPermission:withBlock:
+ @see securityScopedURLForFilePath:persistPermission:bookmark:
+ 
+ @param path A file path, either a file or folder, that the caller needs access to.
+ @param persist If YES will save the permission for future calls.
+ @param block The block that will be given access to the file or folder.
+ @return YES if permission was granted or already available, NO otherwise.
+ */
+- (BOOL)accessFilePath:(NSString *)path persistPermission:(BOOL)persist withBlock:(AppSandboxFileAccessBlock)block;
+
+/*!
+ @warning Deprecated.
+ 
+ @see accessFilePath:persistPermission:withBlock:
+ 
+ @param path A file path, either a file or folder, that the caller needs access to.
+ @param block The block that will be given access to the file or folder.
+ @param persist If YES will save the permission for future calls.
+ @return YES if permission was granted or already available, NO otherwise.
+ */
+- (BOOL)accessFilePath:(NSString *)path withBlock:(AppSandboxFileAccessBlock)block persistPermission:(BOOL)persist __attribute__((deprecated("Use 'accessFilePath:persistPermission:withBlock:' instead.")));
+
+/*! @brief Access a file URL to read or write, automatically gaining permission from the user with NSOpenPanel if required
+ and using persisted permissions if possible.
+ 
+ @see requestAccessPermissionsForFileURL:persistPermission:withBlock:
+ 
+ @discussion Internally calls `requestAccessPermissionsForFileURL:persistPermission:withBlock:` and accesses the returned scoped URL if successful.
+ 
+ @discussion See `requestAccessPermissionsForFileURL:persistPermission:withBlock:` for detailed behaviour.
+ 
+ @param fileURL A file URL, either a file or folder, that the caller needs access to.
+ @param persist If YES will save the permission for future calls.
+ @param block The block that will be given access to the file or folder.
+ @return YES if permission was granted or already available, NO otherwise.
+ */
+- (BOOL)accessFileURL:(NSURL *)fileURL persistPermission:(BOOL)persist withBlock:(AppSandboxFileAccessBlock)block;
+
+/*!
+ @warning Deprecated.
+ 
+ @see accessFileURL:persistPermission:withBlock:
+ 
+ @param fileURL A file URL, either a file or folder, that the caller needs access to.
+ @param persist If YES will save the permission for future calls.
+ @param block The block that will be given access to the file or folder.
+ @return YES if permission was granted or already available, NO otherwise.
+ */
+- (BOOL)accessFileURL:(NSURL *)fileURL withBlock:(AppSandboxFileAccessBlock)block persistPermission:(BOOL)persist __attribute__((deprecated("Use 'accessFileURL:persistPermission:withBlock:' instead.")));
+
+/*! @brief Request access permission for a file path to read or write, automatically with NSOpenPanel if required
+ and using persisted permissions if possible.
+ 
+ @see securityScopedURLForFilePath:persistPermission:bookmark:
+ 
+ @param path A file path, either a file or folder, that the caller needs access to.
+ @param persist If YES will save the permission for future calls.
+ @return YES if permission was granted or already available, NO otherwise.
+ */
+- (BOOL)requestAccessPermissionsForFilePath:(NSString *)filePath persistPermission:(BOOL)persist withBlock:(AppSandboxFileSecurityScopeBlock)block;
+
+/*! @brief Request access permission for a file path to read or write, automatically with NSOpenPanel if required
+ and using persisted permissions if possible.
+ 
+ @discussion Use this function to access a file URL to either read or write in an application restricted by the App Sandbox.
+ This function will ask the user for permission if necessary using a well formed NSOpenPanel. The user will
+ have the option of approving access to the URL you specify, or a parent path for that URL. If persist is YES
+ the permission will be stored as a bookmark in NSUserDefaults and further calls to this function will
+ load the saved permission and not ask for permission again.
+ 
+ @discussion If the file URL does not exist, it's parent directory will be asked for permission instead, since permission
+ to the directory will be required to write the file. If the parent directory doesn't exist, it will ask for
+ permission of whatever part of the parent path exists.
+ 
+ @discussion Note: If the caller has permission to access a file because it was dropped onto the application or introduced
+ to the application in some other way, this function will not be aware of that permission and still prompt
+ the user. To prevent this, use the persistPermission function to persist a permission you've been given
+ whenever a user introduces a file to the application. E.g. when dropping a file onto the application window
+ or dock or when using an NSOpenPanel.
+ 
+ @param fileURL A file URL, either a file or folder, that the caller needs access to.
+ @param persist If YES will save the permission for future calls.
+ @param block The block that will be given access to the file or folder.
+ @return YES if permission was granted or already available, NO otherwise.
+ */
+- (BOOL)requestAccessPermissionsForFileURL:(NSURL *)fileURL persistPermission:(BOOL)persist withBlock:(AppSandboxFileSecurityScopeBlock)block;
+
+/*! @brief Persist a security bookmark for the given path. The calling application must already have permission.
+ 
+ @see persistPermissionURL:
+ 
+ @param path The path with permission that will be persisted.
+ @return Bookmark data if permission was granted or already available, nil otherwise.
+ */
+- (NSData *)persistPermissionPath:(NSString *)path;
+
+/*! @brief Persist a security bookmark for the given URL. The calling application must already have permission.
+ 
+ @discussion Use this function to persist permission of a URL that has already been granted when a user introduced
+ a file to the calling application. E.g. by dropping the file onto the application window, or dock icon, 
+ or when using an NSOpenPanel.
+ 
+ Note: If the calling application does not have access to this file, this call will do nothing.
+ 
+ @param url The URL with permission that will be persisted.
+ @return Bookmark data if permission was granted or already available, nil otherwise.
+ */
+- (NSData *)persistPermissionURL:(NSURL *)url;
+
+@end

+ 243 - 0
PDF Office/PDF Master/Third Pard Library/AppSandboxFileAccess/AppSandboxFileAccess.m

@@ -0,0 +1,243 @@
+//
+//  AppSandboxFileAccess.m
+//  AppSandboxFileAccess
+//
+//  Created by Leigh McCulloch on 23/11/2013.
+//
+//  Copyright (c) 2013, Leigh McCulloch
+//  All rights reserved.
+//
+//  BSD-2-Clause License: http://opensource.org/licenses/BSD-2-Clause
+//
+//  Redistribution and use in source and binary forms, with or without
+//  modification, are permitted provided that the following conditions are
+//  met:
+//
+//  1. Redistributions of source code must retain the above copyright
+//  notice, this list of conditions and the following disclaimer.
+//
+//  2. Redistributions in binary form must reproduce the above copyright
+//  notice, this list of conditions and the following disclaimer in the
+//  documentation and/or other materials provided with the distribution.
+//
+//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+//  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+//  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+//  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+//  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "AppSandboxFileAccess.h"
+#import "AppSandboxFileAccessPersist.h"
+#import "AppSandboxFileAccessOpenSavePanelDelegate.h"
+
+#if !__has_feature(objc_arc)
+#error ARC must be enabled!
+#endif
+
+#define CFBundleDisplayName @"CFBundleDisplayName"
+#define CFBundleName        @"CFBundleName"
+
+@interface AppSandboxFileAccess ()
+@property (nonatomic, strong) AppSandboxFileAccessPersist *defaultDelegate;
+@end
+
+@implementation AppSandboxFileAccess
+
++ (AppSandboxFileAccess *)fileAccess {
+	return [[AppSandboxFileAccess alloc] init];
+}
+
+- (instancetype)init {
+	self = [super init];
+	if (self) {
+		NSString *applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:CFBundleDisplayName];
+		if (!applicationName) {
+			applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:CFBundleName];
+		}
+		
+		self.title = NSLocalizedString(@"Allow Access",nil);
+        applicationName = [applicationName stringByAppendingString:@" "];
+		self.message = [applicationName stringByAppendingString:NSLocalizedString(@"needs to access this path to continue. Click Allow to continue.", nil)];
+		self.prompt = NSLocalizedString(@"Allow",nil);
+		
+		// create default delegate object that persists bookmarks to user defaults
+		self.defaultDelegate = [[AppSandboxFileAccessPersist alloc] init];
+		self.bookmarkPersistanceDelegate = _defaultDelegate;
+	}
+	return self;
+}
+
+- (NSURL *)askPermissionForURL:(NSURL *)url {
+	NSParameterAssert(url);
+	
+	// this url will be the url allowed, it might be a parent url of the url passed in
+	__block NSURL *allowedURL = nil;
+	
+	// create delegate that will limit which files in the open panel can be selected, to ensure only a folder
+	// or file giving permission to the file requested can be selected
+	AppSandboxFileAccessOpenSavePanelDelegate *openPanelDelegate = [[AppSandboxFileAccessOpenSavePanelDelegate alloc] initWithFileURL:url];
+	
+	// check that the url exists, if it doesn't, find the parent path of the url that does exist and ask permission for that
+	NSFileManager *fileManager = [NSFileManager defaultManager];
+	NSString *path = [url path];
+	while (path.length > 1) { // give up when only '/' is left in the path or if we get to a path that exists
+		if ([fileManager fileExistsAtPath:path isDirectory:NULL]) {
+			break;
+		}
+		path = [path stringByDeletingLastPathComponent];
+	}
+	url = [NSURL fileURLWithPath:path];
+	
+	// display the open panel
+	dispatch_block_t displayOpenPanelBlock = ^{
+        
+		NSOpenPanel *openPanel = [NSOpenPanel openPanel];
+		[openPanel setMessage:self.message];
+		[openPanel setCanCreateDirectories:NO];
+		[openPanel setCanChooseFiles:YES];
+		[openPanel setCanChooseDirectories:YES];
+		[openPanel setAllowsMultipleSelection:NO];
+		[openPanel setPrompt:self.prompt];
+		[openPanel setTitle:self.title];
+		[openPanel setShowsHiddenFiles:NO];
+		[openPanel setExtensionHidden:NO];
+        [openPanel setDirectoryURL:url];
+		[openPanel setDelegate:openPanelDelegate];
+		[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
+		NSInteger openPanelButtonPressed = [openPanel runModal];
+		if (openPanelButtonPressed == NSFileHandlingPanelOKButton) {
+            allowedURL = [openPanel URL];
+		}
+	};
+	if ([NSThread isMainThread]) {
+		displayOpenPanelBlock();
+	} else {
+		dispatch_sync(dispatch_get_main_queue(), displayOpenPanelBlock);
+	}
+
+	return allowedURL;
+}
+
+- (NSData *)persistPermissionPath:(NSString *)path {
+	NSParameterAssert(path);
+	
+	return [self persistPermissionURL:[NSURL fileURLWithPath:path]];
+}
+
+- (NSData *)persistPermissionURL:(NSURL *)url {
+    
+    
+	NSParameterAssert(url);
+	
+	// store the sandbox permissions
+	NSData *bookmarkData = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:NULL];
+	if (bookmarkData) {
+		[self.bookmarkPersistanceDelegate setBookmarkData:bookmarkData forURL:url];
+	}
+	return bookmarkData;
+}
+
+- (BOOL)accessFilePath:(NSString *)path withBlock:(AppSandboxFileAccessBlock)block persistPermission:(BOOL)persist {
+	// Deprecated. Use 'accessFilePath:persistPermission:withBlock:' instead.
+	return [self accessFilePath:path persistPermission:persist withBlock:block];
+}
+
+- (BOOL)accessFileURL:(NSURL *)fileURL withBlock:(AppSandboxFileAccessBlock)block persistPermission:(BOOL)persist {
+	// Deprecated. Use 'accessFileURL:persistPermission:withBlock:' instead.
+	return [self accessFileURL:fileURL persistPermission:persist withBlock:block];
+}
+
+- (BOOL)accessFilePath:(NSString *)path persistPermission:(BOOL)persist withBlock:(AppSandboxFileAccessBlock)block {
+	return [self accessFileURL:[NSURL fileURLWithPath:path] persistPermission:persist withBlock:block];
+}
+
+- (BOOL)accessFileURL:(NSURL *)fileURL persistPermission:(BOOL)persist withBlock:(AppSandboxFileAccessBlock)block {
+	NSParameterAssert(fileURL);
+	NSParameterAssert(block);
+	
+	BOOL success = [self requestAccessPermissionsForFileURL:fileURL persistPermission:persist withBlock:^(NSURL *securityScopedFileURL, NSData *bookmarkData) {
+		// execute the block with the file access permissions
+		@try {
+			[securityScopedFileURL startAccessingSecurityScopedResource];
+			block();
+		} @finally {
+			//[securityScopedFileURL stopAccessingSecurityScopedResource];
+		}
+	}];
+	
+	return success;
+}
+
+- (BOOL)requestAccessPermissionsForFilePath:(NSString *)filePath persistPermission:(BOOL)persist withBlock:(AppSandboxFileSecurityScopeBlock)block {
+	NSParameterAssert(filePath);
+	
+	NSURL *fileURL = [NSURL fileURLWithPath:filePath];
+	return [self requestAccessPermissionsForFileURL:fileURL persistPermission:persist withBlock:block];
+}
+
+- (BOOL)requestAccessPermissionsForFileURL:(NSURL *)fileURL persistPermission:(BOOL)persist withBlock:(AppSandboxFileSecurityScopeBlock)block {
+	NSParameterAssert(fileURL);
+	
+	NSURL *allowedURL = nil;
+	
+	// standardize the file url and remove any symlinks so that the url we lookup in bookmark data would match a url given by the askPermissionForURL method
+	fileURL = [[fileURL URLByStandardizingPath] URLByResolvingSymlinksInPath];
+	
+	// lookup bookmark data for this url, this will automatically load bookmark data for a parent path if we have it
+	NSData *bookmarkData = [self.bookmarkPersistanceDelegate bookmarkDataForURL:fileURL];
+	if (bookmarkData) {
+		// resolve the bookmark data into an NSURL object that will allow us to use the file
+		BOOL bookmarkDataIsStale;
+		allowedURL = [NSURL URLByResolvingBookmarkData:bookmarkData options:NSURLBookmarkResolutionWithSecurityScope|NSURLBookmarkResolutionWithoutUI relativeToURL:nil bookmarkDataIsStale:&bookmarkDataIsStale error:NULL];
+		// if the bookmark data is stale we'll attempt to recreate it with the existing url object if possible (not guaranteed)
+		if (bookmarkDataIsStale) {
+			bookmarkData = nil;
+			[self.bookmarkPersistanceDelegate clearBookmarkDataForURL:fileURL];
+			if (allowedURL) {
+				bookmarkData = [self persistPermissionURL:allowedURL];
+				if (!bookmarkData) {
+					allowedURL = nil;
+				}
+			}
+		}
+	}
+	
+	// if allowed url is nil, we need to ask the user for permission
+	if (!allowedURL) {
+		allowedURL = [self askPermissionForURL:fileURL];
+		if (!allowedURL) {
+			// if the user did not give permission, exit out here
+			return NO;
+		}
+	}
+	
+	// if we have no bookmark data and we want to persist, we need to create it
+	if (persist && !bookmarkData) {
+		bookmarkData = [self persistPermissionURL:allowedURL];
+	}
+	
+	if (block) {
+		block(allowedURL, bookmarkData);
+	}
+	
+	return YES;
+}
+
+- (void)setBookmarkPersistanceDelegate:(NSObject<AppSandboxFileAccessProtocol> *)bookmarkPersistanceDelegate
+{
+	// revert to default delegate object if no delegate provided
+	if (bookmarkPersistanceDelegate == nil) {
+		_bookmarkPersistanceDelegate = self.defaultDelegate;
+	} else {
+		_bookmarkPersistanceDelegate = bookmarkPersistanceDelegate;
+	}
+}
+
+@end

+ 44 - 0
PDF Office/PDF Master/Third Pard Library/AppSandboxFileAccess/AppSandboxFileAccessOpenSavePanelDelegate.h

@@ -0,0 +1,44 @@
+//
+//  AppSandboxFileAccessOpenSavePanelDelegate.h
+//  AppSandboxFileAccess
+//
+//  Created by Leigh McCulloch on 23/11/2013.
+//
+//  Copyright (c) 2013, Leigh McCulloch
+//  All rights reserved.
+//
+//  BSD-2-Clause License: http://opensource.org/licenses/BSD-2-Clause
+//
+//  Redistribution and use in source and binary forms, with or without
+//  modification, are permitted provided that the following conditions are
+//  met:
+//
+//  1. Redistributions of source code must retain the above copyright
+//  notice, this list of conditions and the following disclaimer.
+//
+//  2. Redistributions in binary form must reproduce the above copyright
+//  notice, this list of conditions and the following disclaimer in the
+//  documentation and/or other materials provided with the distribution.
+//
+//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+//  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+//  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+//  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+//  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+
+#import <Foundation/Foundation.h>
+#import <AppKit/AppKit.h>
+
+@interface AppSandboxFileAccessOpenSavePanelDelegate : NSObject <NSOpenSavePanelDelegate>
+
+- (instancetype)initWithFileURL:(NSURL *)fileURL;
+
+@end

+ 87 - 0
PDF Office/PDF Master/Third Pard Library/AppSandboxFileAccess/AppSandboxFileAccessOpenSavePanelDelegate.m

@@ -0,0 +1,87 @@
+//
+//  AppSandboxFileAccessOpenSavePanelDelegate.m
+//  AppSandboxFileAccess
+//
+//  Created by Leigh McCulloch on 23/11/2013.
+//
+//  Copyright (c) 2013, Leigh McCulloch
+//  All rights reserved.
+//
+//  BSD-2-Clause License: http://opensource.org/licenses/BSD-2-Clause
+//
+//  Redistribution and use in source and binary forms, with or without
+//  modification, are permitted provided that the following conditions are
+//  met:
+//
+//  1. Redistributions of source code must retain the above copyright
+//  notice, this list of conditions and the following disclaimer.
+//
+//  2. Redistributions in binary form must reproduce the above copyright
+//  notice, this list of conditions and the following disclaimer in the
+//  documentation and/or other materials provided with the distribution.
+//
+//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+//  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+//  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+//  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+//  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+
+#import "AppSandboxFileAccessOpenSavePanelDelegate.h"
+
+#if !__has_feature(objc_arc)
+#error ARC must be enabled!
+#endif
+
+@interface AppSandboxFileAccessOpenSavePanelDelegate ()
+
+@property (readwrite, strong, nonatomic) NSArray *pathComponents;
+
+@end
+
+@implementation AppSandboxFileAccessOpenSavePanelDelegate
+
+- (instancetype)initWithFileURL:(NSURL *)fileURL {
+	self = [super init];
+	if (self) {
+		NSParameterAssert(fileURL);
+		self.pathComponents = fileURL.pathComponents;
+	}
+	return self;
+}
+
+#pragma mark -- NSOpenSavePanelDelegate
+
+- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url {
+	NSParameterAssert(url);
+	
+	NSArray *pathComponents = self.pathComponents;
+	NSArray *otherPathComponents = url.pathComponents;
+	
+	// if the url passed in has more components, it could not be a parent path or a exact same path
+	if (otherPathComponents.count > pathComponents.count) {
+		return NO;
+	}
+	
+	// check that each path component in url, is the same as each corresponding component in self.url
+	for (NSUInteger i = 0; i < otherPathComponents.count; ++i) {
+		NSString *comp1 = otherPathComponents[i];
+		NSString *comp2 = pathComponents[i];
+		// not the same, therefore url is not a parent or exact match to self.url
+		if (![comp1 isEqualToString:comp2]) {
+			return NO;
+		}
+	}
+	
+	// there were no mismatches (or no components meaning url is root)
+	return YES;
+}
+
+@end

+ 45 - 0
PDF Office/PDF Master/Third Pard Library/AppSandboxFileAccess/AppSandboxFileAccessPersist.h

@@ -0,0 +1,45 @@
+//
+//  AppSandboxFileAccessPersist.h
+//  AppSandboxFileAccess
+//
+//  Created by Leigh McCulloch on 23/11/2013.
+//
+//  Copyright (c) 2013, Leigh McCulloch
+//  All rights reserved.
+//
+//  BSD-2-Clause License: http://opensource.org/licenses/BSD-2-Clause
+//
+//  Redistribution and use in source and binary forms, with or without
+//  modification, are permitted provided that the following conditions are
+//  met:
+//
+//  1. Redistributions of source code must retain the above copyright
+//  notice, this list of conditions and the following disclaimer.
+//
+//  2. Redistributions in binary form must reproduce the above copyright
+//  notice, this list of conditions and the following disclaimer in the
+//  documentation and/or other materials provided with the distribution.
+//
+//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+//  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+//  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+//  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+//  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import <Foundation/Foundation.h>
+#import "AppSandboxFileAccess.h"
+
+@interface AppSandboxFileAccessPersist : NSObject <AppSandboxFileAccessProtocol>
+
+- (NSData *)bookmarkDataForURL:(NSURL *)url;
+- (void)setBookmarkData:(NSData *)data forURL:(NSURL *)url;
+- (void)clearBookmarkDataForURL:(NSURL *)url;
+
+@end

+ 81 - 0
PDF Office/PDF Master/Third Pard Library/AppSandboxFileAccess/AppSandboxFileAccessPersist.m

@@ -0,0 +1,81 @@
+//
+//  AppSandboxFileAccessPersist.m
+//  AppSandboxFileAccess
+//
+//  Created by Leigh McCulloch on 23/11/2013.
+//
+//  Copyright (c) 2013, Leigh McCulloch
+//  All rights reserved.
+//
+//  BSD-2-Clause License: http://opensource.org/licenses/BSD-2-Clause
+//
+//  Redistribution and use in source and binary forms, with or without
+//  modification, are permitted provided that the following conditions are
+//  met:
+//
+//  1. Redistributions of source code must retain the above copyright
+//  notice, this list of conditions and the following disclaimer.
+//
+//  2. Redistributions in binary form must reproduce the above copyright
+//  notice, this list of conditions and the following disclaimer in the
+//  documentation and/or other materials provided with the distribution.
+//
+//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+//  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+//  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+//  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+//  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#import "AppSandboxFileAccessPersist.h"
+
+#if !__has_feature(objc_arc)
+#error ARC must be enabled!
+#endif
+
+@implementation AppSandboxFileAccessPersist
+
++ (NSString *)keyForBookmarkDataForURL:(NSURL *)url {
+	NSString *urlStr = [url absoluteString];
+	return [NSString stringWithFormat:@"bd_%1$@", urlStr];
+}
+
+- (NSData *)bookmarkDataForURL:(NSURL *)url {
+	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+	
+	// loop through the bookmarks one path at a time down the URL
+	NSURL *subURL = url;
+	while ([subURL path].length > 1) { // give up when only '/' is left in the path
+		NSString *key = [AppSandboxFileAccessPersist keyForBookmarkDataForURL:subURL];
+		NSData *bookmark = [defaults dataForKey:key];
+		if (bookmark) { // if a bookmark is found, return it
+			return bookmark;
+		}
+		subURL = [subURL URLByDeletingLastPathComponent];
+	}
+	
+	// no bookmarks for the URL, or parent to the URL were found
+	return nil;
+}
+
+- (void)setBookmarkData:(NSData *)data forURL:(NSURL *)url {
+	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+	NSString *key = [AppSandboxFileAccessPersist keyForBookmarkDataForURL:url];
+	[defaults setObject:data forKey:key];
+    [defaults synchronize];
+}
+
+- (void)clearBookmarkDataForURL:(NSURL *)url {
+	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+	NSString *key = [AppSandboxFileAccessPersist keyForBookmarkDataForURL:url];
+	[defaults removeObjectForKey:key];
+    [defaults synchronize];
+}
+
+@end