summaryrefslogtreecommitdiff
path: root/qstd
diff options
context:
space:
mode:
Diffstat (limited to 'qstd')
-rw-r--r--qstd/Makefile7
-rw-r--r--qstd/pack.c165
-rw-r--r--qstd/pack.h40
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