omega-rpg/tools/decrypt.c

181 lines
4.4 KiB
C

/* WDT: todo later: move this into the Omega source, probably changing both
* encode and decode into command line options to omega itself. Oh, and
* change the name from 'crypt' to 'pack'. */
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <assert.h>
#define VERSION 2
#define HEADER_SIZE 3
#define ITEM_SIZE 9
/* These _must_ match the equivalent values in Omega, and if they
* change, I need to define a new version. */
#define MAXWIDTH 128
#define MAXLENGTH 64
void error(char *explanation, ...)
{
va_list ap;
va_start (ap, explanation);
vfprintf (stderr, explanation, ap);
va_end (ap);
abort();
}
int fgetint(FILE *f)
{
int x;
assert(sizeof(int) == 4); /* This assumption is explicit here, but it's
* also elsewhere. */
x = fgetc(f) &0x000000FF;
x|= (fgetc(f) << 8) &0x0000FF00;
x|= (fgetc(f) <<16) &0x00FF0000;
x|= (fgetc(f) <<24) &0xFF000000;
if ( feof(f) )
error("Unexpected end of file while parsing binary file.");
return x;
}
int fgetshort(FILE *f)
{
int x;
assert(sizeof(int) == 4); /* This assumption is explicit here, but it's
* also elsewhere. */
x = fgetc(f) &0x000000FF;
x|= (fgetc(f) << 8) &0x0000FF00;
if ( feof(f) )
error("Unexpected end of file while parsing binary file.");
return x;
}
int rle_decode(char *in, char *out, int inLength, int outLength)
{
int pos = 0;
int run = 0;
int offset = 0;
while (pos < inLength && offset < outLength)
{
run = 1;
if ( in[pos] == 0x55 )
pos++;
else if ( in[pos] & 0x80 )
run = in[pos++] & ~0x80;
if ( offset + run > outLength )
{
fprintf(stderr,"Error: dest overrun during decompression, expected"
" %d, got %d.\n", outLength, offset+run);
return 0;
}
while ( run-- > 0 )
out[offset++] = in[pos];
pos++;
}
return offset;
}
void decode(char **data, int *length, int expectedLength)
{
char *result = malloc(expectedLength);
*length = rle_decode(*data,result,*length,expectedLength);
if ( !*length )
error("Unable to decrypt input map data.\n");
free(*data);
*data = result;
}
int main(int num_args, char *args[])
{
char *code;
FILE *out, *in;
int map, version, maps, x, y, this_map, offset, size, items, depth;
if ( num_args != 4 )
error("Usage: %s <mapfile name> <map number> <output-filename>\n",
args[0]);
out = fopen(args[3],"w");
if ( out == NULL )
error("Unable to open output file '%s'.\n", args[3]);
map = atoi(args[2]);
in = fopen(args[1],"rb");
if (!in)
error("Unable to open map file '%s'.\n", args[1]);
version = fgetc(in); /* The file version */
if ( version != VERSION )
error("Mapfile version mismatch: expected %d, got %d.\n",
VERSION, version);
maps = fgetshort(in); /* The number of files it's supposed to contain */
if ( maps < 1 )
error("Mapfile has bad format: claims to contain %d maps.", maps);
fprintf(out,"v%d\n",VERSION);
fprintf(out,"map %d\n",map);
items = 0;
do {
this_map = fgetshort(in);
x = fgetc(in); y = fgetc(in); depth = fgetc(in);
offset = fgetint(in);
items++;
printf("%d: map %d, %dx%d, offset %d.\n", items, this_map, x, y, offset);
} while (this_map != map && items < maps);
if ( items == maps )
error("Map #%d was not found in mapfile.\n", map );
fprintf(out,"%d %d,%d\n", depth, x, y);
/* Then seek to the location of the data -- to its offset, plus the constant
* space taken by the header, plus the space taken by all of the map
* table of content entries. */
fseek(in,offset+HEADER_SIZE+maps*ITEM_SIZE,SEEK_SET);
while ( depth-- )
{
/* Read the size of this level. */
size = fgetshort(in);
code = malloc(size);
fread(code,size,1,in);
/* Decode the whole level. */
/* decode(&code,&size, x*y);*/
if ( size != x*y )
error("Invalid size: expected %d, got %d.\n", x*y, size);
/* Write every line of the level to the output file. */
y = 0;
while(size)
{
fwrite(code+y*x, x, 1, out);
fputc('\n', out);
y++; size -= x;
}
/* If there's another level in the map, print a seperator. */
if ( depth )
fprintf(out, "========*** Level Seperator ***=======\n");
else fprintf(out, "===END OF MAP===\n");
free(code);
}
fclose(in); fclose(out);
exit(EXIT_SUCCESS);
}