Beispiel #1
0
/* Wad2Archive::isWad2Archive
 * Checks if the given data is a valid Quake wad2 archive
 *******************************************************************/
bool Wad2Archive::isWad2Archive(MemChunk& mc)
{
	// Check size
	if (mc.getSize() < 12)
		return false;

	// Check for IWAD/PWAD header
	if (mc[0] != 'W' || mc[1] != 'A' || mc[2] != 'D' || (mc[3] != '2' && mc[3] != '3'))
		return false;

	// Get number of lumps and directory offset
	int32_t num_lumps = 0;
	int32_t dir_offset = 0;
	mc.seek(4, SEEK_SET);
	mc.read(&num_lumps, 4);
	mc.read(&dir_offset, 4);

	// Reset MemChunk (just in case)
	mc.seek(0, SEEK_SET);

	// Byteswap values for big endian if needed
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// Check directory offset is decent
	if ((unsigned)(dir_offset + (num_lumps * 32)) > mc.getSize() ||
	        dir_offset < 12)
		return false;

	// If it's passed to here it's probably a wad2 file
	return true;
}
Beispiel #2
0
/* ChasmBinArchive::isChasmBinArchive
 * Checks if the given data is a valid Chasm bin archive
 *******************************************************************/
bool ChasmBinArchive::isChasmBinArchive(MemChunk& mc)
{
	// Check given data is valid
	if (mc.getSize() < HEADER_SIZE)
	{
		return false;
	}

	// Read bin header and check it
	char magic[4] = {};
	mc.read(magic, sizeof magic);

	if (   magic[0] != 'C'
		|| magic[1] != 'S'
		|| magic[2] != 'i'
		|| magic[3] != 'd')
	{
		return false;
	}

	uint16_t num_entries = 0;
	mc.read(&num_entries, sizeof num_entries);
	num_entries = wxUINT16_SWAP_ON_BE(num_entries);

	return num_entries > MAX_ENTRY_COUNT
		|| (HEADER_SIZE + ENTRY_SIZE * MAX_ENTRY_COUNT) <= mc.getSize();
}
Beispiel #3
0
/* PakArchive::isPakArchive
 * Checks if the given data is a valid Quake pak archive
 *******************************************************************/
bool PakArchive::isPakArchive(MemChunk& mc)
{
	// Check given data is valid
	if (mc.getSize() < 12)
		return false;

	// Read pak header
	char pack[4];
	long dir_offset;
	long dir_size;
	mc.seek(0, SEEK_SET);
	mc.read(pack, 4);
	mc.read(&dir_offset, 4);
	mc.read(&dir_size, 4);

	// Byteswap values for big endian if needed
	dir_size = wxINT32_SWAP_ON_BE(dir_size);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// Check header
	if (pack[0] != 'P' || pack[1] != 'A' || pack[2] != 'C' || pack[3] != 'K')
		return false;

	// Check directory is sane
	if (dir_offset < 12 || (unsigned)(dir_offset + dir_size) > mc.getSize())
		return false;

	// That'll do
	return true;
}
Beispiel #4
0
/* ADatArchive::isADatArchive
 * Checks if the given data is a valid Anachronox dat archive
 *******************************************************************/
bool ADatArchive::isADatArchive(MemChunk& mc) {
	// Check it opened ok
	if (mc.getSize() < 16)
		return false;

	// Read dat header
	char magic[4];
	long dir_offset;
	long dir_size;
	long version;
	mc.seek(0, SEEK_SET);
	mc.read(magic, 4);
	mc.read(&dir_offset, 4);
	mc.read(&dir_size, 4);
	mc.read(&version, 4);

	// Byteswap values for big endian if needed
	dir_size = wxINT32_SWAP_ON_BE(dir_size);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// Check version
	if (wxINT32_SWAP_ON_BE(version) != 9)
		return false;

	// Check header
	if (magic[0] != 'A' || magic[1] != 'D' || magic[2] != 'A' || magic[3] != 'T')
		return false;

	// Check directory is sane
	if (dir_offset < 16 || (unsigned)(dir_offset + dir_size) > mc.getSize())
		return false;

	// That'll do
	return true;
}
Beispiel #5
0
// -----------------------------------------------------------------------------
// Checks if the given data is a valid pod archive
// -----------------------------------------------------------------------------
bool PodArchive::isPodArchive(MemChunk& mc)
{
	// Check size for header
	if (mc.size() < 84)
		return false;

	// Read no. of files
	mc.seek(0, 0);
	uint32_t num_files;
	mc.read(&num_files, 4);

	// Read id
	char id[80];
	mc.read(id, 80);

	// Check size for directory
	if (mc.size() < 84 + (num_files * 40))
		return false;

	// Read directory and check offsets
	FileEntry entry;
	for (unsigned a = 0; a < num_files; a++)
	{
		mc.read(&entry, 40);
		if (entry.offset + entry.size > mc.size())
			return false;
	}
	return true;
}
Beispiel #6
0
/* GobArchive::isGobArchive
 * Checks if the given data is a valid Dark Forces gob archive
 *******************************************************************/
