diff --git a/CMakeLists.txt b/CMakeLists.txt index f4b95a9..48c7751 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,10 +52,6 @@ target_link_libraries(${PROJECT_NAME} PUBLIC SDL2_ttf ) -add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/intern/pakrd/libpakrd.so ${OUTPUT_BASE_DIR}/${CMAKE_BUILD_TYPE}/lib -) - install(FILES include/aliases.h include/constants.h @@ -71,11 +67,6 @@ install(FILES CONFIGURATIONS Release DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) -install(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/intern/pakrd/libpakrd.so - CONFIGURATIONS Release - DESTINATION ${CMAKE_INSTALL_LIBDIR} -) install(TARGETS ${PROJECT_NAME} CONFIGURATIONS Release RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} @@ -85,3 +76,4 @@ install(TARGETS ${PROJECT_NAME} # SUB-DIRECTORIES add_subdirectory(extern) +add_subdirectory(intern) diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt new file mode 100644 index 0000000..0612444 --- /dev/null +++ b/intern/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.10) + +add_subdirectory(pakrd) diff --git a/intern/pakrd/CMakeLists.txt b/intern/pakrd/CMakeLists.txt new file mode 100644 index 0000000..779c51c --- /dev/null +++ b/intern/pakrd/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.17) + +project(pakrd) + +# VARIABLES +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +set(BUILD_SHARED_LIBS ON) + +if(CMAKE_HOST_WIN32) + # Export both *.lib and *.dll on Windows + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +endif() + +set(CMAKE_INSTALL_RPATH "$ORIGIN;$ORIGIN/../lib") + +# TARGETS +add_library(${PROJECT_NAME} SHARED + src/cpath.c + src/darr.c + src/io.c + src/pak.c +) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_BINARY_DIR} + include + ../../include/ +) + +target_link_libraries(${PROJECT_NAME} PUBLIC SDL2) + +install(FILES + include/cpath.h + include/darr.h + include/io.h + include/pak.h + CONFIGURATIONS Release + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) +install(TARGETS ${PROJECT_NAME} + CONFIGURATIONS Release + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} +) diff --git a/intern/pakrd/include/cpath.h b/intern/pakrd/include/cpath.h new file mode 100644 index 0000000..06f7018 --- /dev/null +++ b/intern/pakrd/include/cpath.h @@ -0,0 +1,18 @@ +#ifndef PATH_UTILS_H +#define PATH_UTILS_H + +#include "aliases.h" + +#define NUMPARTS(...) \ + (sizeof((const char *[]){"", __VA_ARGS__}) / sizeof(const char *) - 1) + +#define JOIN_PATH(DST, ...) join_path(DST, NUMPARTS(__VA_ARGS__), __VA_ARGS__) + +void join_path(char *dst, u64 count, ...); + +#define DIRNAME(DST, PATH) dirup(DST, 1, PATH) +#define DIRUP(DST, COUNT, PATH) dirup(DST, COUNT, PATH) + +void dirup(char *dst, u64 levels, const char *path); + +#endif // !PATH_UTILS_H diff --git a/intern/pakrd/include/darr.h b/intern/pakrd/include/darr.h new file mode 100644 index 0000000..ad47b37 --- /dev/null +++ b/intern/pakrd/include/darr.h @@ -0,0 +1,24 @@ +#ifndef D_ARR_H +#define D_ARR_H + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include "aliases.h" +#include + +#define INVALID_IDX -1 + +typedef struct darr darr_t; + +bool darr_init(darr_t **darr); +i64 darr_add(darr_t **darr, void *item); +void **darr_get_items(darr_t *darr); +void darr_free(darr_t **darr); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // !D_ARR_H diff --git a/intern/pakrd/include/io.h b/intern/pakrd/include/io.h new file mode 100644 index 0000000..29b8bc0 --- /dev/null +++ b/intern/pakrd/include/io.h @@ -0,0 +1,25 @@ +#ifndef IO_H +#define IO_H + +#include "SDL_rwops.h" +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include "aliases.h" +#include +#include +#include +#include + +#define STREQ(S1, S2) (strcmp(S1, S2) == 0) +#define STRNEQ(S1, S2, COUNT) (strncmp(S1, S2, COUNT) == 0) + +u64 get_file_length(SDL_RWops *io); +void read_entire_file(void *dst, SDL_RWops *io); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // !IO_H diff --git a/intern/pakrd/pak.h b/intern/pakrd/include/pak.h similarity index 86% rename from intern/pakrd/pak.h rename to intern/pakrd/include/pak.h index ed1db7b..c906810 100644 --- a/intern/pakrd/pak.h +++ b/intern/pakrd/include/pak.h @@ -30,11 +30,6 @@ typedef struct { u64 patch; } pak_ver_t; -typedef struct { - u64 size; - u8 data[]; -} pak_entry_t; - typedef struct { u64 magic; pak_ver_t version; @@ -43,7 +38,6 @@ typedef struct { typedef struct asset_pack asset_pack_t; -bool create_asset_pack(const char *dirpath, const char *output); asset_pack_t *load_asset_pack(const char *filepath); buf_t *read_file_from_pack(asset_pack_t *pack, const char *filename); void close_pack_file(buf_t **buf); diff --git a/intern/pakrd/libpakrd.so b/intern/pakrd/libpakrd.so deleted file mode 100755 index 5ef0b61..0000000 Binary files a/intern/pakrd/libpakrd.so and /dev/null differ diff --git a/intern/pakrd/src/cpath.c b/intern/pakrd/src/cpath.c new file mode 100644 index 0000000..50531f6 --- /dev/null +++ b/intern/pakrd/src/cpath.c @@ -0,0 +1,78 @@ +#include "cpath.h" +#include "aliases.h" +#include +#include +#include + +#if defined(__unix__) || defined(__APPLE__) || defined(__ANDROID__) +INTERNAL char path_sep = '/'; +#elif defined(_WIN32) || defined(_WIN64) +INTERNAL char path_sep = '\\'; +#endif + +void join_root_and_leaf(const char *root, const char *leaf, char *dst); + +void join_path(char *dst, u64 count, ...) { + va_list args; + + va_start(args, count); + + for (u64 i = 0; i < count; ++i) { + join_root_and_leaf(dst, va_arg(args, const char *), dst); + } + + va_end(args); +} + +void dirup(char *dst, u64 levels, const char *path) { + if (levels < 1) { + return; + } + + u64 end_index = 0; + u64 sep_count = 0; + + u64 length = strlen(path); + if (path[length - 1] == path_sep) { + --length; + } + + for (u64 i = length - 1; i >= 0; --i) { + if (path[i] == path_sep) { + ++sep_count; + end_index = i; + + if (sep_count == levels) { + break; + } + } + } + + if (sep_count < levels) { + end_index = 0; + } + + strncpy(dst, path, end_index); +} + +void join_root_and_leaf(const char *root, const char *leaf, char *dst) { + u64 root_length = strlen(root); + u64 root_end = root_length - 1; + + u64 leaf_length = strlen(leaf); + u64 leaf_start = 0; + + if (root[root_end] == path_sep) { + --root_end; + } + + if (leaf[leaf_start] == path_sep) { + ++leaf_start; + } + + memcpy(dst, root, ++root_end); + + dst[root_end] = path_sep; + + memcpy(&(dst[++root_end]), &(leaf[leaf_start]), leaf_length - leaf_start); +} diff --git a/intern/pakrd/src/darr.c b/intern/pakrd/src/darr.c new file mode 100644 index 0000000..9d45212 --- /dev/null +++ b/intern/pakrd/src/darr.c @@ -0,0 +1,62 @@ +#include "darr.h" +#include "aliases.h" +#include +#include + +#define BASE_CAPACITY 2048 + +struct darr { + u64 count; + u64 capacity; + void *items[]; +}; + +bool darr_init(darr_t **darr) { + u64 size = sizeof(darr_t) + sizeof(void *) * BASE_CAPACITY; + + *darr = malloc(size); + if (!(*darr)) { + return false; + } + + memset((void *)(*darr), 0, size); + + (*darr)->capacity = BASE_CAPACITY; + + return true; +} + +i64 darr_add(darr_t **darr, void *item) { + if ((*darr)->count == (*darr)->capacity) { + u64 new_size = + sizeof(darr_t) + sizeof(void *) * ((*darr)->capacity + BASE_CAPACITY); + + darr_t *orig = *darr; + + *darr = realloc(*darr, new_size); + if (!(*darr)) { + *darr = orig; + + return INVALID_IDX; + } + + (*darr)->capacity += BASE_CAPACITY; + } + + u64 index = (*darr)->count; + + (*darr)->items[((*darr)->count)++] = item; + + return index; +} + +void **darr_get_items(darr_t *darr) { return darr->items; } + +void darr_free(darr_t **darr) { + if (!(*darr)) { + return; + } + + free(*darr); + *darr = NULL; +} diff --git a/intern/pakrd/src/io.c b/intern/pakrd/src/io.c new file mode 100644 index 0000000..3c74b0a --- /dev/null +++ b/intern/pakrd/src/io.c @@ -0,0 +1,37 @@ +#include "io.h" +#include "SDL_rwops.h" +#include "aliases.h" +#include "cpath.h" +#include +#include +#include +#include +#include +#include + +#define MAX_DIR_DEPTH PATH_MAX + +u64 get_file_length(SDL_RWops *io) { + u64 current = SDL_RWtell(io); + + SDL_RWseek(io, 0, SEEK_END); + + u64 length = SDL_RWtell(io); + + // Restore the cursor position to where it was + SDL_RWseek(io, current, SEEK_SET); + + return length; +} + +void read_entire_file(void *dst, SDL_RWops *io) { + u64 length = get_file_length(io); + + u64 current = SDL_RWtell(io); + + SDL_RWseek(io, 0, SEEK_SET); + + SDL_RWread(io, dst, length, 1); + + SDL_RWseek(io, current, SEEK_SET); +} diff --git a/intern/pakrd/src/pak.c b/intern/pakrd/src/pak.c new file mode 100644 index 0000000..9c0a305 --- /dev/null +++ b/intern/pakrd/src/pak.c @@ -0,0 +1,148 @@ +#include "pak.h" +#include "SDL_rwops.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" + +struct asset_pack { + pak_t header; + SDL_RWops *io; + u8 *toc; + toc_entry_t **toc_entries; + u64 assets_length; + u64 assets_offset; +}; + +asset_pack_t *load_asset_pack(const char *filepath) { + char full_path[PATH_MAX] = {0}; + +#ifdef __ANDROID__ + strcpy(full_path, filepath); +#else + realpath(filepath, full_path); +#endif /* ifdef __ANDROID__ */ + + asset_pack_t *pack = (asset_pack_t *)malloc(sizeof(asset_pack_t)); + if (!pack) { + return NULL; + } + + memset((void *)pack, 0, sizeof(asset_pack_t)); + + pack->io = SDL_RWFromFile(full_path, "rb"); + if (!(pack->io)) { + close_asset_pack(&pack); + + return NULL; + } + + u64 file_size = get_file_length(pack->io); + + SDL_RWread(pack->io, (void *)(&(pack->header)), sizeof(pak_t), 1); + + u64 toc_size = pack->header.toc.size; + + pack->toc = (u8 *)malloc(toc_size); + if (!(pack->toc)) { + close_asset_pack(&pack); + + return NULL; + } + + SDL_RWread(pack->io, (void *)(pack->toc), toc_size, 1); + + 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 = SDL_RWtell(pack->io); + + 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)) { + SDL_RWseek(pack->io, pack->assets_offset + entry->offset, SEEK_SET); + + u64 size = 0; + SDL_RWread(pack->io, &size, sizeof(u64), 1); + + output = (buf_t *)malloc(sizeof(buf_t) + size); + if (!output) { + break; + } + + output->size = size; + + SDL_RWread(pack->io, &(output->data), size, 1); + + 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)->io) { + SDL_RWclose((*pack)->io); + } + + free(*pack); + + *pack = NULL; +}