From 4723bedc314af17aea29493af231b60c0da66e0b Mon Sep 17 00:00:00 2001 From: omigamedev Date: Thu, 4 Oct 2018 22:58:42 +0200 Subject: [PATCH] =?UTF-8?q?add=20QuickLook=20plugin=20for=20OS=20X,=20it?= =?UTF-8?q?=E2=80=99s=20embedded=20in=20the=20.app?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PanoPainter.xcodeproj/project.pbxproj | 150 ++++++++++++++++++ QLPlugin/GeneratePreviewForURL.c | 23 +++ QLPlugin/GenerateThumbnailForURL.c | 102 ++++++++++++ QLPlugin/Info.plist | 91 +++++++++++ QLPlugin/main.c | 218 ++++++++++++++++++++++++++ 5 files changed, 584 insertions(+) create mode 100644 QLPlugin/GeneratePreviewForURL.c create mode 100644 QLPlugin/GenerateThumbnailForURL.c create mode 100644 QLPlugin/Info.plist create mode 100644 QLPlugin/main.c diff --git a/PanoPainter.xcodeproj/project.pbxproj b/PanoPainter.xcodeproj/project.pbxproj index d6dd16a..c47a793 100644 --- a/PanoPainter.xcodeproj/project.pbxproj +++ b/PanoPainter.xcodeproj/project.pbxproj @@ -199,6 +199,10 @@ ADE4911F1F86E65E00FB8E92 /* sweep.cc in Sources */ = {isa = PBXBuildFile; fileRef = ADE491131F86D09100FB8E92 /* sweep.cc */; }; ADEBA9062069A4F40085AE16 /* objc_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADEBA9052069A4F40085AE16 /* objc_utils.cpp */; }; ADEBA9092069A50E0085AE16 /* objc_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADEBA9082069A50E0085AE16 /* objc_utils.cpp */; }; + ADFD32152166AA0800F46F85 /* GenerateThumbnailForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = ADFD32142166AA0800F46F85 /* GenerateThumbnailForURL.c */; }; + ADFD32172166AA0800F46F85 /* GeneratePreviewForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = ADFD32162166AA0800F46F85 /* GeneratePreviewForURL.c */; }; + ADFD32192166AA0800F46F85 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = ADFD32182166AA0800F46F85 /* main.c */; }; + ADFD32222166AB2F00F46F85 /* QLPlugin.qlgenerator in CopyFiles */ = {isa = PBXBuildFile; fileRef = ADFD32122166AA0800F46F85 /* QLPlugin.qlgenerator */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -251,6 +255,16 @@ name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; }; + ADFD32202166AA6000F46F85 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = Contents/Library/QuickLook; + dstSubfolderSpec = 1; + files = ( + ADFD32222166AB2F00F46F85 /* QLPlugin.qlgenerator in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -450,6 +464,12 @@ ADEBA9052069A4F40085AE16 /* objc_utils.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = objc_utils.cpp; path = src/objc_utils.cpp; sourceTree = SOURCE_ROOT; }; ADEBA9072069A50E0085AE16 /* objc_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = objc_utils.h; path = src/objc_utils.h; sourceTree = SOURCE_ROOT; }; ADEBA9082069A50E0085AE16 /* objc_utils.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = objc_utils.cpp; path = src/objc_utils.cpp; sourceTree = SOURCE_ROOT; }; + ADFD32122166AA0800F46F85 /* QLPlugin.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QLPlugin.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; }; + ADFD32142166AA0800F46F85 /* GenerateThumbnailForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GenerateThumbnailForURL.c; sourceTree = ""; }; + ADFD32162166AA0800F46F85 /* GeneratePreviewForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GeneratePreviewForURL.c; sourceTree = ""; }; + ADFD32182166AA0800F46F85 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; + ADFD321A2166AA0800F46F85 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + ADFD32232166B12A00F46F85 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -512,6 +532,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + ADFD320E2166AA0800F46F85 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -663,6 +690,7 @@ AD0E5C9D1ECC6F2B00C35669 /* PanoPainter-OSX */, AD787AE020D4611100C4712A /* PanoQL */, AD787AF420D4637E00C4712A /* PanoThumb */, + ADFD32132166AA0800F46F85 /* QLPlugin */, AD58E0501E107411006ACC15 /* Products */, AD759B631F2793AD00211963 /* Frameworks */, ); @@ -675,6 +703,7 @@ AD0E5C9C1ECC6F2B00C35669 /* PanoPainter.app */, AD787ADD20D4611100C4712A /* PanoQL.appex */, AD787AF320D4637E00C4712A /* PanoThumb.appex */, + ADFD32122166AA0800F46F85 /* QLPlugin.qlgenerator */, ); name = Products; sourceTree = ""; @@ -751,6 +780,7 @@ AD759B631F2793AD00211963 /* Frameworks */ = { isa = PBXGroup; children = ( + ADFD32232166B12A00F46F85 /* Foundation.framework */, AD06989820CC6C3E0010825F /* OSX */, AD06989520CC6C210010825F /* iOS */, AD3087C72061D1CD009F9260 /* CoreGraphics.framework */, @@ -837,8 +867,29 @@ name = p2t; sourceTree = ""; }; + ADFD32132166AA0800F46F85 /* QLPlugin */ = { + isa = PBXGroup; + children = ( + ADFD32142166AA0800F46F85 /* GenerateThumbnailForURL.c */, + ADFD32162166AA0800F46F85 /* GeneratePreviewForURL.c */, + ADFD32182166AA0800F46F85 /* main.c */, + ADFD321A2166AA0800F46F85 /* Info.plist */, + ); + path = QLPlugin; + sourceTree = ""; + }; /* End PBXGroup section */ +/* Begin PBXHeadersBuildPhase section */ + ADFD320F2166AA0800F46F85 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + /* Begin PBXNativeTarget section */ AD0E5C9B1ECC6F2B00C35669 /* PanoPainter-OSX */ = { isa = PBXNativeTarget; @@ -850,6 +901,7 @@ AD0E5C9A1ECC6F2B00C35669 /* Resources */, AD2286BB214E96E60074567E /* Versioning Info.plist */, AD30D8201F783B5600B6A112 /* CopyFiles */, + ADFD32202166AA6000F46F85 /* CopyFiles */, ADC8F77421665FD20084ECAD /* Hockeyapp */, ); buildRules = ( @@ -923,6 +975,24 @@ productReference = ADD7D26B1EBF9AE300D5A897 /* PanoPainter.app */; productType = "com.apple.product-type.application"; }; + ADFD32112166AA0800F46F85 /* QLPlugin */ = { + isa = PBXNativeTarget; + buildConfigurationList = ADFD321D2166AA0800F46F85 /* Build configuration list for PBXNativeTarget "QLPlugin" */; + buildPhases = ( + ADFD320D2166AA0800F46F85 /* Sources */, + ADFD320E2166AA0800F46F85 /* Frameworks */, + ADFD320F2166AA0800F46F85 /* Headers */, + ADFD32102166AA0800F46F85 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = QLPlugin; + productName = QLPlugin; + productReference = ADFD32122166AA0800F46F85 /* QLPlugin.qlgenerator */; + productType = "com.apple.product-type.bundle"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -956,6 +1026,11 @@ CreatedOnToolsVersion = 7.2; DevelopmentTeam = ERD9AYQ49S; }; + ADFD32112166AA0800F46F85 = { + CreatedOnToolsVersion = 9.4.1; + DevelopmentTeam = ERD9AYQ49S; + ProvisioningStyle = Automatic; + }; }; }; buildConfigurationList = AD58E04A1E107411006ACC15 /* Build configuration list for PBXProject "PanoPainter" */; @@ -975,6 +1050,7 @@ AD0E5C9B1ECC6F2B00C35669 /* PanoPainter-OSX */, AD787ADC20D4611100C4712A /* PanoQL */, AD787AF220D4637E00C4712A /* PanoThumb */, + ADFD32112166AA0800F46F85 /* QLPlugin */, ); }; /* End PBXProject section */ @@ -1017,6 +1093,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + ADFD32102166AA0800F46F85 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -1339,6 +1422,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + ADFD320D2166AA0800F46F85 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ADFD32152166AA0800F46F85 /* GenerateThumbnailForURL.c in Sources */, + ADFD32172166AA0800F46F85 /* GeneratePreviewForURL.c in Sources */, + ADFD32192166AA0800F46F85 /* main.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -1811,6 +1904,54 @@ }; name = Release; }; + ADFD321B2166AA0800F46F85 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ERD9AYQ49S; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = QLPlugin/Info.plist; + INSTALL_PATH = /Library/QuickLook; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_BUNDLE_IDENTIFIER = com.omixlab.panopainter.osx.QLPlugin; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = qlgenerator; + }; + name = Debug; + }; + ADFD321C2166AA0800F46F85 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ERD9AYQ49S; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = QLPlugin/Info.plist; + INSTALL_PATH = /Library/QuickLook; + MACOSX_DEPLOYMENT_TARGET = 10.7; + PRODUCT_BUNDLE_IDENTIFIER = com.omixlab.panopainter.osx.QLPlugin; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = qlgenerator; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1859,6 +2000,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + ADFD321D2166AA0800F46F85 /* Build configuration list for PBXNativeTarget "QLPlugin" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + ADFD321B2166AA0800F46F85 /* Debug */, + ADFD321C2166AA0800F46F85 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = AD58E0471E107411006ACC15 /* Project object */; diff --git a/QLPlugin/GeneratePreviewForURL.c b/QLPlugin/GeneratePreviewForURL.c new file mode 100644 index 0000000..f18fdae --- /dev/null +++ b/QLPlugin/GeneratePreviewForURL.c @@ -0,0 +1,23 @@ +#include +#include +#include + +OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options); +void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview); + +/* ----------------------------------------------------------------------------- + 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) +{ + // To complete your generator please implement the function GeneratePreviewForURL in GeneratePreviewForURL.c + return noErr; +} + +void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview) +{ + // Implement only if supported +} diff --git a/QLPlugin/GenerateThumbnailForURL.c b/QLPlugin/GenerateThumbnailForURL.c new file mode 100644 index 0000000..6e2b021 --- /dev/null +++ b/QLPlugin/GenerateThumbnailForURL.c @@ -0,0 +1,102 @@ +#include +#include +#include + +OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize); +void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail); + +/* ----------------------------------------------------------------------------- + Generate a thumbnail for file + + This function's job is to create thumbnail for designated file as fast as possible + ----------------------------------------------------------------------------- */ + +struct PPIThumb +{ + int width; + int height; + int comp; + /* + bool valid() + { + return (width == 128 && height == 128 && comp == 4); + } + */ +}; + +struct PPIDocVersion +{ + int major; + int minor; +}; + +struct PPISoftVersion +{ + int major; + int minor; + int fix; + int build; +}; + +struct PPIHeader +{ + char magic[4]; + struct PPIDocVersion doc_version; + struct PPISoftVersion soft_version; + struct PPIThumb thumb_header; + /* + bool valid() + { + if (strcmp(magic, "PPI") != 0) + return false; + if (doc_version.major != 0 || doc_version.minor != 1) + return false; + if (!thumb_header.valid()) + return false; + return true; + } + */ +}; + +OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) +{ + // To complete your generator please implement the function GenerateThumbnailForURL in GenerateThumbnailForURL.c + //maxSize = CGSizeMake(128, 128); + CGContextRef context = QLThumbnailRequestCreateContext(thumbnail, maxSize, true, NULL); + CGRect renderRect = CGRectMake(0., 0., maxSize.width, maxSize.height); + + CFStringRef path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + const char* path_string = CFStringGetCStringPtr(path, kCFStringEncodingUTF8); + + FILE* fp = fopen(path_string, "rb"); + if (fp) + { + struct PPIHeader header; + fread(&header, sizeof(struct PPIHeader), 1, fp); + int w = header.thumb_header.width; + int h = header.thumb_header.height; + int c = header.thumb_header.comp; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef bmp = CGBitmapContextCreate(NULL, w, h, 8, w * c, colorSpace, kCGImageAlphaPremultipliedLast); + uint8_t* data = CGBitmapContextGetData(bmp); + fread(data, w * h * c, 1, fp); + fclose(fp); + + CGImageRef img = CGBitmapContextCreateImage(bmp); + CGContextDrawImage(context, renderRect, img); + } + else + { + CGContextSetRGBFillColor(context, 1, 0, 0, 1); + CGContextFillRect(context, CGRectMake(0, 0, maxSize.width, maxSize.height)); + } + QLThumbnailRequestFlushContext(thumbnail, context); + CFRelease(context); + return noErr; +} + +void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail) +{ + // Implement only if supported +} diff --git a/QLPlugin/Info.plist b/QLPlugin/Info.plist new file mode 100644 index 0000000..ae2bec3 --- /dev/null +++ b/QLPlugin/Info.plist @@ -0,0 +1,91 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + ppi + + CFBundleTypeMIMETypes + + image/ppi + + CFBundleTypeName + PPI + CFBundleTypeRole + QLGenerator + LSItemContentTypes + + public.panorama-image + + + + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + CFPlugInDynamicRegisterFunction + + CFPlugInDynamicRegistration + NO + CFPlugInFactories + + 10D308F3-0D60-4B28-A618-2A599683A839 + QuickLookGeneratorPluginFactory + + CFPlugInTypes + + 5E2D9680-5022-40FA-B806-43349622E5B9 + + 10D308F3-0D60-4B28-A618-2A599683A839 + + + CFPlugInUnloadFunction + + NSHumanReadableCopyright + Copyright © 2018 OmixLab ltd. All rights reserved. + QLNeedsToBeRunInMainThread + + QLPreviewHeight + 600 + QLPreviewWidth + 800 + QLSupportsConcurrentRequests + + QLThumbnailMinimumSize + 17 + UTImportedTypeDeclarations + + + UTTypeConformsTo + + public.data + + UTTypeIdentifier + public.panorama-image + UTTypeTagSpecification + + public.mime-type + image/ppi + public.filename-extension + + ppi + + + + + + diff --git a/QLPlugin/main.c b/QLPlugin/main.c new file mode 100644 index 0000000..6ffb617 --- /dev/null +++ b/QLPlugin/main.c @@ -0,0 +1,218 @@ +//============================================================================== +// +// DO NO MODIFY THE CONTENT OF THIS FILE +// +// This file contains the generic CFPlug-in code necessary for your generator +// To complete your generator implement the function in GenerateThumbnailForURL/GeneratePreviewForURL.c +// +//============================================================================== + + + + + + +#include +#include +#include +#include + +// ----------------------------------------------------------------------------- +// constants +// ----------------------------------------------------------------------------- + +// Don't modify this line +#define PLUGIN_ID "B8F1FFE9-38A4-46C0-A51A-75C338E4C87E" + +// +// 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; +} +