├── .gitignore ├── GeneratePreviewForURL.m ├── GenerateThumbnailForURL.c ├── Info.plist ├── ScriptQL.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── ScriptQL Debug.xcscheme │ └── ScriptQL Release.xcscheme └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /GeneratePreviewForURL.m: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #import 5 | 6 | // In 10.8, and maybe 10.7, if an AppleScript document is edited but not saved manually (so saved via Versions), 7 | // inside its resource fork will contain a 'RTF ' type with the raw rich text of the script. By loading this value 8 | // if it's available we avoid having to compile the script which could launch an application (due to the way AS works). 9 | // Note, this is something I discovered on accident, so it may be gone in future OS X versions. 10 | // Also, this code is from the Carbon/Toolbox Resource Manager and is deprecated as of 10.8. 11 | // You can peek at the resource fork to see if the RTF is there by using 'xattr -l ' 12 | static NSData* RTFDataFromResourceFork(CFURLRef url) 13 | { 14 | #pragma clang diagnostic push 15 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 16 | NSData *rtfData = nil; 17 | FSRef ref; 18 | if (CFURLGetFSRef((CFURLRef)url, &ref) == true) { 19 | ResFileRefNum refNum = FSOpenResFile(&ref, fsRdPerm); 20 | if (refNum) { 21 | const ResType rtfType = 'RTF '; 22 | if (Count1Resources(rtfType) == 1) { 23 | Handle handle = Get1IndResource(rtfType, 1); 24 | if (handle != NULL) { 25 | Size handleSize = GetHandleSize(handle); 26 | if (handleSize > 0) { 27 | rtfData = [NSData dataWithBytes:*handle length:handleSize]; 28 | } 29 | DisposeHandle(handle); 30 | } 31 | } 32 | CloseResFile(refNum); 33 | } 34 | } 35 | return rtfData; 36 | #pragma clang diagnostic pop 37 | } 38 | 39 | /* ----------------------------------------------------------------------------- 40 | Generate a preview for file 41 | 42 | This function's job is to create preview for designated file 43 | ----------------------------------------------------------------------------- */ 44 | 45 | OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options) 46 | { 47 | @autoreleasepool { @try { 48 | // Try the RTF data in the resource fork 49 | NSData *rsrcRTFData = RTFDataFromResourceFork(url); 50 | if (rsrcRTFData != nil) { 51 | QLPreviewRequestSetDataRepresentation(preview, (CFDataRef)rsrcRTFData, kUTTypeRTF, NULL); 52 | } else { 53 | NSAppleScript *script = [[NSAppleScript alloc] initWithContentsOfURL:(NSURL *)url error:NULL]; 54 | if (script != nil) { 55 | // try RTF data 56 | NSAttributedString *richText = [script richTextSource]; 57 | NSData *richTextData = [richText RTFFromRange:NSMakeRange(0, [richText length]) documentAttributes:@{}]; 58 | if (richTextData != nil) { 59 | QLPreviewRequestSetDataRepresentation(preview, (CFDataRef)richTextData, kUTTypeRTF, NULL); 60 | } else { 61 | // try plain text 62 | NSData *plainTextData = [[script source] dataUsingEncoding:NSUTF8StringEncoding]; 63 | if (plainTextData != nil) { 64 | QLPreviewRequestSetDataRepresentation(preview, (CFDataRef)plainTextData, kUTTypePlainText, NULL); 65 | } 66 | } 67 | [script release]; 68 | } 69 | } 70 | } @catch (NSException *ex) {} } 71 | 72 | return noErr; 73 | } 74 | 75 | void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview) 76 | { 77 | // implement only if supported 78 | } 79 | -------------------------------------------------------------------------------- /GenerateThumbnailForURL.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* ----------------------------------------------------------------------------- 6 | Generate a thumbnail for file 7 | 8 | This function's job is to create thumbnail for designated file as fast as possible 9 | ----------------------------------------------------------------------------- */ 10 | 11 | OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) 12 | { 13 | return noErr; 14 | } 15 | 16 | void CancelThumbnailGeneration(void* thisInterface, QLThumbnailRequestRef thumbnail) 17 | { 18 | // implement only if supported 19 | } 20 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDocumentTypes 8 | 9 | 10 | CFBundleTypeRole 11 | QLGenerator 12 | LSItemContentTypes 13 | 14 | com.apple.applescript.script 15 | 16 | 17 | 18 | CFBundleExecutable 19 | ${EXECUTABLE_NAME} 20 | CFBundleIconFile 21 | 22 | CFBundleIdentifier 23 | $(PRODUCT_BUNDLE_IDENTIFIER) 24 | CFBundleInfoDictionaryVersion 25 | 6.0 26 | CFBundleName 27 | ${PRODUCT_NAME} 28 | CFBundleVersion 29 | 1.1 30 | CFPlugInDynamicRegisterFunction 31 | 32 | CFPlugInDynamicRegistration 33 | NO 34 | CFPlugInFactories 35 | 36 | 61AE8566-E57B-42A0-91C7-475ED15FB693 37 | QuickLookGeneratorPluginFactory 38 | 39 | CFPlugInTypes 40 | 41 | 5E2D9680-5022-40FA-B806-43349622E5B9 42 | 43 | 61AE8566-E57B-42A0-91C7-475ED15FB693 44 | 45 | 46 | CFPlugInUnloadFunction 47 | 48 | NSHumanReadableCopyright 49 | Copyright (c) 2007-2021 Kevin Wojniak. 50 | QLNeedsToBeRunInMainThread 51 | 52 | QLPreviewHeight 53 | 600 54 | QLPreviewWidth 55 | 800 56 | QLSupportsConcurrentRequests 57 | 58 | QLThumbnailMinimumSize 59 | 17 60 | 61 | 62 | -------------------------------------------------------------------------------- /ScriptQL.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2C05A19C06CAA52B00D84F6F /* GeneratePreviewForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C05A19B06CAA52B00D84F6F /* GeneratePreviewForURL.m */; }; 11 | 8D576312048677EA00EA77CD /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB77B6FE84183AC02AAC07 /* main.c */; settings = {ATTRIBUTES = (); }; }; 12 | A585CF1D116AD58700081411 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A585CF1C116AD58700081411 /* AppKit.framework */; }; 13 | A585CFD1116ADBE300081411 /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */; }; 14 | A5F1996F15F9A043005BDBEA /* GenerateThumbnailForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = A5F1996E15F9A043005BDBEA /* GenerateThumbnailForURL.c */; }; 15 | F28CFBFD0A3EC0AF000ABFF5 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F28CFBFC0A3EC0AF000ABFF5 /* ApplicationServices.framework */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 08FB77B6FE84183AC02AAC07 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 20 | 2C05A19B06CAA52B00D84F6F /* GeneratePreviewForURL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratePreviewForURL.m; sourceTree = ""; }; 21 | 8D576316048677EA00EA77CD /* ScriptQL.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ScriptQL.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | 8D576317048677EA00EA77CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 23 | A585CF1C116AD58700081411 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 24 | A5F1996E15F9A043005BDBEA /* GenerateThumbnailForURL.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = GenerateThumbnailForURL.c; sourceTree = ""; }; 25 | F28CFBFC0A3EC0AF000ABFF5 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = ""; }; 26 | F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLook.framework; path = /System/Library/Frameworks/QuickLook.framework; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | 8D576313048677EA00EA77CD /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | F28CFBFD0A3EC0AF000ABFF5 /* ApplicationServices.framework in Frameworks */, 35 | A585CF1D116AD58700081411 /* AppKit.framework in Frameworks */, 36 | A585CFD1116ADBE300081411 /* QuickLook.framework in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 089C166AFE841209C02AAC07 /* ScriptQL */ = { 44 | isa = PBXGroup; 45 | children = ( 46 | 08FB77AFFE84173DC02AAC07 /* Source */, 47 | 089C167CFE841241C02AAC07 /* Resources */, 48 | 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */, 49 | 19C28FB6FE9D52B211CA2CBB /* Products */, 50 | ); 51 | name = ScriptQL; 52 | sourceTree = ""; 53 | }; 54 | 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | A585CF1C116AD58700081411 /* AppKit.framework */, 58 | F28CFBFC0A3EC0AF000ABFF5 /* ApplicationServices.framework */, 59 | F28CFC020A3EC0C6000ABFF5 /* QuickLook.framework */, 60 | ); 61 | name = "External Frameworks and Libraries"; 62 | sourceTree = ""; 63 | }; 64 | 089C167CFE841241C02AAC07 /* Resources */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 8D576317048677EA00EA77CD /* Info.plist */, 68 | ); 69 | name = Resources; 70 | sourceTree = ""; 71 | }; 72 | 08FB77AFFE84173DC02AAC07 /* Source */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | A5F1996E15F9A043005BDBEA /* GenerateThumbnailForURL.c */, 76 | 2C05A19B06CAA52B00D84F6F /* GeneratePreviewForURL.m */, 77 | 08FB77B6FE84183AC02AAC07 /* main.c */, 78 | ); 79 | name = Source; 80 | sourceTree = ""; 81 | }; 82 | 19C28FB6FE9D52B211CA2CBB /* Products */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 8D576316048677EA00EA77CD /* ScriptQL.qlgenerator */, 86 | ); 87 | name = Products; 88 | sourceTree = ""; 89 | }; 90 | /* End PBXGroup section */ 91 | 92 | /* Begin PBXNativeTarget section */ 93 | 8D57630D048677EA00EA77CD /* ScriptQL */ = { 94 | isa = PBXNativeTarget; 95 | buildConfigurationList = 2CA3261E0896AD4900168862 /* Build configuration list for PBXNativeTarget "ScriptQL" */; 96 | buildPhases = ( 97 | 8D576311048677EA00EA77CD /* Sources */, 98 | 8D576313048677EA00EA77CD /* Frameworks */, 99 | ); 100 | buildRules = ( 101 | ); 102 | dependencies = ( 103 | ); 104 | name = ScriptQL; 105 | productInstallPath = /Library/QuickLook; 106 | productName = ScriptQL; 107 | productReference = 8D576316048677EA00EA77CD /* ScriptQL.qlgenerator */; 108 | productType = "com.apple.product-type.bundle"; 109 | }; 110 | /* End PBXNativeTarget section */ 111 | 112 | /* Begin PBXProject section */ 113 | 089C1669FE841209C02AAC07 /* Project object */ = { 114 | isa = PBXProject; 115 | attributes = { 116 | LastUpgradeCheck = 1240; 117 | }; 118 | buildConfigurationList = 2CA326220896AD4900168862 /* Build configuration list for PBXProject "ScriptQL" */; 119 | compatibilityVersion = "Xcode 3.1"; 120 | developmentRegion = en; 121 | hasScannedForEncodings = 1; 122 | knownRegions = ( 123 | en, 124 | Base, 125 | ); 126 | mainGroup = 089C166AFE841209C02AAC07 /* ScriptQL */; 127 | projectDirPath = ""; 128 | projectRoot = ""; 129 | targets = ( 130 | 8D57630D048677EA00EA77CD /* ScriptQL */, 131 | ); 132 | }; 133 | /* End PBXProject section */ 134 | 135 | /* Begin PBXSourcesBuildPhase section */ 136 | 8D576311048677EA00EA77CD /* Sources */ = { 137 | isa = PBXSourcesBuildPhase; 138 | buildActionMask = 2147483647; 139 | files = ( 140 | 8D576312048677EA00EA77CD /* main.c in Sources */, 141 | 2C05A19C06CAA52B00D84F6F /* GeneratePreviewForURL.m in Sources */, 142 | A5F1996F15F9A043005BDBEA /* GenerateThumbnailForURL.c in Sources */, 143 | ); 144 | runOnlyForDeploymentPostprocessing = 0; 145 | }; 146 | /* End PBXSourcesBuildPhase section */ 147 | 148 | /* Begin XCBuildConfiguration section */ 149 | 2CA3261F0896AD4900168862 /* Debug */ = { 150 | isa = XCBuildConfiguration; 151 | buildSettings = { 152 | CLANG_ENABLE_OBJC_WEAK = YES; 153 | COPY_PHASE_STRIP = NO; 154 | GCC_DYNAMIC_NO_PIC = NO; 155 | GCC_OPTIMIZATION_LEVEL = 0; 156 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 157 | INFOPLIST_FILE = Info.plist; 158 | INSTALL_PATH = /Library/QuickLook; 159 | PRODUCT_BUNDLE_IDENTIFIER = "com.kainjow.qlgenerator.${PRODUCT_NAME:identifier}"; 160 | PRODUCT_NAME = ScriptQL; 161 | WRAPPER_EXTENSION = qlgenerator; 162 | }; 163 | name = Debug; 164 | }; 165 | 2CA326200896AD4900168862 /* Release */ = { 166 | isa = XCBuildConfiguration; 167 | buildSettings = { 168 | CLANG_ENABLE_OBJC_WEAK = YES; 169 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 170 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 171 | INFOPLIST_FILE = Info.plist; 172 | INSTALL_PATH = /Library/QuickLook; 173 | PRODUCT_BUNDLE_IDENTIFIER = "com.kainjow.qlgenerator.${PRODUCT_NAME:identifier}"; 174 | PRODUCT_NAME = ScriptQL; 175 | WRAPPER_EXTENSION = qlgenerator; 176 | }; 177 | name = Release; 178 | }; 179 | 2CA326230896AD4900168862 /* Debug */ = { 180 | isa = XCBuildConfiguration; 181 | buildSettings = { 182 | ALWAYS_SEARCH_USER_PATHS = NO; 183 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 184 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 185 | CLANG_WARN_BOOL_CONVERSION = YES; 186 | CLANG_WARN_COMMA = YES; 187 | CLANG_WARN_CONSTANT_CONVERSION = YES; 188 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 189 | CLANG_WARN_EMPTY_BODY = YES; 190 | CLANG_WARN_ENUM_CONVERSION = YES; 191 | CLANG_WARN_INFINITE_RECURSION = YES; 192 | CLANG_WARN_INT_CONVERSION = YES; 193 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 194 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 195 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 196 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 197 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 198 | CLANG_WARN_STRICT_PROTOTYPES = YES; 199 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 200 | CLANG_WARN_UNREACHABLE_CODE = YES; 201 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 202 | ENABLE_STRICT_OBJC_MSGSEND = YES; 203 | ENABLE_TESTABILITY = YES; 204 | GCC_NO_COMMON_BLOCKS = YES; 205 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 206 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 207 | GCC_WARN_UNDECLARED_SELECTOR = YES; 208 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 209 | GCC_WARN_UNUSED_FUNCTION = YES; 210 | GCC_WARN_UNUSED_VARIABLE = YES; 211 | MACOSX_DEPLOYMENT_TARGET = 10.11; 212 | ONLY_ACTIVE_ARCH = YES; 213 | }; 214 | name = Debug; 215 | }; 216 | 2CA326240896AD4900168862 /* Release */ = { 217 | isa = XCBuildConfiguration; 218 | buildSettings = { 219 | ALWAYS_SEARCH_USER_PATHS = NO; 220 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 221 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 222 | CLANG_WARN_BOOL_CONVERSION = YES; 223 | CLANG_WARN_COMMA = YES; 224 | CLANG_WARN_CONSTANT_CONVERSION = YES; 225 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 226 | CLANG_WARN_EMPTY_BODY = YES; 227 | CLANG_WARN_ENUM_CONVERSION = YES; 228 | CLANG_WARN_INFINITE_RECURSION = YES; 229 | CLANG_WARN_INT_CONVERSION = YES; 230 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 231 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 232 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 233 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 234 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 235 | CLANG_WARN_STRICT_PROTOTYPES = YES; 236 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 237 | CLANG_WARN_UNREACHABLE_CODE = YES; 238 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 239 | ENABLE_STRICT_OBJC_MSGSEND = YES; 240 | GCC_NO_COMMON_BLOCKS = YES; 241 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 242 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 243 | GCC_WARN_UNDECLARED_SELECTOR = YES; 244 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 245 | GCC_WARN_UNUSED_FUNCTION = YES; 246 | GCC_WARN_UNUSED_VARIABLE = YES; 247 | MACOSX_DEPLOYMENT_TARGET = 10.11; 248 | }; 249 | name = Release; 250 | }; 251 | /* End XCBuildConfiguration section */ 252 | 253 | /* Begin XCConfigurationList section */ 254 | 2CA3261E0896AD4900168862 /* Build configuration list for PBXNativeTarget "ScriptQL" */ = { 255 | isa = XCConfigurationList; 256 | buildConfigurations = ( 257 | 2CA3261F0896AD4900168862 /* Debug */, 258 | 2CA326200896AD4900168862 /* Release */, 259 | ); 260 | defaultConfigurationIsVisible = 0; 261 | defaultConfigurationName = Release; 262 | }; 263 | 2CA326220896AD4900168862 /* Build configuration list for PBXProject "ScriptQL" */ = { 264 | isa = XCConfigurationList; 265 | buildConfigurations = ( 266 | 2CA326230896AD4900168862 /* Debug */, 267 | 2CA326240896AD4900168862 /* Release */, 268 | ); 269 | defaultConfigurationIsVisible = 0; 270 | defaultConfigurationName = Release; 271 | }; 272 | /* End XCConfigurationList section */ 273 | }; 274 | rootObject = 089C1669FE841209C02AAC07 /* Project object */; 275 | } 276 | -------------------------------------------------------------------------------- /ScriptQL.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ScriptQL.xcodeproj/xcshareddata/xcschemes/ScriptQL Debug.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /ScriptQL.xcodeproj/xcshareddata/xcschemes/ScriptQL Release.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // 3 | // DO NO MODIFY THE CONTENT OF THIS FILE 4 | // 5 | // This file contains the generic CFPlug-in code necessary for your generator 6 | // To complete your generator implement the function in GenerateThumbnailForURL/GeneratePreviewForURL.c 7 | // 8 | //============================================================================== 9 | 10 | 11 | 12 | 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | // ----------------------------------------------------------------------------- 21 | // constants 22 | // ----------------------------------------------------------------------------- 23 | 24 | // Don't modify this line 25 | #define PLUGIN_ID "61AE8566-E57B-42A0-91C7-475ED15FB693" 26 | 27 | // 28 | // Below is the generic glue code for all plug-ins. 29 | // 30 | // You should not have to modify this code aside from changing 31 | // names if you decide to change the names defined in the Info.plist 32 | // 33 | 34 | 35 | // ----------------------------------------------------------------------------- 36 | // typedefs 37 | // ----------------------------------------------------------------------------- 38 | 39 | // The thumbnail generation function to be implemented in GenerateThumbnailForURL.c 40 | OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize); 41 | void CancelThumbnailGeneration(void* thisInterface, QLThumbnailRequestRef thumbnail); 42 | 43 | // The preview generation function to be implemented in GeneratePreviewForURL.c 44 | OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options); 45 | void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview); 46 | 47 | // The layout for an instance of QuickLookGeneratorPlugIn 48 | typedef struct __QuickLookGeneratorPluginType 49 | { 50 | void *conduitInterface; 51 | CFUUIDRef factoryID; 52 | UInt32 refCount; 53 | } QuickLookGeneratorPluginType; 54 | 55 | // ----------------------------------------------------------------------------- 56 | // prototypes 57 | // ----------------------------------------------------------------------------- 58 | // Forward declaration for the IUnknown implementation. 59 | // 60 | 61 | QuickLookGeneratorPluginType *AllocQuickLookGeneratorPluginType(CFUUIDRef inFactoryID); 62 | void DeallocQuickLookGeneratorPluginType(QuickLookGeneratorPluginType *thisInstance); 63 | HRESULT QuickLookGeneratorQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv); 64 | void *QuickLookGeneratorPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID); 65 | ULONG QuickLookGeneratorPluginAddRef(void *thisInstance); 66 | ULONG QuickLookGeneratorPluginRelease(void *thisInstance); 67 | 68 | // ----------------------------------------------------------------------------- 69 | // myInterfaceFtbl definition 70 | // ----------------------------------------------------------------------------- 71 | // The QLGeneratorInterfaceStruct function table. 72 | // 73 | static QLGeneratorInterfaceStruct myInterfaceFtbl = { 74 | NULL, 75 | QuickLookGeneratorQueryInterface, 76 | QuickLookGeneratorPluginAddRef, 77 | QuickLookGeneratorPluginRelease, 78 | NULL, 79 | NULL, 80 | NULL, 81 | NULL 82 | }; 83 | 84 | 85 | // ----------------------------------------------------------------------------- 86 | // AllocQuickLookGeneratorPluginType 87 | // ----------------------------------------------------------------------------- 88 | // Utility function that allocates a new instance. 89 | // You can do some initial setup for the generator here if you wish 90 | // like allocating globals etc... 91 | // 92 | QuickLookGeneratorPluginType *AllocQuickLookGeneratorPluginType(CFUUIDRef inFactoryID) 93 | { 94 | QuickLookGeneratorPluginType *theNewInstance; 95 | 96 | theNewInstance = (QuickLookGeneratorPluginType *)malloc(sizeof(QuickLookGeneratorPluginType)); 97 | memset(theNewInstance,0,sizeof(QuickLookGeneratorPluginType)); 98 | 99 | /* Point to the function table Malloc enough to store the stuff and copy the filler from myInterfaceFtbl over */ 100 | theNewInstance->conduitInterface = malloc(sizeof(QLGeneratorInterfaceStruct)); 101 | memcpy(theNewInstance->conduitInterface,&myInterfaceFtbl,sizeof(QLGeneratorInterfaceStruct)); 102 | 103 | /* Retain and keep an open instance refcount for each factory. */ 104 | theNewInstance->factoryID = CFRetain(inFactoryID); 105 | CFPlugInAddInstanceForFactory(inFactoryID); 106 | 107 | /* This function returns the IUnknown interface so set the refCount to one. */ 108 | theNewInstance->refCount = 1; 109 | return theNewInstance; 110 | } 111 | 112 | // ----------------------------------------------------------------------------- 113 | // DeallocQuickLookGeneratorPluginType 114 | // ----------------------------------------------------------------------------- 115 | // Utility function that deallocates the instance when 116 | // the refCount goes to zero. 117 | // In the current implementation generator interfaces are never deallocated 118 | // but implement this as this might change in the future 119 | // 120 | void DeallocQuickLookGeneratorPluginType(QuickLookGeneratorPluginType *thisInstance) 121 | { 122 | CFUUIDRef theFactoryID; 123 | 124 | theFactoryID = thisInstance->factoryID; 125 | /* Free the conduitInterface table up */ 126 | free(thisInstance->conduitInterface); 127 | 128 | /* Free the instance structure */ 129 | free(thisInstance); 130 | if (theFactoryID){ 131 | CFPlugInRemoveInstanceForFactory(theFactoryID); 132 | CFRelease(theFactoryID); 133 | } 134 | } 135 | 136 | // ----------------------------------------------------------------------------- 137 | // QuickLookGeneratorQueryInterface 138 | // ----------------------------------------------------------------------------- 139 | // Implementation of the IUnknown QueryInterface function. 140 | // 141 | HRESULT QuickLookGeneratorQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv) 142 | { 143 | CFUUIDRef interfaceID; 144 | 145 | interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault,iid); 146 | 147 | if (CFEqual(interfaceID,kQLGeneratorCallbacksInterfaceID)){ 148 | /* If the Right interface was requested, bump the ref count, 149 | * set the ppv parameter equal to the instance, and 150 | * return good status. 151 | */ 152 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GenerateThumbnailForURL = GenerateThumbnailForURL; 153 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->CancelThumbnailGeneration = CancelThumbnailGeneration; 154 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GeneratePreviewForURL = GeneratePreviewForURL; 155 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->CancelPreviewGeneration = CancelPreviewGeneration; 156 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType*)thisInstance)->conduitInterface)->AddRef(thisInstance); 157 | *ppv = thisInstance; 158 | CFRelease(interfaceID); 159 | return S_OK; 160 | }else{ 161 | /* Requested interface unknown, bail with error. */ 162 | *ppv = NULL; 163 | CFRelease(interfaceID); 164 | return E_NOINTERFACE; 165 | } 166 | } 167 | 168 | // ----------------------------------------------------------------------------- 169 | // QuickLookGeneratorPluginAddRef 170 | // ----------------------------------------------------------------------------- 171 | // Implementation of reference counting for this type. Whenever an interface 172 | // is requested, bump the refCount for the instance. NOTE: returning the 173 | // refcount is a convention but is not required so don't rely on it. 174 | // 175 | ULONG QuickLookGeneratorPluginAddRef(void *thisInstance) 176 | { 177 | ((QuickLookGeneratorPluginType *)thisInstance )->refCount += 1; 178 | return ((QuickLookGeneratorPluginType*) thisInstance)->refCount; 179 | } 180 | 181 | // ----------------------------------------------------------------------------- 182 | // QuickLookGeneratorPluginRelease 183 | // ----------------------------------------------------------------------------- 184 | // When an interface is released, decrement the refCount. 185 | // If the refCount goes to zero, deallocate the instance. 186 | // 187 | ULONG QuickLookGeneratorPluginRelease(void *thisInstance) 188 | { 189 | ((QuickLookGeneratorPluginType*)thisInstance)->refCount -= 1; 190 | if (((QuickLookGeneratorPluginType*)thisInstance)->refCount == 0){ 191 | DeallocQuickLookGeneratorPluginType((QuickLookGeneratorPluginType*)thisInstance ); 192 | return 0; 193 | }else{ 194 | return ((QuickLookGeneratorPluginType*) thisInstance )->refCount; 195 | } 196 | } 197 | 198 | // ----------------------------------------------------------------------------- 199 | // QuickLookGeneratorPluginFactory 200 | // ----------------------------------------------------------------------------- 201 | void *QuickLookGeneratorPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID) 202 | { 203 | QuickLookGeneratorPluginType *result; 204 | CFUUIDRef uuid; 205 | 206 | /* If correct type is being requested, allocate an 207 | * instance of kQLGeneratorTypeID and return the IUnknown interface. 208 | */ 209 | if (CFEqual(typeID,kQLGeneratorTypeID)){ 210 | uuid = CFUUIDCreateFromString(kCFAllocatorDefault,CFSTR(PLUGIN_ID)); 211 | result = AllocQuickLookGeneratorPluginType(uuid); 212 | CFRelease(uuid); 213 | return result; 214 | } 215 | /* If the requested type is incorrect, return NULL. */ 216 | return NULL; 217 | } 218 | 219 | --------------------------------------------------------------------------------