Created
December 29, 2018 16:13
-
-
Save simontime/9ba59ab1045f204519643666a2f8b56e to your computer and use it in GitHub Desktop.
Monster Hunter Generations Ultimate ARC extractor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _CRT_SECURE_NO_WARNINGS | |
#define ZLIB_WINAPI | |
#include <direct.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/stat.h> | |
#include <zlib.h> | |
#define BUFFERSIZE 0x10000000 | |
typedef struct { | |
char magic[4]; | |
short unk1; | |
short count; | |
int unk2; | |
} header; | |
typedef struct { | |
char name[0x40]; | |
int unk1; | |
int size; | |
int unk2; | |
int offset; | |
} fileEntry; | |
// Source: https://stackoverflow.com/questions/4901842/in-memory-decompression-with-zlib | |
int decompress(const void *src, int srcLen, void *dst, int dstLen) { | |
z_stream strm = { 0 }; | |
strm.total_in = strm.avail_in = srcLen; | |
strm.total_out = strm.avail_out = dstLen; | |
strm.next_in = (Bytef *)src; | |
strm.next_out = (Bytef *)dst; | |
strm.zalloc = Z_NULL; | |
strm.zfree = Z_NULL; | |
strm.opaque = Z_NULL; | |
int err = -1; | |
int ret = -1; | |
err = inflateInit2(&strm, (15 + 32)); | |
if (err == Z_OK) { | |
err = inflate(&strm, Z_FINISH); | |
if (err == Z_STREAM_END) { | |
ret = strm.total_out; | |
} | |
else { | |
inflateEnd(&strm); | |
return err; | |
} | |
} | |
else { | |
inflateEnd(&strm); | |
return err; | |
} | |
inflateEnd(&strm); | |
return ret; | |
} | |
int rmakedir(const char *dir) { | |
char tmp[256]; | |
char *p = NULL; | |
struct stat sb; | |
size_t len = strnlen(dir, 256); | |
memcpy(tmp, dir, len); | |
tmp[len] = '\0'; | |
if (tmp[len - 1] == '\\') | |
tmp[len - 1] = '\0'; | |
for (p = tmp + 1; *p; p++) { | |
if (*p == '\\') { | |
*p = 0; | |
if (stat(tmp, &sb)) | |
if (_mkdir(tmp) < 0) | |
return -1; | |
*p = '\\'; | |
} | |
} | |
if (stat(tmp, &sb)) | |
if (_mkdir(tmp) < 0) | |
return -1; | |
return 0; | |
} | |
int main(int argc, char **argv) { | |
if (argc != 2) { | |
fprintf(stderr, "Usage: %s file.arc", argv[0]); | |
return 1; | |
} | |
FILE *in = fopen(argv[1], "rb"); | |
header hdr; | |
fread(&hdr, sizeof(hdr), 1, in); | |
fileEntry *entries = malloc(sizeof(fileEntry) * hdr.count); | |
fread(entries, sizeof(fileEntry), hdr.count, in); | |
for (int i = 0; i < hdr.count; i++) { | |
char *name = calloc(0x40, 1), | |
*dirname = calloc(0x40, 1); | |
strcpy(name, entries[i].name); | |
char *fnm = strrchr(name, '\\'); | |
if (fnm) { | |
strncpy(dirname, name, (int)(fnm - name)); | |
rmakedir(dirname); | |
} | |
printf("Saving %s...\n", name); | |
FILE *out = fopen(name, "wb"); | |
char *buf = malloc(entries[i].size), | |
*comp = malloc(BUFFERSIZE); | |
fseek(in, entries[i].offset, 0); | |
fread(buf, 1, entries[i].size, in); | |
int sz = decompress(buf, entries[i].size, comp, BUFFERSIZE); | |
fwrite(comp, 1, sz, out); | |
fclose(out); | |
free(buf); | |
free(comp); | |
} | |
puts("\nDone!"); | |
fclose(in); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment