329 lines
6.7 KiB
C
329 lines
6.7 KiB
C
#include "pak.h"
|
|
#include "aliases.h"
|
|
#include "darr.h"
|
|
#include "io.h"
|
|
#include <linux/limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define PAK_MAGIC 0x4B41502054535341
|
|
#define PAK_MAJOR 1
|
|
#define PAK_MINOR 0
|
|
#define PAK_PATCH 0
|
|
#define PAK_EXT ".pak"
|
|
|
|
struct asset_pack {
|
|
pak_t header;
|
|
FILE *fp;
|
|
u8 *toc;
|
|
toc_entry_t **toc_entries;
|
|
u64 assets_length;
|
|
u64 assets_offset;
|
|
};
|
|
|
|
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 + 1] = {0};
|
|
|
|
strcpy(dst, output);
|
|
|
|
strcat(dst, PAK_EXT);
|
|
|
|
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);
|
|
|
|
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 += sizeof(pak_entry_t) + 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;
|
|
}
|
|
|
|
asset_pack_t *load_asset_pack(const char *filepath) {
|
|
char full_path[PATH_MAX] = {0};
|
|
|
|
realpath(filepath, full_path);
|
|
|
|
asset_pack_t *pack = (asset_pack_t *)malloc(sizeof(asset_pack_t));
|
|
if (!pack) {
|
|
return NULL;
|
|
}
|
|
|
|
pack->fp = fopen(full_path, "rb");
|
|
if (!(pack->fp)) {
|
|
close_asset_pack(&pack);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
u64 file_size = get_file_length(pack->fp);
|
|
|
|
fread((void *)(&(pack->header)), sizeof(pak_t), 1, pack->fp);
|
|
|
|
u64 toc_size = pack->header.toc.size;
|
|
|
|
pack->toc = (u8 *)malloc(toc_size);
|
|
if (!(pack->toc)) {
|
|
close_asset_pack(&pack);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
fread((void *)(pack->toc), toc_size, 1, pack->fp);
|
|
|
|
u64 entries_size = sizeof(toc_entry_t *) * pack->header.toc.count;
|
|
|
|
pack->toc_entries = (toc_entry_t **)malloc(entries_size);
|
|
if (!(pack->toc_entries)) {
|
|
close_asset_pack(&pack);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
toc_entry_t *next = (toc_entry_t *)pack->toc;
|
|
|
|
for (u64 i = 0; i < pack->header.toc.count; ++i) {
|
|
pack->toc_entries[i] = next;
|
|
|
|
next = (toc_entry_t *)((u8 *)next + sizeof(toc_entry_t) + next->length);
|
|
}
|
|
|
|
pack->assets_offset = ftell(pack->fp);
|
|
|
|
pack->assets_length = file_size - pack->assets_offset;
|
|
|
|
return pack;
|
|
}
|
|
|
|
buf_t *read_file_from_pack(asset_pack_t *pack, const char *filename) {
|
|
toc_entry_t *entry = NULL;
|
|
buf_t *output = NULL;
|
|
|
|
for (u64 i = 0; i < pack->header.toc.count; ++i) {
|
|
entry = pack->toc_entries[i];
|
|
|
|
if (STRNEQ(filename, entry->name, entry->length)) {
|
|
fseek(pack->fp, pack->assets_offset + entry->offset, SEEK_SET);
|
|
|
|
u64 size = 0;
|
|
fread(&size, sizeof(u64), 1, pack->fp);
|
|
|
|
output = (buf_t *)malloc(sizeof(buf_t) + size);
|
|
if (!output) {
|
|
break;
|
|
}
|
|
|
|
output->size = size;
|
|
|
|
fread(&(output->data), size, 1, pack->fp);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
void close_pack_file(buf_t **buf) {
|
|
buf_t *b = *buf;
|
|
|
|
if (!b || b->size == 0) {
|
|
return;
|
|
}
|
|
|
|
free(*buf);
|
|
*buf = NULL;
|
|
}
|
|
|
|
void close_asset_pack(asset_pack_t **pack) {
|
|
if (!(*pack)) {
|
|
return;
|
|
}
|
|
|
|
if ((*pack)->toc_entries) {
|
|
free((*pack)->toc_entries);
|
|
}
|
|
|
|
if ((*pack)->toc) {
|
|
free((*pack)->toc);
|
|
}
|
|
|
|
if ((*pack)->fp) {
|
|
fclose((*pack)->fp);
|
|
}
|
|
|
|
free(*pack);
|
|
|
|
*pack = NULL;
|
|
}
|
|
|
|
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;
|
|
|
|
strcpy(entry->name, name);
|
|
|
|
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;
|
|
}
|
|
|
|
memset(entry, 0, data_length);
|
|
|
|
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), 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]);
|
|
}
|
|
}
|