ngunix/vpsplit/vpsplit.c
2014-04-12 08:29:30 -04:00

464 lines
11 KiB
C

/*
==============================================================================
Title: "VisPatch file splitter"
(c) 2001 by Matthias "Maddes" Buecher
Authors:
Matthias "Maddes" Buecher <maddes@go.to>
http://www.quake-info-pool.net/
Most of this code is easy to comprehend and there should not be too many
questions about how it works. The heart of the program has been slighty
commented out to help you understand the technical operations being done.
DISCLAIMER WARNING:
WE DO NOT ACCEPT RESPONSIBILITY FOR ANY EFFECTS, POSITIVE OR NEGATIVE,
THAT THIS CODE MAY CAUSE TOWARDS YOUR COMPUTER.
WE DO NOT SUPPORT MODIFICATIONS OF THIS CODE, USE ONLY AT YOUR OWN RISK.
THIS PATCH HAS NOT BEEN ENDORSED BY THE ID SOFTWARE CORPORATION.
THIS PROGRAM IS FREE OF CHARGE. IF YOU HAVE RECEIVED THIS PROGRAM THROUGH
PAYMENT, PLEASE CONTACT US.
THANK YOU.
==============================================================================
*/
/* Compatible headers */
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
/* needed to compile under Linux */
#ifndef _WIN32
#define stricmp strcasecmp
#endif
/* constants */
#define VERSION "1.00 (2001-12-31)"
#define PARM_CHAR '-'
#define BUFLEN 1024
#define VISPATCH_MAPNAME_LENGTH 32
/*
structure definitions
*/
typedef unsigned char BYTE;
/* VisPatch file */
typedef struct vispatch_s {
char mapname[VISPATCH_MAPNAME_LENGTH]; /* map for which these data are for, always use strncpy and strncmp for this field */
int filelen; /* length of data after VisPatch header (VIS+Leafs) */
} vispatch_t;
/* global data definition */
char in_filename[BUFLEN+1];
FILE *in_handle;
char *extension; /* pointer to extension string */
int flag_error; /* error occured */
int flag_warning; /* warning occured */
// taken from Quake's COMMON.C
int (*LittleLong) (int l);
int (*BigLong) (int l);
/*
******************************************************************************
*
* G E N E R A L F U N C T I O N S
*
******************************************************************************
*/
// taken from Quake's COMMON.C
int LongSwap (int l)
{
BYTE b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
// taken from Quake's COMMON.C
int LongNoSwap (int l)
{
return l;
}
/*
==============================================================================
transforms a string to lowercase
==============================================================================
*/
void strlower(char *text)
{
int i;
int length;
length = strlen(text);
for (i=0; i<length; i++)
text[i] = (char)tolower(text[i]);
}
/*
==============================================================================
gets the extension out of the path
==============================================================================
*/
char *get_extension(const char *const filename)
{
char *dot;
char *slash;
char *backslash;
dot = strrchr(filename, '.');
slash = strrchr(filename, '/');
backslash = strrchr(filename, '\\');
if ((dot) && (dot > slash) && (dot > backslash))
{
return dot;
}
return NULL; // no extension found
}
/*
******************************************************************************
*
* U S E R I N T E R F A C E
*
******************************************************************************
*/
/*
==============================================================================
displays the help text
==============================================================================
*/
void display_help(char *call)
{
/* syntax */
printf("Usage: VPSplit [-?] <vispatchfile>\n");
printf(" -? : displays this help text\n");
/* example */
printf("\nExample:\n");
printf("%s \"example.vis\"\n", call);
printf("Extracts the data for each single map inside the vispatch file \"example.vis\"\n");
/* contact */
printf("\nHow to contact the author:\n");
printf("Matthias \"Maddes\" Buecher <maddes@go.to>\n");
printf("http://www.quake-info-pool.net/\n");
}
/*
==============================================================================
checks if string begins with a parameter character
==============================================================================
*/
int chk_paramchar(char *text)
{
/* check for parameter character at beginning */
if (text[0] == PARM_CHAR)
{
strlower(text);
return 1;
}
else
return 0;
}
/*
==============================================================================
checks all parameters
when help parameter is found it displays the help text and leaves the function
checks if the ini file is present
displays all used parameters and asks for confirmation
==============================================================================
*/
void chk_param(int argc, char *argv[])
{
/* define local variables */
int i; /* iteration variable */
int flag_help; /* display help */
/* initialize local variables */
flag_error = 0;
flag_warning = 0;
flag_help = 0;
/* parse parameters */
for (i=1; i<argc; i++)
{
if (chk_paramchar(argv[i]))
{
if (!strcmp(argv[i],"-?") || !stricmp(argv[i],"-h") || !stricmp(argv[i],"-help")) /* help parameter */
{
flag_help = 1;
flag_error = 1;
break;
}
else /* unknown parameter */
{
printf("Error on parameter %i: \"%s\" is an unknown parameter\n", i, argv[i]);
flag_help = 1;
flag_error = 2;
}
}
else /* should be the filename */
{
if (!*in_filename)
{
strcpy(in_filename, argv[i]);
}
else
{
printf("Error on parameter %i: \"%s\", a vispatch file was already named\n", i, argv[i]);
flag_help = 1;
flag_error = 2;
}
}
}
/* check if bsp file exists */
if (!*in_filename)
{
printf("Error: no vispatch file named\n");
flag_error = 2;
flag_help = 1;
}
else
{
in_handle = fopen(in_filename, "rb");
if (!in_handle)
{
// check extension
extension = get_extension(in_filename);
if ( (!extension) || (stricmp(extension, ".vis")) || (stricmp(extension, ".dat")))
{
strcat(in_filename, ".vis");
in_handle = fopen(in_filename, "rb");
}
}
if (!in_handle)
{
printf("Error: could not open vispatch file \"%s\" - %s\n", in_filename, strerror(errno));
flag_error = 2;
}
else
{
fclose(in_handle);
in_handle = NULL;
}
}
/* asked for help */
if (flag_error > 1 || flag_warning)
{
printf("\n");
}
if (flag_help)
{
display_help(argv[0]);
}
if (!flag_error)
{
printf("VisPatch file: \"%s\"\n", in_filename);
printf("\n");
}
}
/*
******************************************************************************
*
* F I L E S R E A D I N G & W R I T I N G
*
******************************************************************************
*/
void process_file(void)
{
int in_filelength;
BYTE *in_data;
int i;
int offset;
vispatch_t *header;
char out_filename[VISPATCH_MAPNAME_LENGTH+5]; // + ".vis" + EoS
FILE *out_handle;
int out_filelength;
long filelen;
/* open vispatch file */
in_handle = fopen(in_filename, "rb");
if (!in_handle)
{
printf("Error: could not open vispatch file \"%s\" - %s\n", in_filename, strerror(errno));
flag_error = 2;
return;
}
/* get file length */
if ( fseek(in_handle, 0, SEEK_END) != 0)
{
printf("Error: couldn't seek file end - %s\n", strerror(errno));
flag_error = 2;
return;
}
in_filelength = ftell(in_handle);
if ( in_filelength < 0)
{
printf("Error: couldn't get file length - %s\n", strerror(errno));
flag_error = 2;
return;
}
if ( fseek(in_handle, 0, SEEK_SET) != 0)
{
printf("Error: couldn't seek file start - %s\n", strerror(errno));
flag_error = 2;
return;
}
/* allocate memory for file */
in_data = malloc(in_filelength);
if (!in_data)
{
printf("Error: couldn't allocate memory for vispatch file\n");
flag_error = 2;
return;
}
/* read file into memory */
i = fread(in_data, 1, in_filelength, in_handle);
if ( i != in_filelength)
{
printf("Error: read %i bytes from vispatch file, expected %i\n", i, in_filelength);
flag_error = 2;
return;
}
/* close file */
fclose(in_handle);
/* extract map data one by one */
offset = 0;
while (offset < in_filelength)
{
/* get vispatch header */
header = (vispatch_t *)(in_data + offset);
filelen = LittleLong(header->filelen);
/* clean up original header */
strncpy(header->mapname, header->mapname, VISPATCH_MAPNAME_LENGTH); // remove junk from original header
/* get output name for map data */
strncpy(out_filename, header->mapname, VISPATCH_MAPNAME_LENGTH);
out_filename[VISPATCH_MAPNAME_LENGTH] = 0;
extension = get_extension(out_filename);
if (extension)
{
extension[0] = 0;
}
strcat(out_filename, ".vis");
/* map output length */
out_filelength = filelen + sizeof(struct vispatch_s);
printf("\"%.32s\" at %i: \"%s\" with %i(%i) bytes\n", header->mapname, offset, out_filename, filelen, out_filelength);
/* open output file */
out_handle = fopen(out_filename, "wb");
if (!out_handle)
{
printf("Error: could not create output file \"%s\" - %s\n", out_filename, strerror(errno));
flag_error = 2;
break;
}
/* write output file */
i = fwrite(header, 1, out_filelength, out_handle);
if ( i != out_filelength)
{
printf("Error: wrote %i bytes in %s, expected %i\n", i, out_filename, out_filelength);
flag_error = 2;
return;
}
/* close output file */
fclose(out_handle);
/* next map date */
offset += out_filelength;
};
}
/*
******************************************************************************
*
* M A I N F U N C T I O N ( S T A R T O F P R O G R A M )
*
******************************************************************************
*/
/*
==============================================================================
here the program starts and all sub functions are called
==============================================================================
*/
int main(int argc, char *argv[])
{
/* initialize variables */
flag_error = 0;
flag_warning = 0;
*in_filename = 0;
// taken from Quake's COMMON.C
BYTE swaptest[2] = {1,0};
// set the byte swapping variables in a portable manner
if ( *(short *)swaptest == 1)
{
BigLong = LongSwap;
LittleLong = LongNoSwap;
}
else
{
BigLong = LongNoSwap;
LittleLong = LongSwap;
}
/* display program header lines */
printf("VisPatch File Splitter\n");
printf("(c) 2001 by Matthias \"Maddes\" Buecher\n");
printf("Version %s\n\n", VERSION);
/* check parameters */
chk_param(argc, argv);
if (flag_error)
{
exit(flag_error);
}
/* here we go with the "real" program */
process_file();
if (flag_error)
{
exit(flag_error);
}
printf("Finished\n");
return 0;
}