bool GobArchive::isGobArchive(MemChunk& mc)
{
	// Check size
	if (mc.getSize() < 12)
		return false;

	// Check magic header
	if (mc[0] != 'G' || mc[1] != 'O' || mc[2] != 'B' || mc[3] != 0xA)
		return false;

	// Get directory offset
	uint32_t dir_offset = 0;
	mc.seek(4, SEEK_SET);
	mc.read(&dir_offset, 4);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// Check size
	if ((unsigned)mc.getSize() < (dir_offset + 4))
		return false;

	// Get number of lumps
	uint32_t num_lumps = 0;
	mc.seek(dir_offset, SEEK_SET);
	mc.read(&num_lumps, 4);
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);

	// Compute directory size
	uint32_t dir_size = (num_lumps * 21) + 4;
	if ((unsigned)mc.getSize() < (dir_offset + dir_size))
		return false;

	// If it's passed to here it's probably a gob file
	return true;
}
Beispiel #7
0
/* ResArchive::open
 * Reads res format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool ResArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	// Read res header
	uint32_t	dir_size = 0;
	uint32_t	dir_offset = 0;
	char		magic[4] = "";
	mc.seek(0, SEEK_SET);
	mc.read(&magic, 4);			// "Res!"
	mc.read(&dir_offset, 4);	// Offset to directory
	mc.read(&dir_size, 4);		// No. of lumps in res

	// Byteswap values for big endian if needed
	dir_size = wxINT32_SWAP_ON_BE(dir_size);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// Check the header
	if (magic[0] != 'R' || magic[1] != 'e' || magic[2] != 's' || magic[3] != '!')
	{
		LOG_MESSAGE(1, "ResArchive::openFile: File %s has invalid header", filename);
		Global::error = "Invalid res header";
		return false;
	}

	if (dir_size % RESDIRENTRYSIZE)
	{
		LOG_MESSAGE(1, "ResArchive::openFile: File %s has invalid directory size", filename);
		Global::error = "Invalid res directory size";
		return false;
	}
	uint32_t num_lumps = dir_size / RESDIRENTRYSIZE;

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	// Read the directory
	mc.seek(dir_offset, SEEK_SET);
	UI::setSplashProgressMessage("Reading res archive data");
	if (!readDirectory(mc, dir_offset, num_lumps, getRoot()))
		return false;

	// Detect maps (will detect map entry types)
	UI::setSplashProgressMessage("Detecting maps");
	detectMaps();

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	UI::setSplashProgressMessage("");

	return true;
}
Beispiel #8
0
void MapTextureManager::onAnnouncement(Announcer* announcer, string event_name, MemChunk& event_data)
{
	// Only interested in the resource manager,
	// archive manager and palette chooser.
	if (announcer != theResourceManager
	        && announcer != thePaletteChooser
	        && announcer != theArchiveManager)
		return;

	// If the map's archive is being closed,
	// we need to close the map editor
	if (event_name == "archive_closing")
	{
		event_data.seek(0, SEEK_SET);
		int32_t ac_index;
		event_data.read(&ac_index, 4);
		if (theArchiveManager->getArchive(ac_index) == archive)
		{
			theMapEditor->Hide();
			theMapEditor->mapEditor().clearMap();
			archive = NULL;
		}
	}

	// If the resources have been updated
	if (event_name == "resources_updated")
		refreshResources();

	if (event_name == "main_palette_changed")
		refreshResources();
}
// -----------------------------------------------------------------------------
// Handles announcements from any announcers listened to
// -----------------------------------------------------------------------------
void MapTextureManager::onAnnouncement(Announcer* announcer, std::string_view event_name, MemChunk& event_data)
{
	// Only interested in the resource manager,
	// archive manager and palette chooser.
	if (announcer != &App::resources() && announcer != theMainWindow->paletteChooser()
		&& announcer != &App::archiveManager())
		return;

	// If the map's archive is being closed,
	// we need to close the map editor
	if (event_name == "archive_closing")
	{
		event_data.seek(0, SEEK_SET);
		int32_t ac_index;
		event_data.read(&ac_index, 4);
		if (App::archiveManager().getArchive(ac_index) == archive_)
		{
			MapEditor::windowWx()->Hide();
			MapEditor::editContext().clearMap();
			archive_ = nullptr;
		}
	}

	// If the resources have been updated
	if (event_name == "resources_updated")
		refreshResources();

	if (event_name == "main_palette_changed")
		refreshResources();
}
Beispiel #10
0
/* RffArchive::isRffArchive
 * Checks if the given data is a valid Duke Nukem 3D grp archive
 *******************************************************************/
bool RffArchive::isRffArchive(MemChunk& mc)
{
	// Check size
	if (mc.getSize() < 12)
		return false;

	// Read grp header
	uint8_t magic[4];
	uint32_t version, dir_offset, num_lumps;

	mc.seek(0, SEEK_SET);
	mc.read(magic, 4);			// Should be "RFF\x18"
	mc.read(&version, 4);		// 0x01 0x03 \x00 \x00
	mc.read(&dir_offset, 4);	// Offset to directory
	mc.read(&num_lumps, 4);		// No. of lumps in rff

	// Byteswap values for big endian if needed
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);
	version = wxINT32_SWAP_ON_BE(version);

	// Check the header
	if (magic[0] != 'R' || magic[1] != 'F' || magic[2] != 'F' || magic[3] != 0x1A || version != 0x301)
		return false;


	// Compute total size
	RFFLump* lumps = new RFFLump[num_lumps];
	mc.seek(dir_offset, SEEK_SET);
	theSplashWindow->setProgressMessage("Reading rff archive data");
	mc.read (lumps, num_lumps * sizeof(RFFLump));
	BloodCrypt (lumps, dir_offset, num_lumps * sizeof(RFFLump));
	uint32_t totalsize = 12 + num_lumps * sizeof(RFFLump);
	uint32_t size = 0;
	for (uint32_t a = 0; a < num_lumps; ++a)
	{
		totalsize += lumps[a].Size;
	}

	// Check if total size is correct
	if (totalsize > mc.getSize())
		return false;

	// If it's passed to here it's probably a grp file
	return true;
}
Beispiel #11
0
// -----------------------------------------------------------------------------
// Checks if the given data is a valid Nerve disk archive
// -----------------------------------------------------------------------------
bool DiskArchive::isDiskArchive(MemChunk& mc)
{
	// Check given data is valid
	size_t mcsize = mc.getSize();
	if (mcsize < 80)
		return false;

	// Read disk header
	uint32_t num_entries;
	uint32_t size_entries;
	mc.seek(0, SEEK_SET);
	mc.read(&num_entries, 4);
	num_entries = wxUINT32_SWAP_ON_LE(num_entries);

	size_t start_offset = (72 * num_entries) + 8;

	if (mcsize < start_offset)
		return false;

	// Read the directory
	for (uint32_t d = 0; d < num_entries; d++)
	{
		// Read entry info
		DiskEntry entry;
		mc.read(&entry, 72);

		// Byteswap if needed
		entry.length = wxUINT32_SWAP_ON_LE(entry.length);
		entry.offset = wxUINT32_SWAP_ON_LE(entry.offset);

		// Increase offset to make it relative to start of archive
		entry.offset += start_offset;

		// Check offset+size
		if (entry.offset + entry.length > mcsize)
			return false;
	}
	mc.read(&size_entries, 4);
	size_entries = wxUINT32_SWAP_ON_LE(size_entries);
	if (size_entries + start_offset != mcsize)
		return false;

	// That'll do
	return true;
}
Beispiel #12
0
/* DatArchive::isDatArchive
 * Checks if the given data is a valid Shadowcaster dat archive
 *******************************************************************/
bool DatArchive::isDatArchive(MemChunk& mc)
{
	// Read dat header
	mc.seek(0, SEEK_SET);
	uint16_t num_lumps;
	uint32_t dir_offset, junk;
	mc.read(&num_lumps, 2);		// Size
	mc.read(&dir_offset, 4);	// Directory offset
	mc.read(&junk, 4);		// Unknown value
	num_lumps	= wxINT16_SWAP_ON_BE(num_lumps);
	dir_offset	= wxINT32_SWAP_ON_BE(dir_offset);
	junk		= wxINT32_SWAP_ON_BE(junk);

	if (dir_offset >= mc.getSize())
		return false;

	// Read the directory
	mc.seek(dir_offset, SEEK_SET);
	// Read lump info
	uint32_t offset = 0;
	uint32_t size = 0;
	uint16_t nameofs = 0;
	uint16_t flags = 0;

	mc.read(&offset,	4);		// Offset
	mc.read(&size,		4);		// Size
	mc.read(&nameofs,	2);		// Name offset
	mc.read(&flags,		2);		// Flags

	// Byteswap values for big endian if needed
	offset	= wxINT32_SWAP_ON_BE(offset);
	size	= wxINT32_SWAP_ON_BE(size);
	nameofs	= wxINT16_SWAP_ON_BE(nameofs);
	flags	= wxINT16_SWAP_ON_BE(flags);

	// The first lump should have a name (subsequent lumps need not have one).
	// Also, sanity check the values.
	if (nameofs == 0 || nameofs >=  mc.getSize() || offset + size >= mc.getSize())
	{
		return false;
	}

	size_t len = 1;
	size_t start = nameofs+dir_offset;
	// Sanity checks again. Make sure there is actually a name.
	if (start > mc.getSize() || mc[start] < 33)
		return false;
	for (size_t i = start; (mc[i] != 0 && i < mc.getSize()); ++i, ++len)
	{
		// Names should not contain garbage characters
		if (mc[i] < 32 || mc[i] > 126)
			return false;
	}
	// Let's be reasonable here. While names aren't limited, if it's too long, it's suspicious.
	if (len > 60)
		return false;
	return true;
}
	void onAnnouncement(Announcer* announcer, string event_name, MemChunk& event_data)
	{
		if (announcer != entry->getParent())
			return;

		bool finished = false;

		// Entry removed
		if (event_name == "entry_removed")
		{
			int index;
			wxUIntPtr ptr;
			event_data.read(&index, sizeof(int));
			event_data.read(&ptr, sizeof(wxUIntPtr));
			if (wxUIntToPtr(ptr) == entry)
				finished = true;
		}

		if (finished)
			delete this;
	}
