Ejemplo n.º 1
0
/* FontManager::initFonts
 * Loads all needed fonts for rendering. SFML 2.x implementation
 *******************************************************************/
int FontManager::initFonts()
{
	// --- Load general fonts ---
	int ret = 0;

	// Normal
	ArchiveEntry* entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans.ttf");
	if (entry) ++ret, font_normal.loadFromMemory((const char*)entry->getData(), entry->getSize());

	// Condensed
	entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_c.ttf");
	if (entry) ++ret, font_condensed.loadFromMemory((const char*)entry->getData(), entry->getSize());

	// Bold
	entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_b.ttf");
	if (entry) ++ret, font_bold.loadFromMemory((const char*)entry->getData(), entry->getSize());

	// Condensed Bold
	entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_cb.ttf");
	if (entry) ++ret, font_boldcondensed.loadFromMemory((const char*)entry->getData(), entry->getSize());

	// Monospace
	entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_mono.ttf");
	if (entry) ++ret, font_small.loadFromMemory((const char*)entry->getData(), entry->getSize());

	return ret;
}
Ejemplo n.º 2
0
/* Wad2Archive::write
 * Writes the wad archive to a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool Wad2Archive::write(MemChunk& mc, bool update)
{
	// Determine directory offset & individual lump offsets
	uint32_t dir_offset = 12;
	ArchiveEntry* entry = NULL;
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		entry->exProp("Offset") = (int)dir_offset;
		dir_offset += entry->getSize();
	}

	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize(dir_offset + numEntries() * 32);

	// Setup wad type
	char wad_type[4] = { 'W', 'A', 'D', '2' };
	if (wad3) wad_type[3] = '3';

	// Write the header
	uint32_t num_lumps = numEntries();
	mc.write(wad_type, 4);
	mc.write(&num_lumps, 4);
	mc.write(&dir_offset, 4);

	// Write the lumps
	for (uint32_t l = 0; l < num_lumps; l++)
	{
		entry = getEntry(l);
		mc.write(entry->getData(), entry->getSize());
	}

	// Write the directory
	for (uint32_t l = 0; l < num_lumps; l++)
	{
		entry = getEntry(l);

		// Setup directory entry
		wad2entry_t info;
		memset(info.name, 0, 16);
		memcpy(info.name, CHR(entry->getName()), entry->getName().Len());
		info.cmprs = (bool)entry->exProp("W2Comp");
		info.dsize = entry->getSize();
		info.size = entry->getSize();
		info.offset = (int)entry->exProp("Offset");
		info.type = (int)entry->exProp("W2Type");

		// Write it
		mc.write(&info, 32);

		if (update)
			entry->setState(0);
	}

	return true;
}
Ejemplo n.º 3
0
/* GobArchive::write
 * Writes the gob archive to a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool GobArchive::write(MemChunk& mc, bool update)
{
	// Determine directory offset & individual lump offsets
	uint32_t dir_offset = 8;
	ArchiveEntry* entry = NULL;
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		setEntryOffset(entry, dir_offset);
		dir_offset += entry->getSize();
	}

	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize(dir_offset + 4 + numEntries() * 21);

	// Write the header
	uint32_t num_lumps = wxINT32_SWAP_ON_BE(numEntries());
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);
	char header[4] = { 'G', 'O', 'B', 0xA };
	mc.write(header, 4);
	mc.write(&dir_offset, 4);

	// Write the lumps
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		mc.write(entry->getData(), entry->getSize());
	}

	// Write the directory
	mc.write(&num_lumps, 4);
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		char name[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
		long offset = wxINT32_SWAP_ON_BE(getEntryOffset(entry));
		long size = wxINT32_SWAP_ON_BE(entry->getSize());

		for (size_t c = 0; c < entry->getName().length() && c < 13; c++)
			name[c] = entry->getName()[c];

		mc.write(&offset, 4);
		mc.write(&size, 4);
		mc.write(name, 13);

		if (update)
		{
			entry->setState(0);
			entry->exProp("Offset") = (int)offset;
		}
	}

	return true;
}
Ejemplo n.º 4
0
/* HogArchive::write
 * Writes the hog archive to a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool HogArchive::write(MemChunk& mc, bool update)
{
	// Determine individual lump offsets
	uint32_t offset = 3;
	ArchiveEntry* entry = NULL;
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		offset += 17;
		entry = getEntry(l);
		setEntryOffset(entry, offset);
		if (update)
		{
			entry->setState(0);
			entry->exProp("Offset") = (int)offset;
		}
		offset += entry->getSize();
	}

	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize(offset);

	// Write the header
	char header[3] = { 'D', 'H', 'F' };
	mc.write(header, 3);

	// Write the lumps
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		mc.write(entry->getData(), entry->getSize());
	}

	// Write the directory
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		char name[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
		long size = wxINT32_SWAP_ON_BE(entry->getSize());

		for (size_t c = 0; c < entry->getName().length() && c < 13; c++)
			name[c] = entry->getName()[c];

		mc.write(name, 13);
		mc.write(&size, 4);
		mc.write(entry->getData(), entry->getSize());
	}

	return true;
}
Ejemplo n.º 5
0
/* MapPreviewCanvas::readThings
 * Reads non-UDMF thing data
 *******************************************************************/
