Exemplo n.º 1
0
/* ArchiveTreeNode::merge
 * Merges [node] with this node. Entries within [node] are added
 * at [position] within this node. Returns false if [node] is invalid,
 * true otherwise
 *******************************************************************/
bool ArchiveTreeNode::merge(ArchiveTreeNode* node, unsigned position, int state)
{
	// Check node was given to merge
	if (!node)
		return false;

	// Merge entries
	for (unsigned a = 0; a < node->numEntries(); a++)
	{
		if (node->getEntry(a))
		{
			string name = Misc::lumpNameToFileName(node->getEntry(a)->getName());
			node->getEntry(a)->setName(name);
		}
		ArchiveEntry* nentry = new ArchiveEntry(*(node->getEntry(a)));
		addEntry(nentry, position);
		nentry->setState(state);

		if (position < entries.size())
			position++;
	}

	// Merge subdirectories
	for (unsigned a = 0; a < node->nChildren(); a++)
	{
		ArchiveTreeNode* child = (ArchiveTreeNode*)STreeNode::addChild(node->getChild(a)->getName());
		child->merge((ArchiveTreeNode*)node->getChild(a));
		child->getDirEntry()->setState(state);
	}

	return true;
}
Exemplo n.º 2
0
/* Archive::removeDir
 * Deletes the directory matching [path], starting from [base]. If
 * [base] is NULL, the root directory is used. Returns false if
 * the directory does not exist, true otherwise
 *******************************************************************/
bool Archive::removeDir(string path, ArchiveTreeNode* base)
{
	// Abort if read only
	if (read_only)
		return false;

	// Get the dir to remove
	ArchiveTreeNode* dir = getDir(path, base);

	// Check it exists (and that it isn't the root dir)
	if (!dir || dir == getRoot())
		return false;

	// Record undo step
	if (UndoRedo::currentlyRecording())
		UndoRedo::currentManager()->recordUndoStep(new DirCreateDeleteUS(false, dir));

	// Remove the directory from its parent
	if (dir->getParent())
		dir->getParent()->removeChild(dir);

	// Delete the directory
	delete dir;

	// Set the archive state to modified
	setModified(true);

	return true;
}
Exemplo n.º 3
0
/* Archive::importDir
 * Imports all files (including subdirectories) from [directory] into
 * the archive
 *******************************************************************/
bool Archive::importDir(string directory)
{
	// Get a list of all files in the directory
	wxArrayString files;
	wxDir::GetAllFiles(directory, &files);

	// Go through files
	for (unsigned a = 0; a < files.size(); a++)
	{
		string name = files[a];
		name.Replace(directory, "", false);	// Remove directory from entry name

		// Split filename into dir+name
		wxFileName fn(name);
		string ename = fn.GetFullName();
		string edir = fn.GetPath();

		// Remove beginning \ or / from dir
		if (edir.StartsWith("\\") || edir.StartsWith("/"))
			edir.Remove(0, 1);

		// Add the entry
		ArchiveTreeNode* dir = createDir(edir);
		ArchiveEntry* entry = addNewEntry(ename, dir->numEntries()+1, dir);

		// Load data
		entry->importFile(files[a]);

		// Set unmodified
		entry->setState(0);
		dir->getDirEntry()->setState(0);
	}

	return true;
}
Exemplo n.º 4
0
void importEditorImages(MapTexHashMap& map, ArchiveTreeNode* dir, string path)
{
	SImage image;

	// Go through entries
	for (unsigned a = 0; a < dir->numEntries(); a++)
	{
		ArchiveEntry* entry = dir->getEntry(a);

		// Load entry to image
		if (image.open(entry->getMCData()))
		{
			// Create texture in hashmap
			string name = path + entry->getName(true);
			//wxLogMessage("Loading editor texture %s", CHR(name));
			map_tex_t& mtex = map[name];
			mtex.texture = new GLTexture(false);
			mtex.texture->setFilter(GLTexture::MIPMAP);
			mtex.texture->loadImage(&image);
		}
	}

	// Go through subdirs
	for (unsigned a = 0; a < dir->nChildren(); a++)
	{
		ArchiveTreeNode* subdir = (ArchiveTreeNode*)dir->getChild(a);
		importEditorImages(map, subdir, path + subdir->getName() + "/");
	}
}
Exemplo n.º 5
0
// ----------------------------------------------------------------------------
// TextLanguage::loadLanguages
//
// Loads all text language definitions from slade.pk3
// ----------------------------------------------------------------------------
bool TextLanguage::loadLanguages()
{
	// Get slade resource archive
	Archive* res_archive = App::archiveManager().programResourceArchive();

	// Read language definitions from resource archive
	if (res_archive)
	{
		// Get 'config/languages' directly
		ArchiveTreeNode* dir = res_archive->getDir("config/languages");

		if (dir)
		{
			// Read all entries in this dir
			for (unsigned a = 0; a < dir->numEntries(); a++)
				readLanguageDefinition(dir->entryAt(a)->getMCData(), dir->entryAt(a)->getName());
		}
		else
			Log::warning(
				1,
				"Warning: 'config/languages' not found in slade.pk3, no builtin text language definitions loaded"
			);
	}

	return true;
}
Exemplo n.º 6
0
	void swapNames()
	{
		ArchiveTreeNode* dir = archive->getDir(path);
		archive->renameDir(dir, old_name);
		old_name = new_name;
		new_name = dir->getName();
		path = dir->getPath();
	}
Exemplo n.º 7
0
	bool doSwap()
	{
		// Get parent dir
		ArchiveTreeNode* dir = archive->getDir(path);
		if (dir)
			return dir->swapEntries(index1, index2);
		return false;
	}
Exemplo n.º 8
0
	bool deleteEntry()
	{
		// Get parent dir
		ArchiveTreeNode* dir = archive->getDir(path);
		if (dir)
			return archive->removeEntry(dir->getEntry(index));
		else
			return false;
	}
Exemplo n.º 9
0
/* ColourConfiguration::getConfigurationNames
 * Adds all available colour configuration names to [names]
 *******************************************************************/
void ColourConfiguration::getConfigurationNames(vector<string>& names)
{
	// TODO: search custom folder

	// Search resource pk3
	Archive* res = theArchiveManager->programResourceArchive();
	ArchiveTreeNode* dir = res->getDir("config/colours");
	for (unsigned a = 0; a < dir->numEntries(); a++)
		names.push_back(dir->getEntry(a)->getName(true));
}
Exemplo n.º 10
0
/* Archive::removeEntry
 * Removes [entry] from the archive. If [delete_entry] is true, the
 * entry will also be deleted. Returns true if the removal succeeded
 *******************************************************************/
bool Archive::removeEntry(ArchiveEntry* entry, bool delete_entry)
{
	// Abort if read only
	if (read_only)
		return false;

	// Check entry
	if (!checkEntry(entry))
		return false;

	// Check if entry is locked
	if (entry->isLocked())
		return false;

	// Get its directory
	ArchiveTreeNode* dir = entry->getParentDir();

	// Error if entry has no parent directory
	if (!dir)
		return false;

	// Create undo step
	if (UndoRedo::currentlyRecording())
		UndoRedo::currentManager()->recordUndoStep(new EntryCreateDeleteUS(false, entry));

	// Get the entry index
	int index = dir->entryIndex(entry);

	// Announce (before actually removing in case entry is still needed)
	MemChunk mc;
	wxUIntPtr ptr = wxPtrToUInt(entry);
	mc.write(&index, sizeof(int));
	mc.write(&ptr, sizeof(wxUIntPtr));
	announce("entry_removing", mc);

	// Remove it from its directory
	bool ok = dir->removeEntry(index);

	// If it was removed ok
	if (ok)
	{
		// Announce removed
		announce("entry_removed", mc);

		// Delete if necessary
		if (delete_entry)
			delete entry;

		// Update variables etc
		setModified(true);
	}

	return ok;
}
Exemplo n.º 11
0
/* Archive::swapEntries
 * Swaps [entry1] and [entry2]. Returns false if either entry is
 * invalid or if both entries are not in the same directory, true
 * otherwise
 *******************************************************************/
