Skip to content

Instantly share code, notes, and snippets.

@kikuchan
Created July 29, 2012 05:02
Show Gist options
  • Save kikuchan/3196179 to your computer and use it in GitHub Desktop.
Save kikuchan/3196179 to your computer and use it in GitHub Desktop.
unpacker for multi game scripter
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
uint8_t read_uint8(FILE *fp)
{
int ch = fgetc(fp);
uint8_t ret = 0;
if (ch == EOF) return 0; /* XXX */
return ch ^ 'R';
}
uint16_t read_uint16(FILE *fp)
{
uint16_t ret = 0;
ret |= read_uint8(fp) << 0;
ret |= read_uint8(fp) << 8;
}
uint32_t read_uint32(FILE *fp)
{
uint32_t ret = 0;
ret |= read_uint8(fp) << 0;
ret |= read_uint8(fp) << 8;
ret |= read_uint8(fp) << 16;
ret |= read_uint8(fp) << 24;
return ret;
}
size_t read_block(FILE *fp, char *buf, size_t len)
{
int i;
for (i = 0; i < len; i++) {
buf[i] = read_uint8(fp);
if (feof(fp)) break;
}
return len;
}
char *progname = "mgs-unpack";
void usage()
{
fprintf(stderr, "Usage: %s <l|x> <filename>\n", progname);
exit(0);
}
struct _pack_dirent {
uint32_t len;
char filename[16];
} *entries;
int main(int argc, char *argv[])
{
FILE *fp = stdin;
unsigned short num = 0;
int i;
int flag_extract = 0;
progname = argv[0];
if (argc < 3) {
usage();
}
if (!strcmp(argv[1], "l")) {
} else if (!strcmp(argv[1], "x")) {
flag_extract = 1;
} else {
usage();
}
if (!!strcmp(argv[2], "-")) fp = fopen(argv[2], "rb");
if (fp == NULL) {
fprintf(stderr, "Can't open the file; %s\n", argv[2]);
return -1;
}
num = read_uint16(fp);
if (num == (0x5a4d ^ 0x5252)) {
fseek(fp, 217792, SEEK_SET);
num = read_uint16(fp);
}
printf("Entries; %d\n", num);
if (num > 0x100) {
fprintf(stderr, "Too many file? num = %d\n", num);
exit(0);
}
entries = malloc(sizeof(struct _pack_dirent) * num);
if (entries == NULL) {
perror("malloc");
exit(0);
}
for (i = 0; i < num; i++) {
struct _pack_dirent *ent = &entries[i];
ent->len = read_uint32(fp);
read_block(fp, ent->filename, 16);
printf("%-16s %d bytes\n", ent->filename, ent->len);
}
if (!flag_extract) return 0;
for (i = 0; i < num; i++) {
struct _pack_dirent *ent = &entries[i];
uint32_t remain = ent->len;
char buf[1024];
FILE *fpw;
fpw = fopen(ent->filename, "w+b");
if (fpw == NULL) {
fprintf(stderr, "Can't open the file for writing\n");
return -1;
}
while (remain > 0) {
int reqlen = remain < sizeof(buf) ? remain : sizeof(buf);
int len = read_block(fp, buf, reqlen);
if (len < reqlen) {
fprintf(stderr, "Premature EOF is detected\n");
return -1;
}
fwrite(buf, 1, len, fpw);
remain -= reqlen;
}
fclose(fpw);
}
if (fp != stdin) fclose(fp);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment