예제 #1
0
// -----------------------------------------------------------------------------
// 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
	auto dir = entry1->parentDir();

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

	// Check they are both in the same directory
	if (entry2->parentDir() != dir)
	{
		Log::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(std::make_unique<EntrySwapUS>(dir, i1, i2));

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

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

	// Set modified
	setModified(true);

	// Return success
	return true;
}
예제 #2
0
// -----------------------------------------------------------------------------
// 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)
{
	// 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
	auto dir = entry->parentDir();

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

	// Create undo step
	if (UndoRedo::currentlyRecording())
		UndoRedo::currentManager()->recordUndoStep(std::make_unique<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);

		// Update variables etc
		setModified(true);
	}

	return ok;
}
예제 #3
0
// -----------------------------------------------------------------------------
// Renames [entry] with [name].
// Returns false if the entry was invalid, true otherwise
// -----------------------------------------------------------------------------
bool Archive::renameEntry(ArchiveEntry* entry, string_view name)
{
	// 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;

	// Check for directory
	if (entry->type() == EntryType::folderType())
		return renameDir(dir(entry->path(true)), name);

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

	// Create undo step
	if (UndoRedo::currentlyRecording())
		UndoRedo::currentManager()->recordUndoStep(std::make_unique<EntryRenameUS>(entry, name));

	// Rename the entry
	entry->setName(name);
	entry->formatName(formatDesc());
	entry->setState(ArchiveEntry::State::Modified, true);

	// Announce modification
	entryStateChanged(entry);

	return true;
}
예제 #4
0
파일: Archive.cpp 프로젝트: Aeyesx/SLADE
/* Archive::entryStateChanged
 * Updates the archive variables and announces if necessary that an
 * entry's state has changed
 *******************************************************************/
void Archive::entryStateChanged(ArchiveEntry* entry)
{
	// Check the entry is valid and part of this archive
	if (!checkEntry(entry))
		return;

	// Get the entry index and announce the change
	MemChunk mc(8);
	wxUIntPtr ptr = wxPtrToUInt(entry);
	uint32_t index = entryIndex(entry);
	mc.write(&index, sizeof(uint32_t));
	mc.write(&ptr, sizeof(wxUIntPtr));
	announce("entry_state_changed", mc);


	// If entry was set to unmodified, don't set the archive to modified
	if (entry->getState() == 0)
		return;

	// Set the archive state to modified
	setModified(true);
}
예제 #5
0
// -----------------------------------------------------------------------------
// Extract all sub-images as individual PNGs
// -----------------------------------------------------------------------------
bool GfxEntryPanel::extractAll() const
{
	if (image()->size() < 2)
		return false;

	// Remember where we are
	int imgindex = image()->index();

	auto parent = entry_->parent();
	if (parent == nullptr)
		return false;

	int      index = parent->entryIndex(entry_, entry_->parentDir());
	wxString name  = wxFileName(entry_->name()).GetName();

	// Loop through subimages and get things done
	int pos = 0;
	for (int i = 0; i < image()->size(); ++i)
	{
		wxString newname = wxString::Format("%s_%i.png", name, i);
		Misc::loadImageFromEntry(image(), entry_, i);

		// Only process images that actually contain some pixels
		if (image()->width() && image()->height())
		{
			auto newimg = parent->addNewEntry(newname.ToStdString(), index + pos + 1, entry_->parentDir());
			if (newimg == nullptr)
				return false;
			SIFormat::getFormat("png")->saveImage(*image(), newimg->data(), &gfx_canvas_->palette());
			EntryType::detectEntryType(newimg);
			pos++;
		}
	}

	// Reload image of where we were
	Misc::loadImageFromEntry(image(), entry_, imgindex);

	return true;
}
예제 #6
0
/* DatArchive::detectNamespace
 * Returns the namespace that [entry] is within
 *******************************************************************/
string DatArchive::detectNamespace(ArchiveEntry* entry)
{
	return detectNamespace(entryIndex(entry));
}
예제 #7
0
/* WadArchive::updateNamespaces
 * Updates the namespace list
 *******************************************************************/