bool MapPreviewCanvas::readThings(ArchiveEntry* map_head, ArchiveEntry* map_end, int map_format)
{
	// Find THINGS entry
	ArchiveEntry* things = NULL;
	while (map_head)
	{
		// Check entry type
		if (map_head->getType() == EntryType::getType("map_things"))
		{
			things = map_head;
			break;
		}

		// Exit loop if we've reached the end of the map entries
		if (map_head == map_end)
			break;
		else
			map_head = map_head->nextEntry();
	}

	// No things
	if (!things)
		return false;

	// Read things data
	if (map_format == MAP_DOOM)
	{
		doomthing_t* thng_data = (doomthing_t*)things->getData(true);
		unsigned nt = things->getSize() / sizeof(doomthing_t);
		for (size_t a = 0; a < nt; a++)
			addThing(thng_data[a].x, thng_data[a].y);
	}
	else if (map_format == MAP_DOOM64)
	{
		doom64thing_t* thng_data = (doom64thing_t*)things->getData(true);
		unsigned nt = things->getSize() / sizeof(doom64thing_t);
		for (size_t a = 0; a < nt; a++)
			addThing(thng_data[a].x, thng_data[a].y);
	}
	else if (map_format == MAP_HEXEN)
	{
		hexenthing_t* thng_data = (hexenthing_t*)things->getData(true);
		unsigned nt = things->getSize() / sizeof(hexenthing_t);
		for (size_t a = 0; a < nt; a++)
			addThing(thng_data[a].x, thng_data[a].y);
	}

	return true;
}
Ejemplo n.º 6
0
SBrush::SBrush(string name)
{

	image = nullptr;
	this->name = name;
	icon = name.AfterFirst('_');
	cx = 0;
	cy = 0;

	Archive* res = App::archiveManager().programResourceArchive();
	if (res == nullptr)
		return;
	ArchiveEntry* file = res->entryAtPath(S_FMT("icons/general/%s.png", icon));
	if (file == nullptr || file->getSize() == 0)
	{
		LOG_MESSAGE(2, "error, no file at icons/general/%s.png", icon);
		return;
	}
	image = new SImage();
	if (!image->open(file->getMCData(), 0, "png"))
	{
		LOG_MESSAGE(2, "couldn't load image data for icons/general/%s.png", icon);
		return;
	}
	image->convertAlphaMap(SImage::ALPHA);
	cx = image->getWidth() >> 1;
	cy = image->getHeight() >> 1;

	theBrushManager->add(this);
}
Ejemplo n.º 7
0
/* ArchiveEntry::ArchiveEntry
 * ArchiveEntry class copy constructor
 *******************************************************************/
