-
-
Save RealNeGate/6560ebb46e48bbc7405f0ee72347469b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdint.h> | |
enum { | |
FS_MAGIC_NUMBER = 0x666f6f64, | |
FS_LATEST_VERSION = 1, | |
}; | |
#define HAS_HASH_IN_ENTRY 1 | |
typedef struct fsIndexingFile { | |
FILE* indexing; | |
FILE* data_blob; | |
// Header info | |
struct fsIndexingFileHeader { | |
uint32_t magic_number; | |
uint32_t version; | |
uint32_t num_files; | |
// string table | |
uint32_t st_offset; | |
uint32_t st_length; | |
// hash table | |
uint32_t ht_offset; | |
uint32_t ht_buckets; | |
uint32_t ht_max_items_per_bucket; | |
} header; | |
} fsIndexingFile; | |
typedef struct fsEntry { | |
struct { | |
uint64_t tag, tag_len; // In the string table | |
uint64_t data_offset, data_length; // In the data blob | |
#if HAS_HASH_IN_ENTRY | |
uint64_t hash; | |
#endif | |
} file; | |
const uint8_t* file_cached; // NULL if the entry isn't being cached at the moment | |
} fsEntry; | |
static const uint64_t fnv64_prime = 1099511628211L; | |
static const uint64_t fnv64_offset_basis = 14695981039346656037UL; | |
uint64_t fsFNV1A(const char* tag) { | |
uint64_t h = fnv64_offset_basis; | |
while (*tag) { | |
h = (h ^ ((uint8_t)*tag)) * fnv64_prime; | |
tag++; | |
} | |
return h; | |
} | |
fsEntry fsLookupEntry(const fsIndexingFile* indexing, const char* tag) { | |
uint64_t hash = fsFNV1A(tag); | |
uint32_t index = (hash % indexing->header.ht_buckets) * indexing->header.ht_max_items_per_bucket; | |
#if 0 | |
fsEntry e; | |
fseek(indexing->indexing, indexing->header.ht_offset + (index * sizeof(e.file)), SEEK_SET); | |
for (int i = 0; i < indexing->header.ht_max_items_per_bucket; i++) { | |
fread(&e, sizeof(e[0].file), 1, indexing->indexing); | |
#if HAS_HASH_IN_ENTRY | |
// Verify hash | |
if (e.hash != hash) continue; | |
#endif | |
// Verify tag | |
char* e_tag = alloca(e.file.tag_len+1); | |
fseek(indexing->indexing, indexing->header.st_offset + e.file.tag, SEEK_SET); | |
fread(e_tag, e.file.tag_len+1, 1, indexing->indexing); | |
if (strcmp(e_tag, tag) != 0) continue; | |
return e; | |
} | |
#else | |
fsEntry e[4]; | |
fseek(indexing->indexing, indexing->header.ht_offset + (index * sizeof(e[0].file)), SEEK_SET); | |
fread(&e[0], sizeof(e[0].file), indexing->header.ht_max_items_per_bucket, indexing->indexing); | |
for (int i = 0; i < indexing->header.ht_max_items_per_bucket; i++) { | |
#if HAS_HASH_IN_ENTRY | |
// Verify hash | |
if (e[i].file.hash != hash) continue; | |
#endif | |
// Verify tag | |
char* e_tag = alloca(e[i].file.tag_len+1); | |
fseek(indexing->indexing, indexing->header.st_offset + e[i].file.tag, SEEK_SET); | |
fread(e_tag, e[i].file.tag_len+1, 1, indexing->indexing); | |
if (strcmp(e_tag, tag) != 0) continue; | |
return e[i]; | |
} | |
#endif | |
exit(1); | |
} | |
fsIndexingFile fsLoadIndexingFile(FILE* index_file, FILE* data_file) { | |
fsIndexingFile index; | |
index.indexing = index_file; | |
index.data_blob = data_file; | |
fread(&index.header, sizeof(index.header), 1, index_file); | |
if (index.header.magic_number != FS_MAGIC_NUMBER) exit(1); | |
if (index.header.version != FS_LATEST_VERSION) exit(1); | |
return index; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment