mirror of
https://github.com/ZDoom/zdbsp.git
synced 2024-11-24 21:01:11 +00:00
5a5aafcce9
(Apparently ZDoom never checks this lump's length.) SVN r2289 (trunk)
485 lines
8.3 KiB
C++
485 lines
8.3 KiB
C++
/*
|
|
WAD-handling routines.
|
|
Copyright (C) 2002-2006 Randy Heit
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
#include "wad.h"
|
|
|
|
static const char MapLumpNames[12][9] =
|
|
{
|
|
"THINGS",
|
|
"LINEDEFS",
|
|
"SIDEDEFS",
|
|
"VERTEXES",
|
|
"SEGS",
|
|
"SSECTORS",
|
|
"NODES",
|
|
"SECTORS",
|
|
"REJECT",
|
|
"BLOCKMAP",
|
|
"BEHAVIOR",
|
|
"SCRIPTS"
|
|
};
|
|
|
|
static const bool MapLumpRequired[12] =
|
|
{
|
|
true, // THINGS
|
|
true, // LINEDEFS
|
|
true, // SIDEDEFS
|
|
true, // VERTEXES
|
|
false, // SEGS
|
|
false, // SSECTORS
|
|
false, // NODES
|
|
true, // SECTORS
|
|
false, // REJECT
|
|
false, // BLOCKMAP
|
|
false, // BEHAVIOR
|
|
false // SCRIPTS
|
|
};
|
|
|
|
static const char GLLumpNames[5][9] =
|
|
{
|
|
"GL_VERT",
|
|
"GL_SEGS",
|
|
"GL_SSECT",
|
|
"GL_NODES",
|
|
"GL_PVS"
|
|
};
|
|
|
|
FWadReader::FWadReader (const char *filename)
|
|
: Lumps (NULL), File (NULL)
|
|
{
|
|
File = fopen (filename, "rb");
|
|
if (File == NULL)
|
|
{
|
|
throw std::runtime_error("Could not open input file");
|
|
}
|
|
|
|
SafeRead (&Header, sizeof(Header));
|
|
if (Header.Magic[0] != 'P' && Header.Magic[0] != 'I' &&
|
|
Header.Magic[1] != 'W' &&
|
|
Header.Magic[2] != 'A' &&
|
|
Header.Magic[3] != 'D')
|
|
{
|
|
fclose (File);
|
|
File = NULL;
|
|
throw std::runtime_error("Input file is not a wad");
|
|
}
|
|
|
|
Header.NumLumps = LittleLong(Header.NumLumps);
|
|
Header.Directory = LittleLong(Header.Directory);
|
|
|
|
if (fseek (File, Header.Directory, SEEK_SET))
|
|
{
|
|
throw std::runtime_error("Could not read wad directory");
|
|
}
|
|
|
|
Lumps = new WadLump[Header.NumLumps];
|
|
SafeRead (Lumps, Header.NumLumps * sizeof(*Lumps));
|
|
|
|
for (int i = 0; i < Header.NumLumps; ++i)
|
|
{
|
|
Lumps[i].FilePos = LittleLong(Lumps[i].FilePos);
|
|
Lumps[i].Size = LittleLong(Lumps[i].Size);
|
|
}
|
|
}
|
|
|
|
FWadReader::~FWadReader ()
|
|
{
|
|
if (File) fclose (File);
|
|
if (Lumps) delete[] Lumps;
|
|
}
|
|
|
|
bool FWadReader::IsIWAD () const
|
|
{
|
|
return Header.Magic[0] == 'I';
|
|
}
|
|
|
|
int FWadReader::NumLumps () const
|
|
{
|
|
return Header.NumLumps;
|
|
}
|
|
|
|
int FWadReader::FindLump (const char *name, int index) const
|
|
{
|
|
if (index < 0)
|
|
{
|
|
index = 0;
|
|
}
|
|
for (; index < Header.NumLumps; ++index)
|
|
{
|
|
if (strnicmp (Lumps[index].Name, name, 8) == 0)
|
|
{
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int FWadReader::FindMapLump (const char *name, int map) const
|
|
{
|
|
int i, j, k;
|
|
++map;
|
|
|
|
for (i = 0; i < 12; ++i)
|
|
{
|
|
if (strnicmp (MapLumpNames[i], name, 8) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == 12)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for (j = k = 0; j < 12; ++j)
|
|
{
|
|
if (strnicmp (Lumps[map+k].Name, MapLumpNames[j], 8) == 0)
|
|
{
|
|
if (i == j)
|
|
{
|
|
return map+k;
|
|
}
|
|
k++;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
bool FWadReader::isUDMF (int index) const
|
|
{
|
|
index++;
|
|
|
|
if (strnicmp(Lumps[index].Name, "TEXTMAP", 8) == 0)
|
|
{
|
|
// UDMF map
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool FWadReader::IsMap (int index) const
|
|
{
|
|
int i, j;
|
|
|
|
if (isUDMF(index)) return true;
|
|
|
|
index++;
|
|
|
|
for (i = j = 0; i < 12; ++i)
|
|
{
|
|
if (strnicmp (Lumps[index+j].Name, MapLumpNames[i], 8) != 0)
|
|
{
|
|
if (MapLumpRequired[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
j++;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int FWadReader::FindGLLump (const char *name, int glheader) const
|
|
{
|
|
int i, j, k;
|
|
++glheader;
|
|
|
|
for (i = 0; i < 5; ++i)
|
|
{
|
|
if (strnicmp (Lumps[glheader+i].Name, name, 8) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == 5)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for (j = k = 0; j < 5; ++j)
|
|
{
|
|
if (strnicmp (Lumps[glheader+k].Name, GLLumpNames[j], 8) == 0)
|
|
{
|
|
if (i == j)
|
|
{
|
|
return glheader+k;
|
|
}
|
|
k++;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
bool FWadReader::IsGLNodes (int index) const
|
|
{
|
|
if (index + 4 >= Header.NumLumps)
|
|
{
|
|
return false;
|
|
}
|
|
if (Lumps[index].Name[0] != 'G' ||
|
|
Lumps[index].Name[1] != 'L' ||
|
|
Lumps[index].Name[2] != '_')
|
|
{
|
|
return false;
|
|
}
|
|
index++;
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
if (strnicmp (Lumps[i+index].Name, GLLumpNames[i], 8) != 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int FWadReader::SkipGLNodes (int index) const
|
|
{
|
|
index++;
|
|
for (int i = 0; i < 5 && index < Header.NumLumps; ++i, ++index)
|
|
{
|
|
if (strnicmp (Lumps[index].Name, GLLumpNames[i], 8) != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return index;
|
|
}
|
|
|
|
bool FWadReader::MapHasBehavior (int map) const
|
|
{
|
|
return FindMapLump ("BEHAVIOR", map) != -1;
|
|
}
|
|
|
|
int FWadReader::NextMap (int index) const
|
|
{
|
|
if (index < 0)
|
|
{
|
|
index = 0;
|
|
}
|
|
else
|
|
{
|
|
index++;
|
|
}
|
|
for (; index < Header.NumLumps; ++index)
|
|
{
|
|
if (IsMap (index))
|
|
{
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int FWadReader::LumpAfterMap (int i) const
|
|
{
|
|
int j, k;
|
|
|
|
if (isUDMF(i))
|
|
{
|
|
// UDMF map
|
|
i += 2;
|
|
while (strnicmp(Lumps[i].Name, "ENDMAP", 8) != 0 && i < Header.NumLumps)
|
|
{
|
|
i++;
|
|
}
|
|
return i+1; // one lump after ENDMAP
|
|
}
|
|
|
|
i++;
|
|
for (j = k = 0; j < 12; ++j)
|
|
{
|
|
if (strnicmp (Lumps[i+k].Name, MapLumpNames[j], 8) != 0)
|
|
{
|
|
if (MapLumpRequired[j])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
k++;
|
|
}
|
|
}
|
|
return i+k;
|
|
}
|
|
|
|
void FWadReader::SafeRead (void *buffer, size_t size)
|
|
{
|
|
if (fread (buffer, 1, size, File) != size)
|
|
{
|
|
throw std::runtime_error("Failed to read");
|
|
}
|
|
}
|
|
|
|
const char *FWadReader::LumpName (int lump)
|
|
{
|
|
static char name[9];
|
|
strncpy (name, Lumps[lump].Name, 8);
|
|
name[8] = 0;
|
|
return name;
|
|
}
|
|
|
|
FWadWriter::FWadWriter (const char *filename, bool iwad)
|
|
: File (NULL)
|
|
{
|
|
File = fopen (filename, "wb");
|
|
if (File == NULL)
|
|
{
|
|
throw std::runtime_error("Could not open output file");
|
|
}
|
|
|
|
WadHeader head;
|
|
|
|
if (iwad)
|
|
{
|
|
head.Magic[0] = 'I';
|
|
}
|
|
else
|
|
{
|
|
head.Magic[0] = 'P';
|
|
}
|
|
head.Magic[1] = 'W';
|
|
head.Magic[2] = 'A';
|
|
head.Magic[3] = 'D';
|
|
|
|
SafeWrite (&head, sizeof(head));
|
|
}
|
|
|
|
FWadWriter::~FWadWriter ()
|
|
{
|
|
if (File)
|
|
{
|
|
Close ();
|
|
}
|
|
}
|
|
|
|
void FWadWriter::Close ()
|
|
{
|
|
if (File)
|
|
{
|
|
int32_t head[2];
|
|
|
|
head[0] = LittleLong(Lumps.Size());
|
|
head[1] = LittleLong(ftell (File));
|
|
|
|
SafeWrite (&Lumps[0], sizeof(WadLump)*Lumps.Size());
|
|
fseek (File, 4, SEEK_SET);
|
|
SafeWrite (head, 8);
|
|
fclose (File);
|
|
File = NULL;
|
|
}
|
|
}
|
|
|
|
void FWadWriter::CreateLabel (const char *name)
|
|
{
|
|
WadLump lump;
|
|
|
|
strncpy (lump.Name, name, 8);
|
|
lump.FilePos = LittleLong(ftell (File));
|
|
lump.Size = 0;
|
|
Lumps.Push (lump);
|
|
}
|
|
|
|
void FWadWriter::WriteLump (const char *name, const void *data, int len)
|
|
{
|
|
WadLump lump;
|
|
|
|
strncpy (lump.Name, name, 8);
|
|
lump.FilePos = LittleLong(ftell (File));
|
|
lump.Size = LittleLong(len);
|
|
Lumps.Push (lump);
|
|
|
|
SafeWrite (data, len);
|
|
}
|
|
|
|
void FWadWriter::CopyLump (FWadReader &wad, int lump)
|
|
{
|
|
BYTE *data;
|
|
int size;
|
|
|
|
ReadLump<BYTE> (wad, lump, data, size);
|
|
if (data != NULL)
|
|
{
|
|
WriteLump (wad.LumpName (lump), data, size);
|
|
delete[] data;
|
|
}
|
|
}
|
|
|
|
void FWadWriter::StartWritingLump (const char *name)
|
|
{
|
|
CreateLabel (name);
|
|
}
|
|
|
|
void FWadWriter::AddToLump (const void *data, int len)
|
|
{
|
|
SafeWrite (data, len);
|
|
Lumps[Lumps.Size()-1].Size += len;
|
|
}
|
|
|
|
void FWadWriter::SafeWrite (const void *buffer, size_t size)
|
|
{
|
|
if (fwrite (buffer, 1, size, File) != size)
|
|
{
|
|
fclose (File);
|
|
File = NULL;
|
|
throw std::runtime_error(
|
|
"Failed to write. Check that this directory is writable and\n"
|
|
"that you have enough free disk space.");
|
|
}
|
|
}
|
|
|
|
FWadWriter &FWadWriter::operator << (BYTE val)
|
|
{
|
|
AddToLump (&val, 1);
|
|
return *this;
|
|
}
|
|
|
|
FWadWriter &FWadWriter::operator << (WORD val)
|
|
{
|
|
val = LittleShort(val);
|
|
AddToLump ((BYTE *)&val, 2);
|
|
return *this;
|
|
}
|
|
|
|
FWadWriter &FWadWriter::operator << (SWORD val)
|
|
{
|
|
val = LittleShort(val);
|
|
AddToLump ((BYTE *)&val, 2);
|
|
return *this;
|
|
}
|
|
|
|
FWadWriter &FWadWriter::operator << (DWORD val)
|
|
{
|
|
val = LittleLong(val);
|
|
AddToLump ((BYTE *)&val, 4);
|
|
return *this;
|
|
}
|
|
|
|
FWadWriter &FWadWriter::operator << (fixed_t val)
|
|
{
|
|
val = LittleLong(val);
|
|
AddToLump ((BYTE *)&val, 4);
|
|
return *this;
|
|
}
|
|
|