diff options
Diffstat (limited to 'qstd')
-rw-r--r-- | qstd/Makefile | 7 | ||||
-rw-r--r-- | qstd/pack.c | 165 | ||||
-rw-r--r-- | qstd/pack.h | 40 |
3 files changed, 210 insertions, 2 deletions
diff --git a/qstd/Makefile b/qstd/Makefile index 3c4b6a8..c4b088b 100644 --- a/qstd/Makefile +++ b/qstd/Makefile @@ -5,7 +5,7 @@ defines = -Dplat_x86 -Dplat_posix -Dallocation_default_alignment=8 cflags = -std=c90 -pedantic -Wall -Wextra $(DEBUG_COMPILE_FLAG) $(includes) $(defines) lflags = $(DEBUG_LINK_FLAG) -objects = plat.o memory.o str.o +objects = plat.o memory.o str.o pack.o .PHONY: all clean @@ -17,9 +17,12 @@ memory.o: memory.c memory.h plat.h plat.o: plat.c plat.h $(CC) -c $(cflags) plat.c -o plat.o -str.o: str.c str.h +str.o: str.c str.h memory.h $(CC) -c $(cflags) str.c -o str.o +pack.o: pack.c pack.h str.h plat.h memory.h + $(CC) -c $(cflags) pack.c -o pack.o + $(target): $(objects) $(AR) -rcs $(target) $(objects) diff --git a/qstd/pack.c b/qstd/pack.c new file mode 100644 index 0000000..e9ca0c3 --- /dev/null +++ b/qstd/pack.c @@ -0,0 +1,165 @@ +#include "memory.h" +#include "pack.h" +#include "plat.h" +#include "str.h" + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#define pack_max_files 4 + +typedef struct Pack_File { + FILE* handle; + Pack_Entry* entry; + int offset; +} Pack_File; + +Pack_Entry* get_pack_table(Pack* p) { + return (Pack_Entry*)( + (char*)&p[1] + pack_max_files * sizeof(Pack_File) + ); +} + +int get_pack_size(int entry_count) { + return sizeof(Pack) + + pack_max_files * sizeof(Pack_File) + + entry_count * sizeof(Pack_Entry); +} + +Pack_Entry* pack_find_entry(Pack* p, const char* name) { + Pack_Entry* tab = get_pack_table(p); + uint32_t hash = hash_string(name); + int idx = (int)(hash % p->file_count), i; + int e = (int)p->file_count; + for (i = 0; i < e; i++) { + Pack_Entry* e = &tab[idx]; + if (!e->name[0] || string_equal(name, e->name)) + return e; + idx = (int)((idx + 1) % p->file_count); + } + return 0; +} + +static void insert_entry(Pack* p, const Pack_Entry* e) { + Pack_Entry* d = pack_find_entry(p, e->name); + assert(d != 0); + if (d->name[0]) + print_war("Duplicate entry in %s: %s\n", p->filename, e->name); + *d = *e; +} + +static void read_table(Pack* p, FILE* f) { + uint32_t i, e = p->file_count; + Pack_Entry* tab = get_pack_table(p); + for (i = 0; i < e; i++) + tab[i].name[0] = 0; + for (i = 0; i < e; i++) { + Pack_Entry e; + fread(&e, sizeof e, 1, f); + insert_entry(p, &e); + } +} + +static void init_files(Pack* p) { + int i; + Pack_File* files = (Pack_File*)&p[1]; + for (i = 0; i < pack_max_files; i++) { + files[i].handle = 0; + } +} + +Pack* pack_open(const char* filename, Arena* a) { + Pack* p; + char magic[4]; + uint32_t entry_count; + FILE* f = fopen(filename, "rb"); + if (!f) return 0; + fread(magic, 1, 4, f); + if ( + magic[0] != 'P' || + magic[1] != 'A' || + magic[2] != 'C' || + magic[3] != 'K' + ) { + fclose(f); + return 0; + } + fread(&entry_count, 4, 1, f); + p = arena_alloc(a, get_pack_size(entry_count)); + p->filename = dup_string(a, filename); + p->file_count = entry_count; + init_files(p); + read_table(p, f); + fclose(f); + return p; +} + +void pack_close(Pack* p) { + (void)p; +} + +Pack_Entry* pack_get_entry(Pack* p, const char* name) { + Pack_Entry* e = pack_find_entry(p, name); + if (!e || e->name[0] == 0) return 0; + return e; +} + +static Pack_File* init_handle( + Pack* p, + Pack_File* h, + const char* name +) { + FILE* f; + Pack_Entry* e = pack_find_entry(p, name); + if (!e || !e->name[0]) return 0; + f = fopen(p->filename, "rb"); + if (!f) return 0; + h->offset = 0; + h->handle = f; + h->entry = e; + return h; +} + +Pack_File* pack_open_file(Pack* p, const char* name) { + int i; + Pack_File* files = (Pack_File*)&p[1]; + for (i = 0; i < pack_max_files; i++) { + Pack_File* file = &files[i]; + if (!file->handle) + return init_handle(p, file, name); + } + return 0; +} + +void pack_close_file(Pack_File* f) { + fclose(f->handle); +} + +int pack_read(Pack_File* f, void* buf, int size) { + int diff = (f->offset + size) - f->entry->size; + int read; + if (diff > 0) size -= diff; + fseek(f->handle, f->entry->offset + f->offset, SEEK_SET); + read = fread(buf, 1, size, f->handle); + f->offset += read; + return read; +} + +void pack_seek(Pack_File* f, int offset, Seek_Rel rel) { + switch (rel) { + case seek_rel_cur: + f->offset += offset; + break; + case seek_rel_start: + f->offset = offset; + break; + case seek_rel_end: + f->offset = f->entry->size - offset; + break; + } +} + +int pack_tell(Pack_File* f) { + return f->offset; +} diff --git a/qstd/pack.h b/qstd/pack.h new file mode 100644 index 0000000..447cd5b --- /dev/null +++ b/qstd/pack.h @@ -0,0 +1,40 @@ +#ifndef pack_h +#define pack_h + +#include <stdint.h> + +struct Arena; +struct Pack_File; + +typedef struct { + char name[56]; + uint32_t offset; + uint32_t size; +} Pack_Entry; + +typedef struct Pack { + char* filename; + uint32_t file_count; +} Pack; + +Pack_Entry* pack_find_entry(Pack* p, const char* name); +Pack_Entry* get_pack_table(Pack* p); +int get_pack_size(int entry_count); + +Pack* pack_open(const char* filename, struct Arena* a); +void pack_close(Pack* p); +Pack_Entry* pack_get_entry(Pack* p, const char* name); + +typedef enum { + seek_rel_cur, + seek_rel_start, + seek_rel_end +} Seek_Rel; + +struct Pack_File* pack_open_file(Pack* p, const char* name); +void pack_close_file(struct Pack_File* h); +int pack_read(struct Pack_File* f, void* buf, int size); +void pack_seek(struct Pack_File* f, int offset, Seek_Rel rel); +int pack_tell(struct Pack_File* f); + +#endif |