Search Kit Index Files and Index Names

Search Kit is one of the lesser known OS X frameworks. It can be used to index large amounts of text and provides some powerful features to search indexed texts. Search Kit is, inter alia, used by Spotlight to index the contents of our hard disks. Once a bunch of text files have been indexed, Search Kit stores the index data in special index files.

To create a yet empty index file, one typically uses the SKIndexCreateWithURL function. It asks for an index name parameter, which is where it gets interesting: Either define an index name, or leave that paramenter empty, i.e. set it to NULL, and Search Kit will assign the default index name IADefaultIndex to it.

If one tries to open an Search Kit index file, this is possible only when knowing the index name of the file. The SKIndexOpenWithURL function asks for the index name, and again it is possible to give NULL to it, in which case the framework will try to apply the default index name IADefaultIndex. However, if this isn’t the name of the index contained in the index file, or otherwise not the correct index name has been provided, Search Kit won’t be able to access the index. And it also doesn’t provide any method to retrieve index names from search index files.

This makes it difficult to access search index files created by somebody else, but fortunately not impossible. There are situations in which one would like to open third party search index files, e.g. when accessing Xcode’s docset files or Spotlight’s hidden index files. To retrieve the name of a search index stored inside an index file, use the following code snippet:

-(NSString*)getIndexNameOfSKFile:(NSString*)filePath
{
    if (!filePath) return nil;

    // open the search index file
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    if (!data) return nil;
    NSUInteger dataLength = [data length];

    // calculate the offset where the index name is stored
    int32_t offset1, offset2;
    if (dataLength<11) return nil;
    [data getBytes:&offset1 range:NSMakeRange(4,4)];
    [data getBytes:&offset2 range:NSMakeRange(8,4)];
    int32_t offset = CFSwapInt32HostToBig(offset1)+(CFSwapInt32HostToBig(offset2)/2)+14;

    // Get index name string (stored as zero-terminated string)
    unichar c;
    NSMutableString *indexName = [NSMutableString stringWithCapacity:0];
    do {
        if (dataLength<(offset+1)) return nil;
        [data getBytes:&c range:NSMakeRange(offset, 2)];
        if (c!=0) [indexName appendString:[NSString stringWithCharacters:&c length:1]];
        offset+=2;
    } while (c!=0);
    return indexName;
}