ArchiveEntry::ArchiveEntry(ArchiveEntry& copy)
{
	// Initialise (copy) attributes
	this->parent = NULL;
	this->name = copy.name;
	this->size = copy.size;
	this->data_loaded = true;
	this->state = 2;
	this->type = copy.type;
	this->locked = false;
	this->state_locked = false;
	this->reliability = copy.reliability;
	this->next = NULL;
	this->prev = NULL;
	this->encrypted = copy.encrypted;

	// Copy data
	data.importMem(copy.getData(true), copy.getSize());

	// Copy extra properties
	copy.exProps().copyTo(ex_props);

	// Clear properties that shouldn't be copied
	ex_props.removeProperty("ZipIndex");
	ex_props.removeProperty("Offset");

	// Set entry state
	state = 2;
	state_locked = false;
}
Ejemplo n.º 8
0
// ----------------------------------------------------------------------------
// ArchiveEntryList::entrySize
//
// Returns either the size of the entry at [index], or if it is a folder, the
// number of entries+subfolders within it
// ----------------------------------------------------------------------------
int ArchiveEntryList::entrySize(long index)
{
	ArchiveEntry* entry = getEntry(index, false);
	if (entry->getType() == EntryType::folderType())
	{
		ArchiveTreeNode* dir = archive->getDir(entry->getName(), current_dir);
		if (dir)
			return dir->numEntries() + dir->nChildren();
		else
			return 0;
	}
	else
		return entry->getSize();
}
Ejemplo n.º 9
0
/* WadArchive::write
 * Writes the wad archive to a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool WadArchive::write(MemChunk& mc, bool update)
{
	// Don't write if iwad
	if (iwad && iwad_lock)
	{
		Global::error = "IWAD saving disabled";
		return false;
	}

	// Determine directory offset & individual lump offsets
	uint32_t dir_offset = 12;
	ArchiveEntry* entry = NULL;
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		setEntryOffset(entry, dir_offset);
		dir_offset += entry->getSize();
	}

	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize(dir_offset + numEntries() * 16);

	// Setup wad type
	char wad_type[4] = { 'P', 'W', 'A', 'D' };
	if (iwad) wad_type[0] = 'I';

	// Write the header
	uint32_t num_lumps = numEntries();
	mc.write(wad_type, 4);
	mc.write(&num_lumps, 4);
	mc.write(&dir_offset, 4);

	// Write the lumps
	for (uint32_t l = 0; l < num_lumps; l++)
	{
		entry = getEntry(l);
		mc.write(entry->getData(), entry->getSize());
	}

	// Write the directory
	for (uint32_t l = 0; l < num_lumps; l++)
	{
		entry = getEntry(l);
		char name[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
		long offset = getEntryOffset(entry);
		long size = entry->getSize();

		for (size_t c = 0; c < entry->getName().length() && c < 8; c++)
			name[c] = entry->getName()[c];

		mc.write(&offset, 4);
		mc.write(&size, 4);
		mc.write(name, 8);

		if (update)
		{
			entry->setState(0);
			entry->exProp("Offset") = (int)offset;
		}
	}

	return true;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
0
// -----------------------------------------------------------------------------
// Reads disk format data from a MemChunk.
// Returns true if successful, false otherwise
// -----------------------------------------------------------------------------
bool DiskArchive::open(MemChunk& mc)
{
	size_t mcsize = mc.getSize();

	// Check given data is valid
	if (mcsize < 80)
		return false;

	// Read disk header
	uint32_t num_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;

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

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

		// Read entry info
		DiskEntry dent;
		mc.read(&dent, 72);

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

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

		// Check offset+size
		if (dent.offset + dent.length > mcsize)
		{
			LOG_MESSAGE(1, "DiskArchive::open: Disk 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
		string name = wxString::FromAscii(dent.name, 64);
		name.Replace("\\", "/");
		name.Replace("GAME:/", "");
		wxFileName fn(name);

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

		// Create entry
		ArchiveEntry* entry     = new ArchiveEntry(fn.GetFullName(), dent.length);
		entry->exProp("Offset") = (int)dent.offset;
		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);
	UI::setSplashProgressMessage("Detecting entry types");
	for (size_t a = 0; a < all_entries.size(); a++)
	{
		// Update splash window progress
		UI::setSplashProgress((((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());
			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");

	UI::setSplashProgressMessage("");

	return true;
}
Ejemplo n.º 12
0
/* DatArchive::write
 * Writes the dat archive to a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool DatArchive::write(MemChunk& mc, bool update)
{
	// Only two bytes are used for storing entry amount,
	// so abort for excessively large files:
	if (numEntries() > 65535)
		return false;

	// Determine directory offset, name offsets & individual lump offsets
	uint32_t dir_offset = 10;
	uint16_t name_offset = numEntries() * 12;
	uint32_t name_size = 0;
	string previousname = "";
	uint16_t* nameoffsets = new uint16_t[numEntries()];
	ArchiveEntry* entry = NULL;
	for (uint16_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		setEntryOffset(entry, dir_offset);
		dir_offset += entry->getSize();

		// Does the entry has a name?
		string name = entry->getName();
		if (l > 0 && previousname.length() > 0 && name.length() > previousname.length() &&
		        !previousname.compare(0, previousname.length(), name, 0, previousname.length()) &&
		        name.at(previousname.length()) == '+')
		{
			// This is a fake name
			name = "";
			nameoffsets[l] = 0;
		}
		else
		{
			// This is a true name
			previousname = name;
			nameoffsets[l] = uint16_t(name_offset + name_size);
			name_size += name.length() + 1;
		}
	}

	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize(dir_offset + name_size + numEntries() * 12);

	// Write the header
	uint16_t num_lumps = wxINT16_SWAP_ON_BE(numEntries());
	dir_offset = wxINT32_SWAP_ON_BE(dir_offset);
	uint32_t unknown = 0;
	mc.write(&num_lumps, 2);
	mc.write(&dir_offset, 4);
	mc.write(&unknown, 4);

	// Write the lumps
	for (uint16_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		mc.write(entry->getData(), entry->getSize());
	}

	// Write the directory
	for (uint16_t l = 0; l < num_lumps; l++)
	{
		entry = getEntry(l);

		uint32_t offset = wxINT32_SWAP_ON_BE(getEntryOffset(entry));
		uint32_t size = wxINT32_SWAP_ON_BE(entry->getSize());
		uint16_t nameofs = wxINT16_SWAP_ON_BE(nameoffsets[l]);
		uint16_t flags = wxINT16_SWAP_ON_BE((entry->isEncrypted() == ENC_SCRLE0) ? 1 : 0);

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

		if (update)
		{
			entry->setState(0);
			entry->exProp("Offset") = (int)wxINT32_SWAP_ON_BE(offset);
		}
	}

	// Write the names
	for (uint16_t l = 0; l < num_lumps; l++)
	{
		uint8_t zero = 0;
		entry = getEntry(l);
		if (nameoffsets[l])
		{
			mc.write(CHR(entry->getName()), entry->getName().length());
			mc.write(&zero, 1);
		}
	}

	// Clean-up
	delete[] nameoffsets;

	// Finished!
	return true;
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
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;
}
Ejemplo n.º 15
0
/* MapPreviewCanvas::openMap
 * Opens a map from a mapdesc_t
 *******************************************************************/
