import Foundation /// A Swift class for implementing a `CFPlugIn`. /// /// This is intended to be subclassed by type-specific subclass (for example, a /// plug-in that provides infrastructure for implementing a Spotlight importer) /// which is, in turn, subclassed by a factory-specific subclass (a specific /// importer). /// /// With this infrastructure a type-specific subclass can only support a single /// interface. For example, you can make a Spotlight importer or a Quick Look /// generator but not a single plug-in that supports both. This isn’t a /// significant restriction in practice. /// /// To create a type-specific subclass: /// /// 1. Create a subclass of `QCFPlugIn`. /// /// 2. Implement a `makeInstance(factoryID:…)` method that calls /// `makeInstance(factoryID:typeID:typeVTableSize:)` with the right type UUID and /// vtable size parameters. /// /// 3. Override `setupVTable(_:for:)` and populate your type-specific vtable /// entries. /// /// 4. For each type-specific vtable entry, introduce a method for the /// factory-specific subclass to override. /// /// 5. And then populate the vtable with callbacks, each of which uses /// `object(forInstance:)` to get the object and then call the corresponding /// method you introduced in step 4. open class QCFPlugIn { /// The factory ID passed to the initialiser. /// /// We need to retain this in order to support cleaning up the instance. private let factoryID: UUID /// A reference count for the plug-in instance. /// /// This is used to implement the `AddRef` and `Release` semantics. Each /// added reference count represents an additional retain of the Swift /// object. When the reference count goes to zero, the Swift object should /// be deallocated (once any temporary references, such as those in /// autorelease pools, are cleaned up). private var plugInRefCount: Int = 0 /// A pointer to the prefix before the vtable. private let vtablePrefixPtr: UnsafeMutablePointer /// A pointer to the vtable after the prefix. private var vtablePtr: UnsafeMutablePointer { (UnsafeMutableRawPointer(vtablePrefixPtr) + MemoryLayout.stride).assumingMemoryBound(to: IUnknownVTbl.self) } /// A pointer to the prefix before the instance. private let instancePrefixPtr: UnsafeMutablePointer /// A pointer to the instance after the prefix. private var instancePtr: UnsafeMutablePointer?> { (UnsafeMutableRawPointer(instancePrefixPtr) + MemoryLayout.stride).assumingMemoryBound(to: UnsafeMutablePointer?.self) } /// Magic values to place in the prefix. private enum Magic: UInt32, RawRepresentable { case instance = 0x51514346 // 'QQCF' case instanceBad = 0x51514321 // 'QQC!' case vtable = 0x51515654 // 'QQVT' case vtableBad = 0x51515621 // 'QQV!' } /// A prefix for both the vtable and instance pointers. /// /// Spotlight has a bug (r. 66627348) where, when it calls an importer /// function, it passes the function its vtable as the first parameter (as /// opposed to passing it the instance pointer). To work around this bug we /// need a way to recover the object pointer based solely on the vtable /// pointer. Our solution is to add a prefix to both pointers and then store /// a magic number and the object pointer in that prefix. /// /// This magic number is a good idea anyway because this code uses a lot of /// scary pointer manipulation and the magic number lets us check that we /// got that right. private struct Prefix { var obj: Unmanaged? var magic: Magic } /// Creates and returns a `CFPlugIn` instance. /// /// A type-specific subclass is expected to defined their own /// `makeInstance(factoryID:…)` method that fills in the details associated /// with that plug-in type, that is, the plug-in type UUID and the plug-in /// vtable size. The header for the plug-in type usually declares this /// information in a convenient format. For example, /// `