203 lines
4.6 KiB
C
203 lines
4.6 KiB
C
// ___________ _________ _____ __
|
|
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
|
|
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
|
|
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
|
|
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
|
|
// \/ \/ \/ \/ \/
|
|
// ______________________ ______________________
|
|
// T H E W A R B E G I N S
|
|
// FreeCraft - A free fantasy real time strategy game engine
|
|
//
|
|
/*
|
|
** Utility for FreeCraft.
|
|
**
|
|
** extract.c - Extract gfx files.
|
|
**
|
|
** (c) Copyright 1998,2000 by Lutz Sammer
|
|
**
|
|
** $Id$
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#undef main
|
|
|
|
//
|
|
// Print debug information of level 0.
|
|
//
|
|
#define DebugLevel0(fmt...) printf(fmt##)
|
|
//
|
|
// Print debug information of level 1.
|
|
//
|
|
#define DebugLevel1(fmt...) printf(fmt##)/**/
|
|
//
|
|
// Print debug information of level 2.
|
|
//
|
|
#define DebugLevel2(fmt...) printf(fmt##)/**/
|
|
//
|
|
// Print debug information of level 3.
|
|
//
|
|
#define DebugLevel3(fmt...) /* ALWAYS TURNED OFF */
|
|
|
|
#define GetByte(p) (*((unsigned char*)(p)))
|
|
#define GetWord(p) (*((unsigned short*)(p)))
|
|
#define GetLong(p) (*((unsigned long*)(p)))
|
|
#define FetchByte(p) (*((unsigned char*)(p))++)
|
|
#define FetchWord(p) (*((unsigned short*)(p))++)
|
|
#define FetchLong(p) (*((unsigned long*)(p))++)
|
|
|
|
long* Offsets;
|
|
|
|
/*
|
|
** Extract entry.
|
|
*/
|
|
unsigned char* ExtractEntry(unsigned char* cp,int length,int* lenp)
|
|
{
|
|
int uncompressed_length;
|
|
int flags;
|
|
int bflags;
|
|
unsigned char buf[4096];
|
|
unsigned char* dest;
|
|
unsigned char* dp;
|
|
unsigned char* ep;
|
|
int bi;
|
|
int i;
|
|
int o;
|
|
int j;
|
|
|
|
DebugLevel3("%08X file length %d\n",cp,length);
|
|
ep=cp+length;
|
|
uncompressed_length=FetchLong(cp);
|
|
flags=uncompressed_length>>24;
|
|
uncompressed_length&=0xFFFFFF;
|
|
DebugLevel3("Entry length %d flags %02x\n",uncompressed_length,flags);
|
|
dp=dest=malloc(uncompressed_length);
|
|
if( !buf ) {
|
|
printf("Can't malloc %d\n",uncompressed_length);
|
|
exit(-1);
|
|
}
|
|
bi=0;
|
|
memset(buf,0,sizeof(buf));
|
|
|
|
if( flags==0x20 ) {
|
|
DebugLevel3("Compressed entry\n");
|
|
while( cp<ep ) {
|
|
bflags=FetchByte(cp);
|
|
DebugLevel3("Ctrl %02x ",bflags);
|
|
for( i=0; i<8; ++i ) {
|
|
if( bflags&1 ) {
|
|
j=FetchByte(cp);
|
|
*dp++=j;
|
|
buf[bi++&0xFFF]=j;
|
|
DebugLevel3("=%02x",j);
|
|
} else {
|
|
o=FetchWord(cp);
|
|
DebugLevel3("*%d,%d",o>>12,o&0xFFF);
|
|
j=(o>>12)+3;
|
|
o&=0xFFF;
|
|
while( j-- ) {
|
|
buf[bi++&0xFFF]=*dp++=buf[o++&0xFFF];
|
|
}
|
|
}
|
|
bflags>>=1;
|
|
}
|
|
DebugLevel3("\n");
|
|
}
|
|
} else {
|
|
DebugLevel3("Uncompressed entry\n");
|
|
memcpy(dp,cp,uncompressed_length);
|
|
}
|
|
*lenp=uncompressed_length;
|
|
return dest;
|
|
}
|
|
|
|
int ExtractFile(const char* file,int entry,const char* output)
|
|
{
|
|
int f;
|
|
struct stat stat_buf;
|
|
unsigned char* buf;
|
|
unsigned char* cp;
|
|
unsigned char* dp;
|
|
int len;
|
|
int entries;
|
|
int i;
|
|
|
|
f=open(file,O_RDONLY,0);
|
|
if( f==-1 ) {
|
|
printf("Can't open %s\n",file);
|
|
exit(-1);
|
|
}
|
|
if( fstat(f,&stat_buf) ) {
|
|
printf("Can't fstat %s\n",file);
|
|
exit(-1);
|
|
}
|
|
DebugLevel3("Filesize %d %dk\n",stat_buf.st_size,stat_buf.st_size/1024);
|
|
buf=malloc(stat_buf.st_size);
|
|
if( !buf ) {
|
|
printf("Can't malloc %ld\n",stat_buf.st_size);
|
|
exit(-1);
|
|
}
|
|
if( read(f,buf,stat_buf.st_size)!=stat_buf.st_size ) {
|
|
printf("Can't read %ld\n",stat_buf.st_size);
|
|
exit(-1);
|
|
}
|
|
close(f);
|
|
|
|
cp=buf;
|
|
i=FetchLong(cp);
|
|
DebugLevel3("Magic\t%08X\n",i);
|
|
entries=FetchWord(cp);
|
|
DebugLevel3("Entries\t%d\n",entries);
|
|
i=FetchWord(cp);
|
|
DebugLevel3("ID\t%d\n",i);
|
|
|
|
//
|
|
// Read offsets.
|
|
//
|
|
Offsets=malloc((entries+1)*sizeof(long));
|
|
if( !Offsets ) {
|
|
printf("Can't malloc %d\n",entries);
|
|
exit(-1);
|
|
}
|
|
for( i=0; i<entries; ++i ) {
|
|
Offsets[i]=FetchLong(cp);
|
|
DebugLevel3("Offset\t%d\n",Offsets[i]);
|
|
}
|
|
Offsets[i]=stat_buf.st_size;
|
|
|
|
dp=ExtractEntry(buf+Offsets[entry],Offsets[entry+1]-Offsets[entry],&len);
|
|
i=open(output,O_WRONLY|O_CREAT|O_TRUNC,0666);
|
|
if( i==-1 ) {
|
|
printf("Can't create output file %s\n",output);
|
|
exit(-1);
|
|
}
|
|
write(i,dp,len);
|
|
close(i);
|
|
free(dp);
|
|
|
|
free(Offsets);
|
|
free(buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc,char** argv)
|
|
{
|
|
int entry;
|
|
|
|
if( argc!=4 ) {
|
|
printf("Usage: %s file.war entry output\n",argv[0]);
|
|
exit(-1);
|
|
}
|
|
entry=atoi(argv[2]);
|
|
|
|
DebugLevel2("Extract %d \"%s\" -> \"%s\"\n",entry,argv[1],argv[3]);
|
|
ExtractFile(argv[1],entry,argv[3]);
|
|
|
|
return 0;
|
|
}
|