bool Archive::swapEntries(ArchiveEntry* entry1, ArchiveEntry* entry2)
{
	// Abort if read only
	if (read_only)
		return false;

	// Check both entries
	if (!checkEntry(entry1) || !checkEntry(entry2))
		return false;

	// Check neither entry is locked
	if (entry1->isLocked() || entry2->isLocked())
		return false;

	// Get their directory
	ArchiveTreeNode* dir = entry1->getParentDir();

	// Error if no dir
	if (!dir)
		return false;

	// Check they are both in the same directory
	if (entry2->getParentDir() != dir)
	{
		wxLogMessage("Error: Can't swap two entries in different directories");
		return false;
	}

	// Get entry indices
	int i1 = dir->entryIndex(entry1);
	int i2 = dir->entryIndex(entry2);

	// Check indices
	if (i1 < 0 || i2 < 0)
		return false;

	// Create undo step
	if (UndoRedo::currentlyRecording())
		UndoRedo::currentManager()->recordUndoStep(new EntrySwapUS(dir, i1, i2));

	// Swap entries
	dir->swapEntries(i1, i2);

	// Announce the swap
	announce("entries_swapped");

	// Set modified
	setModified(true);

	// Return success
	return true;
}
Exemplo n.º 12
0
	bool doRedo()
	{
		// Get entry parent dir
		ArchiveTreeNode* dir = archive->getDir(entry_path);
		if (dir)
		{
			// Rename entry
			ArchiveEntry* entry = dir->getEntry(entry_index);
			return archive->renameEntry(entry, new_name);
		}

		return false;
	}
Exemplo n.º 13
0
// ----------------------------------------------------------------------------
// ArchiveEntryList::getItemText
//
// Called when the widget requests the text for [item] at [column]
// ----------------------------------------------------------------------------
string ArchiveEntryList::getItemText(long item, long column, long index) const
{
	// Get entry
	ArchiveEntry* entry = getEntry(index, false);

	// Check entry
	if (!entry)
		return "INVALID INDEX";

	// Determine what column we want
	int col = columnType(column);

	if (col == 0)
		return entry->getName();	// Name column
	else if (col == 1)
	{
		// Size column
		if (entry->getType() == EntryType::folderType())
		{
			// Entry is a folder, return the number of entries+subdirectories in it
			ArchiveTreeNode* dir = nullptr;

			// Get selected directory
			if (entry == entry_dir_back)
				dir = (ArchiveTreeNode*)current_dir->getParent();	// If it's the 'back directory', get the current dir's parent
			else
				dir = archive->getDir(entry->getName(), current_dir);

			// If it's null, return error
			if (!dir)
				return "INVALID DIRECTORY";

			// Return the number of items in the directory
			return S_FMT("%d entries", dir->numEntries() + dir->nChildren());
		}
		else
			return entry->getSizeString();	// Not a folder, just return the normal size string
	}
	else if (col == 2)
		return entry->getTypeString();	// Type column
	else if (col == 3)
	{
		// Index column
		if (entry->getType() == EntryType::folderType())
			return "";
		else
			return S_FMT("%d", entry->getParentDir()->entryIndex(entry));
	}
	else
		return "INVALID COLUMN";		// Invalid column
}
Exemplo n.º 14
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();
}
Exemplo n.º 15
0
/* ColourConfiguration::readConfiguration
 * Reads saved colour configuration [name]
 *******************************************************************/
bool ColourConfiguration::readConfiguration(string name)
{
	// TODO: search custom folder

	// Search resource pk3
	Archive* res = theArchiveManager->programResourceArchive();
	ArchiveTreeNode* dir = res->getDir("config/colours");
	for (unsigned a = 0; a < dir->numEntries(); a++)
	{
		if (S_CMPNOCASE(dir->getEntry(a)->getName(true), name))
			return readConfiguration(dir->getEntry(a)->getMCData());
	}

	return false;
}
Exemplo n.º 16
0
/* ArchiveTreeNode::clone
 * Returns a clone of this node
 *******************************************************************/
