elbereth / DragonUnPACKer

Free/Open source game file resource explorer/unpacking tool made easy!
https://www.elberethzone.net/dragon-unpacker.html
179 stars 21 forks source link

FPK Archives #117

Open elbereth opened 15 years ago

elbereth commented 15 years ago

Here are some files from FPK archives used in wii games I have extracted the files but I can not decompress them. Here is a quickbms script I wrote to extract them.

get IDSTRING long endian BIG get FILES long get NULL long get ARCSIZE long endian little for i = 0 < files getdstring NAME 0x24 endian BIG get OFFSET long get ZSIZE long get SIZE long endian little log NAME OFFSET ZSIZE

comtype lzss

clog NAME OFFSET ZSIZE SIZE

next i

can anyone help with this I believe the compression is some kind of lzss or lz77 here are some extracted and unextracted sample files. http://www.MegaShare.com/994561

Reported by: chrrox

elbereth commented 15 years ago

I found some documentation on LZSS http://www.zophar.net/wwwthreads/attachment.php?Cat=&Board=romhack&Post=254983 I am trying to work on this for these files.

Original comment by: chrrox

elbereth commented 15 years ago

Is it possible for you to add this compression format to your packer / unpacker? some nice people at xentax have figured out the format but the tool is not the friendliest thing to use. This format is used bye all games made with the company 8ing. Here is the code

include

include

include

include

include

include <sys/stat.h>

include

typedef unsigned int u32; typedef unsigned short u16; typedef unsigned char u8;

int endian=1;

u32 BE32(u32 data) { if(endian) return ( (data<<24) | ((data<<8)&0x00ff0000) | ((data>>8)&0x0000ff00) | (data>>24) ); else return data; }

int blen; int fbuf;

/* PRS get bit form lsb to msb, FPK get it form msb to lsb / int get_bits(int n, char sbuf, int *sptr) { int retv;

retv = 0; while(n){ retv <<= 1; if(blen==0){ fbuf = sbuf[_sptr]; //if(_sptr<256) //{ printf("[%02x] ", fbuf&0xff); fflush(0); } (*sptr)++; blen = 8; }

  if(fbuf&0x80)
     retv |= 1;

  fbuf <<= 1;
  blen --;
  n --;

}

return retv; }

int uncomp(char dbuf, int dlen, char sbuf, int slen) { int sptr; int dptr; int i, flag, len, pos;

blen = 0;

sptr = 0; dptr = 0; while(sptr<slen){ flag = get_bits(1, sbuf, &sptr); if(flag==1){ //if(sptr<256) //{ printf("%02x ", (u8)sbuf[sptr]); fflush(0); } if(dptr<dlen) dbuf[dptr++] = sbuf[sptr++]; }else{ flag = get_bits(1, sbuf, &sptr); if(flag==0){ len = get_bits(2, sbuf, &sptr)+2; pos = sbuf[sptr++]|0xffffff00; }else{ pos = (sbuf[sptr++]<<8)|0xffff0000; pos |= sbuf[sptr++]&0xff; len = pos&0x07; pos >>= 3; if(len==0){ len = (sbuf[sptr++]&0xff)+1; }else{ len += 2; } } //if(sptr<256) //{ printf("<%08x(%08x): %08x %d> \n", dptr, dlen, pos, len); fflush(0); } pos += dptr; for(i=0; i<len; i++){ if(dptr<dlen) dbuf[dptr++] = dbuf[pos++]; } } }

return dptr; }

void mkdir_p(char dname) { char name[256]; char p, *cp;

strcpy(name, dname);

cp = name; while(1){ p = strchr(cp, '/'); if(p==NULL) p = strchr(cp, '\'); if(p==NULL) break;

  *p = 0;
  //mkdir(name, 0777);
  mkdir(name);
  *p = '/';
  cp = p+1;

}; }

int process_file(char infname) { FILE fp, outfp; char fname, dptr, buf, dbuf; int i, fcnt, flen, dlen, offset; char dname[256], tname[256], p;

p = strchr(infname, '.'); if(p==NULL) return -1; if(strcmp(p+1, "fpk")) return -1;

printf("process file %s ...\n", infname);

/* Open fpk file */ fp = fopen(infname, "rb"); if(fp==NULL){ printf("Can't open %s!\n", infname); return -1; }

/* Make directory / strcpy(dname, infname); p = strchr(dname, '.'); if(p) p = '_'; //mkdir(dname, 0777); mkdir(dname);

fseek(fp, 0, SEEK_END); flen = ftell(fp); fseek(fp, 0, SEEK_SET);

buf = (char*)malloc(flen); fread(buf, flen, 1, fp); fclose(fp);

if((short)(buf+0)==0){ endian = 1; }else{ endian = 0; }

fcnt = BE32((int)(buf+4)); for(i=0; i<fcnt; i++){ dptr = buf+0x10+i0x30; fname = dptr; flen = BE32((int)(dptr+0x28)); offset = BE32((int)(dptr+0x24)); dlen = BE32((int*)(dptr+0x2c)); printf("offset: %08x flen: %08x length: %08x file: %s\n", offset, flen, dlen, fname);

  dbuf = malloc(dlen+256);
  uncomp(dbuf, dlen, buf+offset, flen);

  sprintf(tname, "%s/%s", dname, fname);
  mkdir_p(tname);

  outfp = fopen(tname, "wb");
  if(outfp==NULL){
     printf("Can't open output file %s !\n", tname);
  }else{
     fwrite(dbuf, dlen, 1, outfp);
     fclose(outfp);
  }
  free(dbuf);

}

free(buf); return 0; }

////////////////////////////////////////////////////////////////////////////

int process_dir(char dname) { DIR pdir; struct dirent *d; struct stat statbuf; char fname[256]; int i, ndir;

/* process file */ memset(&statbuf, 0, sizeof(statbuf)); stat(dname, &statbuf); if((statbuf.st_mode&S_IFMT) != S_IFDIR){ return process_file(dname); }

/* open directory */ pdir = opendir(dname); if(pdir==NULL){ printf("Can't open directory <%s>\n", dname); return -1; }

/* get number of files in dircetory _/ ndir = 0; while((d=readdir(pdir))){ ndir++; } d = malloc(sizeof(struct dirent)_ndir);

/* read dirent first */ rewinddir(pdir); for(i=0; i<ndir; i++){ memcpy(&d[i], readdir(pdir), sizeof(struct dirent)); }

/* process each files */ printf("Enter directory <%s> ...\n", dname); for(i=0; i<ndir; i++){ if( d[i].d_name[0]=='.' &&( d[i].d_name[1] =='\0' || (d[i].d_name[1] == '.' && d[i].d_name[2] == '\0') )) continue;

  if(dname[0]=='.'){
     sprintf(fname, "%s", d[i].d_name);
  }else{
     sprintf(fname, "%s/%s", dname, d[i].d_name);
  }
  process_dir(fname);

} printf("Leave directory <%s> ...\n", dname);

free(d); closedir(pdir); return 0; }

int main(int argc, char *argv[]) { if(argc==1){ return process_dir("."); }else{ return process_dir(argv[1]); }

Original comment by: chrrox

elbereth commented 15 years ago

Nice. I will try to add support for those FPK and compression format. I need to translate the code to Delphi (which is not always easy). Can you tell me exactly how I can retrieve a FPK file for testing?

Original comment by: elbereth

elbereth commented 15 years ago

Here are some files http://www.MegaShare.com/994561 if you need some more just let me know. these are found in a lot of games made bye the company 8ing and there is a slight variant of this used in a lot of sega games.

Original comment by: chrrox