From ea19c2767facb8002347fadf869c1597f780c16c Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sat, 21 Oct 2023 18:58:38 +0100 Subject: [PATCH] Add pack writing functionality --- include/pak.h | 37 +++++++++ src/pak.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 include/pak.h create mode 100644 src/pak.c diff --git a/include/pak.h b/include/pak.h new file mode 100644 index 0000000..51fffcd --- /dev/null +++ b/include/pak.h @@ -0,0 +1,37 @@ +#ifndef PAK_H +#define PAK_H + +#include "aliases.h" +#include + +typedef struct { + u64 offset; + u64 length; + char name[]; +} toc_entry_t; + +typedef struct { + u64 count; + u64 size; +} toc_t; + +typedef struct { + u64 major; + u64 minor; + u64 patch; +} pak_ver_t; + +typedef struct { + u64 size; + u8 data[]; +} pak_entry_t; + +typedef struct { + u64 magic; + pak_ver_t version; + toc_t toc; +} pak_t; + +bool create_asset_pack(const char *dirpath, const char *output); + +#endif // !PAK_H diff --git a/src/pak.c b/src/pak.c new file mode 100644 index 0000000..17e099f --- /dev/null +++ b/src/pak.c @@ -0,0 +1,203 @@ +#include "pak.h" +#include "aliases.h" +#include "darr.h" +#include "io.h" +#include +#include +#include +#include + +#define PAK_MAGIC 0x4B41502054535341 +#define PAK_MAJOR 1 +#define PAK_MINOR 0 +#define PAK_PATCH 0 +#define PAK_EXT ".pak" + +toc_entry_t *create_toc_entry(const char *name, u64 offset); +void write_toc_entry(toc_entry_t *entry, FILE *fp); +void write_toc_entries(const toc_t *toc, toc_entry_t **entries, FILE *fp); +pak_entry_t *create_pak_entry(u64 data_length); +pak_entry_t *create_pak_entry_from_file(FILE *fp); +void write_pak_entry(const pak_entry_t *entry, FILE *fp); +void write_pak(const pak_t *pak, toc_entry_t **toc_entries, + pak_entry_t **pak_entries, FILE *fp); + +bool create_asset_pack(const char *dirpath, const char *output) { + bool created = false; + + char dst[PATH_MAX] = {0}; + + u64 output_length = strlen(output); + strncpy(dst, output, output_length); + + u64 ext_length = strlen(PAK_EXT); + strncat(dst, PAK_EXT, ext_length); + + FILE *fp = fopen(dst, "wb"); + if (!fp) { + goto RETURN_CREATE_ASSET_PAK; + } + + darr_t *toc_entries_darr = NULL; + darr_t *pak_entries_darr = NULL; + + bool initialiased = + darr_init(&toc_entries_darr) && darr_init(&pak_entries_darr); + + if (!initialiased) { + goto FREE_ARRAYS_CREATE_ASSET_PAK; + } + + pak_t pak = { + .magic = PAK_MAGIC, + .version = + (pak_ver_t){ + .major = PAK_MAJOR, + .minor = PAK_MINOR, + .patch = PAK_PATCH, + }, + .toc = + (toc_t){ + .count = 0, + .size = 0, + }, + }; + + dirwalk_t *dw = NULL; + dirwalk_result_t result = {0}; + + result = walk_dir(&dw, dirpath); + if (!(result.fp)) { + goto FREE_ARRAYS_CREATE_ASSET_PAK; + } + + u64 offset = 0; + + while (result.reading) { + if (result.fp) { + ++(pak.toc.count); + + offset += sizeof(pak_entry_t); + + toc_entry_t *toc_entry = create_toc_entry(result.name, offset); + pak_entry_t *pak_entry = create_pak_entry_from_file(result.fp); + + if (!toc_entry || !pak_entry) { + goto FREE_ARRAYS_CREATE_ASSET_PAK; + } + + pak.toc.size += sizeof(toc_entry_t) + toc_entry->length; + offset += pak_entry->size; + + darr_add(&toc_entries_darr, (void *)toc_entry); + darr_add(&pak_entries_darr, (void *)pak_entry); + } + + result = walk_dir(&dw, NULL); + } + + toc_entry_t **toc_entries = (toc_entry_t **)darr_get_items(toc_entries_darr); + pak_entry_t **pak_entries = (pak_entry_t **)darr_get_items(pak_entries_darr); + + write_pak(&pak, toc_entries, pak_entries, fp); + + created = true; + +FREE_ARRAYS_CREATE_ASSET_PAK: + darr_free(&pak_entries_darr); + darr_free(&toc_entries_darr); + + fclose(fp); + +RETURN_CREATE_ASSET_PAK: + return created; +} + +toc_entry_t *create_toc_entry(const char *name, u64 offset) { + u64 length = strlen(name); + u64 size = sizeof(toc_entry_t) + length + 1; + + toc_entry_t *entry = (toc_entry_t *)malloc(size); + if (!entry) { + return NULL; + } + + memset((void *)entry, 0, size); + + entry->offset = offset; + entry->length = length + 1; + + strncpy(entry->name, name, length); + + return entry; +} + +void write_toc_entry(toc_entry_t *entry, FILE *fp) { + fwrite((void *)entry, sizeof(toc_entry_t) + entry->length, 1, fp); +} + +void write_toc_entries(const toc_t *toc, toc_entry_t **entries, FILE *fp) { + if (!fp || !entries) { + return; + } + + for (u64 i = 0; i < toc->count; ++i) { + write_toc_entry(entries[i], fp); + + if (!entries[i]) { + continue; + } + + free(entries[i]); + + entries[i] = NULL; + } +} + +pak_entry_t *create_pak_entry(u64 data_length) { + pak_entry_t *entry = (pak_entry_t *)malloc(sizeof(pak_entry_t) + data_length); + if (!entry) { + return NULL; + } + + entry->size = data_length; + + return entry; +} + +pak_entry_t *create_pak_entry_from_file(FILE *fp) { + pak_entry_t *entry = NULL; + + if (!fp) { + goto RETURN_PAK_ENTRY; + } + + u64 length = get_file_length(fp) + 1; + + entry = create_pak_entry(length); + if (!entry) { + goto RETURN_PAK_ENTRY; + } + + read_entire_file((void *)(entry->data), length, fp); + +RETURN_PAK_ENTRY: + return entry; +} + +void write_pak_entry(const pak_entry_t *entry, FILE *fp) { + fwrite((void *)entry, sizeof(pak_entry_t) + entry->size, 1, fp); +} + +void write_pak(const pak_t *pak, toc_entry_t **toc_entries, + pak_entry_t **pak_entries, FILE *fp) { + fwrite(pak, sizeof(pak_t), 1, fp); + + write_toc_entries(&(pak->toc), toc_entries, fp); + + for (u64 i = 0; i < pak->toc.count; ++i) { + write_pak_entry(pak_entries[i], fp); + + free(pak_entries[i]); + } +}