Add pack writing functionality

This commit is contained in:
Abdelrahman Said 2023-10-21 18:58:38 +01:00
parent d7792998ea
commit ea19c2767f
2 changed files with 240 additions and 0 deletions
include
src

37
include/pak.h Normal file

@ -0,0 +1,37 @@
#ifndef PAK_H
#define PAK_H
#include "aliases.h"
#include <stdbool.h>
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

203
src/pak.c Normal file

@ -0,0 +1,203 @@
#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"
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]);
}
}