Can one Spotlight importer call another?

87 views Asked by At

I have a macOS application that stores text as an HTML file inside a package (directory bundle). The system Rich Text importer already knows how to extract text from HTML files. Is there a way to write an importer for my application that calls the Rich Text importer on the HTML file? I can see from the Spotlight Importer boilerplate code that it is being invoked as a COM plugin, but it is not obvious how to invoke it from my importer.

1

There are 1 answers

1
Alan Snyder On

I figured out how to do it:

#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <CoreFoundation/CFPlugInCom.h>

Boolean GetMetadataForFile(void *thisInterface,
                           CFMutableDictionaryRef attributes,
                           CFStringRef contentTypeUTI,
                           CFStringRef pathToFile);

Boolean getMetadataFromRichTextFile(CFMutableDictionaryRef attributes,
                                    CFStringRef contentTypeUTI,
                                    CFStringRef pathToFile)
{
    CFURLRef url = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/Spotlight/RichText.mdimporter"), kCFURLPOSIXPathStyle, TRUE);
    CFPlugInRef plugin = CFPlugInCreate(NULL, url);

    Boolean result = FALSE;
    if (!plugin) {
        printf("Unable to load RichText importer\n");
    } else {
        CFArrayRef factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn(kMDImporterTypeID, plugin);
        if ((factories != NULL) && (CFArrayGetCount(factories) > 0)) {
            CFUUIDRef factoryID = CFArrayGetValueAtIndex(factories, 0);
            IUnknownVTbl **iunknown = CFPlugInInstanceCreate(NULL, factoryID, kMDImporterTypeID);
            if (iunknown) {
                MDImporterInterfaceStruct **interface = NULL;
                (*iunknown)->QueryInterface(iunknown, CFUUIDGetUUIDBytes(kMDImporterInterfaceID), (LPVOID *)(&interface));
                (*iunknown)->Release(iunknown);
                if (interface) {
                    (*interface)->ImporterImportData(interface, attributes, contentTypeUTI, pathToFile);
                    (*interface)->Release(interface);
                    result = TRUE;
                } else {
                    printf("Failed to get MDImporter interface.\n");
                }
            } else {
                printf("Failed to create RichText importer instance.\n");
            }
        } else {
            printf("Could not find RichText importer factory.\n");
        }

        CFRelease(plugin);
    }
    return result;
}

Boolean GetMetadataForFile(void *thisInterface,
                           CFMutableDictionaryRef attributes,
                           CFStringRef contentTypeUTI,
                           CFStringRef pathToFile)
{
    Boolean result = FALSE;
    @autoreleasepool {
        CFStringRef path = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/index.html"), pathToFile);
        result = getMetadataFromRichTextFile(attributes, kUTTypeHTML, path);
    }
    return result;
}