ArchiveTreeNode* ArchiveTreeNode::clone()
{
	// Create copy
	ArchiveTreeNode* copy = new ArchiveTreeNode();
	copy->setName(dir_entry->getName());

	// Copy entries
	for (unsigned a = 0; a < entries.size(); a++)
		copy->addEntry(new ArchiveEntry(*(entries[a])));

	// Copy subdirectories
	for (unsigned a = 0; a < children.size(); a++)
		copy->addChild(((ArchiveTreeNode*)children[a])->clone());

	return copy;
}
Exemplo n.º 17
0
/* ArchiveManager::addArchive
 * Adds an archive to the archive list
 *******************************************************************/
bool ArchiveManager::addArchive(Archive* archive)
{
	// Only add if archive is a valid pointer
	if (archive)
	{
		// Add to the list
		archive_t n_archive;
		n_archive.archive = archive;
		n_archive.resource = true;
		open_archives.push_back(n_archive);

		// Listen to the archive
		listenTo(archive);

		// Announce the addition
		announce("archive_added");

		// Add to resource manager
		theResourceManager->addArchive(archive);

		// ZDoom also loads any WADs found in the root of a PK3 or directory
		if ((archive->getType() == ARCHIVE_ZIP || archive->getType() == ARCHIVE_FOLDER) && auto_open_wads_root)
		{
			ArchiveTreeNode* root = archive->getRoot();
			ArchiveEntry* entry;
			EntryType* type;
			for (unsigned a = 0; a < root->numEntries(); a++)
			{
				entry = root->getEntry(a);

				if (entry->getType() == EntryType::unknownType())
					EntryType::detectEntryType(entry);

				type = entry->getType();

				if (type->getId() == "wad")
					// First true: yes, manage this
					// Second true: open silently, don't open a tab for it
					openArchive(entry, true, true);
			}
		}

		return true;
	}
	else
		return false;
}
Exemplo n.º 18
0
	bool doUndo()
	{
		if (created)
			return archive->removeDir(path);
		else
		{
			// Create directory
			ArchiveTreeNode* dir = archive->createDir(path);

			// Restore entries/subdirs if needed
			if (dir && cb_tree)
				dir->merge(cb_tree->getTree(), 0, 0);

			dir->getDirEntry()->setState(0);

			return !!dir;
		}
	}
Exemplo n.º 19
0
// -----------------------------------------------------------------------------
// Returns the entry at the given path in the archive, or null if it doesn't
// exist
// -----------------------------------------------------------------------------
shared_ptr<ArchiveEntry> Archive::entryAtPathShared(string_view path)
{
	// Get path as wxFileName for processing
	StrUtil::Path fn(StrUtil::startsWith(path, '/') ? path.substr(1) : path);

	// Get directory from path
	ArchiveTreeNode* dir;
	if (fn.path(false).empty())
		dir = &dir_root_;
	else
		dir = this->dir(fn.path(true));

	// If dir doesn't exist, return nullptr
	if (!dir)
		return nullptr;

	// Return entry
	return dir->sharedEntry(fn.fileName());
}
Exemplo n.º 20
0
/* ADatArchive::detectNamespace
 * Returns the namespace that [entry] is within
 *******************************************************************/
string ADatArchive::detectNamespace(ArchiveEntry* entry) {
	// Check entry
	if (!checkEntry(entry))
		return "global";

	// If the entry is in the root dir, it's in the global namespace
	if (entry->getParentDir() == getRoot())
		return "global";

	// Get the entry's *first* parent directory after root (ie <root>/namespace/)
	ArchiveTreeNode* dir = entry->getParentDir();
	while (dir && dir->getParent() != getRoot())
		dir = (ArchiveTreeNode*)dir->getParent();

	// Namespace is the directory's name (in lowercase)
	if (dir)
		return dir->getName().Lower();
	else
		return "global"; // Error, just return global
}
Exemplo n.º 21
0
/* ZipArchive::detectMaps
 * Detects all the maps in the archive and returns a vector of
 * information about them.
 *******************************************************************/
