Пример #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;
}
Пример #2
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;
}
Пример #3
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;
		}
	}
Пример #4
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;
}
Пример #5
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;
}
Пример #6
0
/* DirArchive::updateChangedEntries
 * Updates entries/directories based on [changes] list
 *******************************************************************/
void DirArchive::updateChangedEntries(vector<dir_entry_change_t>& changes)
{
	bool was_modified = isModified();

	for (unsigned a = 0; a < changes.size(); a++)
	{
		ignored_file_changes.erase(changes[a].file_path);

		// Modified Entries
		if (changes[a].action == dir_entry_change_t::UPDATED)
		{
			ArchiveEntry* entry = entryAtPath(changes[a].entry_path);
			entry->importFile(changes[a].file_path);
			EntryType::detectEntryType(entry);
			file_modification_times[entry] = wxFileModificationTime(changes[a].file_path);
		}

		// Deleted Entries
		else if (changes[a].action == dir_entry_change_t::DELETED_FILE)
			removeEntry(entryAtPath(changes[a].entry_path));

		// Deleted Directories
		else if (changes[a].action == dir_entry_change_t::DELETED_DIR)
			removeDir(changes[a].entry_path);

		// New Directory
		else if (changes[a].action == dir_entry_change_t::ADDED_DIR)
		{
			string name = changes[a].file_path;
			name.Remove(0, filename.Length());
			if (name.StartsWith(separator))
				name.Remove(0, 1);
			name.Replace("\\", "/");

			ArchiveTreeNode* ndir = createDir(name);
			ndir->getDirEntry()->setState(0);
			ndir->getDirEntry()->exProp("filePath") = changes[a].file_path;
		}

		// New Entry
		else if (changes[a].action == dir_entry_change_t::ADDED_FILE)
		{
			string name = changes[a].file_path;
			name.Remove(0, filename.Length());
			if (name.StartsWith(separator))
				name.Remove(0, 1);
			name.Replace("\\", "/");

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

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

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

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

			time_t modtime = wxFileModificationTime(changes[a].file_path);
			file_modification_times[new_entry] = modtime;

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

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

			// Set entry not modified
			new_entry->setState(0);
		}
	}

	// Preserve old modified state
	setModified(was_modified);
}