Unreal packages are a fucking mess ahahahahahaha.

I really should just merge together all the extractors for modern packages.
This commit is contained in:
Marisa the Magician 2019-12-12 20:16:57 +01:00
commit 71bca23b6e
4 changed files with 214 additions and 127 deletions

View file

@ -4,6 +4,12 @@
final formats final formats
fortunately this one is more third party tool friendly as you don't fortunately this one is more third party tool friendly as you don't
need to know the structure of all object types to read the data need to know the structure of all object types to read the data
known issues:
- SBase.utx from some versions (e.g. 0.874d) has some incongruencies
in its internal texture struct that I have yet to reverse engineer.
It's a feckin' mess, that's for sure. It's not even the same as
other version 25 packages.
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
@ -376,7 +382,8 @@ int main( int argc, char **argv )
fread(&objects[i].class,2,1,f); fread(&objects[i].class,2,1,f);
fread(&objects[i].flags,4,2,f); fread(&objects[i].flags,4,2,f);
if ( objects[i].headerofs != 0 ) fread(&objects[i].crc,4,4,f); if ( objects[i].headerofs != 0 ) fread(&objects[i].crc,4,4,f);
if ( !strcmp(names[objects[i].class-1].name,"Class") ) if ( (head.version >= 27)
&& !strcmp(names[objects[i].class-1].name,"Class") )
fseek(f,14,SEEK_CUR); // haven't figured this out yet fseek(f,14,SEEK_CUR); // haven't figured this out yet
} }
/*for ( int i=0; i<head.nnames; i++ ) /*for ( int i=0; i<head.nnames; i++ )

View file

@ -130,7 +130,7 @@ int32_t readimport( void )
{ {
readindex(); readindex();
readindex(); readindex();
if ( head->pkgver >= 60 ) fpos += 4; if ( head->pkgver >= 55 ) fpos += 4;
else readindex(); else readindex();
return readindex(); return readindex();
} }
@ -150,7 +150,7 @@ void readexport( int32_t *class, int32_t *ofs, int32_t *siz, int32_t *name )
{ {
*class = readindex(); *class = readindex();
readindex(); readindex();
if ( head->pkgver >= 60 ) fpos += 4; if ( head->pkgver >= 55 ) fpos += 4;
*name = readindex(); *name = readindex();
fpos += 4; fpos += 4;
*siz = readindex(); *siz = readindex();
@ -280,12 +280,72 @@ int main( int argc, char **argv )
// begin reading data // begin reading data
size_t prev = fpos; size_t prev = fpos;
fpos = ofs; fpos = ofs;
if ( head->pkgver < 40 ) fpos += 8; if ( head->pkgver < 45 ) fpos += 4;
if ( head->pkgver < 60 ) fpos += 16; if ( head->pkgver < 55 ) fpos += 16;
if ( head->pkgver <= 44 ) fpos -= 6; // ???
if ( head->pkgver == 45 ) fpos -= 2; // ???
if ( head->pkgver <= 35 ) fpos += 8; // ???
// process properties
int32_t prop = readindex(); int32_t prop = readindex();
if ( prop >= head->nnames ) continue; if ( (uint32_t)prop >= head->nnames )
{
printf("Unknown property %d, skipping\n",prop);
fpos = prev;
continue;
}
char *pname = pkgfile+getname(prop,&l); char *pname = pkgfile+getname(prop,&l);
if ( strncasecmp(pname,"none",l) ) continue; retry:
if ( strncasecmp(pname,"None",l) )
{
uint8_t info = readbyte();
int array = info&0x80;
int type = info&0xf;
int psiz = (info>>4)&0x7;
switch ( psiz )
{
case 0:
psiz = 1;
break;
case 1:
psiz = 2;
break;
case 2:
psiz = 4;
break;
case 3:
psiz = 12;
break;
case 4:
psiz = 16;
break;
case 5:
psiz = readbyte();
break;
case 6:
psiz = readword();
break;
case 7:
psiz = readdword();
break;
}
//printf(" prop %.*s (%u, %u, %u, %u)\n",l,pname,array,type,(info>>4)&7,psiz);
if ( array && (type != 3) )
{
int idx = readindex();
//printf(" index: %d\n",idx);
}
if ( type == 10 )
{
int32_t tl, sn;
sn = readindex();
char *sname = (char*)(pkgfile+getname(sn,&tl));
//printf(" struct: %.*s\n",tl,sname);
}
fpos += psiz;
prop = readindex();
pname = (char*)(pkgfile+getname(prop,&l));
goto retry;
}
int32_t ext; int32_t ext;
if ( head->pkgver >= 120 ) if ( head->pkgver >= 120 )
{ {

View file

@ -171,7 +171,7 @@ void readimport2( int32_t *cpkg, int32_t *cname, int32_t *pkg, int32_t *name )
*cpkg = readindex(); *cpkg = readindex();
*cname = readindex(); *cname = readindex();
if ( head->pkgver >= 55 ) *pkg = readdword(); if ( head->pkgver >= 55 ) *pkg = readdword();
else *pkg = readindex(); else *pkg = 0;
*name = readindex(); *name = readindex();
} }
@ -214,7 +214,7 @@ void readexport2( int32_t *class, int32_t *super, int32_t *pkg, int32_t *name,
*class = readindex(); *class = readindex();
*super = readindex(); *super = readindex();
if ( head->pkgver >= 55 ) *pkg = readdword(); if ( head->pkgver >= 55 ) *pkg = readdword();
else *pkg = readindex(); else *pkg = 0;
*name = readindex(); *name = readindex();
*flags = readdword(); *flags = readdword();
*siz = readindex(); *siz = readindex();
@ -231,37 +231,31 @@ void getexport2( int index, int32_t *class, int32_t *super, int32_t *pkg,
fpos = prev; fpos = prev;
} }
void savesound( int32_t namelen, char *name, int version ) void savesound( int32_t namelen, char *name, int version, int32_t grouplen, char *group )
{ {
char fname[256] = {0};
int32_t fmt = readindex(); // not really needed, always assume wav int32_t fmt = readindex(); // not really needed, always assume wav
int32_t grp, grouplen; // in some versions it's the group, though
char *group; if ( version <= 35 )
if ( version > 35 )
{ {
// ???? int32_t grp = readindex();
readindex();
readindex();
grp = readindex();
grouplen = 0;
group = (char*)(pkgfile+getname(grp,&grouplen));
// ????
readindex();
}
else
{
grp = readindex();
grouplen = 0;
group = (char*)(pkgfile+getname(grp,&grouplen)); group = (char*)(pkgfile+getname(grp,&grouplen));
readindex(); // unknown readindex(); // unknown
} }
else if ( version < 55 )
group = (char*)(pkgfile+getname(fmt,&grouplen));
uint32_t ofsnext = 0; uint32_t ofsnext = 0;
if ( version >= 63 ) ofsnext = readdword(); // not needed but gotta read if ( version >= 63 ) ofsnext = readdword(); // not needed but gotta read
// the actual important info starts now // the actual important info starts now
int32_t sndsize = readindex(); int32_t sndsize = readindex();
char *snddata = (char*)(pkgfile+fpos); char *snddata = (char*)(pkgfile+fpos);
if ( strncmp(group,"None",grouplen) ) snprintf(fname,256,"%.*s.%.*s.wav",grouplen,group,namelen,name); char fname[256];
else snprintf(fname,256,"%.*s.wav",namelen,name); if ( group && strncmp(group,"None",grouplen) )
{
snprintf(fname,256,"Sounds/%.*s",grouplen,group);
mkdir(fname,0775);
snprintf(fname,256,"Sounds/%.*s/%.*s.wav",grouplen,group,namelen,name);
}
else snprintf(fname,256,"Sounds/%.*s.wav",namelen,name);
FILE *f = fopen(fname,"wb"); FILE *f = fopen(fname,"wb");
fwrite(snddata,sndsize,1,f); fwrite(snddata,sndsize,1,f);
fclose(f); fclose(f);
@ -318,8 +312,8 @@ int main( int argc, char **argv )
fpos = head->oexports; fpos = head->oexports;
for ( uint32_t i=0; i<head->nexports; i++ ) for ( uint32_t i=0; i<head->nexports; i++ )
{ {
int32_t class, ofs, siz, name; int32_t class, super, pkg, name, flags, siz, ofs;
readexport(&class,&ofs,&siz,&name); readexport2(&class,&super,&pkg,&name,&flags,&siz,&ofs);
if ( (siz <= 0) || (class >= 0) ) continue; if ( (siz <= 0) || (class >= 0) ) continue;
// get the class name // get the class name
class = -class-1; class = -class-1;
@ -328,8 +322,21 @@ int main( int argc, char **argv )
char *n = (char*)(pkgfile+getname(getimport(class),&l)); char *n = (char*)(pkgfile+getname(getimport(class),&l));
int ismesh = !strncmp(n,"Sound",l); int ismesh = !strncmp(n,"Sound",l);
if ( !ismesh ) continue; if ( !ismesh ) continue;
mkdir("Sounds",0775);
// get the highest group name (must be an export)
char *pkgn = 0;
int32_t pkgl = 0;
while ( pkg > 0 )
{
int32_t pclass, psuper, ppkg, pname, pflags, psiz, pofs;
getexport2(pkg-1,&pclass,&psuper,&ppkg,&pname,&pflags,&psiz,&pofs);
pkgn = (char*)(pkgfile+getname(pname,&pkgl));
pkg = ppkg;
}
char *snd = (char*)(pkgfile+getname(name,&l)); char *snd = (char*)(pkgfile+getname(name,&l));
printf("Sound found: %.*s\n",l,snd); if ( pkgn && strncmp(pkgn,"None",pkgl) )
printf("Sound found: %.*s.%.*s\n",pkgl,pkgn,l,snd);
else printf("Sound found: %.*s\n",l,snd);
int32_t sndl = l; int32_t sndl = l;
#ifdef _DEBUG #ifdef _DEBUG
char fname[256] = {0}; char fname[256] = {0};
@ -346,10 +353,8 @@ int main( int argc, char **argv )
if ( head->pkgver < 45 ) fpos += 4; if ( head->pkgver < 45 ) fpos += 4;
if ( head->pkgver < 55 ) fpos += 16; if ( head->pkgver < 55 ) fpos += 16;
if ( head->pkgver <= 44 ) fpos -= 6; // ??? if ( head->pkgver <= 44 ) fpos -= 6; // ???
if ( head->pkgver == 45 ) fpos -= 2; // ???
if ( head->pkgver <= 35 ) fpos += 8; // ??? if ( head->pkgver <= 35 ) fpos += 8; // ???
// only very old packages have properties for sound classes
if ( head->pkgver > 35 )
goto noprop;
// process properties // process properties
int32_t prop = readindex(); int32_t prop = readindex();
if ( (uint32_t)prop >= head->nnames ) if ( (uint32_t)prop >= head->nnames )
@ -393,26 +398,25 @@ retry:
psiz = readdword(); psiz = readdword();
break; break;
} }
printf(" prop %.*s (%u, %u, %u, %u)\n",l,pname,array,type,(info>>4)&7,psiz); //printf(" prop %.*s (%u, %u, %u, %u)\n",l,pname,array,type,(info>>4)&7,psiz);
if ( array && (type != 3) ) if ( array && (type != 3) )
{ {
int idx = readindex(); int idx = readindex();
printf(" index: %d\n",idx); //printf(" index: %d\n",idx);
} }
if ( type == 10 ) if ( type == 10 )
{ {
int32_t tl, sn; int32_t tl, sn;
sn = readindex(); sn = readindex();
char *sname = (char*)(pkgfile+getname(sn,&tl)); char *sname = (char*)(pkgfile+getname(sn,&tl));
printf(" struct: %.*s\n",tl,sname); //printf(" struct: %.*s\n",tl,sname);
} }
fpos += psiz; fpos += psiz;
prop = readindex(); prop = readindex();
pname = (char*)(pkgfile+getname(prop,&l)); pname = (char*)(pkgfile+getname(prop,&l));
goto retry; goto retry;
} }
noprop: savesound(sndl,snd,head->pkgver,pkgl,pkgn);
savesound(sndl,snd,head->pkgver);
fpos = prev; fpos = prev;
} }
free(pkgfile); free(pkgfile);

View file

@ -215,7 +215,7 @@ void readexport2( int32_t *class, int32_t *super, int32_t *pkg, int32_t *name,
*class = readindex(); *class = readindex();
*super = readindex(); *super = readindex();
if ( head->pkgver >= 55 ) *pkg = readdword(); if ( head->pkgver >= 55 ) *pkg = readdword();
else *pkg = readindex(); else *pkg = 0;
*name = readindex(); *name = readindex();
*flags = readdword(); *flags = readdword();
*siz = readindex(); *siz = readindex();
@ -296,104 +296,99 @@ typedef struct
void readpalette( uint32_t pal, int32_t *num, color_t **col ) void readpalette( uint32_t pal, int32_t *num, color_t **col )
{ {
size_t prev = fpos; size_t prev = fpos;
fpos = head->oexports; int32_t class, ofs, siz, name;
for ( uint32_t i=0; i<head->nexports; i++ ) getexport(pal-1,&class,&ofs,&siz,&name);
int32_t l = 0;
char *n = (char*)(pkgfile+getname(name,&l));
// begin reading data
fpos = ofs;
if ( head->pkgver < 45 ) fpos += 4;
if ( head->pkgver < 55 ) fpos += 16;
if ( head->pkgver <= 44 ) fpos -= 6; // ???
if ( head->pkgver == 45 ) fpos -= 2; // ???
if ( head->pkgver <= 35 ) fpos += 8; // ???
// process properties
int32_t prop = readindex();
if ( (uint32_t)prop >= head->nnames )
{ {
int32_t class, ofs, siz, name; printf("Unknown property %d, skipping\n",prop);
readexport(&class,&ofs,&siz,&name);
if ( i != pal-1 ) continue;
int32_t l = 0;
char *n = (char*)(pkgfile+getname(name,&l));
// begin reading data
fpos = ofs;
if ( head->pkgver < 45 ) fpos += 4;
if ( head->pkgver < 55 ) fpos += 16;
if ( head->pkgver <= 44 ) fpos -= 6; // ???
if ( head->pkgver <= 35 ) fpos += 8; // ???
// process properties
int32_t prop = readindex();
if ( (uint32_t)prop >= head->nnames )
{
printf("Unknown property %d, skipping\n",prop);
fpos = prev;
return;
}
char *pname = (char*)(pkgfile+getname(prop,&l));
retrypal:
if ( strncasecmp(pname,"none",l) )
{
uint8_t info = readbyte();
int array = info&0x80;
int type = info&0xf;
int psiz = (info>>4)&0x7;
switch ( psiz )
{
case 0:
psiz = 1;
break;
case 1:
psiz = 2;
break;
case 2:
psiz = 4;
break;
case 3:
psiz = 12;
break;
case 4:
psiz = 16;
break;
case 5:
psiz = readbyte();
break;
case 6:
psiz = readword();
break;
case 7:
psiz = readdword();
break;
}
if ( type == 10 )
readindex(); // skip struct name
fpos += psiz;
prop = readindex();
pname = (char*)(pkgfile+getname(prop,&l));
goto retrypal;
}
if ( (head->pkgver <= 56) )
{
// group?
fpos++;
readindex();
}
*num = readindex();
printf(" palette: %u colors\n",*num);
*col = calloc(sizeof(color_t),*num);
memcpy(*col,pkgfile+fpos,*num*sizeof(color_t));
fpos = prev; fpos = prev;
return; return;
} }
char *pname = (char*)(pkgfile+getname(prop,&l));
retrypal:
if ( strncasecmp(pname,"none",l) )
{
uint8_t info = readbyte();
int array = info&0x80;
int type = info&0xf;
int psiz = (info>>4)&0x7;
switch ( psiz )
{
case 0:
psiz = 1;
break;
case 1:
psiz = 2;
break;
case 2:
psiz = 4;
break;
case 3:
psiz = 12;
break;
case 4:
psiz = 16;
break;
case 5:
psiz = readbyte();
break;
case 6:
psiz = readword();
break;
case 7:
psiz = readdword();
break;
}
if ( type == 10 )
readindex(); // skip struct name
fpos += psiz;
prop = readindex();
pname = (char*)(pkgfile+getname(prop,&l));
goto retrypal;
}
if ( head->pkgver < 55 )
{
// group
fpos++;
readindex();
}
*num = readindex();
//printf(" palette: %u colors\n",*num);
*col = calloc(sizeof(color_t),*num);
memcpy(*col,pkgfile+fpos,*num*sizeof(color_t));
fpos = prev; fpos = prev;
} }
void savetexture( int32_t namelen, char *name, int32_t pal, int masked, void savetexture( int32_t namelen, char *name, int32_t pal, int masked,
int version ) int version, int32_t grouplen, char *group )
{ {
uint32_t ncolors = 256; uint32_t ncolors = 256;
color_t *paldata = 0; color_t *paldata = 0;
readpalette(pal,&ncolors,&paldata); readpalette(pal,&ncolors,&paldata);
if ( version <= 56 ) if ( version < 55 )
{ {
// group? // group
fpos++; fpos++;
readindex(); int32_t grp = readindex();
group = (char*)(pkgfile+getname(grp,&grouplen));
} }
uint32_t mipcnt = readbyte(); uint32_t mipcnt = readbyte();
printf(" %u mips\n",mipcnt); //printf(" %u mips\n",mipcnt);
uint32_t ofs = 0; uint32_t ofs = 0;
if ( version >= 63 ) ofs = readdword(); if ( version >= 63 ) ofs = readdword();
uint32_t datasiz = readindex(); uint32_t datasiz = readindex();
printf(" %u size\n",datasiz); //printf(" %u size\n",datasiz);
uint8_t *imgdata = malloc(datasiz); uint8_t *imgdata = malloc(datasiz);
memcpy(imgdata,pkgfile+fpos,datasiz); memcpy(imgdata,pkgfile+fpos,datasiz);
imgdata = malloc(datasiz); imgdata = malloc(datasiz);
@ -424,7 +419,14 @@ void savetexture( int32_t namelen, char *name, int32_t pal, int masked,
} }
} }
char fname[256]; char fname[256];
snprintf(fname,256,"%.*s.png",namelen,name); if ( group && strncmp(group,"None",grouplen) )
{
snprintf(fname,256,"Textures/%.*s",grouplen,group);
mkdir(fname,0775);
snprintf(fname,256,"Textures/%.*s/%.*s.png",grouplen,group,
namelen,name);
}
else snprintf(fname,256,"Textures/%.*s.png",namelen,name);
writepng(fname,imgdata,w,h,fpal,ncolors,masked); writepng(fname,imgdata,w,h,fpal,ncolors,masked);
} }
@ -473,8 +475,8 @@ int main( int argc, char **argv )
fpos = head->oexports; fpos = head->oexports;
for ( uint32_t i=0; i<head->nexports; i++ ) for ( uint32_t i=0; i<head->nexports; i++ )
{ {
int32_t class, ofs, siz, name; int32_t class, super, pkg, name, flags, siz, ofs;
readexport(&class,&ofs,&siz,&name); readexport2(&class,&super,&pkg,&name,&flags,&siz,&ofs);
if ( (siz <= 0) || (class >= 0) ) continue; if ( (siz <= 0) || (class >= 0) ) continue;
// get the class name // get the class name
class = -class-1; class = -class-1;
@ -483,8 +485,21 @@ int main( int argc, char **argv )
char *n = (char*)(pkgfile+getname(getimport(class),&l)); char *n = (char*)(pkgfile+getname(getimport(class),&l));
int istex = !strncasecmp(n,"Texture",l); int istex = !strncasecmp(n,"Texture",l);
if ( !istex ) continue; if ( !istex ) continue;
mkdir("Textures",0775);
// get the highest group name (must be an export)
char *pkgn = 0;
int32_t pkgl = 0;
while ( pkg > 0 )
{
int32_t pclass, psuper, ppkg, pname, pflags, psiz, pofs;
getexport2(pkg-1,&pclass,&psuper,&ppkg,&pname,&pflags,&psiz,&pofs);
pkgn = (char*)(pkgfile+getname(pname,&pkgl));
pkg = ppkg;
}
char *tex = (char*)(pkgfile+getname(name,&l)); char *tex = (char*)(pkgfile+getname(name,&l));
printf("Texture found: %.*s\n",l,tex); if ( pkgn && strncmp(pkgn,"None",pkgl) )
printf("Texture found: %.*s.%.*s\n",pkgl,pkgn,l,tex);
else printf("Texture found: %.*s\n",l,tex);
int32_t texl = l; int32_t texl = l;
#ifdef _DEBUG #ifdef _DEBUG
char fname[256] = {0}; char fname[256] = {0};
@ -501,6 +516,7 @@ int main( int argc, char **argv )
if ( head->pkgver < 45 ) fpos += 4; if ( head->pkgver < 45 ) fpos += 4;
if ( head->pkgver < 55 ) fpos += 16; if ( head->pkgver < 55 ) fpos += 16;
if ( head->pkgver <= 44 ) fpos -= 6; // ??? if ( head->pkgver <= 44 ) fpos -= 6; // ???
if ( head->pkgver == 45 ) fpos -= 2; // ???
if ( head->pkgver <= 35 ) fpos += 8; // ??? if ( head->pkgver <= 35 ) fpos += 8; // ???
// process properties // process properties
int32_t prop = readindex(); int32_t prop = readindex();
@ -555,7 +571,7 @@ retry:
} }
if ( !strncasecmp(pname,"Palette",l) ) if ( !strncasecmp(pname,"Palette",l) )
pal = readindex(); pal = readindex();
if ( !strncasecmp(pname,"bMasked",l) ) else if ( !strncasecmp(pname,"bMasked",l) )
masked = array; masked = array;
else else
{ {
@ -563,7 +579,7 @@ retry:
{ {
int32_t tl, sn; int32_t tl, sn;
sn = readindex(); sn = readindex();
//char *sname = (char*)(pkgfile+getname(sn,&tl)); char *sname = (char*)(pkgfile+getname(sn,&tl));
//printf(" struct: %.*s\n",tl,sname); //printf(" struct: %.*s\n",tl,sname);
} }
fpos += psiz; fpos += psiz;
@ -572,8 +588,8 @@ retry:
pname = (char*)(pkgfile+getname(prop,&l)); pname = (char*)(pkgfile+getname(prop,&l));
goto retry; goto retry;
} }
if ( !pal ) continue; if ( pal )
savetexture(texl,tex,pal,masked,head->pkgver); savetexture(texl,tex,pal,masked,head->pkgver,pkgl,pkgn);
fpos = prev; fpos = prev;
} }
free(pkgfile); free(pkgfile);