home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 24
/
CD_ASCQ_24_0995.iso
/
vrac
/
deu53b9.zip
/
deu
/
source
/
d_wads.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-07
|
21KB
|
765 lines
/*----------------------------------------------------------------------------*
| This file is part of DEU (Doom Editing Utilities), created by the DEU team:|
| Raphael Quinet, Brendon Wyber, Ted Vessenes and others. See README.1ST or |
| the "about" dialog box for full credits. |
| |
| DEU is an open project: if you think that you can contribute, please join |
| the DEU team. You will be credited for any code (or ideas) included in |
| the next version of the program. |
| |
| If you want to make any modifications and re-distribute them on your own, |
| you must follow the conditions of the DEU license. Read the file LICENSE |
| in this directory or README.1ST in the top directory. If do not have a |
| copy of these files, you can request them from any member of the DEU team, |
| or by mail: Raphael Quinet, Rue des Martyrs 9, B-4550 Nandrin (Belgium). |
| |
| This program comes with absolutely no warranty. Use it at your own risks! |
*----------------------------------------------------------------------------*
D_WADS.C - WAD loading and saving routines
*/
/* the includes */
#include "deu.h"
#include "d_main.h"
#include "d_misc.h"
#include "d_config.h"
#include "d_wads.h"
/* global variables */
WadPtr WadFileList = NULL; /* linked list of wad files */
MDirPtr MasterDir = NULL; /* the master directory */
/*
Open the main wad file, read in its directory and create the
master directory.
*/
void OpenMainWad(char *filename)
{
MDirPtr lastp, newp;
UInt16 n;
WadPtr wad;
/* open the wad file */
printf("\nLoading main WAD file: %s...\n", filename);
wad = BasicWadOpen(filename);
if (strncmp(wad->type, "IWAD", 4))
ProgError("\"%s\" is not the main WAD file", filename);
/* create the master directory */
lastp = NULL;
for (n = 0; n < wad->dirsize; n++)
{
newp = (MDirPtr) GetMemory(sizeof(struct MasterDirectory));
newp->next = NULL;
newp->wadfile = wad;
memcpy(&(newp->dir), &(wad->directory[n]), sizeof(struct Directory));
if (MasterDir)
lastp->next = newp;
else
MasterDir = newp;
lastp = newp;
}
/* check version of the game */
if (FindMasterDir(MasterDir, "E2M1") != NULL)
DoomVersion = 1;
else if (FindMasterDir(MasterDir, "MAP28") != NULL)
DoomVersion = 2;
else
{
printf(" *--------------------------------------------*\n");
printf(" | Warning: you are using a SHAREWARE game. |\n");
printf(" | You won't be allowed to save your changes. |\n");
printf(" | PLEASE REGISTER YOUR COPY OF THE GAME. |\n");
printf(" *--------------------------------------------*\n");
/* If you change the next line, bad things will happen to you... */
DoomVersion = 0;
}
if (FindMasterDir(MasterDir, "M_HTIC") != NULL)
DoomVersion += 16;
}
/* Note from R.Q.:
This function should be re-written so that it doesn't use the master
directory, which will disappear from DEU.
Some parts of the code to update a directory may be transferred to the
BuildCompoundWad function.
*/
/*
Open a patch wad file, read in its directory and alter the master
directory.
*/
void OpenPatchWad(char *filename)
{
WadPtr wad;
MDirPtr mdir;
UInt16 n;
Int16 l;
char entryname[9];
#ifdef DEU_DOS
strupr(filename);
#endif
/* ignore the file if it doesn't exist */
if (! Exists(filename))
{
printf("Warning: patch WAD file \"%s\" doesn't exist. Ignored.\n", filename);
return;
}
/* open the wad file */
if (Config.verbose == TRUE)
printf("Loading patch WAD file: %s...\n", filename);
wad = BasicWadOpen(filename);
/* Check if the file is a PWAD or DWAD (Hi Bernt!) */
if (strncmp(wad->type, "PWAD", 4) && strncmp(wad->type, "DWAD", 4))
ProgError("\"%s\" is not a patch WAD file", filename);
/* alter the master directory */
/*! This should be changed - RQ */
l = 0;
for (n = 0; n < wad->dirsize; n++)
{
strncpy(entryname, wad->directory[n].name, 8);
entryname[8] = '\0';
if (l == 0)
{
mdir = FindMasterDir(MasterDir, wad->directory[n].name);
/* if this entry is not in the master directory, then add it */
if (mdir == NULL)
{
printf(" [Adding new entry %s]\n", entryname);
mdir = MasterDir;
while (mdir->next)
mdir = mdir->next;
mdir->next = (MDirPtr) GetMemory(sizeof(struct MasterDirectory));
mdir = mdir->next;
mdir->next = NULL;
}
/* if this is a level, then copy this entry and the next 10 */
else if ((wad->directory[n].name[0] == 'E' && wad->directory[n].name[2] == 'M' && wad->directory[n].name[4] == '\0')
|| (wad->directory[n].name[0] == 'M' && wad->directory[n].name[1] == 'A' && wad->directory[n].name[2] == 'P' && wad->directory[n].name[5] == '\0'))
{
printf(" [Updating level %s]\n", entryname);
l = 10;
}
else
printf(" [Updating entry %s]\n", entryname);
}
else
{
mdir = mdir->next;
/* the level data should replace an existing level */
if (mdir == NULL || strncmp(mdir->dir.name, wad->directory[n].name, 8))
ProgError("\\%s\" is not an understandable PWAD file (error with %s)", filename, entryname);
l--;
}
mdir->wadfile = wad;
memcpy(&(mdir->dir), &(wad->directory[n]), sizeof(struct Directory));
}
}
/*
Close all the wad files, deallocating the WAD file structures.
*/
void CloseWadFiles(void)
{
WadPtr curw, nextw;
MDirPtr curd, nextd;
/* close the wad files */
curw = WadFileList;
WadFileList = NULL;
while (curw)
{
nextw = curw->next;
fclose(curw->fileinfo);
FreeMemory(curw->directory);
FreeMemory(curw);
curw = nextw;
}
/* delete the master directory */
curd = MasterDir;
MasterDir = NULL;
while (curd)
{
nextd = curd->next;
FreeMemory(curd);
curd = nextd;
}
}
/*
Forget unused patch wad files.
*/
void CloseUnusedWadFiles(void)
{
WadPtr curw, prevw;
MDirPtr mdir;
prevw = NULL;
curw = WadFileList;
while (curw)
{
/* check if the wad file is used by a directory entry */
mdir = MasterDir;
while (mdir && mdir->wadfile != curw)
mdir = mdir->next;
if (mdir)
prevw = curw;
else
{
/* if this wad file is never used, close it */
if (prevw)
prevw->next = curw->next;
else
WadFileList = curw->next;
fclose(curw->fileinfo);
FreeMemory(curw->directory);
FreeMemory(curw);
}
curw = prevw->next;
}
}
/*
Basic opening of WAD file and creation of node in Wad linked list.
*/
WadPtr BasicWadOpen(char *filename)
{
WadPtr curw, prevw;
#ifdef FAT_ENDIAN
int i;
#endif
/* find the wad file in the wad file list */
prevw = WadFileList;
if (prevw)
{
curw = prevw->next;
while (curw && strcmp(filename, curw->filename))
{
prevw = curw;
curw = prevw->next;
}
}
else
curw = NULL;
/* if this entry doesn't exist, add it to the WadFileList */
if (curw == NULL)
{
curw = (WadPtr) GetMemory(sizeof(struct WadFileInfo));
if (prevw == NULL)
WadFileList = curw;
else
prevw->next = curw;
curw->next = NULL;
curw->filename = filename;
}
/* open the file */
if ((curw->fileinfo = fopen(filename, "rb")) == NULL)
{
if (!prevw)
{
WadFileList = NULL;
}
else
{
prevw->next = curw->next;
}
FreeMemory(curw);
ProgError("error opening \"%s\"", filename);
}
/* read in the WAD directory info */
BasicWadRead(curw, curw->type, 4L);
/* check if the file is the IWAD or a PWAD */
if (strncmp(curw->type + 1, "WAD", 3))
ProgError("\"%s\" is not a valid WAD file", filename);
WadReadInt32(curw, &curw->dirsize);
WadReadInt32(curw, &curw->dirstart);
/* read in the WAD directory itself */
curw->directory = (DirPtr) GetMemory(sizeof(struct Directory) * curw->dirsize);
BasicWadSeek(curw, curw->dirstart);
BasicWadRead(curw, curw->directory, sizeof(struct Directory) * curw->dirsize);
#ifdef FAT_ENDIAN
/* swap all integers read from the directory */
for (i = 0; i < curw->dirsize; i++)
{
curw->directory[i].start = (Int32) SwapInt32(curw->directory[i].start);
curw->directory[i].size = (Int32) SwapInt32(curw->directory[i].size);
}
#endif
/* all done */
return curw;
}
/*
Read bytes from a file and store it into an address with error checking.
*/
void BasicWadRead(WadPtr wadfile, void huge *addr, long size)
{
if (fread(addr, 1, size, wadfile->fileinfo) != size)
ProgError("error reading from \"%s\"", wadfile->filename);
}
/*
Go to offset of wad file with error checking.
*/
void BasicWadSeek(WadPtr wadfile, long offset)
{
if (fseek(wadfile->fileinfo, offset, 0))
ProgError("error reading from \"%s\"", wadfile->filename);
}
/*
Find an entry in the master directory.
*/
MDirPtr FindMasterDir(MDirPtr from, char *name)
{
while (from)
{
if (!strncmp(from->dir.name, name, 8))
break;
from = from->next;
}
return from;
}
/*
List the master directory.
*/
void ListMasterDirectory(FILE *file)
{
char dataname[9];
MDirPtr dir;
char key;
Int16 lines = 3;
dataname[8] = '\0';
fprintf(file, "The Master Directory\n");
fprintf(file, "====================\n\n");
fprintf(file, "NAME____ FILE________________ SIZE__ START____\n");
for (dir = MasterDir; dir; dir = dir->next)
{
strncpy(dataname, dir->dir.name, 8);
fprintf(file, "%-8s %-20s %6ld x%08lx\n", dataname, dir->wadfile->filename, dir->dir.size, dir->dir.start);
if (file == stdout && lines++ > 21)
{
lines = 0;
printf("[Q to abort, any other key to continue]");
key = getchar();
printf("\r \r");
if (key == 'Q' || key == 'q')
break;
}
}
}
/*
List the directory of a file.
*/
void ListFileDirectory(FILE *file, WadPtr wad)
{
char dataname[9];
char key;
Int16 lines = 5;
UInt32 n;
dataname[8] = '\0';
fprintf(file, "WAD File Directory\n");
fprintf(file, "==================\n\n");
fprintf(file, "Wad File: %s\n\n", wad->filename);
fprintf(file, "NAME____ SIZE__ START____ END______\n");
for (n = 0; n < wad->dirsize; n++)
{
strncpy(dataname, wad->directory[n].name, 8);
fprintf(file, "%-8s %6ld x%08lx x%08lx\n", dataname, wad->directory[n].size, wad->directory[n].start, wad->directory[n].size + wad->directory[n].start - 1);
if (file == stdout && lines++ > 21)
{
lines = 0;
printf("[Q to abort, any other key to continue]");
key = getchar();
printf("\r \r");
if (key == 'Q' || key == 'q')
break;
}
}
}
/* Note from R.Q. (Jan 95):
The following function should be replaced by a new BuildCompoundWad
function, which takes two arguments: the new file name and a list of
WadPtrs. BuildCompoundWad will create a new file by copying all entries
from the WAD files given in the WadPtr list. If the list contains the
WadPtr for the main WAD (IWAD), then a new IWAD will be rebuilt.
This new funtion will not use the master directory, so the entries will
have to be re-ordered according to the IWAD directory, with the _first_
WadPtr in the list taking precedence if some entries are duplicated.
*/
/*
Build a new wad file from master directory.
*/
void BuildNewMainWad(char *filename, Bool patchonly)
{
FILE *file;
UInt32 counter = 12;
MDirPtr cur;
UInt32 size;
UInt32 dirstart;
UInt32 dirnum;
/* open the file and store signatures */
if (patchonly)
printf("Building a compound Patch Wad file \"%s\".\n", filename);
else
printf("Building a new Main Wad file \"%s\" (size approx 10000K)\n", filename);
if (FindMasterDir(MasterDir, "E2M4") == NULL && FindMasterDir(MasterDir, "MAP24") == NULL)
ProgError("You were warned: you are not allowed to do this.");
if ((file = fopen(filename, "wb")) == NULL)
ProgError("unable to open file \"%s\"", filename);
if (patchonly)
WriteBytes(file, "PWAD", 4);
else
WriteBytes(file, "IWAD", 4);
WriteInt32(file, &counter); /* put true value in later */
WriteInt32(file, &counter); /* put true value in later */
/* output the directory data chuncks */
for (cur = MasterDir; cur; cur = cur->next)
{
if (patchonly && cur->wadfile == WadFileList)
continue;
size = cur->dir.size;
counter += size;
BasicWadSeek(cur->wadfile, cur->dir.start);
CopyBytes(file, cur->wadfile->fileinfo, size);
printf("Size: %ldK\r", counter / 1024);
}
/* output the directory */
dirstart = counter;
counter = 12;
dirnum = 0;
for (cur = MasterDir; cur; cur = cur->next)
{
if (patchonly && cur->wadfile == WadFileList)
continue;
if (dirnum % 100 == 0)
printf("Outputting directory %04ld...\r", dirnum);
if (cur->dir.start)
WriteInt32(file, &counter);
else
WriteInt32(file, &(cur->dir.start));
WriteInt32(file, &(cur->dir.size));
WriteBytes(file, &(cur->dir.name), 8L);
counter += cur->dir.size;
dirnum++;
}
/* fix up the number of entries and directory start information */
if (fseek(file, 4L, 0))
ProgError("error writing to file");
WriteInt32(file, &dirnum);
WriteInt32(file, &dirstart);
/* close the file */
printf(" \r");
fclose(file);
}
/*
Output bytes to a binary file with error checking.
*/
void WriteBytes(FILE *file, void huge *addr, long size)
{
if (DoomVersion < 1)
return;
while (size > 0x8000)
{
if (fwrite(addr, 1, 0x8000, file) != 0x8000)
ProgError("error writing to file");
addr = (char huge *)addr + 0x8000;
size -= 0x8000;
}
if (fwrite(addr, 1, size, file) != size)
ProgError("error writing to file");
}
/*
Copy bytes from a binary file to another with error checking.
*/
void CopyBytes(FILE *dest, FILE *source, long size)
{
void huge *data;
data = GetFarMemory(0x8000 + 2);
while (size > 0x8000)
{
if (DoomVersion > 0)
if (fread(data, 1, 0x8000, source) != 0x8000)
ProgError("error reading from file");
if (fwrite(data, 1, 0x8000, dest) != 0x8000)
ProgError("error writing to file");
size -= 0x8000;
}
if (DoomVersion > 0)
if (fread(data, 1, size, source) != size)
ProgError("error reading from file");
if (fwrite(data, 1, size, dest) != size)
ProgError("error writing to file");
FreeFarMemory(data);
}
/*
Dump a directory entry in hex.
*/
void DumpDirectoryEntry(FILE *file, char *entryname)
{
MDirPtr entry;
char dataname[9];
char key;
int lines = 5;
UInt32 n, c, i;
UInt8 buf[16];
c = 0L;
entry = MasterDir;
while (entry)
{
if (!strnicmp(entry->dir.name, entryname, 8))
{
strncpy(dataname, entry->dir.name, 8);
dataname[8] = '\0';
fprintf(file, "Contents of entry %s (size = %ld bytes):\n", dataname, entry->dir.size);
BasicWadSeek(entry->wadfile, entry->dir.start);
n = 0L;
for (c = 0L; c < entry->dir.size; c += 16L)
{
fprintf(file, "%04lX: ", n);
for (i = 0L; i < 16L; i++)
{
BasicWadRead(entry->wadfile, &(buf[i]), 1);
fprintf(file, " %02X", buf[i]);
n++;
}
fprintf(file, " ");
for (i = 0L; i < 16L; i++)
{
if (buf[i] >= ' ')
fprintf(file, "%c", buf[i]);
else
fprintf(file, " ");
}
fprintf(file, "\n");
if (file == stdout && lines++ > 21)
{
lines = 0;
printf("[%ld%% - Q to abort, S to skip this entry, any other key to continue]", n * 100 / entry->dir.size);
key = getchar();
printf("\r \r");
if (key == 'S' || key == 's')
break;
if (key == 'Q' || key == 'q')
return;
}
}
}
entry = entry->next;
}
if (! c)
{
printf("[Entry not in master directory]\n");
return;
}
}
/*
Save a directory entry to disk.
*/
void SaveDirectoryEntry(FILE *file, char *entryname)
{
MDirPtr entry;
UInt32 counter;
UInt32 size;
for (entry = MasterDir; entry; entry = entry->next)
if (!strnicmp(entry->dir.name, entryname, 8))
break;
if (entry)
{
WriteBytes(file, "PWAD", 4L); /* PWAD file */
counter = 1L;
WriteInt32(file, &counter); /* 1 entry */
counter = 12L;
WriteInt32(file, &counter);
counter = 28L;
WriteInt32(file, &counter);
size = entry->dir.size;
WriteInt32(file, &size);
WriteBytes(file, &(entry->dir.name), 8L);
BasicWadSeek(entry->wadfile, entry->dir.start);
CopyBytes(file, entry->wadfile->fileinfo, size);
}
else
{
printf("[Entry not in master directory]\n");
return;
}
}
/*
Save a directory entry to disk, without a PWAD header.
*/
void SaveEntryToRawFile(FILE *file, char *entryname)
{
MDirPtr entry;
for (entry = MasterDir; entry; entry = entry->next)
if (!strnicmp(entry->dir.name, entryname, 8))
break;
if (entry)
{
BasicWadSeek(entry->wadfile, entry->dir.start);
CopyBytes(file, entry->wadfile->fileinfo, entry->dir.size);
}
else
{
printf("[Entry not in master directory]\n");
return;
}
}
/*
Encapsulate a raw file in a PWAD file.
*/
void SaveEntryFromRawFile(FILE *file, FILE *raw, char *entryname)
{
UInt32 counter;
Int32 size;
char name8[8];
for (counter = 0L; counter < 8L; counter++)
name8[counter] = '\0';
strncpy(name8, entryname, 8);
WriteBytes(file, "PWAD", 4L); /* PWAD file */
counter = 1L;
WriteInt32(file, &counter); /* 1 entry */
counter = 12L;
WriteInt32(file, &counter);
counter = 28L;
WriteInt32(file, &counter);
if (fseek(raw, 0L, SEEK_END) != 0)
ProgError("error reading from raw file");
size = ftell(raw);
if (size < 0L)
ProgError("error reading from raw file");
if (fseek(raw, 0L, SEEK_SET) != 0)
ProgError("error reading from raw file");
WriteInt32(file, (UInt32 *) &size);
WriteBytes(file, name8, 8L);
CopyBytes(file, raw, size);
}
#ifdef FAT_ENDIAN
UInt16 SwapInt16(UInt16 x)
{
return ((x<<8) & 0xff00) | ((x>>8) & 0x00ff);
}
UInt32 SwapInt32(UInt32 x)
{
return (((x << 24) & 0xff000000)
| ((x<< 8) & 0x00ff0000)
| ((x>> 8) & 0x0000ff00)
| ((x>>24) & 0x000000ff));
}
void WadReadInt16(WadPtr wadfile, UInt16 huge *x)
{
BasicWadRead(wadfile, x, 2L);
*x = SwapInt16(*x);
}
void WadReadInt32(WadPtr wadfile, UInt32 huge *x)
{
BasicWadRead(wadfile, x, 4L);
*x = SwapInt32(*x);
}
void WriteInt16(FILE *file, UInt16 huge *x)
{
UInt16 n;
n = SwapInt16(*x);
WriteBytes(file, &n, 2L);
}
void WriteInt32(FILE *file, UInt32 huge *x)
{
UInt32 n;
n = SwapInt32(*x);
WriteBytes(file, &n, 4L);
}
#endif /* FAT_ENDIAN */
/* end of file */