vector<Archive::mapdesc_t> ZipArchive::detectMaps()
{
	vector<mapdesc_t> ret;

	// Get the maps directory
	ArchiveTreeNode* mapdir = getDir("maps");
	if (!mapdir)
		return ret;

	// Go through entries in map dir
	for (unsigned a = 0; a < mapdir->numEntries(); a++)
	{
		ArchiveEntry* entry = mapdir->getEntry(a);

		// Maps can only be wad archives
		if (entry->getType()->getFormat() != "archive_wad")
			continue;

		// Detect map format (probably kinda slow but whatever, no better way to do it really)
		int format = MAP_UNKNOWN;
		Archive* tempwad = new WadArchive();
		tempwad->open(entry);
		vector<mapdesc_t> emaps = tempwad->detectMaps();
		if (emaps.size() > 0)
			format = emaps[0].format;
		delete tempwad;

		// Add map description
		mapdesc_t md;
		md.head = entry;
		md.end = entry;
		md.archive = true;
		md.name = entry->getName(true).Upper();
		md.format = format;
		ret.push_back(md);
	}

	return ret;
}
Exemplo n.º 22
0
/* ArchiveManager::deleteBookmarksInDir
 * Removes any bookmarked entries in [node] from the list
 *******************************************************************/
bool ArchiveManager::deleteBookmarksInDir(ArchiveTreeNode* node)
{
	// Go through bookmarks
	Archive * archive = node->getArchive();
	bool removed = deleteBookmark(node->getDirEntry());
	for (unsigned a = 0; a < bookmarks.size(); ++a)
	{
		// Check bookmarked entry's parent archive
		if (bookmarks[a]->getParent() == archive)
		{
			// Now check if the bookmarked entry is within 
			// the removed dir or one of its descendants
			ArchiveTreeNode* anode = bookmarks[a]->getParentDir();
			bool remove = false;
			while (anode != archive->getRoot() && !remove)
			{
				if (anode == node)
					remove = true;
				else anode = (ArchiveTreeNode*)anode->getParent();
			}
			if (remove)
			{
				bookmarks.erase(bookmarks.begin() + a);
				--a;
				removed = true;
			}
		}
	}

	if (removed)
	{
		// Announce
		announce("bookmarks_changed");
		return true;
	}
	else
		return false;
}
Exemplo n.º 23
0
/* Archive::entryAtPath
 * Returns the entry at the given path in the archive, or NULL if it
 * doesn't exist
 *******************************************************************/
ArchiveEntry* Archive::entryAtPath(string path)
{
	// Remove leading / from path if needed
	if (path.StartsWith("/"))
		path.Remove(0, 1);

	// Get path as wxFileName for processing
	wxFileName fn(path);

	// Get directory from path
	ArchiveTreeNode* dir;
	if (fn.GetPath(false, wxPATH_UNIX).IsEmpty())
		dir = getRoot();
	else
		dir = getDir(fn.GetPath(true, wxPATH_UNIX));

	// If dir doesn't exist, return null
	if (!dir)
		return NULL;

	// Return entry
	return dir->getEntry(fn.GetFullName());
}
Exemplo n.º 24
0
/* MapBackupPanel::updateMapPreview
 * Updates the map preview with the currently selected backup
 *******************************************************************/
void MapBackupPanel::updateMapPreview()
{
	// Clear current preview
	canvas_map->clearMap();

	// Check for selection
	if (list_backups->selectedItems().IsEmpty())
		return;
	int selection = (list_backups->GetItemCount()-1) - list_backups->selectedItems()[0];

	// Load map data to temporary wad
	if (archive_mapdata)
		delete archive_mapdata;
	archive_mapdata = new WadArchive();
	ArchiveTreeNode* dir = (ArchiveTreeNode*)dir_current->getChild(selection);
	for (unsigned a = 0; a < dir->numEntries(); a++)
		archive_mapdata->addEntry(dir->getEntry(a), "", true);

	// Open map preview
	vector<Archive::mapdesc_t> maps = archive_mapdata->detectMaps();
	if (!maps.empty())
		canvas_map->openMap(maps[0]);
}
Exemplo n.º 25
0
/* ZipArchive::open
 * Reads zip data from a file
 * Returns true if successful, false otherwise
 *******************************************************************/
