diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..28bf1b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,60 @@ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xcuserstate + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +Pods/ + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md + +fastlane/report.xml +fastlane/screenshots + +#Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..2356308 --- /dev/null +++ b/Info.plist @@ -0,0 +1,63 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDocumentTypes + + + CFBundleTypeName + Adobe XD Project + LSHandlerRank + Default + CFBundleTypeRole + QLGenerator + LSItemContentTypes + + com.adobe.xd.project + + + + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundleVersion + 1.0 + CFPlugInDynamicRegisterFunction + + CFPlugInDynamicRegistration + NO + CFPlugInFactories + + ${PRODUCT_BUNDLE_IDENTIFIER} + QuickLookGeneratorPluginFactory + + CFPlugInTypes + + 5E2D9680-5022-40FA-B806-43349622E5B9 + + ${PRODUCT_BUNDLE_IDENTIFIER} + + + CFPlugInUnloadFunction + + QLNeedsToBeRunInMainThread + + QLPreviewHeight + 800 + QLPreviewWidth + 600 + QLSupportsConcurrentRequests + + QLThumbnailMinimumSize + 17 + + diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..c6ddb9c --- /dev/null +++ b/Podfile @@ -0,0 +1,11 @@ +# Uncomment the next line to define a global platform for your project +platform :macos, '10.15' + +target 'QuickLookXD' do + # Comment the next line if you don't want to use dynamic frameworks + use_frameworks! + + # Pods for QuickLookXD + pod 'SSZipArchive', '~> 2.5.0' + +end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..82f3899 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,16 @@ +PODS: + - SSZipArchive (2.5.4) + +DEPENDENCIES: + - SSZipArchive (~> 2.5.0) + +SPEC REPOS: + trunk: + - SSZipArchive + +SPEC CHECKSUMS: + SSZipArchive: 285b618a158ebc421039c22db5b77d345c7c03db + +PODFILE CHECKSUM: 3dd765180780ef3cfaca81d033308cbde625cb20 + +COCOAPODS: 1.12.1 diff --git a/QuickLookXD.xcodeproj/project.pbxproj b/QuickLookXD.xcodeproj/project.pbxproj new file mode 100644 index 0000000..39b86bb --- /dev/null +++ b/QuickLookXD.xcodeproj/project.pbxproj @@ -0,0 +1,503 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 53; + objects = { + +/* Begin PBXBuildFile section */ + 14677FF62A56BEB000DAB587 /* GenerateThumbnailForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 14677FD72A56B97700DAB587 /* GenerateThumbnailForURL.m */; }; + 14677FF72A56BEB100DAB587 /* GeneratePreviewForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 14677FD32A56B3D000DAB587 /* GeneratePreviewForURL.m */; }; + 14677FFE2A56C24800DAB587 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 14677FFD2A56C24800DAB587 /* main.c */; }; + 146780002A56D26900DAB587 /* Document.m in Sources */ = {isa = PBXBuildFile; fileRef = 14677FFF2A56D26900DAB587 /* Document.m */; }; + 1497C49D2A55C6CE004C4C03 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E452A5529B2001221C8 /* Cocoa.framework */; }; + 1497C49E2A55C6CE004C4C03 /* Cocoa.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E452A5529B2001221C8 /* Cocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 1497C4A02A55C6CF004C4C03 /* Pods_QuickLookXD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AD71E06BE3F3F49B5B83F4D /* Pods_QuickLookXD.framework */; }; + 1497C4A12A55C6CF004C4C03 /* Pods_QuickLookXD.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1AD71E06BE3F3F49B5B83F4D /* Pods_QuickLookXD.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 1497C4A22A55C6D0004C4C03 /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */; }; + 1497C4A32A55C6D0004C4C03 /* QuickLook.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 1497C4A42A55C6D1004C4C03 /* QuickLookThumbnailing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E302A552562001221C8 /* QuickLookThumbnailing.framework */; }; + 1497C4A52A55C6D1004C4C03 /* QuickLookThumbnailing.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E302A552562001221C8 /* QuickLookThumbnailing.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 1497C4A62A55C6D2004C4C03 /* QuickLookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E322A552579001221C8 /* QuickLookUI.framework */; }; + 1497C4A72A55C6D2004C4C03 /* QuickLookUI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 14CD3E322A552579001221C8 /* QuickLookUI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 1497C4A82A55C6D3004C4C03 /* SSZipArchive.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 149F81532A5532B4003078F1 /* SSZipArchive.framework */; }; + 1497C4A92A55C6D3004C4C03 /* SSZipArchive.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 149F81532A5532B4003078F1 /* SSZipArchive.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 14F06C002A572C1C007D7E47 /* docs in Resources */ = {isa = PBXBuildFile; fileRef = 14F06BFF2A572C1C007D7E47 /* docs */; }; + 440BBDE80B0537AC0075B7E5 /* QuickLookXD.qlgenerator in Copy Files */ = {isa = PBXBuildFile; fileRef = 8D576316048677EA00EA77CD /* QuickLookXD.qlgenerator */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 1497C49F2A55C6CE004C4C03 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ./Frameworks; + dstSubfolderSpec = 6; + files = ( + 1497C49E2A55C6CE004C4C03 /* Cocoa.framework in Embed Frameworks */, + 1497C4A92A55C6D3004C4C03 /* SSZipArchive.framework in Embed Frameworks */, + 1497C4A72A55C6D2004C4C03 /* QuickLookUI.framework in Embed Frameworks */, + 1497C4A12A55C6CF004C4C03 /* Pods_QuickLookXD.framework in Embed Frameworks */, + 1497C4A32A55C6D0004C4C03 /* QuickLook.framework in Embed Frameworks */, + 1497C4A52A55C6D1004C4C03 /* QuickLookThumbnailing.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + 440BBDFA0B0537B10075B7E5 /* Copy Files */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "${HOME}/Library/QuickLook"; + dstSubfolderSpec = 0; + files = ( + 440BBDE80B0537AC0075B7E5 /* QuickLookXD.qlgenerator in Copy Files */, + ); + name = "Copy Files"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 14677FD32A56B3D000DAB587 /* GeneratePreviewForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = GeneratePreviewForURL.m; path = src/GeneratePreviewForURL.m; sourceTree = ""; }; + 14677FD72A56B97700DAB587 /* GenerateThumbnailForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = GenerateThumbnailForURL.m; path = src/GenerateThumbnailForURL.m; sourceTree = ""; }; + 14677FFD2A56C24800DAB587 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = ""; }; + 14677FFF2A56D26900DAB587 /* Document.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Document.m; path = src/Document.m; sourceTree = ""; }; + 146780012A56DACF00DAB587 /* Document.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Document.h; path = src/Document.h; sourceTree = ""; }; + 1497C49C2A55C356004C4C03 /* Pods_QuickLookXD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pods_QuickLookXD.framework; path = "/Users/Emmanuel/Library/Developer/Xcode/DerivedData/QuickLookXD-anldcwhcionfhrehdwpudqytenml/Build/Products/Debug/Pods_QuickLookXD.framework"; sourceTree = ""; }; + 149F81532A5532B4003078F1 /* SSZipArchive.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = SSZipArchive.framework; path = SSZipArchive/SSZipArchive.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 149F81602A55BE6B003078F1 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = ""; }; + 14CD3E302A552562001221C8 /* QuickLookThumbnailing.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLookThumbnailing.framework; path = /System/Library/Frameworks/QuickLookThumbnailing.framework; sourceTree = ""; }; + 14CD3E322A552579001221C8 /* QuickLookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLookUI.framework; path = /System/Library/Frameworks/QuickLookUI.framework; sourceTree = ""; }; + 14CD3E452A5529B2001221C8 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 14CD3E4B2A552BFB001221C8 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = ""; }; + 14E6041629207D6600F29499 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 14F06BFF2A572C1C007D7E47 /* docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = docs; sourceTree = ""; }; + 14F06C012A572C3C007D7E47 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + 1AD71E06BE3F3F49B5B83F4D /* Pods_QuickLookXD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_QuickLookXD.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 622150340BBDD60C00126F4B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 7216DC60EEF9EF77E634BEDF /* Pods-QuickLookXD.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QuickLookXD.debug.xcconfig"; path = "Target Support Files/Pods-QuickLookXD/Pods-QuickLookXD.debug.xcconfig"; sourceTree = ""; }; + 8D576316048677EA00EA77CD /* QuickLookXD.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QuickLookXD.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; }; + B552E3B261F2B53BF191EFD1 /* Pods-QuickLookXD.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-QuickLookXD.release.xcconfig"; path = "Target Support Files/Pods-QuickLookXD/Pods-QuickLookXD.release.xcconfig"; sourceTree = ""; }; + F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLook.framework; path = /System/Library/Frameworks/QuickLook.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D576313048677EA00EA77CD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1497C4A02A55C6CF004C4C03 /* Pods_QuickLookXD.framework in Frameworks */, + 1497C4A82A55C6D3004C4C03 /* SSZipArchive.framework in Frameworks */, + 1497C49D2A55C6CE004C4C03 /* Cocoa.framework in Frameworks */, + 1497C4A42A55C6D1004C4C03 /* QuickLookThumbnailing.framework in Frameworks */, + 1497C4A62A55C6D2004C4C03 /* QuickLookUI.framework in Frameworks */, + 1497C4A22A55C6D0004C4C03 /* QuickLook.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 089C166AFE841209C02AAC07 /* QuickLookXD */ = { + isa = PBXGroup; + children = ( + 08FB77AFFE84173DC02AAC07 /* Quick Look Generator */, + 089C167CFE841241C02AAC07 /* Resources */, + 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */, + 19C28FB6FE9D52B211CA2CBB /* Products */, + C7DC56FC83F8B07BBB1A97F8 /* Pods */, + B22F00DD4297C5607BDD3806 /* Frameworks */, + ); + name = QuickLookXD; + sourceTree = ""; + }; + 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 14CD3E452A5529B2001221C8 /* Cocoa.framework */, + 149F81602A55BE6B003078F1 /* CoreServices.framework */, + 14CD3E4B2A552BFB001221C8 /* ApplicationServices.framework */, + F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */, + 14CD3E322A552579001221C8 /* QuickLookUI.framework */, + 14CD3E302A552562001221C8 /* QuickLookThumbnailing.framework */, + 1497C49C2A55C356004C4C03 /* Pods_QuickLookXD.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 14F06BFF2A572C1C007D7E47 /* docs */, + 622150340BBDD60C00126F4B /* Info.plist */, + 14F06C012A572C3C007D7E47 /* README.md */, + 8D5B49A704867FD3000E48DA /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 08FB77AFFE84173DC02AAC07 /* Quick Look Generator */ = { + isa = PBXGroup; + children = ( + 14677FFD2A56C24800DAB587 /* main.c */, + 14677FD32A56B3D000DAB587 /* GeneratePreviewForURL.m */, + 14677FD72A56B97700DAB587 /* GenerateThumbnailForURL.m */, + 14677FFF2A56D26900DAB587 /* Document.m */, + 146780012A56DACF00DAB587 /* Document.h */, + ); + name = "Quick Look Generator"; + sourceTree = ""; + }; + 19C28FB6FE9D52B211CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D576316048677EA00EA77CD /* QuickLookXD.qlgenerator */, + ); + name = Products; + sourceTree = ""; + }; + B22F00DD4297C5607BDD3806 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1AD71E06BE3F3F49B5B83F4D /* Pods_QuickLookXD.framework */, + 149F81532A5532B4003078F1 /* SSZipArchive.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + C7DC56FC83F8B07BBB1A97F8 /* Pods */ = { + isa = PBXGroup; + children = ( + 7216DC60EEF9EF77E634BEDF /* Pods-QuickLookXD.debug.xcconfig */, + B552E3B261F2B53BF191EFD1 /* Pods-QuickLookXD.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8D57630E048677EA00EA77CD /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 8D57630D048677EA00EA77CD /* QuickLookXD */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2CA3261E0896AD4900168862 /* Build configuration list for PBXNativeTarget "QuickLookXD" */; + buildPhases = ( + FF58800300124DF6D6902D34 /* [CP] Check Pods Manifest.lock */, + 8D57630E048677EA00EA77CD /* Headers */, + 8D57630F048677EA00EA77CD /* Resources */, + 8D576311048677EA00EA77CD /* Sources */, + 8D576313048677EA00EA77CD /* Frameworks */, + 8D576315048677EA00EA77CD /* Rez */, + 1497C49F2A55C6CE004C4C03 /* Embed Frameworks */, + 440BBDFA0B0537B10075B7E5 /* Copy Files */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = QuickLookXD; + productInstallPath = /Library/Spotlight; + productName = QuickLookXD; + productReference = 8D576316048677EA00EA77CD /* QuickLookXD.qlgenerator */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 089C1669FE841209C02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 1430; + LastUpgradeCheck = 1430; + TargetAttributes = { + 8D57630D048677EA00EA77CD = { + LastSwiftMigration = 1430; + }; + }; + }; + buildConfigurationList = 2CA326220896AD4900168862 /* Build configuration list for PBXProject "QuickLookXD" */; + compatibilityVersion = "Xcode 2.4"; + developmentRegion = en; + hasScannedForEncodings = 1; + knownRegions = ( + en, + Base, + ); + mainGroup = 089C166AFE841209C02AAC07 /* QuickLookXD */; + productRefGroup = 19C28FB6FE9D52B211CA2CBB /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D57630D048677EA00EA77CD /* QuickLookXD */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D57630F048677EA00EA77CD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */, + 14F06C002A572C1C007D7E47 /* docs in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 8D576315048677EA00EA77CD /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + FF58800300124DF6D6902D34 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-QuickLookXD-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D576311048677EA00EA77CD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 14677FFE2A56C24800DAB587 /* main.c in Sources */, + 146780002A56D26900DAB587 /* Document.m in Sources */, + 14677FF62A56BEB000DAB587 /* GenerateThumbnailForURL.m in Sources */, + 14677FF72A56BEB100DAB587 /* GeneratePreviewForURL.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 8D5B49A704867FD3000E48DA /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 14E6041629207D6600F29499 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 2CA3261F0896AD4900168862 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7216DC60EEF9EF77E634BEDF /* Pods-QuickLookXD.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = NO; + DEVELOPMENT_TEAM = 54HE8SFBAE; + EAGER_LINKING = YES; + FRAMEWORK_SEARCH_PATHS = ( + "${inherited}", + "${FRAMEWORK_SEARCH_PATHS_QUOTED_1}", + ); + FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"${SYSTEM_LIBRARY_DIR}/Frameworks\""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + INFOPLIST_FILE = Info.plist; + INFOPLIST_KEY_NSPrincipalClass = ""; + INSTALL_PATH = /Library/QuickLook; + LIBRARY_STYLE = Bundle; + MACOSX_BUILD_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = "${MACOSX_BUILD_TARGET}"; + PLUGIN_ID = "74565352-F5FE-4DAD-9FDE-BF4791F600F8"; + PRELINK_LIBS = SSZipArchive; + "PRELINK_LIBS[arch=*]" = SSZipArchive; + PRODUCT_BUNDLE_IDENTIFIER = com.qbrkts.quicklookxd; + PRODUCT_NAME = QuickLookXD; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + WRAPPER_EXTENSION = qlgenerator; + ZERO_LINK = YES; + }; + name = Debug; + }; + 2CA326200896AD4900168862 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B552E3B261F2B53BF191EFD1 /* Pods-QuickLookXD.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEAD_CODE_STRIPPING = NO; + DEVELOPMENT_TEAM = 54HE8SFBAE; + EAGER_LINKING = YES; + FRAMEWORK_SEARCH_PATHS = ( + "${inherited}", + "${FRAMEWORK_SEARCH_PATHS_QUOTED_1}", + ); + FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"${SYSTEM_LIBRARY_DIR}/Frameworks\""; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + INFOPLIST_FILE = Info.plist; + INFOPLIST_KEY_NSPrincipalClass = ""; + INSTALL_PATH = /Library/QuickLook; + LIBRARY_STYLE = Bundle; + MACOSX_BUILD_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = "${MACOSX_BUILD_TARGET}"; + PLUGIN_ID = "74565352-F5FE-4DAD-9FDE-BF4791F600F8"; + PRELINK_LIBS = SSZipArchive; + PRODUCT_BUNDLE_IDENTIFIER = com.qbrkts.quicklookxd; + PRODUCT_NAME = QuickLookXD; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = ""; + SWIFT_VERSION = 5.0; + WRAPPER_EXTENSION = qlgenerator; + }; + name = Release; + }; + 2CA326230896AD4900168862 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + DEAD_CODE_STRIPPING = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = "${MACOSX_BUILD_TARGET}"; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 2CA326240896AD4900168862 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD)"; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + DEAD_CODE_STRIPPING = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = "${MACOSX_BUILD_TARGET}"; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2CA3261E0896AD4900168862 /* Build configuration list for PBXNativeTarget "QuickLookXD" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2CA3261F0896AD4900168862 /* Debug */, + 2CA326200896AD4900168862 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2CA326220896AD4900168862 /* Build configuration list for PBXProject "QuickLookXD" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2CA326230896AD4900168862 /* Debug */, + 2CA326240896AD4900168862 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 089C1669FE841209C02AAC07 /* Project object */; +} diff --git a/QuickLookXD.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/QuickLookXD.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..fce45f3 --- /dev/null +++ b/QuickLookXD.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..9b59d84 --- /dev/null +++ b/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/QuickLookXD.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/QuickLookXD.xcodeproj/xcshareddata/xcschemes/QuickLookXD.xcscheme b/QuickLookXD.xcodeproj/xcshareddata/xcschemes/QuickLookXD.xcscheme new file mode 100644 index 0000000..e3556f3 --- /dev/null +++ b/QuickLookXD.xcodeproj/xcshareddata/xcschemes/QuickLookXD.xcscheme @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/QuickLookXD.xcworkspace/contents.xcworkspacedata b/QuickLookXD.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..d447b08 --- /dev/null +++ b/QuickLookXD.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/QuickLookXD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/QuickLookXD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/QuickLookXD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/QuickLookXD.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/QuickLookXD.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/QuickLookXD.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..3560d85 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# AdobeXD MacOS Quick Look Plugin + +Enables previews of XD files [(Adobe Experience Designer)][adobe-xd]. + +[QL plugin discussion][ql-win-issue]. + +Based on [QuickLookASE][ql-ase]. + +[XD format reference][xd-format-reference]. + + + +## Notes + +How to find the UTI of a file: + +```sh +$ mdls -name kMDItemContentType ./docs/example/file01.xd +kMDItemContentType = "com.adobe.xd.project" +``` + +## Demo + +![Image showing list of XD files with thumbnails and preview](./docs/example/screenshot01.png) + + + +[adobe-xd]: https://www.adobe.com/ca/products/xd.html +[xd-format-reference]: https://docs.fileformat.com/web/xd +[ql-win-issue]: https://github.com/QL-Win/QuickLook/issues/307#issuecomment-1473989813 +[ql-ase]: https://github.com/rsodre/QuickLookASE diff --git a/docs/example/file01.xd b/docs/example/file01.xd new file mode 100644 index 0000000..c6fa2b9 Binary files /dev/null and b/docs/example/file01.xd differ diff --git a/docs/example/file02.xd b/docs/example/file02.xd new file mode 100644 index 0000000..de98fc8 Binary files /dev/null and b/docs/example/file02.xd differ diff --git a/docs/example/screenshot01.png b/docs/example/screenshot01.png new file mode 100644 index 0000000..66afc9e Binary files /dev/null and b/docs/example/screenshot01.png differ diff --git a/en.lproj/InfoPlist.strings b/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..cfb1402 Binary files /dev/null and b/en.lproj/InfoPlist.strings differ diff --git a/src/Document.h b/src/Document.h new file mode 100644 index 0000000..65db982 --- /dev/null +++ b/src/Document.h @@ -0,0 +1,19 @@ +// +// Document.h +// QuickLookXD +// +// Created by Ogbizi on 2023-07-06. +// + +#ifndef Document_h +#define Document_h + + +#endif /* Document_h */ + +// Constants +#define IMAGE_PREVIEW_FILENAME @"preview.png" +#define IMAGE_THUMBNAIL_FILENAME @"thumbnail.png" + +/// Get preview or thumbnail image from adobe xd file +CGImageRef GetImageFromDocument(NSURL* docURL, NSString *imageFileName, NSString *fallbackImageFileName); diff --git a/src/Document.m b/src/Document.m new file mode 100644 index 0000000..be30f3d --- /dev/null +++ b/src/Document.m @@ -0,0 +1,47 @@ +// +// Document.m +// QuickLookXD +// +// Created by Ogbizi on 2023-07-06. +// + +#include +#include +#include "SSZipArchive.h" +#include "Document.h" + + +CGImageRef GetImageFromDocument(NSURL* docURL, NSString *imageFileName, NSString *fallbackImageFileName) { + // path to local XD file + NSString *zipPath = docURL.path; + // folder to unzip the file into + NSString *zipFileName = [docURL.pathComponents lastObject]; + // full path to unzip location in the user tmp directory + NSString *unzippedPath = [NSString stringWithFormat:@"%@/%@/", NSTemporaryDirectory(), zipFileName]; + // unzip the file and check for success + BOOL success = [SSZipArchive unzipFileAtPath:zipPath toDestination:unzippedPath]; + if (!success) { + NSLog(@"Failed to unzip the file at path: %@", zipPath); + } + + NSString *imageFilePath = [unzippedPath stringByAppendingPathComponent:imageFileName]; + BOOL imageFileExists = [[NSFileManager defaultManager] fileExistsAtPath:imageFilePath]; + + if (!imageFileExists) { + NSLog(@"No image file found at: %@", imageFilePath); + + imageFilePath = [unzippedPath stringByAppendingPathComponent:fallbackImageFileName]; + imageFileExists = [[NSFileManager defaultManager] fileExistsAtPath:imageFilePath]; + + if (!imageFileExists) { + NSLog(@"No image file found at: %@", imageFilePath); + return NULL; + } + } + + NSLog(@"Found image file at: %@", imageFilePath); + + CGDataProviderRef provider = CGDataProviderCreateWithFilename(imageFilePath.UTF8String); + CGImageRef image = CGImageCreateWithPNGDataProvider(provider, NULL, true, kCGRenderingIntentDefault); + return image; +} diff --git a/src/GeneratePreviewForURL.m b/src/GeneratePreviewForURL.m new file mode 100644 index 0000000..f041858 --- /dev/null +++ b/src/GeneratePreviewForURL.m @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include "Document.h" + + +/* ----------------------------------------------------------------------------- + Generate a preview for file + + This function's job is to create preview for designated file + ----------------------------------------------------------------------------- */ + +OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + CGImageRef image = GetImageFromDocument((NSURL *)url, IMAGE_PREVIEW_FILENAME, IMAGE_THUMBNAIL_FILENAME); + + if (!image) { + [pool release]; + NSLog(@"Exiting because no image retrieved from document."); + return noErr; + } + + CGSize imageSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image)); + + // Preview will be drawn in a vectorized context + // Here we create a graphics context to draw the Quick Look Preview in + CGContextRef cgContext = QLPreviewRequestCreateContext(preview, imageSize, false, NULL); + if(cgContext) { + CGRect canvas = CGRectMake(0, 0, imageSize.width, imageSize.height); + CGContextDrawImage(cgContext, canvas, image); + + // When we are done with our drawing code QLPreviewRequestFlushContext() is called to flush the context + QLPreviewRequestFlushContext(preview, cgContext); + + CFRelease(cgContext); + } + + [pool release]; + return noErr; +} + +void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview) +{ + // implement only if supported +} diff --git a/src/GenerateThumbnailForURL.m b/src/GenerateThumbnailForURL.m new file mode 100644 index 0000000..07c582c --- /dev/null +++ b/src/GenerateThumbnailForURL.m @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include "Document.h" + +OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + CGImageRef image = GetImageFromDocument((NSURL *)url, IMAGE_THUMBNAIL_FILENAME, IMAGE_PREVIEW_FILENAME); + + if (!image) { + [pool release]; + NSLog(@"Exiting because no image retrieved from document."); + return noErr; + } + + CGSize imageSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image)); + CGFloat scaleFactor = MIN(maxSize.width / imageSize.width, maxSize.height / imageSize.height); + CGSize canvasSize = CGSizeMake(imageSize.width * scaleFactor, imageSize.height * scaleFactor); + + // Thumbnail will be drawn with maximum resolution for desired thumbnail request + // Here we create a graphics context to draw the Quick Look Thumbnail in. + CGContextRef cgContext = QLThumbnailRequestCreateContext(thumbnail, canvasSize, false, NULL); + if(cgContext) { + CGRect canvas = CGRectMake(0, 0, canvasSize.width, canvasSize.height); + CGContextDrawImage(cgContext, canvas, image); + + // When we are done with our drawing code QLThumbnailRequestFlushContext() is called to flush the context + QLThumbnailRequestFlushContext(thumbnail, cgContext); + + CFRelease(cgContext); + } + + [pool release]; + return noErr; +} + +void CancelThumbnailGeneration(void* thisInterface, QLThumbnailRequestRef thumbnail) +{ + // implement only if supported +} + diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..296ed7a --- /dev/null +++ b/src/main.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include + +// ----------------------------------------------------------------------------- +// constants +// ----------------------------------------------------------------------------- + +// Using plugin product identifier +#define PLUGIN_ID "com.qbrkts.quicklookxd" + +// +// Below is the generic glue code for all plug-ins. +// +// You should not have to modify this code aside from changing +// names if you decide to change the names defined in the Info.plist +// + + +// ----------------------------------------------------------------------------- +// typedefs +// ----------------------------------------------------------------------------- + +// The thumbnail generation function to be implemented in GenerateThumbnailForURL.c +OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize); +void CancelThumbnailGeneration(void* thisInterface, QLThumbnailRequestRef thumbnail); + +// The preview generation function to be implemented in GeneratePreviewForURL.c +OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options); +void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview); + +// The layout for an instance of QuickLookGeneratorPlugIn +typedef struct __QuickLookGeneratorPluginType +{ + void *conduitInterface; + CFUUIDRef factoryID; + UInt32 refCount; +} QuickLookGeneratorPluginType; + +// ----------------------------------------------------------------------------- +// prototypes +// ----------------------------------------------------------------------------- +// Forward declaration for the IUnknown implementation. +// + +QuickLookGeneratorPluginType *AllocQuickLookGeneratorPluginType(CFUUIDRef inFactoryID); +void DeallocQuickLookGeneratorPluginType(QuickLookGeneratorPluginType *thisInstance); +HRESULT QuickLookGeneratorQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv); +void *QuickLookGeneratorPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID); +ULONG QuickLookGeneratorPluginAddRef(void *thisInstance); +ULONG QuickLookGeneratorPluginRelease(void *thisInstance); + +// ----------------------------------------------------------------------------- +// myInterfaceFtbl definition +// ----------------------------------------------------------------------------- +// The QLGeneratorInterfaceStruct function table. +// +static QLGeneratorInterfaceStruct myInterfaceFtbl = { + NULL, + QuickLookGeneratorQueryInterface, + QuickLookGeneratorPluginAddRef, + QuickLookGeneratorPluginRelease, + NULL, + NULL, + NULL, + NULL +}; + + +// ----------------------------------------------------------------------------- +// AllocQuickLookGeneratorPluginType +// ----------------------------------------------------------------------------- +// Utility function that allocates a new instance. +// You can do some initial setup for the generator here if you wish +// like allocating globals etc... +// +QuickLookGeneratorPluginType *AllocQuickLookGeneratorPluginType(CFUUIDRef inFactoryID) +{ + QuickLookGeneratorPluginType *theNewInstance; + + theNewInstance = (QuickLookGeneratorPluginType *)malloc(sizeof(QuickLookGeneratorPluginType)); + memset(theNewInstance,0,sizeof(QuickLookGeneratorPluginType)); + + /* Point to the function table Malloc enough to store the stuff and copy the filler from myInterfaceFtbl over */ + theNewInstance->conduitInterface = malloc(sizeof(QLGeneratorInterfaceStruct)); + memcpy(theNewInstance->conduitInterface,&myInterfaceFtbl,sizeof(QLGeneratorInterfaceStruct)); + + /* Retain and keep an open instance refcount for each factory. */ + theNewInstance->factoryID = CFRetain(inFactoryID); + CFPlugInAddInstanceForFactory(inFactoryID); + + /* This function returns the IUnknown interface so set the refCount to one. */ + theNewInstance->refCount = 1; + return theNewInstance; +} + +// ----------------------------------------------------------------------------- +// DeallocQuickLookGeneratorPluginType +// ----------------------------------------------------------------------------- +// Utility function that deallocates the instance when +// the refCount goes to zero. +// In the current implementation generator interfaces are never deallocated +// but implement this as this might change in the future +// +void DeallocQuickLookGeneratorPluginType(QuickLookGeneratorPluginType *thisInstance) +{ + CFUUIDRef theFactoryID; + + theFactoryID = thisInstance->factoryID; + /* Free the conduitInterface table up */ + free(thisInstance->conduitInterface); + + /* Free the instance structure */ + free(thisInstance); + if (theFactoryID){ + CFPlugInRemoveInstanceForFactory(theFactoryID); + CFRelease(theFactoryID); + } +} + +// ----------------------------------------------------------------------------- +// QuickLookGeneratorQueryInterface +// ----------------------------------------------------------------------------- +// Implementation of the IUnknown QueryInterface function. +// +HRESULT QuickLookGeneratorQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv) +{ + CFUUIDRef interfaceID; + + interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault,iid); + + if (CFEqual(interfaceID,kQLGeneratorCallbacksInterfaceID)){ + /* If the Right interface was requested, bump the ref count, + * set the ppv parameter equal to the instance, and + * return good status. + */ + ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GenerateThumbnailForURL = GenerateThumbnailForURL; + ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->CancelThumbnailGeneration = CancelThumbnailGeneration; + ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GeneratePreviewForURL = GeneratePreviewForURL; + ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->CancelPreviewGeneration = CancelPreviewGeneration; + ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType*)thisInstance)->conduitInterface)->AddRef(thisInstance); + *ppv = thisInstance; + CFRelease(interfaceID); + return S_OK; + }else{ + /* Requested interface unknown, bail with error. */ + *ppv = NULL; + CFRelease(interfaceID); + return E_NOINTERFACE; + } +} + +// ----------------------------------------------------------------------------- +// QuickLookGeneratorPluginAddRef +// ----------------------------------------------------------------------------- +// Implementation of reference counting for this type. Whenever an interface +// is requested, bump the refCount for the instance. NOTE: returning the +// refcount is a convention but is not required so don't rely on it. +// +ULONG QuickLookGeneratorPluginAddRef(void *thisInstance) +{ + ((QuickLookGeneratorPluginType *)thisInstance )->refCount += 1; + return ((QuickLookGeneratorPluginType*) thisInstance)->refCount; +} + +// ----------------------------------------------------------------------------- +// QuickLookGeneratorPluginRelease +// ----------------------------------------------------------------------------- +// When an interface is released, decrement the refCount. +// If the refCount goes to zero, deallocate the instance. +// +ULONG QuickLookGeneratorPluginRelease(void *thisInstance) +{ + ((QuickLookGeneratorPluginType*)thisInstance)->refCount -= 1; + if (((QuickLookGeneratorPluginType*)thisInstance)->refCount == 0){ + DeallocQuickLookGeneratorPluginType((QuickLookGeneratorPluginType*)thisInstance ); + return 0; + }else{ + return ((QuickLookGeneratorPluginType*) thisInstance )->refCount; + } +} + +// ----------------------------------------------------------------------------- +// QuickLookGeneratorPluginFactory +// ----------------------------------------------------------------------------- +void *QuickLookGeneratorPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID) +{ + QuickLookGeneratorPluginType *result; + CFUUIDRef uuid; + + /* If correct type is being requested, allocate an + * instance of kQLGeneratorTypeID and return the IUnknown interface. + */ + if (CFEqual(typeID,kQLGeneratorTypeID)){ + uuid = CFUUIDCreateFromString(kCFAllocatorDefault,CFSTR(PLUGIN_ID)); + result = AllocQuickLookGeneratorPluginType(uuid); + CFRelease(uuid); + return result; + } + /* If the requested type is incorrect, return NULL. */ + return NULL; +}