bool MapPreviewCanvas::openMap(Archive::mapdesc_t map)
{
	// All errors = invalid map
	Global::error = "Invalid map";

	// Check if this map is a pk3 map
	bool map_archive = false;
	if (map.archive)
	{
		map_archive = true;

		// Attempt to open entry as wad archive
		temp_archive = new WadArchive();
		if (!temp_archive->open(map.head))
		{
			delete temp_archive;
			return false;
		}

		// Detect maps
		vector<Archive::mapdesc_t> maps = temp_archive->detectMaps();

		// Set map if there are any in the archive
		if (maps.size() > 0)
			map = maps[0];
		else
			return false;
	}

	// Parse UDMF map
	if (map.format == MAP_UDMF)
	{
		ArchiveEntry* udmfdata = NULL;
		for (ArchiveEntry* mapentry = map.head; mapentry != map.end; mapentry = mapentry->nextEntry())
		{
			// Check entry type
			if (mapentry->getType() == EntryType::getType("udmf_textmap"))
			{
				udmfdata = mapentry;
				break;
			}
		}
		if (udmfdata == NULL)
			return false;

		// Start parsing
		Tokenizer tz;
		tz.openMem(udmfdata->getData(), udmfdata->getSize(), map.head->getName());

		// Get first token
		string token = tz.getToken();
		size_t vertcounter = 0, linecounter = 0, thingcounter = 0;
		while (!token.IsEmpty())
		{
			if (!token.CmpNoCase("namespace"))
			{
				//  skip till we reach the ';'
				do { token = tz.getToken(); }
				while (token.Cmp(";"));
			}
			else if (!token.CmpNoCase("vertex"))
			{
				// Get X and Y properties
				bool gotx = false;
				bool goty = false;
				double x = 0.;
				double y = 0.;
				do
				{
					token = tz.getToken();
					if (!token.CmpNoCase("x") || !token.CmpNoCase("y"))
					{
						bool isx = !token.CmpNoCase("x");
						token = tz.getToken();
						if (token.Cmp("="))
						{
							wxLogMessage("Bad syntax for vertex %i in UDMF map data", vertcounter);
							return false;
						}
						if (isx) x = tz.getDouble(), gotx = true;
						else y = tz.getDouble(), goty = true;
						// skip to end of declaration after each key
						do { token = tz.getToken(); }
						while (token.Cmp(";"));
					}
				}
				while (token.Cmp("}"));
				if (gotx && goty)
					addVertex(x, y);
				else
				{
					wxLogMessage("Wrong vertex %i in UDMF map data", vertcounter);
					return false;
				}
				vertcounter++;
			}
			else if (!token.CmpNoCase("linedef"))
			{
				bool special = false;
				bool twosided = false;
				bool gotv1 = false, gotv2 = false;
				size_t v1 = 0, v2 = 0;
				do
				{
					token = tz.getToken();
					if (!token.CmpNoCase("v1") || !token.CmpNoCase("v2"))
					{
						bool isv1 = !token.CmpNoCase("v1");
						token = tz.getToken();
						if (token.Cmp("="))
						{
							wxLogMessage("Bad syntax for linedef %i in UDMF map data", linecounter);
							return false;
						}
						if (isv1) v1 = tz.getInteger(), gotv1 = true;
						else v2 = tz.getInteger(), gotv2 = true;
						// skip to end of declaration after each key
						do { token = tz.getToken(); }
						while (token.Cmp(";"));
					}
					else if (!token.CmpNoCase("special"))
					{
						special = true;
						// skip to end of declaration after each key
						do { token = tz.getToken(); }
						while (token.Cmp(";"));
					}
					else if (!token.CmpNoCase("sideback"))
					{
						twosided = true;
						// skip to end of declaration after each key
						do { token = tz.getToken(); }
						while (token.Cmp(";"));
					}
				}
				while (token.Cmp("}"));
				if (gotv1 && gotv2)
					addLine(v1, v2, twosided, special);
				else
				{
					wxLogMessage("Wrong line %i in UDMF map data", linecounter);
					return false;
				}
				linecounter++;
			}
			else if (S_CMPNOCASE(token, "thing"))
			{
				// Get X and Y properties
				bool gotx = false;
				bool goty = false;
				double x = 0.;
				double y = 0.;
				do
				{
					token = tz.getToken();
					if (!token.CmpNoCase("x") || !token.CmpNoCase("y"))
					{
						bool isx = !token.CmpNoCase("x");
						token = tz.getToken();
						if (token.Cmp("="))
						{
							wxLogMessage("Bad syntax for thing %i in UDMF map data", vertcounter);
							return false;
						}
						if (isx) x = tz.getDouble(), gotx = true;
						else y = tz.getDouble(), goty = true;
						// skip to end of declaration after each key
						do { token = tz.getToken(); } while (token.Cmp(";"));
					}
				} while (token.Cmp("}"));
				if (gotx && goty)
					addThing(x, y);
				else
				{
					wxLogMessage("Wrong thing %i in UDMF map data", vertcounter);
					return false;
				}
				vertcounter++;
			}
			else
			{
				// Check for side or sector definition (increase counts)
				if (S_CMPNOCASE(token, "sidedef"))
					n_sides++;
				else if (S_CMPNOCASE(token, "sector"))
					n_sectors++;

				// map preview ignores sidedefs, sectors, comments,
				// unknown fields, etc. so skip to end of block
				do { token = tz.getToken(); }
				while (token.Cmp("}"));
			}
			// Iterate to next token
			token = tz.getToken();
		}
	}

	// Non-UDMF map
	if (map.format != MAP_UDMF)
	{
		// Read vertices (required)
		if (!readVertices(map.head, map.end, map.format))
			return false;

		// Read linedefs (required)
		if (!readLines(map.head, map.end, map.format))
			return false;

		// Read things
		if (map.format != MAP_UDMF)
			readThings(map.head, map.end, map.format);

		// Read sides & sectors (count only)
		ArchiveEntry* sidedefs = NULL;
		ArchiveEntry* sectors = NULL;
		while (map.head)
		{
			// Check entry type
			if (map.head->getType() == EntryType::getType("map_sidedefs"))
				sidedefs = map.head;
			if (map.head->getType() == EntryType::getType("map_sectors"))
				sectors = map.head;

			// Exit loop if we've reached the end of the map entries
			if (map.head == map.end)
				break;
			else
				map.head = map.head->nextEntry();
		}
		if (sidedefs && sectors)
		{
			// Doom64 map
			if (map.format != MAP_DOOM64)
			{
				n_sides = sidedefs->getSize() / 30;
				n_sectors = sectors->getSize() / 26;
			}

			// Doom/Hexen map
			else
			{
				n_sides = sidedefs->getSize() / 12;
				n_sectors = sectors->getSize() / 16;
			}
		}
	}

	// Clean up
	if (map_archive)
	{
		temp_archive->close();
		delete temp_archive;
		temp_archive = NULL;
	}

	// Refresh map
	Refresh();

	return true;
}
Ejemplo n.º 16
0
/* LfdArchive::write
 * Writes the lfd archive to a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool LfdArchive::write(MemChunk& mc, bool update)
{
	// Determine total size
	uint32_t dir_size = (numEntries() + 1)<<4;
	uint32_t total_size = dir_size;
	ArchiveEntry* entry = NULL;
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		total_size += 16;
		setEntryOffset(entry, total_size);
		if (update)
		{
			entry->setState(0);
			entry->exProp("Offset") = (int)total_size;
		}
		total_size += entry->getSize();
	}

	// Clear/init MemChunk
	mc.clear();
	mc.seek(0, SEEK_SET);
	mc.reSize(total_size);

	// Variables
	char type[5] = "RMAP";
	char name[9] = "resource";
	size_t size = wxINT32_SWAP_ON_BE(numEntries()<<4);


	// Write the resource map first
	mc.write(type, 4);
	mc.write(name, 8);
	mc.write(&size,4);
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		for (int t = 0; t < 5; ++t) type[t] = 0;
		for (int n = 0; n < 9; ++n) name[n] = 0;
		size = wxINT32_SWAP_ON_BE(entry->getSize());
		wxFileName fn(entry->getName());

		for (size_t c = 0; c < fn.GetName().length() && c < 9; c++)
			name[c] = fn.GetName()[c];
		for (size_t c = 0; c < fn.GetExt().length() && c < 5; c++)
			type[c] = fn.GetExt()[c];

		mc.write(type, 4);
		mc.write(name, 8);
		mc.write(&size,4);
	}

	// Write the lumps
	for (uint32_t l = 0; l < numEntries(); l++)
	{
		entry = getEntry(l);
		for (int t = 0; t < 5; ++t) type[t] = 0;
		for (int n = 0; n < 9; ++n) name[n] = 0;
		size = wxINT32_SWAP_ON_BE(entry->getSize());
		wxFileName fn(entry->getName());

		for (size_t c = 0; c < fn.GetName().length() && c < 9; c++)
			name[c] = fn.GetName()[c];
		for (size_t c = 0; c < fn.GetExt().length() && c < 5; c++)
			type[c] = fn.GetExt()[c];

		mc.write(type, 4);
		mc.write(name, 8);
		mc.write(&size,4);
		mc.write(entry->getData(), entry->getSize());
	}

	return true;
}
Ejemplo n.º 17
0
/* LfdArchive::open
 * Reads lfd format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool LfdArchive::open(MemChunk& mc)
{
	// Check data was given
	if (!mc.hasData())
		return false;

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

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

	// Get directory length
	uint32_t dir_len = 0;
	mc.seek(12, SEEK_SET);
	mc.read(&dir_len, 4);
	dir_len = wxINT32_SWAP_ON_BE(dir_len);

	// Check size
	if ((unsigned)mc.getSize() < (dir_len) || dir_len % 16)
		return false;

	// Guess number of lumps
	uint32_t num_lumps = dir_len / 16;

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

	// Read each entry
	theSplashWindow->setProgressMessage("Reading lfd archive data");
	size_t offset = dir_len + 16;
	size_t size = mc.getSize();
	for (uint32_t d = 0; offset < size; d++)
	{
		// Update splash window progress
		theSplashWindow->setProgress(((float)d / (float)num_lumps));

		// Read lump info
		uint32_t length = 0;
		char type[5] = "";
		char name[9] = "";

		mc.read(type, 4);		// Type
		mc.read(name, 8);		// Name
		mc.read(&length, 4);	// Size
		name[8] = '\0'; type[4] = 0;

		// Move past the header
		offset += 16;

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

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

		// Create & setup lump
		wxFileName fn(name);
		fn.SetExt(type);
		ArchiveEntry* nlump = new ArchiveEntry(fn.GetFullName(), length);
		nlump->setLoaded(false);
		nlump->exProp("Offset") = (int)offset;
		nlump->setState(0);

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

		// Move to next entry
		offset += length;
		mc.seek(offset, SEEK_SET);
	}

	if (num_lumps != numEntries())
		wxLogMessage("Warning: computed %i lumps, but actually %i entries", num_lumps, numEntries());

	// 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;
}
Ejemplo n.º 18
0
/* PakArchive::open
 * Reads pak format data from a MemChunk
 * Returns true if successful, false otherwise
 *******************************************************************/
