Update this shit.
This commit is contained in:
parent
8d0c3e84f2
commit
cc65edd617
8 changed files with 786 additions and 21 deletions
170
umodextract.c
Normal file
170
umodextract.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define UMOD_MAGIC 0x9FE3C5A3
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t sig, dir, size, ver, crc;
|
||||
} umodfoot_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *fname;
|
||||
uint32_t ofs, len, flags;
|
||||
} umoddir_t;
|
||||
|
||||
// CRC has to be done in this very specific way or shit will go wrong
|
||||
// I totally did not take this from leaked Unreal Engine source code
|
||||
|
||||
uint32_t crctable[256];
|
||||
|
||||
void crcinit( void )
|
||||
{
|
||||
for( uint32_t i=0; i<256; i++ ) for ( uint32_t c=(i<<24), j=8; j; j-- )
|
||||
crctable[i] = c = (c&0x80000000)?((c<<1)^0x04C11DB7):(c<<1);
|
||||
}
|
||||
|
||||
uint32_t crc( const void *s, size_t l, uint32_t crc )
|
||||
{
|
||||
uint8_t *d = (uint8_t*)s;
|
||||
crc = ~crc;
|
||||
for ( size_t i=0; i<l; i++ ) crc = (crc<<8)^crctable[(crc>>24)^d[i]];
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
// fuck you tim sweeney (or whoever else is responsible for this crime)
|
||||
int32_t readindex( FILE *f )
|
||||
{
|
||||
uint8_t byte[5] = {0};
|
||||
fread(&byte[0],1,1,f);
|
||||
if ( !byte[0] ) return 0;
|
||||
if ( byte[0]&0x40 )
|
||||
{
|
||||
for ( int i=1; i<5; i++ )
|
||||
{
|
||||
fread(&byte[i],1,1,f);
|
||||
if ( !(byte[i]&0x80) ) break;
|
||||
}
|
||||
}
|
||||
int32_t tf = byte[0]&0x3f;
|
||||
tf |= (int32_t)(byte[1]&0x7f)<<6;
|
||||
tf |= (int32_t)(byte[2]&0x7f)<<13;
|
||||
tf |= (int32_t)(byte[3]&0x7f)<<20;
|
||||
tf |= (int32_t)(byte[4]&0x7f)<<27;
|
||||
if ( byte[0]&0x80 ) tf *= -1;
|
||||
return tf;
|
||||
}
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
if ( argc < 2 )
|
||||
{
|
||||
fprintf(stderr,"usage: umodextract <umod file>\n");
|
||||
return 1;
|
||||
}
|
||||
FILE *f = fopen(argv[1],"rb");
|
||||
fseek(f,-20,SEEK_END);
|
||||
umodfoot_t feet;
|
||||
fread(&feet,1,20,f);
|
||||
if ( feet.sig != UMOD_MAGIC )
|
||||
{
|
||||
fclose(f);
|
||||
return 2;
|
||||
}
|
||||
//printf("sig: %08X\ndir: &%u\nsize: %u bytes\nver: %u\ncrc: %08X\n",
|
||||
// feet.sig,feet.dir,feet.size,feet.ver,feet.crc);
|
||||
// CRC verification
|
||||
void *dat = malloc(feet.size-20);
|
||||
fseek(f,0,SEEK_SET);
|
||||
fread(dat,1,feet.size-20,f);
|
||||
crcinit();
|
||||
uint32_t thiscrc = crc(dat,feet.size-20,0);
|
||||
free(dat);
|
||||
if ( thiscrc != feet.crc )
|
||||
{
|
||||
fprintf(stderr,"CRC mismatch! %08X != %08X\n",thiscrc,feet.crc);
|
||||
fclose(f);
|
||||
return 4;
|
||||
}
|
||||
fseek(f,feet.dir,SEEK_SET);
|
||||
int32_t ndir = readindex(f);
|
||||
//printf("ndir: %d\n",ndir);
|
||||
umoddir_t *dir = calloc(ndir,sizeof(umoddir_t));
|
||||
for ( int32_t i=0; i<ndir; i++ )
|
||||
{
|
||||
int32_t flen = readindex(f);
|
||||
dir[i].fname = malloc(flen);
|
||||
fread(dir[i].fname,1,flen,f);
|
||||
fread(&(dir[i].ofs),1,4,f);
|
||||
fread(&(dir[i].len),1,4,f);
|
||||
fread(&(dir[i].flags),1,4,f);
|
||||
//printf("fname: %.*s (%d)\nofs: &%u\nlen: %u\nflags: %08X\n",
|
||||
// flen,dir[i].fname,flen,dir[i].ofs,dir[i].len,dir[i].flags);
|
||||
long saved = ftell(f);
|
||||
fseek(f,dir[i].ofs,SEEK_SET);
|
||||
int isini = 0;
|
||||
if ( (isini=!!strstr(dir[i].fname,"Manifest.ini")) || !!strstr(dir[i].fname,"Manifest.int") )
|
||||
{
|
||||
printf("==== BEGIN Manifest.in%c ====\n\n",isini?'i':'t');
|
||||
uint8_t *str = malloc(dir[i].len);
|
||||
fread(str,1,dir[i].len,f);
|
||||
fwrite(str,1,dir[i].len,stdout);
|
||||
free(str);
|
||||
printf("\n==== END Manifest.in%c ====\n",isini?'i':'t');
|
||||
}
|
||||
else
|
||||
{
|
||||
char *rpath = dir[i].fname;
|
||||
if ( !strchr(rpath,'\\') )
|
||||
{
|
||||
FILE *fout = fopen(rpath,"wb");
|
||||
void *dat = malloc(dir[i].len);
|
||||
fread(dat,1,dir[i].len,f);
|
||||
fwrite(dat,1,dir[i].len,fout);
|
||||
free(dat);
|
||||
fclose(fout);
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE *fout;
|
||||
// subdivide folders
|
||||
char *nxt = 0;
|
||||
//int i = 0;
|
||||
do
|
||||
{
|
||||
nxt = strchr(rpath,'\\');
|
||||
if ( nxt )
|
||||
{
|
||||
*nxt = '\0';
|
||||
//printf("path%d: %s\n",i,rpath);
|
||||
mkdir(rpath,0755);
|
||||
*nxt = '/';
|
||||
rpath = nxt+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the file itself
|
||||
//printf("fout: %s\n",dir[i].fname);
|
||||
printf("==== EXTRACTING %s (%u bytes) ====\n",dir[i].fname,dir[i].len);
|
||||
fout = fopen(dir[i].fname,"wb");
|
||||
void *dat = malloc(dir[i].len);
|
||||
fread(dat,1,dir[i].len,f);
|
||||
fwrite(dat,1,dir[i].len,fout);
|
||||
free(dat);
|
||||
fclose(fout);
|
||||
}
|
||||
//i++;
|
||||
} while ( nxt );
|
||||
}
|
||||
}
|
||||
fseek(f,saved,SEEK_SET);
|
||||
}
|
||||
for ( int32_t i=0; i<ndir; i++ ) free(dir[i].fname);
|
||||
free(dir);
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue