From 68e7dc8051df5bb61d4ad6e1c2446ae77250ceed Mon Sep 17 00:00:00 2001 From: Martins Mozeiko Date: Mon, 30 Oct 2017 23:15:25 -0700 Subject: [PATCH] add -x argument to create individual files without zip file --- README.md | 4 + build.cmd | 2 +- pkg2zip.c | 285 ++++++++++++++++++++++++++++++++++---------------- pkg2zip_sys.c | 53 ++++++++++ pkg2zip_sys.h | 4 + pkg2zip_zip.c | 10 +- 6 files changed, 265 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index eec1d05..edc056f 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,10 @@ If you don't have zRIF fake license, but just want to unpack files, then omit la Resulting zip file will not include work.bin. This is useful for patch pkg files. +To avoid zipping process and create individual files, use `-x` argument (must come before pkg file): + + pkg2zip -x package.pkg [zRIF_STRING] + PSX pkg files do not require zRIF argument. It will be ignored. # Generating zRIF string diff --git a/build.cmd b/build.cmd index 949cf34..6fc6204 100644 --- a/build.cmd +++ b/build.cmd @@ -3,7 +3,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=amd64 -host_arch=amd64 cd "%~dp0" -set CL=/nologo /errorReport:none /Gm- /GF /GS- /MT /W4 /WX /wd4324 +set CL=/nologo /errorReport:none /Gm- /GF /GS- /MT /W4 /WX /wd4324 /D_CRT_SECURE_NO_DEPRECATE set LINK=/errorReport:none /INCREMENTAL:NO set CL=%CL% /Ox diff --git a/pkg2zip.c b/pkg2zip.c index 64b3b5c..d4cb836 100644 --- a/pkg2zip.c +++ b/pkg2zip.c @@ -261,18 +261,119 @@ static const char* get_region(const char* id) } } +static zip out_zip; +static int out_zipped; +static sys_file out_file; +static uint64_t out_file_offset; + +static void out_begin(const char* name, int zipped) +{ + if (zipped) + { + zip_create(&out_zip, name); + } + else + { + sys_mkdir(name); + } + out_zipped = zipped; +} + +static void out_end(void) +{ + if (out_zipped) + { + zip_close(&out_zip); + } +} + +static void out_add_folder(const char* path) +{ + if (out_zipped) + { + zip_add_folder(&out_zip, path); + } + else + { + sys_mkdir(path); + } +} + +static void out_begin_file(const char* name) +{ + if (out_zipped) + { + zip_begin_file(&out_zip, name); + } + else + { + out_file = sys_create(name); + out_file_offset = 0; + } +} + +static void out_end_file(void) +{ + if (out_zipped) + { + zip_end_file(&out_zip); + } + else + { + sys_close(out_file); + } +} + +static void out_write(const void* buffer, uint32_t size) +{ + if (out_zipped) + { + zip_write_file(&out_zip, buffer, size); + } + else + { + sys_write(out_file, out_file_offset, buffer, size); + out_file_offset += size; + } +} + int main(int argc, char* argv[]) { printf("pkg2zip v1.5\n"); - if (argc < 2 || argc > 3) + + int zipped = 1; + const char* pkg_arg = NULL; + const char* zrif_arg = NULL; + for (int i = 1; i < argc; i++) { - fatal("Usage: %s file.pkg [zRIF]\n", argv[0]); + if (strcmp(argv[i], "-x") == 0) + { + zipped = 0; + } + else + { + if (pkg_arg != NULL) + { + zrif_arg = argv[i]; + break; + } + else + { + pkg_arg = argv[i]; + } + } + } + + if (pkg_arg == NULL) + { + fprintf(stderr, "ERROR: no pkg file specified\n"); + fatal("Usage: %s [-x] file.pkg [zRIF]\n", argv[0]); } printf("[*] loading...\n"); uint64_t pkg_size; - sys_file pkg = sys_open(argv[1], &pkg_size); + sys_file pkg = sys_open(pkg_arg, &pkg_size); uint8_t pkg_header[PKG_HEADER_SIZE + PKG_HEADER_EXT_SIZE]; sys_read(pkg, 0, pkg_header, sizeof(pkg_header)); @@ -385,9 +486,9 @@ int main(int argc, char* argv[]) { parse_sfo(pkg, sfo_offset, sfo_size, &patch, title, content, min_version, pkg_version); - if (argc == 3 && !patch) + if (!patch && zrif_arg != NULL) { - zrif_decode(argv[2], rif); + zrif_decode(zrif_arg, rif); if (strncmp((char*)rif + 0x10, content, 0x30) != 0) { fatal("ERROR: zRIF content id '%s' doesn't match pkg '%s'\n", rif + 0x10, content); @@ -395,98 +496,106 @@ int main(int argc, char* argv[]) } } - char path[1024]; + const char* ext = zipped ? ".zip" : ""; + + char root[1024]; if (psp) { id = (char*)pkg_header + 0x37; const char* type_str = content_type == 7 ? "PSP" : "PSPMini"; - snprintf(path, sizeof(path), "%s [%.9s] [%s].zip", title, id, type_str); + snprintf(root, sizeof(root), "%s [%.9s] [%s]%s", title, id, type_str, ext); printf("[*] unpacking %s\n", type_str); } else if (psx) { id = (char*)pkg_header + 0x37; - snprintf(path, sizeof(path), "%s [%.9s] [PSX].zip", title, id); + snprintf(root, sizeof(root), "%s [%.9s] [PSX]%s", title, id, ext); printf("[*] unpacking PSX\n"); } else if (dlc) { - snprintf(path, sizeof(path), "%s [%.9s] [%s] [DLC-%s].zip", title, id, get_region(id), id2); + snprintf(root, sizeof(root), "%s [%.9s] [%s] [DLC-%s]%s", title, id, get_region(id), id2, ext); printf("[*] unpacking DLC\n"); } else if (patch) { - snprintf(path, sizeof(path), "%s [%.9s] [%s] [PATCH] [v%s].zip", title, id, get_region(id), pkg_version); + snprintf(root, sizeof(root), "%s [%.9s] [%s] [PATCH] [v%s]%s", title, id, get_region(id), pkg_version, ext); printf("[*] unpacking PATCH\n"); } else { - snprintf(path, sizeof(path), "%s [%.9s] [%s].zip", title, id, get_region(id)); + snprintf(root, sizeof(root), "%s [%.9s] [%s]%s", title, id, get_region(id), ext); printf("[*] unpacking APP\n"); } - printf("[*] creating '%s' archive\n", path); + out_begin(root, zipped); - zip z; - zip_create(&z, path); - - char root[64]; - - if (psp) + if (zipped) { + printf("[*] creating '%s' archive\n", root); root[0] = 0; } - else if (psx) - { - snprintf(path, sizeof(path), "pspemu/"); - zip_add_folder(&z, path); - - snprintf(path, sizeof(path), "pspemu/PSP/"); - zip_add_folder(&z, path); - - snprintf(path, sizeof(path), "pspemu/PSP/GAME/"); - zip_add_folder(&z, path); - - snprintf(path, sizeof(path), "pspemu/PSP/GAME/%.9s/", id); - zip_add_folder(&z, path); - - snprintf(root, sizeof(root), "pspemu/PSP/GAME/%.9s", id); - } - else if (dlc) - { - snprintf(path, sizeof(path), "addcont/"); - zip_add_folder(&z, path); - - snprintf(path, sizeof(path), "addcont/%.9s/", id); - zip_add_folder(&z, path); - - snprintf(path, sizeof(path), "addcont/%.9s/%s/", id, id2); - zip_add_folder(&z, path); - - snprintf(root, sizeof(root), "addcont/%.9s/%s", id, id2); - } - else if (patch) - { - snprintf(path, sizeof(path), "patch/"); - zip_add_folder(&z, path); - - snprintf(path, sizeof(path), "patch/%.9s/", id); - zip_add_folder(&z, path); - - snprintf(root, sizeof(root), "patch/%.9s", id); - } else { - snprintf(path, sizeof(path), "app/"); - zip_add_folder(&z, path); + printf("[*] output to '%s' folder\n", root); + sys_vstrncat(root, sizeof(root), "/"); + } - snprintf(path, sizeof(path), "app/%.9s/", id); - zip_add_folder(&z, path); + if (psp) + { + } + else if (psx) + { + sys_vstrncat(root, sizeof(root), "pspemu"); + out_add_folder(root); - snprintf(root, sizeof(root), "app/%.9s/", id); + sys_vstrncat(root, sizeof(root), "/PSP"); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/GAME"); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/%.9s", id); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/"); + } + else if (dlc) + { + sys_vstrncat(root, sizeof(root), "addcont"); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/%.9s", id); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/%s", id2); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/"); + } + else if (patch) + { + sys_vstrncat(root, sizeof(root), "patch"); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/%.9s", id); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/"); + } + else + { + sys_vstrncat(root, sizeof(root), "app"); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/%.9s", id); + out_add_folder(root); + + sys_vstrncat(root, sizeof(root), "/"); } printf("[*] decrypting...\n"); + char path[1024]; for (uint32_t item_index = 0; item_index < item_count; item_index++) { @@ -537,8 +646,8 @@ int main(int argc, char* argv[]) { if (!psx) { - snprintf(path, sizeof(path), "%s/%s/", root, name); - zip_add_folder(&z, path); + snprintf(path, sizeof(path), "%s%s/", root, name); + out_add_folder(path); } } else @@ -554,11 +663,11 @@ int main(int argc, char* argv[]) { if (strcmp("USRDIR/CONTENT/DOCUMENT.DAT", name) == 0) { - snprintf(path, sizeof(path), "%s/DOCUMENT.DAT", root); + snprintf(path, sizeof(path), "%sDOCUMENT.DAT", root); } else if (strcmp("USRDIR/CONTENT/EBOOT.PBP", name) == 0) { - snprintf(path, sizeof(path), "%s/EBOOT.PBP", root); + snprintf(path, sizeof(path), "%sEBOOT.PBP", root); } else { @@ -567,12 +676,12 @@ int main(int argc, char* argv[]) } else { - snprintf(path, sizeof(path), "%s/%s", root, name); + snprintf(path, sizeof(path), "%s%s", root, name); } uint64_t offset = data_offset; - zip_begin_file(&z, path); + out_begin_file(path); while (data_size != 0) { uint8_t buffer[1 << 16]; @@ -584,21 +693,21 @@ int main(int argc, char* argv[]) aes128_ctr_xor(item_key, iv, offset / 16, buffer, size); } - zip_write_file(&z, buffer, size); + out_write(buffer, size); offset += size; data_size -= size; } - zip_end_file(&z); + out_end_file(); } } if (!psp && !psx) { printf("[*] creating head.bin\n"); - snprintf(path, sizeof(path), "%s/sce_sys/package/head.bin", root); + snprintf(path, sizeof(path), "%ssce_sys/package/head.bin", root); - zip_begin_file(&z, path); + out_begin_file(path); uint64_t head_size = enc_offset + items_size; uint64_t head_offset = 0; while (head_size != 0) @@ -606,53 +715,53 @@ int main(int argc, char* argv[]) uint8_t buffer[1 << 16]; uint32_t size = (uint32_t)min64(head_size, sizeof(buffer)); sys_read(pkg, head_offset, buffer, size); - zip_write_file(&z, buffer, size); + out_write(buffer, size); head_size -= size; head_offset += size; } - zip_end_file(&z); + out_end_file(); } if (!psp && !psx) { printf("[*] creating tail.bin\n"); - snprintf(path, sizeof(path), "%s/sce_sys/package/tail.bin", root); + snprintf(path, sizeof(path), "%ssce_sys/package/tail.bin", root); - zip_begin_file(&z, path); + out_begin_file(path); uint64_t tail_offset = enc_offset + enc_size; while (tail_offset != pkg_size) { uint8_t buffer[1 << 16]; uint32_t size = (uint32_t)min64(pkg_size - tail_offset, sizeof(buffer)); sys_read(pkg, tail_offset, buffer, size); - zip_write_file(&z, buffer, size); + out_write(buffer, size); tail_offset += size; } - zip_end_file(&z); + out_end_file(); } if (!psp && !psx) { printf("[*] creating stat.bin\n"); - snprintf(path, sizeof(path), "%s/sce_sys/package/stat.bin", root); + snprintf(path, sizeof(path), "%ssce_sys/package/stat.bin", root); uint8_t stat[768] = { 0 }; - zip_begin_file(&z, path); - zip_write_file(&z, stat, sizeof(stat)); - zip_end_file(&z); + out_begin_file(path); + out_write(stat, sizeof(stat)); + out_end_file(); } - if (!psp && !psx && !patch && argc == 3) + if (!psp && !psx && !patch && zrif_arg != NULL) { printf("[*] creating work.bin\n"); - snprintf(path, sizeof(path), "%s/sce_sys/package/work.bin", root); + snprintf(path, sizeof(path), "%ssce_sys/package/work.bin", root); - zip_begin_file(&z, path); - zip_write_file(&z, rif, sizeof(rif)); - zip_end_file(&z); + out_begin_file(path); + out_write(rif, sizeof(rif)); + out_end_file(); } - zip_close(&z); + out_end(); if (!psp && !psx && !dlc) { diff --git a/pkg2zip_sys.c b/pkg2zip_sys.c index fe0a6a1..52a7291 100644 --- a/pkg2zip_sys.c +++ b/pkg2zip_sys.c @@ -2,12 +2,29 @@ #include "pkg2zip_utils.h" #include +#include +#include +#include #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #include +static void sys_mkdir_real(const char* path) +{ + WCHAR wpath[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH); + + if (CreateDirectoryW(wpath, NULL) == 0) + { + if (GetLastError() != ERROR_ALREADY_EXISTS) + { + fatal("ERROR: cannot create '%s' folder\n", path); + } + } +} + sys_file sys_open(const char* fname, uint64_t* size) { WCHAR path[MAX_PATH]; @@ -82,9 +99,21 @@ void sys_write(sys_file file, uint64_t offset, const void* buffer, uint32_t size #define _FILE_OFFSET_BITS 64 #include #include +#include #include #include +static void sys_mkdir_real(const char* path) +{ + if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + { + if (errno != EEXIST) + { + fatal("ERROR: cannot create '%s' folder\n", path); + } + } +} + sys_file sys_open(const char* fname, uint64_t* size) { int fd = open(fname, O_RDONLY); @@ -142,6 +171,18 @@ void sys_write(sys_file file, uint64_t offset, const void* buffer, uint32_t size #endif +void sys_mkdir(const char* path) +{ + char* last = strrchr(path, '/'); + if (last) + { + *last = 0; + sys_mkdir(path); + *last = '/'; + } + sys_mkdir_real(path); +} + void* sys_realloc(void* ptr, size_t size) { void* result = NULL; @@ -170,3 +211,15 @@ void* sys_realloc(void* ptr, size_t size) return result; } + +void sys_vstrncat(char* dst, size_t n, const char* format, ...) +{ + char temp[1024]; + + va_list args; + va_start(args, format); + vsnprintf(temp, sizeof(temp), format, args); + va_end(args); + + strncat(dst, temp, n - strlen(dst) - 1); +} \ No newline at end of file diff --git a/pkg2zip_sys.h b/pkg2zip_sys.h index 466b1e5..6ffa8ae 100644 --- a/pkg2zip_sys.h +++ b/pkg2zip_sys.h @@ -5,6 +5,8 @@ typedef void* sys_file; +void sys_mkdir(const char* path); + sys_file sys_open(const char* fname, uint64_t* size); sys_file sys_create(const char* fname); void sys_close(sys_file file); @@ -15,3 +17,5 @@ void sys_write(sys_file file, uint64_t offset, const void* buffer, uint32_t size // if ptr && !size => free // if ptr && size => realloc void* sys_realloc(void* ptr, size_t size); + +void sys_vstrncat(char* dst, size_t n, const char* format, ...); \ No newline at end of file diff --git a/pkg2zip_zip.c b/pkg2zip_zip.c index 8b1de1c..e543163 100644 --- a/pkg2zip_zip.c +++ b/pkg2zip_zip.c @@ -1,8 +1,6 @@ #if defined(__MINGW32__) && !defined(__x86_64__) # define _USE_32BIT_TIME_T # define __CRT__NO_INLINE -#elif defined(_MSC_VER) -# define _CRT_SECURE_NO_DEPRECATE #endif #include "pkg2zip_zip.h" @@ -102,7 +100,7 @@ void zip_create(zip* z, const char* name) void zip_add_folder(zip* z, const char* name) { - size_t name_length = strlen(name); + size_t name_length = strlen(name) + 1; if (name_length > ZIP_MAX_FILENAME) { fatal("ERROR: dirname too long\n"); @@ -131,7 +129,11 @@ void zip_add_folder(zip* z, const char* name) z->total += sizeof(header); sys_write(z->file, z->total, name, (uint16_t)name_length); - z->total += name_length; + z->total += name_length - 1; + + char slash = '/'; + sys_write(z->file, z->total, &slash, 1); + z->total += 1; } void zip_begin_file(zip* z, const char* name)