bool PakArchive::open(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);

	// Check it
	if (pack[0] != 'P' || pack[1] != 'A' || pack[2] != 'C' || pack[3] != 'K')
	{
		wxLogMessage("PakArchive::open: Opening failed, invalid header");
		Global::error = "Invalid pak 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 / 64;
	mc.seek(dir_offset, SEEK_SET);
	theSplashWindow->setProgressMessage("Reading pak 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[56];
		long offset;
		long size;
		mc.read(name, 56);
		mc.read(&offset, 4);
		mc.read(&size, 4);

		// Byteswap if needed
		offset = wxINT32_SWAP_ON_BE(offset);
		size = wxINT32_SWAP_ON_BE(size);

		// Check offset+size
		if ((unsigned)(offset + size) > mc.getSize())
		{
			wxLogMessage("PakArchive::open: Pak 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, 56));

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

		// Create entry
		ArchiveEntry* entry = new ArchiveEntry(fn.GetFullName(), size);
		entry->exProp("Offset") = (int)offset;
		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());
			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;
}
Ejemplo n.º 19
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;
}
Ejemplo n.º 20
0
/* FontManager::initFonts
 * Loads all needed fonts for rendering. Non-SFML implementation
 *******************************************************************/
int FontManager::initFonts()
{
	// --- Load general fonts ---
	int ret = 0;

	if (font_normal)		{ delete font_normal;			font_normal = NULL;			}
	if (font_condensed)		{ delete font_condensed;		font_condensed = NULL;		}
	if (font_bold)			{ delete font_bold;				font_bold = NULL;			}
	if (font_boldcondensed) { delete font_boldcondensed;	font_boldcondensed = NULL;	}
	if (font_mono)			{ delete font_mono;				font_mono = NULL;			}
	if (font_small)			{ delete font_small;			font_small = NULL;			}

	// Normal
	ArchiveEntry* entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans.ttf");
	if (entry)
	{
		font_normal = new FTTextureFont(entry->getData(), entry->getSize());
		font_normal->FaceSize(gl_font_size);

		// Check it loaded ok
		if (font_normal->Error())
		{
			delete font_normal;
			font_normal = NULL;
		}
		else ++ ret;
	}

	// Condensed
	entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_c.ttf");
	if (entry)
	{
		font_condensed = new FTTextureFont(entry->getData(), entry->getSize());
		font_condensed->FaceSize(gl_font_size);

		// Check it loaded ok
		if (font_condensed->Error())
		{
			delete font_condensed;
			font_condensed = NULL;
		}
		else ++ ret;
	}

	// Bold
	entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_b.ttf");
	if (entry)
	{
		font_bold = new FTTextureFont(entry->getData(), entry->getSize());
		font_bold->FaceSize(gl_font_size);

		// Check it loaded ok
		if (font_bold->Error())
		{
			delete font_bold;
			font_bold = NULL;
		}
		else ++ ret;
	}

	// Condensed bold
	entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans_cb.ttf");
	if (entry)
	{
		font_boldcondensed = new FTTextureFont(entry->getData(), entry->getSize());
		font_boldcondensed->FaceSize(gl_font_size);

		// Check it loaded ok
		if (font_boldcondensed->Error())
		{
			delete font_boldcondensed;
			font_boldcondensed = NULL;
		}
		else ++ ret;
	}

	// Monospace
	entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_mono.ttf");
	if (entry)
	{
		font_mono = new FTTextureFont(entry->getData(), entry->getSize());
		font_mono->FaceSize(gl_font_size);

		// Check it loaded ok
		if (font_mono->Error())
		{
			delete font_mono;
			font_mono = NULL;
		}
		else ++ ret;
	}

	// Small
	entry = theArchiveManager->programResourceArchive()->entryAtPath("fonts/dejavu_sans.ttf");
	if (entry)
	{
		font_small = new FTTextureFont(entry->getData(), entry->getSize());
		font_small->FaceSize((gl_font_size * 0.6) + 1);

		// Check it loaded ok
		if (font_small->Error())
		{
			delete font_small;
			font_small = NULL;
		}
		else ++ ret;
	}

	return ret;
}
Ejemplo n.º 21
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;
}
Ejemplo n.º 22
0
GLTexture* MapTextureManager::getSprite(string name, string translation, string palette)
{
	// Don't bother looking for nameless sprites
	if (name.IsEmpty())
		return NULL;

	// Get sprite matching name
	string hashname = name.Upper();
	if (!translation.IsEmpty())
		hashname += translation.Lower();
	if (!palette.IsEmpty())
		hashname += palette.Upper();
	map_tex_t& mtex = sprites[hashname];

	// Get desired filter type
	int filter = 1;
	if (map_tex_filter == 0)
		filter = GLTexture::NEAREST_LINEAR_MIN;
	else if (map_tex_filter == 1)
		filter = GLTexture::LINEAR;
	else if (map_tex_filter == 2)
		filter = GLTexture::LINEAR;
	else if (map_tex_filter == 3)
		filter = GLTexture::NEAREST_MIPMAP;

	// If the texture is loaded
	if (mtex.texture)
	{
		// If the texture filter matches the desired one, return it
		if (mtex.texture->getFilter() == filter)
			return mtex.texture;
		else
		{
			// Otherwise, reload the texture
			delete mtex.texture;
			mtex.texture = NULL;
		}
	}

	// Sprite not found, look for it
	bool found = false;
	bool mirror = false;
	SImage image;
	Palette8bit* pal = getResourcePalette();
	ArchiveEntry* entry = theResourceManager->getPatchEntry(name, "sprites", archive);
	if (!entry) entry = theResourceManager->getPatchEntry(name, "", archive);
	if (!entry && name.length() == 8)
	{
		string newname = name;
		newname[4] = name[6]; newname[5] = name[7]; newname[6] = name[4]; newname[7] = name[5];
		entry = theResourceManager->getPatchEntry(newname, "sprites", archive);
		if (entry) mirror = true;
	}
	if (entry)
	{
		found = true;
		Misc::loadImageFromEntry(&image, entry);
	}
	else  	// Try composite textures then
	{
		CTexture* ctex = theResourceManager->getTexture(name, archive);
		if (ctex && ctex->toImage(image, archive, pal))
			found = true;
	}

	// We have a valid image either from an entry or a composite texture.
	if (found)
	{
		// Apply translation
		if (!translation.IsEmpty()) image.applyTranslation(translation, pal);
		// Apply palette override
		if (!palette.IsEmpty())
		{
			ArchiveEntry* newpal = theResourceManager->getPaletteEntry(palette, archive);
			if (newpal && newpal->getSize() == 768)
			{
				// Why is this needed?
				// Copying data in pal->loadMem shouldn't
				// change it in the original entry...
				// We shouldn't need to copy the data in a temporary place first.
				pal = image.getPalette();
				MemChunk mc;
				mc.importMem(newpal->getData(), newpal->getSize());
				pal->loadMem(mc);
			}
		}
		// Apply mirroring
		if (mirror) image.mirror(false);
		// Turn into GL texture
		mtex.texture = new GLTexture(false);
		mtex.texture->setFilter(filter);
		mtex.texture->setTiling(false);
		mtex.texture->loadImage(&image, pal);
		return mtex.texture;
	}
	else if (name.EndsWith("?"))
	{
		name.RemoveLast(1);
		GLTexture* sprite = getSprite(name + '0', translation, palette);
		if (!sprite)
			sprite = getSprite(name + '1', translation, palette);
		if (sprite)
			return sprite;
		if (!sprite && name.length() == 5)
		{
			for (char chr = 'A'; chr <= ']'; ++chr)
			{
				sprite = getSprite(name + '0' + chr + '0', translation, palette);
				if (sprite) return sprite;
				sprite = getSprite(name + '1' + chr + '1', translation, palette);
				if (sprite) return sprite;
			}
		}
	}

	return NULL;
}
Ejemplo n.º 23
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;
}
Ejemplo n.º 24
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;
}
Ejemplo n.º 25
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;
}
Ejemplo n.º 26
0
/* MapPreviewCanvas::openMap
 * Opens a map from a mapdesc_t
 *******************************************************************/
