From 415067497ef1931c6c98878fc1c42f39e04a7d5c Mon Sep 17 00:00:00 2001 From: yellows8 Date: Fri, 8 Sep 2017 21:52:59 -0400 Subject: [PATCH] Added build_pfs0 under tools/. Added tools/types.h, which is from 3dstools. --- tools/build_pfs0.c | 226 +++++++++++++++++++++++++++++++++++++++++++++ tools/types.h | 54 +++++++++++ 2 files changed, 280 insertions(+) create mode 100644 tools/build_pfs0.c create mode 100644 tools/types.h diff --git a/tools/build_pfs0.c b/tools/build_pfs0.c new file mode 100644 index 00000000..48632f64 --- /dev/null +++ b/tools/build_pfs0.c @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include + +#include "types.h" + +//Build with: gcc -o build_pfs0 build_pfs0.c + +#define MAX_FS_ENTRIES 0x10//If ever needed, this constant and the size of stringtable can be increased. + +typedef struct { + u32 magicnum;//"PFS0" + u32 file_count; + u32 stringtable_size; + u32 val_xc;//"Zero/Reserved" +} pfs0_header; + +typedef struct { + u64 offset; + u64 size; + u32 stringtable_offset; + u32 val_x14;//"Normally zero?" +} pfs0_fsentry; + +int build_pfs0(char *in_dirpath, char *out_pfs0_filepath) +{ + DIR *dir = NULL; + struct dirent *cur_dirent = NULL; + struct stat objstats; + FILE *fout = NULL, *fin = NULL; + int ret=0; + u32 tmplen=0; + u32 pos; + u8 *tmpbuf; + + u32 objcount = 0; + u32 stringtable_offset=0; + u64 filedata_reloffset=0; + + pfs0_header header; + pfs0_fsentry fsentries[MAX_FS_ENTRIES]; + pfs0_fsentry *fsentry; + + char objpath[256]; + + char stringtable[0x100]; + + memset(&header, 0, sizeof(header)); + memset(fsentries, 0, sizeof(fsentries)); + memset(stringtable, 0, sizeof(stringtable)); + + dir = opendir(in_dirpath); + if(dir==NULL) + { + printf("Failed to open dirpath.\n"); + return 1; + } + + fout = fopen(out_pfs0_filepath, "wb"); + if(fout==NULL) + { + printf("Failed to open PFS0 filepath.\n"); + closedir(dir); + return 1; + } + + while((cur_dirent = readdir(dir))) + { + if(strcmp(cur_dirent->d_name, ".")==0 || strcmp(cur_dirent->d_name, "..")==0)continue; + + memset(objpath, 0, sizeof(objpath)); + snprintf(objpath, sizeof(objpath)-1, "%s%s", in_dirpath, cur_dirent->d_name); + + if(stat(objpath, &objstats)==-1) + { + printf("Failed to stat: %s\n", objpath); + ret = 2; + break; + } + + if((objstats.st_mode & S_IFMT) == S_IFDIR)//directory + { + printf("Directories aren't supported, skipping... (%s)\n", objpath); + } + else if((objstats.st_mode & S_IFMT) == S_IFREG)//file + { + if(objcount>=MAX_FS_ENTRIES) + { + printf("Maximum fs object count already reached.\n"); + ret = 3; + break; + } + + fsentry = &fsentries[objcount]; + + fsentry->offset = filedata_reloffset; + fsentry->size = objstats.st_size; + filedata_reloffset+= fsentry->size; + fsentry->stringtable_offset = stringtable_offset; + + tmplen = strlen(cur_dirent->d_name)+1; + if(stringtable_offset+tmplen > sizeof(stringtable)) + { + printf("Max size of stringtable reached.\n"); + ret = 4; + break; + } + + strncpy(&stringtable[stringtable_offset], cur_dirent->d_name, sizeof(stringtable)-stringtable_offset); + stringtable_offset+= tmplen; + + objcount++; + } + else + { + printf("Invalid FS object type.\n"); + ret = 14; + break; + } + } + + closedir(dir); + + if(ret==0) + { + stringtable_offset = (stringtable_offset+0x1f) & ~0x1f; + + header.magicnum = le_word(0x30534650); + header.file_count = le_word(objcount); + header.stringtable_size = le_word(stringtable_offset); + + fwrite(&header, 1, sizeof(header), fout); + fwrite(fsentries, 1, sizeof(pfs0_fsentry)*objcount, fout); + fwrite(stringtable, 1, stringtable_offset, fout); + + stringtable_offset = 0; + + for(pos=0; pos sizeof(stringtable)) + { + printf("Max size of stringtable reached during stringtable entry reading.\n"); + ret = 4; + break; + } + + memset(objpath, 0, sizeof(objpath)); + snprintf(objpath, sizeof(objpath)-1, "%s%s", in_dirpath, &stringtable[stringtable_offset]); + stringtable_offset+=tmplen; + + fin = fopen(objpath, "rb"); + if(fin==NULL) + { + printf("Failed to open filepath for filedata.\n"); + ret = 1; + break; + } + + tmpbuf = malloc(fsentries[pos].size); + if(tmpbuf==NULL) + { + printf("Failed to allocate filedata.\n"); + ret = 6; + fclose(fin); + break; + } + + tmplen = fread(tmpbuf, 1, fsentries[pos].size, fin); + fclose(fin); + + fwrite(tmpbuf, 1, fsentries[pos].size, fout); + free(tmpbuf); + } + } + + fclose(fout); + + return ret; +} + +int main(int argc, char **argv) +{ + int ret = 0; + u32 pos; + + char dirpath[256]; + + if(argc < 3) + { + printf("%s\n", argv[0]); + printf("Build a PFS0 from an input directory.\n"); + printf("Usage:\n"); + printf("%s \n", argv[0]); + return 0; + } + + pos = strlen(argv[1]); + + if(pos==0 || pos>sizeof(dirpath)-1) + { + printf("Dirpath is length is invalid.\n"); + return 1; + } + pos--; + + memset(dirpath, 0, sizeof(dirpath)); + strncpy(dirpath, argv[1], sizeof(dirpath)-1); + if(dirpath[pos] != '/')dirpath[pos+1] = '/'; + + ret = build_pfs0(dirpath, argv[2]); + + if(ret)printf("Failed to build PFS0.\n"); + return 0; +} + diff --git a/tools/types.h b/tools/types.h new file mode 100644 index 00000000..ea83e9bd --- /dev/null +++ b/tools/types.h @@ -0,0 +1,54 @@ +#pragma once +#include + +typedef uint64_t dword_t; +typedef uint32_t word_t; +typedef uint16_t hword_t; +typedef uint8_t byte_t; +typedef int64_t dlong_t; +typedef int32_t long_t; +typedef int16_t short_t; +typedef int8_t char_t; +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +#define BIT(n) (1U << (n)) + +static inline uint16_t __local_bswap16(uint16_t x) { + return ((x << 8) & 0xff00) | ((x >> 8) & 0x00ff); +} + + +static inline uint32_t __local_bswap32(uint32_t x) { + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} + +static inline uint64_t __local_bswap64(uint64_t x) +{ + return (uint64_t)__local_bswap32(x>>32) | + ((uint64_t)__local_bswap32(x&0xFFFFFFFF) << 32); +} + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define be_dword(a) __local_bswap64(a) +#define be_word(a) __local_bswap32(a) +#define be_hword(a) __local_bswap16(a) +#define le_dword(a) (a) +#define le_word(a) (a) +#define le_hword(a) (a) +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define be_dword(a) (a) +#define be_word(a) (a) +#define be_hword(a) (a) +#define le_dword(a) __local_bswap64(a) +#define le_word(a) __local_bswap32(a) +#define le_hword(a) __local_bswap16(a) +#else +#error "What's the endianness of the platform you're targeting?" +#endif +