bool ZipArchive::open(string filename)
{
	// Open the file
	wxFFileInputStream in(filename);
	if (!in.IsOk())
	{
		Global::error = "Unable to open file";
		return false;
	}

	// Create zip stream
	wxZipInputStream zip(in);
	if (!zip.IsOk())
	{
		Global::error = "Invalid zip file";
		return false;
	}

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

	// Go through all zip entries
	int entry_index = 0;
	wxZipEntry* entry = zip.GetNextEntry();
	theSplashWindow->setProgressMessage("Reading zip data");
	while (entry)
	{
		theSplashWindow->setProgress(-1.0f);
		if (entry->GetMethod() != wxZIP_METHOD_DEFLATE && entry->GetMethod() != wxZIP_METHOD_STORE)
		{
			Global::error = "Unsupported zip compression method";
			setMuted(false);
			return false;
		}

		if (!entry->IsDir())
		{
			// Get the entry name as a wxFileName (so we can break it up)
			wxFileName fn(entry->GetName(wxPATH_UNIX), wxPATH_UNIX);

			// Create entry
			ArchiveEntry* new_entry = new ArchiveEntry(fn.GetFullName(), entry->GetSize());

			// Setup entry info
			new_entry->setLoaded(false);
			new_entry->exProp("ZipIndex") = entry_index;

			// Add entry and directory to directory tree
			ArchiveTreeNode* ndir = createDir(fn.GetPath(true, wxPATH_UNIX));
			ndir->addEntry(new_entry);
			//zipdir_t* ndir = addDirectory(fn.GetPath(true, wxPATH_UNIX));
			//ndir->entries.push_back(new_entry);

			// Read the data, if possible
			if (entry->GetSize() < 250 * 1024 * 1024)
			{
				uint8_t* data = new uint8_t[entry->GetSize()];
				zip.Read(data, entry->GetSize());	// Note: this is where exceedingly large files cause an exception.
				new_entry->importMem(data, entry->GetSize());
				new_entry->setLoaded(true);

				// Determine its type
				EntryType::detectEntryType(new_entry);

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

				// Clean up
				delete[] data;
			}
			else
			{
				Global::error = S_FMT("Entry too large: %s is %u mb",
				                      entry->GetName(wxPATH_UNIX), entry->GetSize() / (1<<20));
				setMuted(false);
				return false;
			}
		}
		else
		{
			// Zip entry is a directory, add it to the directory tree
			wxFileName fn(entry->GetName(wxPATH_UNIX), wxPATH_UNIX);
			createDir(fn.GetPath(true, wxPATH_UNIX));
			//addDirectory(fn.GetPath(true, wxPATH_UNIX));
		}

		// Go to next entry in the zip file
		delete entry;
		entry = zip.GetNextEntry();
		entry_index++;
	}
	theSplashWindow->forceRedraw();

	// Set all entries/directories to unmodified
	vector<ArchiveEntry*> entry_list;
	getEntryTreeAsList(entry_list);
	for (size_t a = 0; a < entry_list.size(); a++)
		entry_list[a]->setState(0);

	// Enable announcements
	setMuted(false);

	// Setup variables
	this->filename = filename;
	setModified(false);
	on_disk = true;

	theSplashWindow->setProgressMessage("");

	return true;
}
Exemplo n.º 26
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;
}
Exemplo n.º 27
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;
}
Exemplo n.º 28
0
/* StyleSet::loadResourceStyles
 * Loads all text styles from the slade resource archive (slade.pk3)
 *******************************************************************/
