270 lines
5.6 KiB
C
270 lines
5.6 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 pak_read {
|
|
pak_t header;
|
|
u8 *buf;
|
|
u8 *toc;
|
|
u64 assets_length;
|
|
u8 *assets;
|
|
};
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
|
|
pak_read_t *load_asset_pack(const char *filepath) {
|
|
char full_path[PATH_MAX] = {0};
|
|
|
|
realpath(filepath, full_path);
|
|
|
|
pak_read_t *pack = NULL;
|
|
|
|
FILE *fp = fopen(full_path, "rb");
|
|
if (!fp) {
|
|
goto RETURN_LOAD_ASSET_PACK;
|
|
}
|
|
|
|
pack = (pak_read_t *)malloc(sizeof(pak_read_t));
|
|
if (!pack) {
|
|
goto CLOSE_FILE_LOAD_ASSET_PACK;
|
|
}
|
|
|
|
u64 file_size = get_file_length(fp);
|
|
|
|
fread((void *)(&(pack->header)), sizeof(pak_t), 1, fp);
|
|
|
|
u64 data_size = file_size - sizeof(pak_t);
|
|
|
|
pack->buf = (u8 *)malloc(data_size);
|
|
if (!(pack->buf)) {
|
|
free(pack);
|
|
|
|
pack = NULL;
|
|
|
|
goto CLOSE_FILE_LOAD_ASSET_PACK;
|
|
}
|
|
|
|
fread((void *)(pack->buf), data_size, 1, fp);
|
|
|
|
pack->toc = pack->buf;
|
|
|
|
pack->assets_length = data_size - pack->header.toc.size;
|
|
|
|
pack->assets = pack->buf + pack->header.toc.size;
|
|
|
|
CLOSE_FILE_LOAD_ASSET_PACK:
|
|
fclose(fp);
|
|
|
|
RETURN_LOAD_ASSET_PACK:
|
|
return pack;
|
|
}
|
|
|
|
// buf_t read_file_from_pack(pak_read_t *pack, const char *filename) {}
|
|
|
|
void close_asset_pack(pak_read_t **pack) {
|
|
if (!(*pack)) {
|
|
return;
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
}
|
|
|
|
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]);
|
|
}
|
|
}
|