Beispiel #14
0
	bool readImage(SImage& image, MemChunk& data, int index)
	{
		// Get info
		SImage::info_t info = getInfo(data, index);

		// Create image from data
		image.create(info.width, info.height, PALMASK);
		data.read(imageData(image), info.width * info.height, 0);
		image.fillAlpha(255);

		return true;
	}
Beispiel #15
0
bool ResArchive::isResArchive(MemChunk& mc, size_t& dir_offset, size_t& num_lumps)
{
	// Check size
	if (mc.getSize() < 12)
		return false;

	// Check for "Res!" header
	if (!(mc[0] == 'R' && mc[1] == 'e' && mc[2] == 's' && mc[3] == '!'))
		return false;

	// Get number of lumps and directory offset
	uint32_t offset_offset = 0;
	uint32_t rel_offset = 0;
	uint32_t dir_size = 0;
	mc.seek(4, SEEK_SET);
	mc.read(&dir_offset, 4);
	mc.read(&dir_size, 4);

	// Byteswap values for big endian if needed
	dir_size = wxINT32_SWAP_ON_BE(dir_size);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// A&A contains nested resource files. The offsets are then always relative to
	// the top-level file. This causes problem with the embedded archive system
	// used by SLADE3. The solution is to compute the offset offset. :)
	offset_offset = dir_offset - (mc.getSize() - dir_size);
	rel_offset = dir_offset - offset_offset;

	// Check directory offset and size are both decent
	if (dir_size % RESDIRENTRYSIZE || (rel_offset + dir_size) > mc.getSize())
		return false;

	num_lumps = dir_size / RESDIRENTRYSIZE;

	// Reset MemChunk (just in case)
	mc.seek(0, SEEK_SET);

	// If it's passed to here it's probably a res file
	return true;
}
Beispiel #16
0
// -----------------------------------------------------------------------------
// Checks if the given data is a valid Duke Nukem 3D grp archive
// -----------------------------------------------------------------------------
bool GrpArchive::isGrpArchive(MemChunk& mc)
{
	// Check size
	if (mc.size() < 16)
		return false;

	// Get number of lumps
	uint32_t num_lumps     = 0;
	char     ken_magic[13] = "";
	mc.seek(0, SEEK_SET);
	mc.read(ken_magic, 12); // "KenSilverman"
	mc.read(&num_lumps, 4); // No. of lumps in grp

	// Byteswap values for big endian if needed
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);

	// Null-terminate the magic header
	ken_magic[12] = 0;

	// Check the header
	if (!(S_CMP(wxString::From8BitData(ken_magic), "KenSilverman")))
		return false;

	// Compute total size
	uint32_t totalsize = (1 + num_lumps) * 16;
	uint32_t size      = 0;
	for (uint32_t a = 0; a < num_lumps; ++a)
	{
		mc.read(ken_magic, 12);
		mc.read(&size, 4);
		totalsize += size;
	}

	// Check if total size is correct
	if (totalsize > mc.size())
		return false;

	// If it's passed to here it's probably a grp file
	return true;
}
Beispiel #17
0
/* LfdArchive::isLfdArchive
 * Checks if the given data is a valid Dark Forces lfd archive
 *******************************************************************/
bool LfdArchive::isLfdArchive(MemChunk& mc)
{
	// Check size
	if (mc.getSize() < 12)
		return false;

	// Check magic header
	if (mc[0] != 'R' || mc[1] != 'M' || mc[2] != 'A' || mc[3] != 'P')
		return false;

	// Get offset of first entry
	uint32_t dir_offset = 0;
	mc.seek(12, SEEK_SET);
	mc.read(&dir_offset, 4);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset) + 16;
	if (dir_offset % 16) return false;
	char type1[5]; char type2[5];
	char name1[9]; char name2[9];
	uint32_t len1; uint32_t len2;
	mc.read(type1, 4); type1[4] = 0;
	mc.read(name1, 8); name1[8] = 0;
	mc.read(&len1, 4); len1 = wxINT32_SWAP_ON_BE(len1);

	// Check size
	if ((unsigned)mc.getSize() < (dir_offset + 16 + len1))
		return false;

	// Compare
	mc.seek(dir_offset, SEEK_SET);
	mc.read(type2, 4); type2[4] = 0;
	mc.read(name2, 8); name2[8] = 0;
	mc.read(&len2, 4); len2 = wxINT32_SWAP_ON_BE(len2);

	if (strcmp(type1, type2) || strcmp(name1, name2) || len1 != len2)
		return false;

	// If it's passed to here it's probably a lfd file
	return true;
}
Beispiel #18
0
// -----------------------------------------------------------------------------
// Checks if the given data is a valid BZip2 archive
// -----------------------------------------------------------------------------
bool BZip2Archive::isBZip2Archive(MemChunk& mc)
{
	size_t size = mc.size();
	if (size < 14)
		return false;

	// Read header
	uint8_t header[4];
	mc.read(header, 4);

	// Check for BZip2 header (reject BZip1 headers)
	if (header[0] == 'B' && header[1] == 'Z' && header[2] == 'h' && (header[3] >= '1' && header[3] <= '9'))
		return true;

	return false;
}
Beispiel #19
0
// -----------------------------------------------------------------------------
// Reads bzip2 format data from a MemChunk
// Returns true if successful, false otherwise
// -----------------------------------------------------------------------------
bool BZip2Archive::open(MemChunk& mc)
{
	size_t size = mc.size();
	if (size < 14)
		return false;

	// Read header
	uint8_t header[4];
	mc.read(header, 4);

	// Check for BZip2 header (reject BZip1 headers)
	if (!(header[0] == 'B' && header[1] == 'Z' && header[2] == 'h' && (header[3] >= '1' && header[3] <= '9')))
		return false;

	// Build name from filename
	string     name = filename(false);
	wxFileName fn(name);
	if (!fn.GetExt().CmpNoCase("tbz") || !fn.GetExt().CmpNoCase("tb2") || !fn.GetExt().CmpNoCase("tbz2"))
		fn.SetExt("tar");
	else if (!fn.GetExt().CmpNoCase("bz2"))
		fn.ClearExt();
	name = fn.GetFullName();

	// Let's create the entry
	setMuted(true);
	auto     entry = std::make_shared<ArchiveEntry>(name, size);
	MemChunk xdata;
	if (Compression::bzip2Decompress(mc, xdata))
	{
		entry->importMemChunk(xdata);
	}
	else
	{
		setMuted(false);
		return false;
	}
	rootDir()->addEntry(entry);
	EntryType::detectEntryType(entry.get());
	entry->setState(ArchiveEntry::State::Unmodified);

	setMuted(false);
	setModified(false);
	announce("opened");

	// Finish
	return true;
}
Beispiel #20
0
/* ZipArchive::isZipArchive
 * Checks if the given data is a valid zip archive
 *******************************************************************/