bool StyleSet::loadResourceStyles()
{
	// Get 'config/text_styles' directory in slade.pk3
	ArchiveTreeNode* dir = theArchiveManager->programResourceArchive()->getDir("config/text_styles");

	// Check it exists
	if (!dir)
	{
		wxLogMessage("Warning: No 'config/text_styles' directory exists in slade.pk3");
		return false;
	}

	// Read default style set first
	ArchiveEntry* default_style = dir->getEntry("default.sss");
	if (default_style)
	{
		// Read entry data into tokenizer
		Tokenizer tz;
		tz.openMem(&default_style->getMCData(), default_style->getName());

		// Parse it
		ParseTreeNode root;
		root.allowDup(true);
		root.parse(tz);

		// Read any styleset definitions
		vector<STreeNode*> nodes = root.getChildren("styleset");
		for (unsigned b = 0; b  < nodes.size(); b++)
		{
			StyleSet* newset = new StyleSet();
			if (newset->parseSet((ParseTreeNode*)nodes[b]))
				style_sets.push_back(newset);
			else
				delete newset;
		}
	}

	// Go through all entries within it
	for (unsigned a = 0; a < dir->numEntries(); a++)
	{
		ArchiveEntry* entry = dir->getEntry(a);

		// Skip default
		if (entry->getName(true) == "default")
			continue;

		// Read entry data into tokenizer
		Tokenizer tz;
		tz.openMem(&entry->getMCData(), entry->getName());

		// Parse it
		ParseTreeNode root;
		root.allowDup(true);
		root.parse(tz);

		// Read any styleset definitions
		vector<STreeNode*> nodes = root.getChildren("styleset");
		for (unsigned b = 0; b  < nodes.size(); b++)
		{
			StyleSet* newset = new StyleSet();
			if (newset->parseSet((ParseTreeNode*)nodes[b]))
				style_sets.push_back(newset);
			else
				delete newset;
		}
	}

	return true;
}
Exemplo n.º 29
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;
}
Exemplo n.º 30
0
/* DirArchive::open
 * Reads files from the directory [filename] into the archive
 * Returns true if successful, false otherwise
 *******************************************************************/
bool DirArchive::open(string filename)
{
	theSplashWindow->setProgressMessage("Reading directory structure");
	theSplashWindow->setProgress(0);
	//wxArrayString files;
	//wxDir::GetAllFiles(filename, &files, wxEmptyString, wxDIR_FILES|wxDIR_DIRS);
	vector<string> files, dirs;
	DirArchiveTraverser traverser(files, dirs);
	wxDir dir(filename);
	dir.Traverse(traverser, "", wxDIR_FILES | wxDIR_DIRS);

	theSplashWindow->setProgressMessage("Reading files");
	for (unsigned a = 0; a < files.size(); a++)
	{
		theSplashWindow->setProgress((float)a / (float)files.size());

		// Cut off directory to get entry name + relative path
		string name = files[a];
		name.Remove(0, filename.Length());
		if (name.StartsWith(separator))
			name.Remove(0, 1);

		//LOG_MESSAGE(3, fn.GetPath(true, wxPATH_UNIX));

		// Create entry
		wxFileName fn(name);
		ArchiveEntry* new_entry = new ArchiveEntry(fn.GetFullName());

		// Setup entry info
		new_entry->setLoaded(false);
		new_entry->exProp("filePath") = files[a];

		// Add entry and directory to directory tree
		ArchiveTreeNode* ndir = createDir(fn.GetPath(true, wxPATH_UNIX));
		ndir->addEntry(new_entry);
		ndir->getDirEntry()->exProp("filePath") = filename + fn.GetPath(true, wxPATH_UNIX);

		// Read entry data
		new_entry->importFile(files[a]);
		new_entry->setLoaded(true);

		time_t modtime = wxFileModificationTime(files[a]);
		file_modification_times[new_entry] = modtime;

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

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

	// Add empty directories
	for (unsigned a = 0; a < dirs.size(); a++)
	{
		string name = dirs[a];
		name.Remove(0, filename.Length());
		if (name.StartsWith(separator))
			name.Remove(0, 1);
		name.Replace("\\", "/");
		ArchiveTreeNode* ndir = createDir(name);
		ndir->getDirEntry()->exProp("filePath") = dirs[a];
	}

	// Set all entries/directories to unmodified
	vector<ArchiveEntry*> entry_list;
	getEntryTreeAsList(entry_list);
	for (size_t a = 0; a < entry_list.size(); a++)
		entry_list[a]->setState(0);

	// Enable announcements
	setMuted(false);

	// Setup variables
	this->filename = filename;
	setModified(false);
	on_disk = true;

	theSplashWindow->setProgressMessage("");

	return true;
}