void WadArchive::updateNamespaces()
{
	// Clear current namespace info
	while (namespaces.size() > 0)
		namespaces.pop_back();

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

		// Check for namespace begin
		if (entry->getName().Matches("*_START"))
		{
			// Create new namespace
			wad_ns_pair_t ns(entry, NULL);
			string name = entry->getName();
			ns.name = name.Left(name.Length() - 6).Lower();
			ns.start_index = entryIndex(ns.start);

			// Convert some special cases (because technically PP_START->P_END is a valid namespace)
			if (ns.name == "pp")
				ns.name = "p";
			if (ns.name == "ff")
				ns.name = "f";
			if (ns.name == "ss")
				ns.name = "s";
			if (ns.name == "tt")
				ns.name = "t";

			// Add to namespace list
			namespaces.push_back(ns);
		}
		// Check for namespace end
		else if (entry->getName().Matches("?_END") || entry->getName().Matches("??_END"))
		{
			// Get namespace 'name'
			int len = entry->getName().Length() - 4;
			string ns_name = entry->getName().Left(len).Lower();

			// Convert some special cases (because technically P_START->PP_END is a valid namespace)
			if (ns_name == "pp")
				ns_name = "p";
			if (ns_name == "ff")
				ns_name = "f";
			if (ns_name == "ss")
				ns_name = "s";
			if (ns_name == "tt")
				ns_name = "t";

			// Check if it's the end of an existing namespace
			// Remember entry is getEntry(a)? index is 'a'
			//size_t index = entryIndex(entry);

			bool found = false;
			for (unsigned b = 0; b < namespaces.size(); b++)
			{
				// Can't close a namespace that starts afterwards
				if (namespaces[b].start_index > a)
					break;
				// Can't close an already-closed namespace
				if (namespaces[b].end != NULL)
					continue;
				if (S_CMP(ns_name, namespaces[b].name))
				{
					found = true;
					namespaces[b].end = entry;
					namespaces[b].end_index = a;
					break;
				}
			}
			// Flat hack: closing the flat namespace without opening it
			if (found == false && ns_name == "f")
			{
				wad_ns_pair_t ns(getRoot()->getEntry(0), entry);
				ns.start_index = 0;
				ns.end_index = a;
				ns.name = "f";
				namespaces.push_back(ns);
			}
		}
	}

	// ROTT stuff. The first lump in the archive is always WALLSTRT, the last lump is either
	// LICENSE (darkwar.wad) or VENDOR (huntbgin.wad), with TABLES just before in both cases.
	// The shareware version has 2091 lumps, the complete version has about 50% more.
	if (numEntries() > 2090 && getRoot()->getEntry(0)->getName().Matches("WALLSTRT") &&
	        getRoot()->getEntry(numEntries()-2)->getName().Matches("TABLES"))
	{
		wad_ns_pair_t ns(getRoot()->getEntry(0), getRoot()->getEntry(numEntries()-1));
		ns.name = "rott";
		ns.start_index = 0;
		ns.end_index = entryIndex(ns.end);
		namespaces.push_back(ns);
	}


	// Check namespaces
	for (unsigned a = 0; a < namespaces.size(); a++)
	{
		wad_ns_pair_t& ns = namespaces[a];

		// Check the namespace has an end
		if (!ns.end)
		{
			// If not, remove the namespace as it is invalid
			namespaces.erase(namespaces.begin() + a);
			a--;
			continue;
		}

		// Check namespace name for special cases
		for (int n = 0; n < n_special_namespaces; n++)
		{
			if (S_CMP(ns.name, special_namespaces[n].letter))
				ns.name = special_namespaces[n].name;
		}

		ns.start_index = entryIndex(ns.start);
		ns.end_index = entryIndex(ns.end);

		// Testing
		//wxLogMessage("Namespace %s from %s (%d) to %s (%d)", ns.name,
		//	ns.start->getName(), ns.start_index, ns.end->getName(), ns.end_index);
	}
}