bool ZipArchive::isZipArchive(MemChunk& mc)
{
	// Check size
	if (mc.getSize() < sizeof(zip_file_header_t))
		return false;

	// Read first file header
	zip_file_header_t header;
	mc.seek(0, SEEK_SET);
	mc.read(&header, sizeof(zip_file_header_t));

	// Check header signature
	if (header.sig != 0x04034b50)
		return false;

	// The zip format is horrendous, so this will do for checking
	return true;
}
Beispiel #21
0
/* ResArchive::readDirectory
 * Reads a res directory from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool ResArchive::readDirectory(MemChunk& mc, size_t dir_offset, size_t num_lumps, ArchiveTreeNode* parent)
{
	if (!parent)
	{
		LOG_MESSAGE(1, "ReadDir: No parent node");
		Global::error = "Archive is invalid and/or corrupt";
		return false;
	}
	mc.seek(dir_offset, SEEK_SET);
	for (uint32_t d = 0; d < num_lumps; d++)
	{
		// Update splash window progress
		UI::setSplashProgress(((float)d / (float)num_lumps));

		// Read lump info
		char magic[4] = "";
		char name[15] = "";
		uint32_t dumzero1, dumzero2;
		uint16_t dumff, dumze;
		uint8_t flags = 0;
		uint32_t offset = 0;
		uint32_t size = 0;

		mc.read(magic, 4);		// ReS\0
		mc.read(name, 14);		// Name
		mc.read(&offset, 4);	// Offset
		mc.read(&size, 4);		// Size

		// Check the identifier
		if (magic[0] != 'R' || magic[1] != 'e' || magic[2] != 'S' || magic[3] != 0)
		{
			LOG_MESSAGE(1, "ResArchive::readDir: Entry %s (%i@0x%x) has invalid directory entry", name, size, offset);
			Global::error = "Archive is invalid and/or corrupt";
			return false;
		}

		// Byteswap values for big endian if needed
		offset = wxINT32_SWAP_ON_BE(offset);
		size = wxINT32_SWAP_ON_BE(size);
		name[14] = '\0';

		mc.read(&dumze, 2); if (dumze) LOG_MESSAGE(1, "Flag guard not null for entry %s", name);
		mc.read(&flags, 1); if (flags != 1 && flags != 17) LOG_MESSAGE(1, "Unknown flag value for entry %s", name);
		mc.read(&dumzero1, 4); if (dumzero1) LOG_MESSAGE(1, "Near-end values not set to zero for entry %s", name);
		mc.read(&dumff, 2); if (dumff != 0xFFFF) LOG_MESSAGE(1, "Dummy set to a non-FF value for entry %s", name);
		mc.read(&dumzero2, 4); if (dumzero2) LOG_MESSAGE(1, "Trailing values not set to zero for entry %s", name);

		// If the lump data goes past the end of the file,
		// the resfile is invalid
		if (offset + size > mc.getSize())
		{
			LOG_MESSAGE(1, "ResArchive::readDirectory: Res archive is invalid or corrupt, offset overflow");
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		// Create & setup lump
		ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(0);

		// Read entry data if it isn't zero-sized
		if (nlump->getSize() > 0)
		{
			// Read the entry data
			MemChunk edata;
			mc.exportMemChunk(edata, offset, size);
			nlump->importMemChunk(edata);
		}

		// What if the entry is a directory?
		size_t d_o, n_l;
		if (isResArchive(nlump->getMCData(), d_o, n_l))
		{
			ArchiveTreeNode* ndir = createDir(name, parent);
			if (ndir)
			{
				UI::setSplashProgressMessage(S_FMT("Reading res archive data: %s directory", name));
				// Save offset to restore it once the recursion is done
				size_t myoffset = mc.currentPos();
				readDirectory(mc, d_o, n_l, ndir);
				ndir->getDirEntry()->setState(0);
				// Restore offset and clean out the entry
				mc.seek(myoffset, SEEK_SET);
				delete nlump;
			}
			else
			{
				delete nlump;
				return false;
			}
			// Not a directory, then add to entry list
		}
		else
		{
			parent->addEntry(nlump);
			// Detect entry type
			EntryType::detectEntryType(nlump);
			// Unload entry data if needed
			if (!archive_load_data)
				nlump->unloadData();
			// Set entry to unchanged
			nlump->setState(0);
		}
	}
	return true;
}
Beispiel #22
0
/* ADatArchive::open
 * Reads dat format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool ADatArchive::open(MemChunk& mc) {
	// Check given data is valid
	if (mc.getSize() < 16)
		return false;

	// Read dat header
	char magic[4];
	long dir_offset;
	long dir_size;
	mc.seek(0, SEEK_SET);
	mc.read(magic, 4);
	mc.read(&dir_offset, 4);
	mc.read(&dir_size, 4);

	// Check it
	if (magic[0] != 'A' || magic[1] != 'D' || magic[2] != 'A' || magic[3] != 'T') {
		wxLogMessage("ADatArchive::open: Opening failed, invalid header");
		Global::error = "Invalid dat header";
		return false;
	}

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	// Read the directory
	size_t num_entries = dir_size / DIRENTRY;
	mc.seek(dir_offset, SEEK_SET);
	theSplashWindow->setProgressMessage("Reading dat archive data");
	for (uint32_t d = 0; d < num_entries; d++) {
		// Update splash window progress
		theSplashWindow->setProgress(((float)d / (float)num_entries));

		// Read entry info
		char name[128];
		long offset;
		long decsize;
		long compsize;
		long whatever;			// No idea what this could be
		mc.read(name, 128);
		mc.read(&offset, 4);
		mc.read(&decsize, 4);
		mc.read(&compsize, 4);
		mc.read(&whatever, 4);

		// Byteswap if needed
		offset = wxINT32_SWAP_ON_BE(offset);
		decsize = wxINT32_SWAP_ON_BE(decsize);
		compsize = wxINT32_SWAP_ON_BE(compsize);

		// Check offset+size
		if ((unsigned)(offset + compsize) > mc.getSize()) {
			wxLogMessage("ADatArchive::open: dat archive is invalid or corrupt (entry goes past end of file)");
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		// Parse name
		wxFileName fn(wxString::FromAscii(name, 128));

		// Create directory if needed
		ArchiveTreeNode* dir = createDir(fn.GetPath(true, wxPATH_UNIX));

		// Create entry
		ArchiveEntry* entry = new ArchiveEntry(fn.GetFullName(), compsize);
		entry->exProp("Offset") = (int)offset;
		entry->exProp("FullSize") = (int)decsize;
		entry->setLoaded(false);
		entry->setState(0);

		// Add to directory
		dir->addEntry(entry);
	}

	// Detect all entry types
	MemChunk edata;
	vector<ArchiveEntry*> all_entries;
	getEntryTreeAsList(all_entries);
	theSplashWindow->setProgressMessage("Detecting entry types");
	for (size_t a = 0; a < all_entries.size(); a++) {
		// Update splash window progress
		theSplashWindow->setProgress((((float)a / (float)num_entries)));

		// Get entry
		ArchiveEntry* entry = all_entries[a];

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0) {
			// Read the entry data
			mc.exportMemChunk(edata, (int)entry->exProp("Offset"), entry->getSize());
			MemChunk xdata;
			if (Compression::ZlibInflate(edata, xdata, (int)entry->exProp("FullSize")))
				entry->importMemChunk(xdata);
			else {
				wxLogMessage("Entry %s couldn't be inflated", CHR(entry->getName()));
				entry->importMemChunk(edata);
			}
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Unload entry data if needed
		if (!archive_load_data)
			entry->unloadData();

		// Set entry to unchanged
		entry->setState(0);
	}

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	theSplashWindow->setProgressMessage("");

	return true;
}
Beispiel #23
0
/* HogArchive::open
 * Reads hog format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool HogArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	// Check size
	size_t archive_size = mc.getSize();
	if (archive_size < 3)
		return false;

	// Check magic header (DHF for "Descent Hog File")
	if (mc[0] != 'D' || mc[1] != 'H' || mc[2] != 'F')
		return false;

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	// Iterate through files to see if the size seems okay
	theSplashWindow->setProgressMessage("Reading hog archive data");
	size_t iter_offset = 3;
	uint32_t num_lumps = 0;
	while (iter_offset < archive_size)
	{
		// Update splash window progress
		theSplashWindow->setProgress(((float)iter_offset / (float)archive_size));

		// If the lump data goes past the end of the file,
		// the hogfile is invalid
		if (iter_offset + 17 > archive_size)
		{
			wxLogMessage("HogArchive::open: hog archive is invalid or corrupt");
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		// Setup variables
		num_lumps++;
		size_t offset = iter_offset + 17;
		size_t size = READ_L32(mc, iter_offset + 13);
		char name[14] = "";
		mc.seek(iter_offset, SEEK_SET);
		mc.read(name, 13);
		name[13] = 0;

		// Create & setup lump
		ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(0);

		// Add to entry list
		getRoot()->addEntry(nlump);

		// Update entry size to compute next offset
		iter_offset = offset + size;
	}

	// Detect all entry types
	MemChunk edata;
	theSplashWindow->setProgressMessage("Detecting entry types");
	for (size_t a = 0; a < numEntries(); a++)
	{
		// Update splash window progress
		theSplashWindow->setProgress((((float)a / (float)num_lumps)));

		// Get entry
		ArchiveEntry* entry = getEntry(a);

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, getEntryOffset(entry), entry->getSize());
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Unload entry data if needed
		if (!archive_load_data)
			entry->unloadData();

		// Set entry to unchanged
		entry->setState(0);
	}

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	theSplashWindow->setProgressMessage("");

	return true;
}
Beispiel #24
0
/* RffArchive::open
 * Reads grp format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool RffArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	// Read grp header
	uint8_t magic[4];
	uint32_t version, dir_offset, num_lumps;

	mc.seek(0, SEEK_SET);
	mc.read(magic, 4);			// Should be "RFF\x18"
	mc.read(&version, 4);		// 0x01 0x03 \x00 \x00
	mc.read(&dir_offset, 4);	// Offset to directory
	mc.read(&num_lumps, 4);		// No. of lumps in rff

	// Byteswap values for big endian if needed
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);
	version = wxINT32_SWAP_ON_BE(version);

	// Check the header
	if (magic[0] != 'R' || magic[1] != 'F' || magic[2] != 'F' || magic[3] != 0x1A || version != 0x301)
	{
		wxLogMessage("RffArchive::openFile: File %s has invalid header", filename);
		Global::error = "Invalid rff header";
		return false;
	}

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	// Read the directory
	RFFLump* lumps = new RFFLump[num_lumps];
	mc.seek(dir_offset, SEEK_SET);
	theSplashWindow->setProgressMessage("Reading rff archive data");
	mc.read (lumps, num_lumps * sizeof(RFFLump));
	BloodCrypt (lumps, dir_offset, num_lumps * sizeof(RFFLump));
	for (uint32_t d = 0; d < num_lumps; d++)
	{
		// Update splash window progress
		theSplashWindow->setProgress(((float)d / (float)num_lumps));

		// Read lump info
		char name[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
		uint32_t offset = wxINT32_SWAP_ON_BE(lumps[d].FilePos);
		uint32_t size = wxINT32_SWAP_ON_BE(lumps[d].Size);

		// Reconstruct name
		int i, j = 0;
		for (i = 0; i < 8; ++i)
		{
			if (lumps[d].Name[i] == 0) break;
			name[i] = lumps[d].Name[i];
		}
		for (name[i++] = '.'; j < 3; ++j)
			name[i+j] = lumps[d].Extension[j];

		// If the lump data goes past the end of the file,
		// the rfffile is invalid
		if (offset + size > mc.getSize())
		{
			wxLogMessage("RffArchive::open: rff archive is invalid or corrupt");
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		// Create & setup lump
		ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(0);

		// Is the entry encrypted?
		if (lumps[d].Flags & 0x10)
			nlump->setEncryption(ENC_BLOOD);

		// Add to entry list
		getRoot()->addEntry(nlump);
	}
	delete[] lumps;

	// Detect all entry types
	MemChunk edata;
	theSplashWindow->setProgressMessage("Detecting entry types");
	for (size_t a = 0; a < numEntries(); a++)
	{
		// Update splash window progress
		theSplashWindow->setProgress((((float)a / (float)num_lumps)));

		// Get entry
		ArchiveEntry* entry = getEntry(a);

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, getEntryOffset(entry), entry->getSize());

			// If the entry is encrypted, decrypt it
			if (entry->isEncrypted())
			{
				uint8_t* cdata = new uint8_t[entry->getSize()];
				memcpy(cdata, edata.getData(), entry->getSize());
				int cryptlen = entry->getSize() < 256 ? entry->getSize() : 256;
				BloodCrypt(cdata, 0, cryptlen);
				edata.importMem(cdata, entry->getSize());
				delete[] cdata;
			}

			// Import data
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Unload entry data if needed
		if (!archive_load_data)
			entry->unloadData();

		// Set entry to unchanged
		entry->setState(0);
	}

	// Detect maps (will detect map entry types)
	//theSplashWindow->setProgressMessage("Detecting maps");
	//detectMaps();

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	theSplashWindow->setProgressMessage("");

	return true;
}
Beispiel #25
0
/* GobArchive::open
 * Reads gob format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool GobArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	// Check size
	if (mc.getSize() < 12)
		return false;

	// Check magic header
	if (mc[0] != 'G' || mc[1] != 'O' || mc[2] != 'B' || mc[3] != 0xA)
		return false;

	// Get directory offset
	uint32_t dir_offset = 0;
	mc.seek(4, SEEK_SET);
	mc.read(&dir_offset, 4);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// Check size
	if ((unsigned)mc.getSize() < (dir_offset + 4))
		return false;

	// Get number of lumps
	uint32_t num_lumps = 0;
	mc.seek(dir_offset, SEEK_SET);
	mc.read(&num_lumps, 4);
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);

	// Compute directory size
	uint32_t dir_size = (num_lumps * 21) + 4;
	if ((unsigned)mc.getSize() < (dir_offset + dir_size))
		return false;

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	// Read the directory
	theSplashWindow->setProgressMessage("Reading gob archive data");
	for (uint32_t d = 0; d < num_lumps; d++)
	{
		// Update splash window progress
		theSplashWindow->setProgress(((float)d / (float)num_lumps));

		// Read lump info
		uint32_t offset = 0;
		uint32_t size = 0;
		char name[13] = "";

		mc.read(&offset, 4);	// Offset
		mc.read(&size, 4);		// Size
		mc.read(name, 13);		// Name
		name[12] = '\0';

		// Byteswap values for big endian if needed
		size = wxINT32_SWAP_ON_BE(size);

		// If the lump data goes past the end of the file,
		// the gobfile is invalid
		if (offset + size > mc.getSize())
		{
			wxLogMessage("GobArchive::open: gob archive is invalid or corrupt");
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		// Create & setup lump
		ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(0);

		// Add to entry list
		getRoot()->addEntry(nlump);
	}

	// Detect all entry types
	MemChunk edata;
	theSplashWindow->setProgressMessage("Detecting entry types");
	for (size_t a = 0; a < numEntries(); a++)
	{
		// Update splash window progress
		theSplashWindow->setProgress((((float)a / (float)num_lumps)));

		// Get entry
		ArchiveEntry* entry = getEntry(a);

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, getEntryOffset(entry), entry->getSize());
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Unload entry data if needed
		if (!archive_load_data)
			entry->unloadData();

		// Set entry to unchanged
		entry->setState(0);
	}

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	theSplashWindow->setProgressMessage("");

	return true;
}
Beispiel #26
0
/* DatArchive::open
 * Reads wad format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool DatArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	const uint8_t* mcdata = mc.getData();

	// Read dat header
	mc.seek(0, SEEK_SET);
	uint16_t num_lumps;
	uint32_t dir_offset, unknown;
	mc.read(&num_lumps, 2);		// Size
	mc.read(&dir_offset, 4);	// Directory offset
	mc.read(&unknown, 4);		// Unknown value
	num_lumps	= wxINT16_SWAP_ON_BE(num_lumps);
	dir_offset	= wxINT32_SWAP_ON_BE(dir_offset);
	unknown		= wxINT32_SWAP_ON_BE(unknown);
	string lastname(wxString::FromAscii("-noname-"));
	size_t namecount = 0;

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	// Read the directory
	mc.seek(dir_offset, SEEK_SET);
	theSplashWindow->setProgressMessage("Reading dat archive data");
	for (uint32_t d = 0; d < num_lumps; d++)
	{
		// Update splash window progress
		theSplashWindow->setProgress(((float)d / (float)num_lumps));

		// Read lump info
		uint32_t offset = 0;
		uint32_t size = 0;
		uint16_t nameofs = 0;
		uint16_t flags = 0;

		mc.read(&offset,	4);		// Offset
		mc.read(&size,		4);		// Size
		mc.read(&nameofs,	2);		// Name offset
		mc.read(&flags,		2);		// Flags (only one: RLE encoded)

		// Byteswap values for big endian if needed
		offset = wxINT32_SWAP_ON_BE(offset);
		size = wxINT32_SWAP_ON_BE(size);
		nameofs = wxINT16_SWAP_ON_BE(nameofs);
		flags = wxINT16_SWAP_ON_BE(flags);

		// If the lump data goes past the directory,
		// the data file is invalid
		if (offset + size > mc.getSize())
		{
			wxLogMessage("DatArchive::open: Dat archive is invalid or corrupt at entry %i", d);
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		string myname;
		if (nameofs != 0)
		{
			size_t len = 1;
			size_t start = nameofs+dir_offset;
			for (size_t i = start; mcdata[i] != 0; ++i) { ++len; }
			lastname = myname = wxString::FromAscii(mcdata+start, len);
			namecount = 0;
		}
		else
		{
			myname = S_FMT("%s+%d", lastname, ++namecount);
		}

		// Create & setup lump
		ArchiveEntry* nlump = new ArchiveEntry(myname, size);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(0);

		if (flags & 1) nlump->setEncryption(ENC_SCRLE0);

		// Check for markers
		if (!nlump->getName().Cmp("startflats"))
			flats[0] = d;
		if (!nlump->getName().Cmp("endflats"))
			flats[1] = d;
		if (!nlump->getName().Cmp("startsprites"))
			sprites[0] = d;
		if (!nlump->getName().Cmp("endmonsters"))
			sprites[1] = d;
		if (!nlump->getName().Cmp("startwalls"))
			walls[0] = d;
		if (!nlump->getName().Cmp("endwalls"))
			walls[1] = d;

		// Add to entry list
		getRoot()->addEntry(nlump);
	}

	// Detect all entry types
	MemChunk edata;
	theSplashWindow->setProgressMessage("Detecting entry types");
	for (size_t a = 0; a < numEntries(); a++)
	{
		// Update splash window progress
		theSplashWindow->setProgress((((float)a / (float)num_lumps)));

		// Get entry
		ArchiveEntry* entry = getEntry(a);

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, getEntryOffset(entry), entry->getSize());
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Set entry to unchanged
		entry->setState(0);
	}

	// Detect maps (will detect map entry types)
	//theSplashWindow->setProgressMessage("Detecting maps");
	//detectMaps();

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	theSplashWindow->setProgressMessage("");

	return true;
}
Beispiel #27
0
/* WadArchive::open
 * Reads wad format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool WadArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	// Read wad header
	uint32_t	num_lumps = 0;
	uint32_t	dir_offset = 0;
	char		wad_type[4] = "";
	mc.seek(0, SEEK_SET);
	mc.read(&wad_type, 4);		// Wad type
	mc.read(&num_lumps, 4);		// No. of lumps in wad
	mc.read(&dir_offset, 4);	// Offset to directory

	// Byteswap values for big endian if needed
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// Check the header
	if (wad_type[1] != 'W' || wad_type[2] != 'A' || wad_type[3] != 'D')
	{
		wxLogMessage("WadArchive::openFile: File %s has invalid header", filename);
		Global::error = "Invalid wad header";
		return false;
	}

	// Check for iwad
	if (wad_type[0] == 'I')
		iwad = true;

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	vector<uint32_t> offsets;

	// Read the directory
	mc.seek(dir_offset, SEEK_SET);
	theSplashWindow->setProgressMessage("Reading wad archive data");
	for (uint32_t d = 0; d < num_lumps; d++)
	{
		// Update splash window progress
		theSplashWindow->setProgress(((float)d / (float)num_lumps));

		// Read lump info
		char name[9] = "";
		uint32_t offset = 0;
		uint32_t size = 0;

		mc.read(&offset, 4);	// Offset
		mc.read(&size, 4);		// Size
		mc.read(name, 8);		// Name
		name[8] = '\0';

		// Byteswap values for big endian if needed
		offset = wxINT32_SWAP_ON_BE(offset);
		size = wxINT32_SWAP_ON_BE(size);

		// Check to catch stupid shit
		if (size > 0)
		{
			if (offset == 0)
			{
				LOG_MESSAGE(2, "No.");
				continue;
			}
			if (VECTOR_EXISTS(offsets, offset))
			{
				LOG_MESSAGE(1, "Ignoring entry %d: %s, is a clone of a previous entry", d, name);
				continue;
			}
			offsets.push_back(offset);
		}

		// Hack to open Operation: Rheingold WAD files
		if (size == 0 && offset > mc.getSize())
			offset = 0;

		// Is there a compression/encryption thing going on?
		bool jaguarencrypt = !!(name[0] & 0x80);	// look at high bit
		name[0] = name[0] & 0x7F;					// then strip it away

		// Look for encryption shenanigans
		size_t actualsize = size;
		if (jaguarencrypt)
		{
			if (d < num_lumps - 1)
			{
				size_t pos = mc.currentPos();
				uint32_t nextoffset = 0;
				for (int i = 0; i + d < num_lumps; ++i)
				{
					mc.read(&nextoffset, 4);
					if (nextoffset != 0) break;
					mc.seek(12, SEEK_CUR);
				}
				nextoffset = wxINT32_SWAP_ON_BE(nextoffset);
				if (nextoffset == 0) nextoffset = dir_offset;
				mc.seek(pos, SEEK_SET);
				actualsize = nextoffset - offset;
			}
			else
			{
				if (offset > dir_offset)
				{
					actualsize = mc.getSize() - offset;
				}
				else
				{
					actualsize = dir_offset - offset;
				}
			}
		}

		// If the lump data goes past the end of the file,
		// the wadfile is invalid
		if (offset + actualsize > mc.getSize())
		{
			wxLogMessage("WadArchive::open: Wad archive is invalid or corrupt");
			Global::error = S_FMT("Archive is invalid and/or corrupt (lump %d: %s data goes past end of file)", d, name);
			setMuted(false);
			return false;
		}

		// Create & setup lump
		ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(name), size);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(0);

		if (jaguarencrypt)
		{
			nlump->setEncryption(ENC_JAGUAR);
			nlump->exProp("FullSize") = (int)size;
		}

		// Add to entry list
		getRoot()->addEntry(nlump);
	}

	// Detect namespaces (needs to be done before type detection as some types
	// rely on being within certain namespaces)
	updateNamespaces();

	// Detect all entry types
	MemChunk edata;
	theSplashWindow->setProgressMessage("Detecting entry types");
	for (size_t a = 0; a < numEntries(); a++)
	{
		// Update splash window progress
		theSplashWindow->setProgress((((float)a / (float)numEntries())));

		// Get entry
		ArchiveEntry* entry = getEntry(a);

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, getEntryOffset(entry), entry->getSize());
			if (entry->isEncrypted())
			{
				if (entry->exProps().propertyExists("FullSize")
				        && (unsigned)(int)(entry->exProp("FullSize")) >  entry->getSize())
					edata.reSize((int)(entry->exProp("FullSize")), true);
				if (!JaguarDecode(edata))
					wxLogMessage("%i: %s (following %s), did not decode properly", a, entry->getName(), a>0?getEntry(a-1)->getName():"nothing");
			}
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Unload entry data if needed
		if (!archive_load_data)
			entry->unloadData();

		// Set entry to unchanged
		entry->setState(0);
	}

	// Identify #included lumps (DECORATE, GLDEFS, etc.)
	detectIncludes();

	// Detect maps (will detect map entry types)
	theSplashWindow->setProgressMessage("Detecting maps");
	detectMaps();

	// Setup variables
	setMuted(false);
	setModified(false);
	//if (iwad && iwad_lock) read_only = true;
	announce("opened");

	theSplashWindow->setProgressMessage("");

	return true;
}
Beispiel #28
0
// -----------------------------------------------------------------------------
// Reads grp format data from a MemChunk
// Returns true if successful, false otherwise
// -----------------------------------------------------------------------------
bool GrpArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	// Read grp header
	uint32_t num_lumps     = 0;
	char     ken_magic[13] = "";
	mc.seek(0, SEEK_SET);
	mc.read(ken_magic, 12); // "KenSilverman"
	mc.read(&num_lumps, 4); // No. of lumps in grp

	// Byteswap values for big endian if needed
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);

	// Null-terminate the magic header
	ken_magic[12] = 0;

	// Check the header
	if (!(S_CMP(wxString::FromAscii(ken_magic), "KenSilverman")))
	{
		Log::error(S_FMT("GrpArchive::openFile: File %s has invalid header", filename_));
		Global::error = "Invalid grp header";
		return false;
	}

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	// The header takes as much space as a directory entry
	uint32_t entryoffset = 16 * (1 + num_lumps);

	// Read the directory
	UI::setSplashProgressMessage("Reading grp archive data");
	for (uint32_t d = 0; d < num_lumps; d++)
	{
		// Update splash window progress
		UI::setSplashProgress(((float)d / (float)num_lumps));

		// Read lump info
		char     name[13] = "";
		uint32_t offset   = entryoffset;
		uint32_t size     = 0;

		mc.read(name, 12); // Name
		mc.read(&size, 4); // Size
		name[12] = '\0';

		// Byteswap values for big endian if needed
		size = wxINT32_SWAP_ON_BE(size);

		// Increase offset of next entry by this entry's size
		entryoffset += size;

		// If the lump data goes past the end of the file,
		// the grpfile is invalid
		if (offset + size > mc.size())
		{
			Log::error("GrpArchive::open: grp archive is invalid or corrupt");
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		// Create & setup lump
		auto nlump = std::make_shared<ArchiveEntry>(wxString::FromAscii(name), size);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(ArchiveEntry::State::Unmodified);

		// Add to entry list
		rootDir()->addEntry(nlump);
	}

	// Detect all entry types
	MemChunk edata;
	UI::setSplashProgressMessage("Detecting entry types");
	for (size_t a = 0; a < numEntries(); a++)
	{
		// Update splash window progress
		UI::setSplashProgress((((float)a / (float)num_lumps)));

		// Get entry
		auto entry = entryAt(a);

		// Read entry data if it isn't zero-sized
		if (entry->size() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, getEntryOffset(entry), entry->size());
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Unload entry data if needed
		if (!archive_load_data)
			entry->unloadData();

		// Set entry to unchanged
		entry->setState(ArchiveEntry::State::Unmodified);
	}

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	UI::setSplashProgressMessage("");

	return true;
}
Beispiel #29
0
// -----------------------------------------------------------------------------
// Reads Chasm bin format data from a MemChunk
// Returns true if successful, false otherwise
// -----------------------------------------------------------------------------
bool ChasmBinArchive::open(MemChunk& mc)
{
	// Check given data is valid
	if (mc.getSize() < HEADER_SIZE)
	{
		return false;
	}

	// Read .bin header and check it
	char magic[4] = {};
	mc.read(magic, sizeof magic);

	if (magic[0] != 'C' || magic[1] != 'S' || magic[2] != 'i' || magic[3] != 'd')
	{
		LOG_MESSAGE(1, "ChasmBinArchive::open: Opening failed, invalid header");
		Global::error = "Invalid Chasm bin header";
		return false;
	}

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	uint16_t num_entries = 0;
	mc.read(&num_entries, sizeof num_entries);
	num_entries = wxUINT16_SWAP_ON_BE(num_entries);

	// Read the directory
	UI::setSplashProgressMessage("Reading Chasm bin archive data");

	for (uint16_t i = 0; i < num_entries; ++i)
	{
		// Update splash window progress
		UI::setSplashProgress(static_cast<float>(i) / num_entries);

		// Read entry info
		char name[NAME_SIZE] = {};
		mc.read(name, sizeof name);

		uint32_t size;
		mc.read(&size, sizeof size);
		size = wxUINT32_SWAP_ON_BE(size);

		uint32_t offset;
		mc.read(&offset, sizeof offset);
		offset = wxUINT32_SWAP_ON_BE(offset);

		// Check offset+size
		if (offset + size > mc.getSize())
		{
			LOG_MESSAGE(1, "ChasmBinArchive::open: Bin archive is invalid or corrupt (entry goes past end of file)");
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		// Convert Pascal to zero-terminated string
		memmove(name, name + 1, sizeof name - 1);
		name[sizeof name - 1] = '\0';

		// Create entry
		ArchiveEntry* const entry = new ArchiveEntry(name, size);
		entry->exProp("Offset")   = static_cast<int>(offset);
		entry->setLoaded(false);
		entry->setState(0);

		rootDir()->addEntry(entry);
	}

	// Detect all entry types
	UI::setSplashProgressMessage("Detecting entry types");

	vector<ArchiveEntry*> all_entries;
	getEntryTreeAsList(all_entries);

	MemChunk edata;

	for (size_t i = 0; i < all_entries.size(); ++i)
	{
		// Update splash window progress
		UI::setSplashProgress(static_cast<float>(i) / num_entries);

		// Get entry
		ArchiveEntry* const entry = all_entries[i];

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, static_cast<int>(entry->exProp("Offset")), entry->getSize());
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);
		fixBrokenWave(entry);

		// Unload entry data if needed
		if (!archive_load_data)
		{
			entry->unloadData();
		}

		// Set entry to unchanged
		entry->setState(0);
	}

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	UI::setSplashProgressMessage("");

	return true;
}
Beispiel #30
0
/* Wad2Archive::open
 * Reads wad format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool Wad2Archive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

	// Read wad header
	uint32_t	num_lumps = 0;
	uint32_t	dir_offset = 0;
	char		wad_type[4] = "";
	mc.seek(0, SEEK_SET);
	mc.read(&wad_type, 4);		// Wad type
	mc.read(&num_lumps, 4);		// No. of lumps in wad
	mc.read(&dir_offset, 4);	// Offset to directory

	// Byteswap values for big endian if needed
	num_lumps = wxINT32_SWAP_ON_BE(num_lumps);
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);

	// Check the header
	if (wad_type[0] != 'W' || wad_type[1] != 'A' || wad_type[2] != 'D' ||
	        (wad_type[3] != '2' && wad_type[3] != '3'))
	{
		wxLogMessage("Wad2Archive::open: Invalid header");
		Global::error = "Invalid wad2 header";
		return false;
	}
	if (wad_type[3] == '3')
		wad3 = true;

	// Stop announcements (don't want to be announcing modification due to entries being added etc)
	setMuted(true);

	// Read the directory
	mc.seek(dir_offset, SEEK_SET);
	theSplashWindow->setProgressMessage("Reading wad archive data");
	for (uint32_t d = 0; d < num_lumps; d++)
	{
		// Update splash window progress
		theSplashWindow->setProgress(((float)d / (float)num_lumps));

		// Read lump info
		wad2entry_t info;
		mc.read(&info, 32);

		// Byteswap values for big endian if needed
		info.offset = wxINT32_SWAP_ON_BE(info.offset);
		info.size = wxINT32_SWAP_ON_BE(info.size);
		info.dsize = wxINT32_SWAP_ON_BE(info.dsize);

		// If the lump data goes past the end of the file,
		// the wadfile is invalid
		if ((unsigned)(info.offset + info.dsize) > mc.getSize())
		{
			wxLogMessage("Wad2Archive::open: Wad2 archive is invalid or corrupt");
			Global::error = "Archive is invalid and/or corrupt";
			setMuted(false);
			return false;
		}

		// Create & setup lump
		ArchiveEntry* nlump = new ArchiveEntry(wxString::FromAscii(info.name, 16), info.dsize);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)info.offset;
		nlump->exProp("W2Type") = info.type;
		nlump->exProp("W2Size") = (int)info.size;
		nlump->exProp("W2Comp") = !!(info.cmprs);
		nlump->setState(0);

		// Add to entry list
		getRoot()->addEntry(nlump);
	}

	// Detect all entry types
	MemChunk edata;
	theSplashWindow->setProgressMessage("Detecting entry types");
	for (size_t a = 0; a < numEntries(); a++)
	{
		// Update splash window progress
		theSplashWindow->setProgress((((float)a / (float)num_lumps)));

		// Get entry
		ArchiveEntry* entry = getEntry(a);

		// Read entry data if it isn't zero-sized
		if (entry->getSize() > 0)
		{
			// Read the entry data
			mc.exportMemChunk(edata, (int)entry->exProp("Offset"), entry->getSize());
			entry->importMemChunk(edata);
		}

		// Detect entry type
		EntryType::detectEntryType(entry);

		// Unload entry data if needed
		if (!archive_load_data)
			entry->unloadData();

		// Set entry to unchanged
		entry->setState(0);
	}

	// Detect maps (will detect map entry types)
	theSplashWindow->setProgressMessage("Detecting maps");
	detectMaps();

	// Setup variables
	setMuted(false);
	setModified(false);
	announce("opened");

	theSplashWindow->setProgressMessage("");

	return true;
}