bool MapPreviewCanvas::openMap(Archive::mapdesc_t map)
{
	// All errors = invalid map
	Global::error = "Invalid map";

	// Check if this map is a pk3 map
	bool map_archive = false;
	if (map.archive)
	{
		map_archive = true;

		// Attempt to open entry as wad archive
		temp_archive = new WadArchive();
		if (!temp_archive->open(map.head))
		{
			delete temp_archive;
			return false;
		}

		// Detect maps
		vector<Archive::mapdesc_t> maps = temp_archive->detectMaps();

		// Set map if there are any in the archive
		if (maps.size() > 0)
			map = maps[0];
		else
			return false;
	}

	// Parse UDMF map
	if (map.format == MAP_UDMF)
	{
		ArchiveEntry* udmfdata = NULL;
		for (ArchiveEntry* mapentry = map.head; mapentry != map.end; mapentry = mapentry->nextEntry())
		{
			// Check entry type
			if (mapentry->getType() == EntryType::getType("udmf_textmap"))
			{
				udmfdata = mapentry;
				break;
			}
		}
		if (udmfdata == NULL)
			return false;

		// Start parsing
		Tokenizer tz;
		tz.openMem(udmfdata->getData(), udmfdata->getSize(), map.head->getName());

		// Get first token
		string token = tz.getToken();
		size_t vertcounter = 0, linecounter = 0;
		while (!token.IsEmpty())
		{
			if (!token.CmpNoCase("namespace"))
			{
				//  skip till we reach the ';'
				do { token = tz.getToken(); }
				while (token.Cmp(";"));
			}
			else if (!token.CmpNoCase("vertex"))
			{
				// Get X and Y properties
				bool gotx = false;
				bool goty = false;
				double x = 0.;
				double y = 0.;
				do
				{
					token = tz.getToken();
					if (!token.CmpNoCase("x") || !token.CmpNoCase("y"))
					{
						bool isx = !token.CmpNoCase("x");
						token = tz.getToken();
						if (token.Cmp("="))
						{
							wxLogMessage("Bad syntax for vertex %i in UDMF map data", vertcounter);
							return false;
						}
						if (isx) x = tz.getDouble(), gotx = true;
						else y = tz.getDouble(), goty = true;
						// skip to end of declaration after each key
						do { token = tz.getToken(); }
						while (token.Cmp(";"));
					}
				}
				while (token.Cmp("}"));
				if (gotx && goty)
					addVertex(x, y);
				else
				{
					wxLogMessage("Wrong vertex %i in UDMF map data", vertcounter);
					return false;
				}
				vertcounter++;
			}
			else if (!token.CmpNoCase("linedef"))
			{
				bool special = false;
				bool twosided = false;
				bool gotv1 = false, gotv2 = false;
				size_t v1 = 0, v2 = 0;
				do
				{
					token = tz.getToken();
					if (!token.CmpNoCase("v1") || !token.CmpNoCase("v2"))
					{
						bool isv1 = !token.CmpNoCase("v1");
						token = tz.getToken();
						if (token.Cmp("="))
						{
							wxLogMessage("Bad syntax for linedef %i in UDMF map data", linecounter);
							return false;
						}
						if (isv1) v1 = tz.getInteger(), gotv1 = true;
						else v2 = tz.getInteger(), gotv2 = true;
						// skip to end of declaration after each key
						do { token = tz.getToken(); }
						while (token.Cmp(";"));
					}
					else if (!token.CmpNoCase("special"))
					{
						special = true;
						// skip to end of declaration after each key
						do { token = tz.getToken(); }
						while (token.Cmp(";"));
					}
					else if (!token.CmpNoCase("sideback"))
					{
						twosided = true;
						// skip to end of declaration after each key
						do { token = tz.getToken(); }
						while (token.Cmp(";"));
					}
				}
				while (token.Cmp("}"));
				if (gotv1 && gotv2)
					addLine(v1, v2, twosided, special);
				else
				{
					wxLogMessage("Wrong line %i in UDMF map data", linecounter);
					return false;
				}
				linecounter++;
			}
			else
			{
				// map preview ignores things, sidedefs, sectors, comments,
				// unknown fields, etc. so skip to end of block
				do { token = tz.getToken(); }
				while (token.Cmp("}"));
			}
			// Iterate to next token
			token = tz.getToken();
		}
	}

	// Read vertices
	if (map.format == MAP_DOOM || map.format == MAP_HEXEN || map.format == MAP_DOOM64)
	{
		// Find VERTEXES entry
		ArchiveEntry* mapentry = map.head;
		ArchiveEntry* vertexes = NULL;
		while (mapentry)
		{
			// Check entry type
			if (mapentry->getType() == EntryType::getType("map_vertexes"))
			{
				vertexes = mapentry;
				break;
			}

			// Exit loop if we've reached the end of the map entries
			if (mapentry == map.end)
				break;
			else
				mapentry = mapentry->nextEntry();
		}

		// Can't open a map without vertices
		if (!vertexes)
			return false;

		// Read vertex data
		MemChunk& mc = vertexes->getMCData();
		mc.seek(0, SEEK_SET);

		if (map.format == MAP_DOOM64)
		{
			doom64vertex_t v;
			while (1)
			{
				// Read vertex
				if (!mc.read(&v, 8))
					break;

				// Add vertex
				addVertex((double)v.x/65536, (double)v.y/65536);
			}
		}
		else
		{
			doomvertex_t v;
			while (1)
			{
				// Read vertex
				if (!mc.read(&v, 4))
					break;

				// Add vertex
				addVertex((double)v.x, (double)v.y);
			}
		}
	}


	// Read linedefs
	if (map.format == MAP_DOOM || map.format == MAP_HEXEN || map.format == MAP_DOOM64)
	{
		// Find LINEDEFS entry
		ArchiveEntry* mapentry = map.head;
		ArchiveEntry* linedefs = NULL;
		while (mapentry)
		{
			// Check entry type
			if (mapentry->getType() == EntryType::getType("map_linedefs"))
			{
				linedefs = mapentry;
				break;
			}

			// Exit loop if we've reached the end of the map entries
			if (mapentry == map.end)
				break;
			else
				mapentry = mapentry->nextEntry();
		}

		// Can't open a map without linedefs
		if (!linedefs)
			return false;

		// Read line data
		MemChunk& mc = linedefs->getMCData();
		mc.seek(0, SEEK_SET);
		if (map.format == MAP_DOOM)
		{
			while (1)
			{
				// Read line
				doomline_t l;
				if (!mc.read(&l, sizeof(doomline_t)))
					break;

				// Check properties
				bool special = false;
				bool twosided = false;
				if (l.side2 != 0xFFFF)
					twosided = true;
				if (l.type > 0)
					special = true;

				// Add line
				addLine(l.vertex1, l.vertex2, twosided, special);
			}
		}
		else if (map.format == MAP_DOOM64)
		{
			while (1)
			{
				// Read line
				doom64line_t l;
				if (!mc.read(&l, sizeof(doom64line_t)))
					break;

				// Check properties
				bool macro = false;
				bool special = false;
				bool twosided = false;
				if (l.side2  != 0xFFFF)
					twosided = true;
				if (l.type > 0)
				{
					if (l.type & 0x100)
						macro = true;
					else special = true;
				}

				// Add line
				addLine(l.vertex1, l.vertex2, twosided, special, macro);
			}
		}
		else if (map.format == MAP_HEXEN)
		{
			while (1)
			{
				// Read line
				hexenline_t l;
				if (!mc.read(&l, sizeof(hexenline_t)))
					break;

				// Check properties
				bool special = false;
				bool twosided = false;
				if (l.side2 != 0xFFFF)
					twosided = true;
				if (l.type > 0)
					special = true;

				// Add line
				addLine(l.vertex1, l.vertex2, twosided, special);
			}
		}
	}

	// Clean up
	if (map_archive)
	{
		temp_archive->close();
		delete temp_archive;
		temp_archive = NULL;
	}

	// Refresh map
	Refresh();

	return true;
}