commit - f76a6cd42ebbf205c570bde5a9864c0dd2b2d947
commit + 1c83e9394bf7c14ba4ae8712b7098eaca1fe5565
blob - c632bbe2c1d9d1b97e31551197ebbd333c4b0c5d (mode 644)
blob + /dev/null
--- .gitea/workflows/jobs.yaml
+++ /dev/null
----
-name: Test and Deploy
-on:
- push:
- branches:
- - master
-
-jobs:
- test:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout repository
- uses: actions/checkout@v2
- with:
- submodules: recursive
-
- - name: Install dependencies
- run: |
- sudo apt-get update
- sudo apt-get install -y cmake build-essential
-
- - name: Build and test
- run: |
- mkdir build
- cd build
- cmake ..
- make
- ./test
-
- docs:
- runs-on: ubuntu-latest
- timeout-minutes: 5
- steps:
- - name: Checkout repository
- uses: actions/checkout@v2
-
- - name: Install SSH client
- run: |
- sudo apt-get update
- sudo apt-get install -y openssh-client
-
- - name: Setup SSH
- run: |
- mkdir -p ~/.ssh
- ssh-keyscan -H burkey.co >> ~/.ssh/known_hosts
- echo "${{ secrets.BURKEY_CO_KEY}}" >> ~/.ssh/id_rsa
- chmod -R 700 ~/.ssh
- eval "$(ssh-agent -s)"
- ssh-add ~/.ssh/id_rsa
-
- - name: Install mkdocs
- run: |
- pip install mkdocs
-
- - name: Build documentation
- run: |
- mkdocs build
-
- - name: Deploy documentation
- run: |
- ssh debian@burkey.co "rm -rf /var/www/docs/spitwad"
- ssh debian@burkey.co "mkdir -p /var/www/docs/spitwad"
- ssh debian@burkey.co "chmod 755 /var/www/docs/spitwad"
- scp -r ./site/* debian@burkey.co:/var/www/docs/spitwad/
-
blob - ee600298adafd60c227f38fdde624f67759eb4b7 (mode 644)
blob + /dev/null
--- docs/index.md
+++ /dev/null
-# spitwad
-
-Originally conceived as a joke between some friends after we laughed about how it would be better to use WADs to send data
-between applications then JSON, because JSON is stupid and wasteful. `spitwad` is a library for interacting with WAD
-files, popularized by ID games like DOOM and Quake. You can use it in your DOOM clone, or to package your data and
-send it over a network as a WAD. Why? Why not!
-
-## Requirements
-
-Should work on any POSIX platform out of the box
-
-## Usage
-
-Docs are a work in progress!
\ No newline at end of file
blob - 9127b893dd48e64a6564fcd143fc9fe0dfea7116 (mode 644)
blob + /dev/null
--- mkdocs.yml
+++ /dev/null
-site_name: spitwad
-site_url: https://fputs.com/docs/spitwad
-theme:
- name: readthedocs
-nav:
- - 'index.md'
\ No newline at end of file
blob - 8e8812898f17bcdf50c44202a7b180e4dfd225d0
blob + 73461c2c15a535c506582c2d2005c1359d48dad6
--- spitwad.c
+++ spitwad.c
#include "spitwad.h"
-static int fail(const char* msg) {
+static int fail(const char *msg) {
fprintf(stderr, "%s\n", msg);
return 1;
}
-static uint32_t getlong(const unsigned char* data, size_t offset) {
- return data[offset] | data[offset + 1] << 8 | data[offset + 2] << 16 | data[offset + 3] << 24;
+static uint32_t read_u32(const unsigned char *data, size_t offset) {
+ return (uint32_t)data[offset]
+ | (uint32_t)data[offset + 1] << 8
+ | (uint32_t)data[offset + 2] << 16
+ | (uint32_t)data[offset + 3] << 24;
}
-static uint16_t getshort(const unsigned char* data, size_t offset) {
- return data[offset] | data[offset + 1] << 8;
+static void write_u32(unsigned char *buf, size_t offset, uint32_t val) {
+ buf[offset] = val & 0xFF;
+ buf[offset + 1] = (val >> 8) & 0xFF;
+ buf[offset + 2] = (val >> 16) & 0xFF;
+ buf[offset + 3] = (val >> 24) & 0xFF;
}
-static char* getstring(const unsigned char* data, size_t offset) {
- char* s = malloc(sizeof(char) * 9);
- strncpy(s, data + offset, 8);
- return s;
+static int grow_lumps(struct WAD *wad) {
+ uint32_t new_cap = wad->capacity ? wad->capacity * 2 : 8;
+ struct Lump *new_lumps = realloc(wad->lumps, sizeof(struct Lump) * new_cap);
+ if (new_lumps == NULL)
+ return fail("Failed to grow lump array");
+ wad->lumps = new_lumps;
+ wad->capacity = new_cap;
+ return 0;
}
-int new_WAD_from_data(struct WAD* wad, const unsigned char* data, size_t data_sz) {
- if (wad == NULL) {
- return fail("Supplied wad to new_WAD_from_data was NULL");
- }
+int wad_init(struct WAD *wad, enum WAD_Type type) {
+ if (wad == NULL)
+ return fail("NULL wad passed to wad_init");
+ wad->type = type;
+ wad->num_lumps = 0;
+ wad->capacity = 0;
+ wad->lumps = NULL;
+ return 0;
+}
- wad->data = malloc(sizeof(unsigned char) * data_sz);
- if (wad->data == NULL) {
- destroy_WAD(wad);
- return fail("Allocation failure for wad->data");
- }
- memcpy(wad->data, data, data_sz);
- wad->data_sz = data_sz;
+void wad_destroy(struct WAD *wad) {
+ if (wad == NULL)
+ return;
+ for (uint32_t i = 0; i < wad->num_lumps; i++)
+ free(wad->lumps[i].data);
+ free(wad->lumps);
+ wad->lumps = NULL;
+ wad->num_lumps = 0;
+ wad->capacity = 0;
+}
- char name[5];
- memcpy(name, data, 4);
- name[4] = '\0';
- if (strcmp(name, "IWAD") == 0) {
+int wad_load_data(struct WAD *wad, const unsigned char *data, size_t size) {
+ if (wad == NULL)
+ return fail("NULL wad passed to wad_load_data");
+ if (data == NULL || size < 12)
+ return fail("Invalid data passed to wad_load_data");
+
+ char sig[5];
+ memcpy(sig, data, 4);
+ sig[4] = '\0';
+ if (strcmp(sig, "IWAD") == 0)
wad->type = IWAD;
- } else if (strcmp(name, "PWAD") == 0) {
+ else if (strcmp(sig, "PWAD") == 0)
wad->type = PWAD;
+ else
+ return fail("WAD signature was not IWAD or PWAD");
+
+ uint32_t num_lumps = read_u32(data, 4);
+ uint32_t dir_offset = read_u32(data, 8);
+
+ if (dir_offset + (size_t)num_lumps * 16 > size)
+ return fail("Directory extends beyond data");
+
+ wad->num_lumps = 0;
+ wad->capacity = 0;
+ wad->lumps = NULL;
+
+ for (uint32_t i = 0; i < num_lumps; i++) {
+ size_t entry = dir_offset + (size_t)i * 16;
+ uint32_t lump_offset = read_u32(data, entry);
+ uint32_t lump_size = read_u32(data, entry + 4);
+
+ if (lump_offset + (size_t)lump_size > size) {
+ wad_destroy(wad);
+ return fail("Lump data extends beyond input");
+ }
+
+ char name[9];
+ memcpy(name, data + entry + 8, 8);
+ name[8] = '\0';
+
+ if (wad_add_lump(wad, name, data + lump_offset, lump_size) != 0) {
+ wad_destroy(wad);
+ return fail("Failed to add lump during load");
+ }
+ }
+
+ return 0;
+}
+
+int wad_load_file(struct WAD *wad, const char *path) {
+ if (wad == NULL)
+ return fail("NULL wad passed to wad_load_file");
+
+ FILE *fp = fopen(path, "rb");
+ if (fp == NULL) {
+ fprintf(stderr, "Failed to open %s\n", path);
+ return 1;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size_t fsz = ftell(fp);
+ rewind(fp);
+
+ unsigned char *buf = malloc(fsz);
+ if (buf == NULL) {
+ fclose(fp);
+ return fail("Failed to allocate read buffer");
+ }
+
+ if (fread(buf, 1, fsz, fp) != fsz) {
+ free(buf);
+ fclose(fp);
+ return fail("Failed to read file");
+ }
+ fclose(fp);
+
+ int ret = wad_load_data(wad, buf, fsz);
+ free(buf);
+ return ret;
+}
+
+static size_t wad_serialized_size(const struct WAD *wad) {
+ size_t size = 12; // header
+ for (uint32_t i = 0; i < wad->num_lumps; i++)
+ size += wad->lumps[i].size;
+ size += (size_t)wad->num_lumps * 16; // directory
+ return size;
+}
+
+int wad_write_data(const struct WAD *wad, unsigned char **out, size_t *out_size) {
+ if (wad == NULL || out == NULL || out_size == NULL)
+ return fail("NULL argument to wad_write_data");
+
+ size_t total = wad_serialized_size(wad);
+ unsigned char *buf = calloc(1, total);
+ if (buf == NULL)
+ return fail("Failed to allocate write buffer");
+
+ // Header
+ const char *sig = (wad->type == IWAD) ? "IWAD" : "PWAD";
+ memcpy(buf, sig, 4);
+ write_u32(buf, 4, wad->num_lumps);
+
+ size_t data_offset = 12;
+ for (uint32_t i = 0; i < wad->num_lumps; i++)
+ data_offset += wad->lumps[i].size;
+ write_u32(buf, 8, (uint32_t)data_offset);
+
+ // Lump data
+ size_t offset = 12;
+ size_t dir_pos = data_offset;
+ for (uint32_t i = 0; i < wad->num_lumps; i++) {
+ struct Lump *l = &wad->lumps[i];
+ if (l->size > 0)
+ memcpy(buf + offset, l->data, l->size);
+
+ // Directory entry
+ write_u32(buf, dir_pos, (uint32_t)offset);
+ write_u32(buf, dir_pos + 4, l->size);
+ memset(buf + dir_pos + 8, 0, 8);
+ memcpy(buf + dir_pos + 8, l->name, strlen(l->name));
+ dir_pos += 16;
+
+ offset += l->size;
+ }
+
+ *out = buf;
+ *out_size = total;
+ return 0;
+}
+
+int wad_write_file(const struct WAD *wad, const char *path) {
+ if (wad == NULL || path == NULL)
+ return fail("NULL argument to wad_write_file");
+
+ unsigned char *buf = NULL;
+ size_t size = 0;
+ if (wad_write_data(wad, &buf, &size) != 0)
+ return 1;
+
+ FILE *fp = fopen(path, "wb");
+ if (fp == NULL) {
+ free(buf);
+ fprintf(stderr, "Failed to open %s for writing\n", path);
+ return 1;
+ }
+
+ size_t written = fwrite(buf, 1, size, fp);
+ fclose(fp);
+ free(buf);
+
+ if (written != size)
+ return fail("Failed to write all data");
+ return 0;
+}
+
+int wad_add_lump(struct WAD *wad, const char *name, const unsigned char *data, uint32_t size) {
+ if (wad == NULL || name == NULL)
+ return fail("NULL argument to wad_add_lump");
+
+ if (wad->num_lumps >= wad->capacity) {
+ if (grow_lumps(wad) != 0)
+ return 1;
+ }
+
+ struct Lump *l = &wad->lumps[wad->num_lumps];
+ memset(l->name, 0, 9);
+ strncpy(l->name, name, 8);
+
+ if (size > 0 && data != NULL) {
+ l->data = malloc(size);
+ if (l->data == NULL)
+ return fail("Failed to allocate lump data");
+ memcpy(l->data, data, size);
} else {
- destroy_WAD(wad);
- return fail("WAD Type was not IWAD or PWAD");
+ l->data = NULL;
}
+ l->size = size;
- wad->dir_sz = getlong(data, 4);
- wad->dir_offset = getlong(data, 8);
+ wad->num_lumps++;
+ return 0;
+}
- wad->directory = malloc(sizeof(struct DirEntry) * wad->dir_sz);
- if (wad->directory == NULL) {
- destroy_WAD(wad);
- return fail("Allocation failure for wad->directory");
+int wad_remove_lump(struct WAD *wad, const char *name) {
+ if (wad == NULL || name == NULL)
+ return fail("NULL argument to wad_remove_lump");
+
+ for (uint32_t i = 0; i < wad->num_lumps; i++) {
+ if (strncmp(wad->lumps[i].name, name, 8) == 0)
+ return wad_remove_lump_at(wad, i);
}
+ return fail("Lump not found");
+}
- for (size_t i = wad->dir_offset, j = 0; i < data_sz; i += 16, ++j) {
- wad->directory[j].offset = getlong(data, i);
- wad->directory[j].length = getlong(data, i + 4);
+int wad_remove_lump_at(struct WAD *wad, uint32_t index) {
+ if (wad == NULL)
+ return fail("NULL wad passed to wad_remove_lump_at");
+ if (index >= wad->num_lumps)
+ return fail("Index out of bounds");
- char *s = getstring(data, i + 8);
- strncpy(wad->directory[j].name, s, 8);
- wad->directory[j].name[8] = '\0';
- free(s);
- }
+ free(wad->lumps[index].data);
+ for (uint32_t i = index; i < wad->num_lumps - 1; i++)
+ wad->lumps[i] = wad->lumps[i + 1];
+
+ wad->num_lumps--;
return 0;
}
-int new_WAD_from_file(struct WAD* wad, const char* path) {
- if (wad == NULL) {
- fprintf(stderr, "Supplied wad to new_WAD_from_file was NULL\n");
+const struct Lump *wad_find_lump(const struct WAD *wad, const char *name) {
+ if (wad == NULL || name == NULL)
+ return NULL;
+ for (uint32_t i = 0; i < wad->num_lumps; i++) {
+ if (strncmp(wad->lumps[i].name, name, 8) == 0)
+ return &wad->lumps[i];
+ }
+ return NULL;
+}
+
+const struct Lump *wad_get_lump(const struct WAD *wad, uint32_t index) {
+ if (wad == NULL || index >= wad->num_lumps)
+ return NULL;
+ return &wad->lumps[index];
+}
+
+uint32_t wad_num_lumps(const struct WAD *wad) {
+ if (wad == NULL)
return 0;
- }
-
- FILE *fp = NULL;
- fp = fopen(path, "r");
- if (fp == NULL) {
- destroy_WAD(wad);
- fprintf(stderr, "Failed to open %s. Returning NULL\n", path);
- return 1;
- }
-
- fseek(fp, 0, SEEK_END);
- size_t fsz = ftell(fp);
- rewind(fp);
-
- unsigned char *buf = NULL;
- buf = (unsigned char*)malloc(sizeof(unsigned char) * fsz);
- if (buf == NULL) {
- destroy_WAD(wad);
- fclose(fp);
- return fail("Failed to allocate buf in new_WAD_from_file");
- }
-
- fread(buf, 1, fsz, fp);
- fclose(fp);
-
- new_WAD_from_data(wad, buf, fsz);
- free(buf);
- return 0;
+ return wad->num_lumps;
}
-
-int new_WAD(struct WAD* wad) {
- wad->data = NULL;
- wad->data_sz = 0;
- wad->directory = NULL;
- wad->dir_sz = 0;
- wad->dir_offset = 0;
-}
-
-void destroy_WAD(struct WAD* wad) {
- free(wad->data);
- free(wad->directory);
- free(wad);
-}
-
-int write_to_file(struct WAD* wad, const char* path) {
- FILE *fp = NULL;
- fp = fopen(path, "wb");
- if (fp == NULL) {
- fprintf(stderr, "Failed to open %s\n", path);
- return 1;
- }
- fwrite(wad->data, sizeof(unsigned char), wad->data_sz, fp);
- fclose(fp);
- return 0;
-}
blob - 3783f1be9e6f56351d578b08410921ddabb5abb9
blob + e45d9cf73e95356bf471b71cc306002301726ef2
--- spitwad.h
+++ spitwad.h
PWAD
};
-struct DirEntry {
- uint32_t offset;
- uint32_t length;
+struct Lump {
char name[9];
+ unsigned char *data;
+ uint32_t size;
};
struct WAD {
enum WAD_Type type;
- uint32_t dir_sz;
- uint32_t dir_offset;
- unsigned char *data;
- size_t data_sz;
- struct DirEntry *directory;
+ uint32_t num_lumps;
+ uint32_t capacity;
+ struct Lump *lumps;
};
-int new_WAD_from_data(struct WAD* wad, const unsigned char* data, size_t data_sz);
-int new_WAD_from_file(struct WAD* wad, const char* path);
-int new_WAD(struct WAD* wad);
-void destroy_WAD(struct WAD* wad);
-int write_to_file(struct WAD* wad, const char* path);
+int wad_init(struct WAD *wad, enum WAD_Type type);
+void wad_destroy(struct WAD *wad);
+int wad_load_file(struct WAD *wad, const char *path);
+int wad_load_data(struct WAD *wad, const unsigned char *data, size_t size);
+int wad_write_file(const struct WAD *wad, const char *path);
+int wad_write_data(const struct WAD *wad, unsigned char **out, size_t *out_size);
+
+int wad_add_lump(struct WAD *wad, const char *name, const unsigned char *data, uint32_t size);
+int wad_remove_lump(struct WAD *wad, const char *name);
+int wad_remove_lump_at(struct WAD *wad, uint32_t index);
+
+const struct Lump *wad_find_lump(const struct WAD *wad, const char *name);
+const struct Lump *wad_get_lump(const struct WAD *wad, uint32_t index);
+uint32_t wad_num_lumps(const struct WAD *wad);
+
#endif //SPITWAD_H
blob - fd787e23c487a32031b5cede1f970877bd3c81e6
blob + 3d90a01631e5ac9e00e5677382b7bd65581fd2ef
--- test.c
+++ test.c
#include "spitwad.h"
-// Values from manually inspecting DOOM1.WAD with a third-party tool
void assert_doom1_wad(struct WAD *wad) {
assert(wad->type == IWAD);
- assert(wad->dir_sz == 1264);
- assert(wad->dir_offset == 4175796);
- assert(wad->directory[0].offset == 12);
- assert(wad->directory[0].length == 10752);
- assert(strcmp(wad->directory[0].name, "PLAYPAL") == 0);
+ assert(wad->num_lumps == 1264);
+ const struct Lump *first = wad_get_lump(wad, 0);
+ assert(first != NULL);
+ assert(first->size == 10752);
+ assert(strcmp(first->name, "PLAYPAL") == 0);
}
-void basic_test() {
- struct WAD *wad = malloc(sizeof(struct WAD));
- assert(new_WAD_from_file(wad, "DOOM1.WAD") == 0);
- assert_doom1_wad(wad);
- destroy_WAD(wad);
- wad = NULL;
+void test_load_file() {
+ struct WAD wad;
+ assert(wad_load_file(&wad, "DOOM1.WAD") == 0);
+ assert_doom1_wad(&wad);
+ wad_destroy(&wad);
}
-void read_write_test() {
- struct WAD *orig = malloc(sizeof(struct WAD));
- assert(new_WAD_from_file(orig, "DOOM1.WAD") == 0);
+void test_round_trip() {
+ struct WAD orig;
+ assert(wad_load_file(&orig, "DOOM1.WAD") == 0);
+ assert(wad_write_file(&orig, "TEST.WAD") == 0);
- assert(write_to_file(orig, "TEST.WAD") == 0);
- struct WAD *new = malloc(sizeof(struct WAD));
- assert(new_WAD_from_file(new, "TEST.WAD") == 0);
- assert_doom1_wad(new);
+ struct WAD copy;
+ assert(wad_load_file(©, "TEST.WAD") == 0);
+ assert_doom1_wad(©);
- destroy_WAD(orig);
- orig = NULL;
- destroy_WAD(new);
- new = NULL;
+ assert(orig.num_lumps == copy.num_lumps);
+ for (uint32_t i = 0; i < orig.num_lumps; i++) {
+ const struct Lump *a = wad_get_lump(&orig, i);
+ const struct Lump *b = wad_get_lump(©, i);
+ assert(strcmp(a->name, b->name) == 0);
+ assert(a->size == b->size);
+ if (a->size > 0)
+ assert(memcmp(a->data, b->data, a->size) == 0);
+ }
+
+ wad_destroy(&orig);
+ wad_destroy(©);
remove("TEST.WAD");
}
+void test_create_and_manipulate() {
+ struct WAD wad;
+ assert(wad_init(&wad, PWAD) == 0);
+ assert(wad.type == PWAD);
+ assert(wad_num_lumps(&wad) == 0);
+
+ const unsigned char data1[] = "hello world";
+ const unsigned char data2[] = {0xDE, 0xAD, 0xBE, 0xEF};
+ const unsigned char data3[] = "test data here";
+
+ assert(wad_add_lump(&wad, "GREETING", data1, sizeof(data1)) == 0);
+ assert(wad_add_lump(&wad, "DEADBEEF", data2, sizeof(data2)) == 0);
+ assert(wad_add_lump(&wad, "TESTDATA", data3, sizeof(data3)) == 0);
+ assert(wad_num_lumps(&wad) == 3);
+
+ // Find by name
+ const struct Lump *found = wad_find_lump(&wad, "DEADBEEF");
+ assert(found != NULL);
+ assert(found->size == 4);
+ assert(memcmp(found->data, data2, 4) == 0);
+
+ // Get by index
+ const struct Lump *first = wad_get_lump(&wad, 0);
+ assert(first != NULL);
+ assert(strcmp(first->name, "GREETING") == 0);
+
+ // Remove by name
+ assert(wad_remove_lump(&wad, "DEADBEEF") == 0);
+ assert(wad_num_lumps(&wad) == 2);
+ assert(wad_find_lump(&wad, "DEADBEEF") == NULL);
+ assert(strcmp(wad_get_lump(&wad, 1)->name, "TESTDATA") == 0);
+
+ // Remove by index
+ assert(wad_remove_lump_at(&wad, 0) == 0);
+ assert(wad_num_lumps(&wad) == 1);
+ assert(strcmp(wad_get_lump(&wad, 0)->name, "TESTDATA") == 0);
+
+ wad_destroy(&wad);
+}
+
+void test_write_and_reload() {
+ struct WAD wad;
+ assert(wad_init(&wad, PWAD) == 0);
+
+ const unsigned char data1[] = "first lump data";
+ const unsigned char data2[] = {1, 2, 3, 4, 5, 6, 7, 8};
+ assert(wad_add_lump(&wad, "FIRST", data1, sizeof(data1)) == 0);
+ assert(wad_add_lump(&wad, "SECOND", data2, sizeof(data2)) == 0);
+
+ // Write to buffer
+ unsigned char *buf = NULL;
+ size_t buf_sz = 0;
+ assert(wad_write_data(&wad, &buf, &buf_sz) == 0);
+ assert(buf != NULL);
+ assert(buf_sz > 0);
+
+ // Reload from buffer
+ struct WAD wad2;
+ assert(wad_load_data(&wad2, buf, buf_sz) == 0);
+ assert(wad2.type == PWAD);
+ assert(wad_num_lumps(&wad2) == 2);
+
+ const struct Lump *l1 = wad_get_lump(&wad2, 0);
+ assert(strcmp(l1->name, "FIRST") == 0);
+ assert(l1->size == sizeof(data1));
+ assert(memcmp(l1->data, data1, sizeof(data1)) == 0);
+
+ const struct Lump *l2 = wad_get_lump(&wad2, 1);
+ assert(strcmp(l2->name, "SECOND") == 0);
+ assert(l2->size == sizeof(data2));
+ assert(memcmp(l2->data, data2, sizeof(data2)) == 0);
+
+ free(buf);
+ wad_destroy(&wad);
+ wad_destroy(&wad2);
+
+ // Also test file round-trip
+ assert(wad_init(&wad, PWAD) == 0);
+ assert(wad_add_lump(&wad, "FIRST", data1, sizeof(data1)) == 0);
+ assert(wad_add_lump(&wad, "SECOND", data2, sizeof(data2)) == 0);
+ assert(wad_write_file(&wad, "TEST2.WAD") == 0);
+
+ struct WAD wad3;
+ assert(wad_load_file(&wad3, "TEST2.WAD") == 0);
+ assert(wad_num_lumps(&wad3) == 2);
+ assert(memcmp(wad_get_lump(&wad3, 0)->data, data1, sizeof(data1)) == 0);
+
+ wad_destroy(&wad);
+ wad_destroy(&wad3);
+ remove("TEST2.WAD");
+}
+
+void test_name_truncation() {
+ struct WAD wad;
+ assert(wad_init(&wad, PWAD) == 0);
+ assert(wad_add_lump(&wad, "LONGERNAME", (const unsigned char *)"x", 1) == 0);
+ const struct Lump *l = wad_get_lump(&wad, 0);
+ assert(strlen(l->name) == 8);
+ assert(strcmp(l->name, "LONGERNA") == 0);
+ wad_destroy(&wad);
+}
+
+void test_empty_lump() {
+ struct WAD wad;
+ assert(wad_init(&wad, PWAD) == 0);
+ assert(wad_add_lump(&wad, "EMPTY", NULL, 0) == 0);
+ const struct Lump *l = wad_get_lump(&wad, 0);
+ assert(l->size == 0);
+ assert(l->data == NULL);
+
+ unsigned char *buf = NULL;
+ size_t sz = 0;
+ assert(wad_write_data(&wad, &buf, &sz) == 0);
+
+ struct WAD wad2;
+ assert(wad_load_data(&wad2, buf, sz) == 0);
+ assert(wad_get_lump(&wad2, 0)->size == 0);
+
+ free(buf);
+ wad_destroy(&wad);
+ wad_destroy(&wad2);
+}
+
+void test_error_cases() {
+ assert(wad_init(NULL, PWAD) != 0);
+ assert(wad_load_file(NULL, "foo") != 0);
+ assert(wad_load_data(NULL, NULL, 0) != 0);
+
+ struct WAD wad;
+ assert(wad_load_data(&wad, (const unsigned char *)"short", 5) != 0);
+ assert(wad_load_data(&wad, (const unsigned char *)"NOPE01234567", 12) != 0);
+
+ assert(wad_find_lump(NULL, "X") == NULL);
+ assert(wad_get_lump(NULL, 0) == NULL);
+ assert(wad_num_lumps(NULL) == 0);
+}
+
int main() {
- basic_test();
- read_write_test();
-}
\ No newline at end of file
+ test_load_file();
+ test_round_trip();
+ test_create_and_manipulate();
+ test_write_and_reload();
+ test_name_truncation();
+ test_empty_lump();
+ test_error_cases();
+ printf("All tests passed.\n");
+ return 0;
+}