Ejemplo n.º 1
0
/* CTexture::removePatch
 * Removes all instances of [patch] from the texture. Returns true if
 * any were removed, false otherwise
 *******************************************************************/
bool CTexture::removePatch(string patch)
{
	// Go through patches
	bool removed = false;
	vector<CTPatch*>::iterator i = patches.begin();
	while (i != patches.end())
	{
		if (S_CMP((*i)->getName(), patch))
		{
			delete (*i);
			patches.erase(i);
			removed = true;
		}
		else
			i++;
	}

	// Cannot be a simple define anymore
	this->defined = false;

	if (removed)
		announce("patches_modified");

	return removed;
}
Ejemplo n.º 2
0
/* PatchTable::patch
 * Returns the patch matching [name], or an 'invalid' patch if no
 * match is found
 *******************************************************************/
patch_t& PatchTable::patch(string name)
{
	// Go through list
	for (unsigned a = 0; a < patches.size(); a++)
	{
		if (S_CMP(patches[a].name, name))
			return patches[a];
	}

	return patch_invalid;
}
Ejemplo n.º 3
0
/* MainApp::getAction
 * Returns the SAction matching [id]
 *******************************************************************/
SAction* MainApp::getAction(string id)
{
	// Find matching action
	for (unsigned a = 0; a < actions.size(); a++)
	{
		if (S_CMP(actions[a]->getId(), id))
			return actions[a];
	}

	// Not found
	return action_invalid;
}
Ejemplo n.º 4
0
// -----------------------------------------------------------------------------
// Checks if the file at [filename] is a valid DN3D grp archive
// -----------------------------------------------------------------------------
bool GrpArchive::isGrpArchive(const string& filename)
{
	// Open file for reading
	wxFile file(filename);

	// Check it opened ok
	if (!file.IsOpened())
		return false;

	// Check size
	if (file.Length() < 16)
		return false;

	// Get number of lumps
	uint32_t num_lumps     = 0;
	char     ken_magic[13] = "";
	file.Seek(0, wxFromStart);
	file.Read(ken_magic, 12); // "KenSilverman"
	file.Read(&num_lumps, 4); // No. of lumps in grp

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

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

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

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

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

	// If it's passed to here it's probably a grp file
	return true;
}
Ejemplo n.º 5
0
bool SAction::addToMenu(wxMenu* menu, bool show_shortcut, string text_override, string icon_override, int wx_id_offset)
{
	// Can't add to nonexistant menu
	if (!menu)
		return false;

	// Determine shortcut key
	string sc = shortcut;
	bool is_bind = false;
	bool sc_control = shortcut.Contains("Ctrl") || shortcut.Contains("Alt");
	if (shortcut.StartsWith("kb:"))
	{
		is_bind = true;
		keypress_t kp = KeyBind::getBind(shortcut.Mid(3)).getKey(0);
		if (kp.key != "")
			sc = kp.as_string();
		else
			sc = "None";
		sc_control = (kp.ctrl || kp.alt);
	}

	// Setup menu item string
	string item_text = text;
	if (!(S_CMP(text_override, "NO")))
		item_text = text_override;
	if (!sc.IsEmpty() && sc_control)
		item_text = S_FMT("%s\t%s", item_text, sc);

	// Append this action to the menu
	string help = helptext;
	int wid = wx_id + wx_id_offset;
	string real_icon = (icon_override == "NO") ? icon : icon_override;
	if (!sc.IsEmpty()) help += S_FMT(" (Shortcut: %s)", sc);
	if (type == NORMAL)
		menu->Append(createMenuItem(menu, wid, item_text, help, real_icon));
	else if (type == CHECK)
	{
		wxMenuItem* item = menu->AppendCheckItem(wid, item_text, help);
		item->Check(toggled);
	}
	else if (type == RADIO)
		menu->AppendRadioItem(wid, item_text, help);

	return true;
}
Ejemplo n.º 6
0
/* ArchiveManager::addBaseResourcePath
 * Adds [path] to the list of base resource paths
 *******************************************************************/
bool ArchiveManager::addBaseResourcePath(string path)
{
	// Firstly, check the file exists
	if (!wxFileExists(path))
		return false;;

	// Second, check the path doesn't already exist
	for (unsigned a = 0; a < base_resource_paths.size(); a++)
	{
		if (S_CMP(base_resource_paths[a], path))
			return false;
	}

	// Add it
	base_resource_paths.push_back(path);

	// Announce
	announce("base_resource_path_added");

	return true;
}
Ejemplo n.º 7
0
/* SAction::addToToolbar
 * Adds this action to [toolbar]. If [icon_override] is not "NO", it
 * will be used instead of the action's icon as the tool icon
 *******************************************************************/
bool SAction::addToToolbar(wxToolBar* toolbar, string icon_override)
{
	// Can't add to nonexistant toolbar
	if (!toolbar)
		return false;

	// Setup icon
	string useicon = icon;
	if (!(S_CMP(icon_override, "NO")))
		useicon = icon_override;

	// Append this action to the toolbar
	if (type == NORMAL)
		toolbar->AddTool(wx_id, "", getIcon(useicon), helptext);
	else if (type == CHECK)
		toolbar->AddTool(wx_id, "", getIcon(useicon), helptext, wxITEM_CHECK);
	else if (type == RADIO)
		toolbar->AddTool(wx_id, "", getIcon(useicon), helptext, wxITEM_RADIO);

	return true;
}
Ejemplo n.º 8
0
// -----------------------------------------------------------------------------
// Adds [path] to the list of base resource paths
// -----------------------------------------------------------------------------
bool ArchiveManager::addBaseResourcePath(const string& path)
{
	// Firstly, check the file exists
	if (!wxFileExists(path))
		return false;

	// Second, check the path doesn't already exist
	for (auto& base_resource_path : base_resource_paths_)
	{
		if (S_CMP(base_resource_path, path))
			return false;
	}

	// Add it
	base_resource_paths_.push_back(path);

	// Announce
	announce("base_resource_path_added");

	return true;
}
Ejemplo n.º 9
0
// -----------------------------------------------------------------------------
// Checks if the given data is a valid Duke Nukem 3D grp archive
// -----------------------------------------------------------------------------
bool GrpArchive::isGrpArchive(MemChunk& mc)
{
	// Check size
	if (mc.size() < 16)
		return false;

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

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

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

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

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

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

	// If it's passed to here it's probably a grp file
	return true;
}
Ejemplo n.º 10
0
/* SAction::addToToolbar
 * Adds this action to [toolbar]. If [icon_override] is not "NO", it
 * will be used instead of the action's icon as the tool icon
 *******************************************************************/
bool SAction::addToToolbar(wxToolBar* toolbar, string icon_override, int wx_id_offset)
{
	// Can't add to nonexistant toolbar
	if (!toolbar)
		return false;

	// Setup icon
	string useicon = icon;
	if (!(S_CMP(icon_override, "NO")))
		useicon = icon_override;

	// Append this action to the toolbar
	int wid = wx_id + wx_id_offset;
	if (type == Type::Normal)
		toolbar->AddTool(wid, "", Icons::getIcon(Icons::GENERAL, useicon), helptext);
	else if (type == Type::Check)
		toolbar->AddTool(wid, "", Icons::getIcon(Icons::GENERAL, useicon), helptext, wxITEM_CHECK);
	else if (type == Type::Radio)
		toolbar->AddTool(wid, "", Icons::getIcon(Icons::GENERAL, useicon), helptext, wxITEM_RADIO);

	return true;
}
Ejemplo n.º 11
0
bool SAction::addToMenu(wxMenu* menu, bool menubar, string text_override)
{
	// Can't add to nonexistant menu
	if (!menu)
		return false;

	// Determine shortcut key
	string sc = shortcut;
	bool is_bind = false;
	if (shortcut.StartsWith("kb:"))
	{
		is_bind = true;
		keypress_t kp = KeyBind::getBind(shortcut.Mid(3)).getKey(0);
		if (kp.key != "")
			sc = kp.as_string();
	}

	// Setup menu item string
	string item_text = text;
	if (!(S_CMP(text_override, "NO")))
		item_text = text_override;
	if (!sc.IsEmpty() && (!is_bind || !menubar))
		item_text = S_FMT("%s\t%s", item_text, sc);

	// Append this action to the menu
	string help = helptext;
	if (!sc.IsEmpty()) help += S_FMT(" (Shortcut: %s)", sc);
	if (type == NORMAL)
		menu->Append(createMenuItem(menu, wx_id, item_text, help, icon));
	else if (type == CHECK)
	{
		wxMenuItem* item = menu->AppendCheckItem(wx_id, item_text, help);
		item->Check(toggled);
	}
	else if (type == RADIO)
		menu->AppendRadioItem(wx_id, item_text, help);

	return true;
}
Ejemplo n.º 12
0
/* SAction::addToMenu
 * Adds this action to [menu]. If [text_override] is not "NO", it
 * will be used instead of the action's text as the menu item label
 *******************************************************************/
bool SAction::addToMenu(wxMenu* menu, string text_override)
{
	// Can't add to nonexistant menu
	if (!menu)
		return false;

	// Setup menu item string
	string item_text = text;
	if (!(S_CMP(text_override, "NO")))
		item_text = text_override;
	if (!shortcut.IsEmpty())
		item_text = S_FMT("%s\t%s", CHR(item_text), CHR(shortcut));

	// Append this action to the menu
	if (type == NORMAL)
		menu->Append(createMenuItem(menu, wx_id, item_text, helptext, icon));
	else if (type == CHECK)
		menu->AppendCheckItem(wx_id, item_text, helptext);
	else if (type == RADIO)
		menu->AppendRadioItem(wx_id, item_text, helptext);

	return true;
}
Ejemplo n.º 13
0
/* SAction::addToToolbar
 * Adds this action to [toolbar]. If [icon_override] is not "NO", it
 * will be used instead of the action's icon as the tool icon
 *******************************************************************/
bool SAction::addToToolbar(wxAuiToolBar* toolbar, string icon_override, int wx_id_offset)
{
	// Can't add to nonexistant toolbar
	if (!toolbar)
		return false;

	// Setup icon
	string useicon = icon;
	if (!(S_CMP(icon_override, "NO")))
		useicon = icon_override;

	// Append this action to the toolbar
	wxAuiToolBarItem* item = NULL;
	int wid = wx_id + wx_id_offset;
	if (type == NORMAL)
		item = toolbar->AddTool(wid, text, Icons::getIcon(Icons::GENERAL, useicon), helptext);
	else if (type == CHECK)
		item = toolbar->AddTool(wid, text, Icons::getIcon(Icons::GENERAL, useicon), helptext, wxITEM_CHECK);
	else if (type == RADIO)
		item = toolbar->AddTool(wid, text, Icons::getIcon(Icons::GENERAL, useicon), helptext, wxITEM_RADIO);

	return true;
}
Ejemplo n.º 14
0
/* PatchTable::addPatch
 * Adds a new patch with [name] to the end of the list
 *******************************************************************/
bool PatchTable::addPatch(string name, bool allow_dup)
{
	// Check patch doesn't already exist
	if (!allow_dup)
	{
		for (unsigned a = 0; a < patches.size(); a++)
		{
			if (S_CMP(name, patches[a].name))
				return false;
		}
	}

	// Create/init new patch
	patch_t patch;
	patch.name = name;

	// Add the patch
	patches.push_back(patch);

	// Announce
	announce("modified");

	return true;
}
Ejemplo n.º 15
0
/* WadArchive::detectMaps
 * Searches for any maps in the wad and adds them to the map list
 *******************************************************************/
vector<Archive::mapdesc_t> WadArchive::detectMaps()
{
	vector<mapdesc_t> maps;

	// Go through all lumps
	ArchiveEntry* entry = getEntry(0);
	bool lastentryismapentry = false;
	while (entry)
	{
		// UDMF format map check ********************************************************

		// Check for UDMF format map lump (TEXTMAP lump)
		if (entry->getName() == "TEXTMAP" && entry->prevEntry())
		{
			// Get map info
			mapdesc_t md = getMapInfo(entry->prevEntry());

			// Add to map list
			if (md.head != NULL)
			{
				entry = md.end;
				maps.push_back(md);
			}

			// Current index is ENDMAP, we don't want to check for a doom/hexen format
			// map so just go to the next index and continue the loop
			entry = entry->nextEntry();
			continue;
		}

		// Doom/Hexen format map check **************************************************
		// TODO maybe get rid of code duplication by calling getMapInfo() here too?

		// Array to keep track of what doom/hexen map lumps have been found
		uint8_t existing_map_lumps[NUMMAPLUMPS];
		memset(existing_map_lumps, 0, NUMMAPLUMPS);

		// Check if the current lump is a doom/hexen map lump
		bool maplump_found = false;
		for (int a = 0; a < 5; a++)
		{
			// Compare with all base map lump names
			if (S_CMP(entry->getName(), map_lumps[a]))
			{
				maplump_found = true;
				existing_map_lumps[a] = 1;
				break;
			}
		}

		// If we've found what might be a map
		if (maplump_found && entry->prevEntry())
		{
			// Save map header entry
			ArchiveEntry* header_entry = entry->prevEntry();

			// Check off map lumps until we find a non-map lump
			bool done = false;
			while (!done)
			{
				// Loop will end if no map lump is found
				done = true;

				// Compare with all map lump names
				for (int a = 0; a < NUMMAPLUMPS; a++)
				{
					// Compare with all base map lump names
					if (S_CMP(entry->getName(), map_lumps[a]))
					{
						existing_map_lumps[a] = 1;
						done = false;
						break;
					}
				}

				// If we're at the end of the wad, exit the loop
				if (!entry->nextEntry())
				{
					lastentryismapentry = true;
					break;
				}

				// Go to next lump if there is one
				if (!lastentryismapentry) entry = entry->nextEntry();
			}

			// Go back to the lump just after the last map lump found, but only if we actually moved
			if (!lastentryismapentry) entry = entry->prevEntry();

			// Check that we have all the required map lumps: VERTEXES, LINEDEFS, SIDEDEFS, THINGS & SECTORS
			if (!memchr(existing_map_lumps, 0, 5))
			{
				// Get map info
				mapdesc_t md;
				md.head = header_entry;				// Header lump
				md.name = header_entry->getName();	// Map title
				md.end = lastentryismapentry ?		// End lump
				         entry : entry->prevEntry();

				// If BEHAVIOR lump exists, it's a hexen format map
				if (existing_map_lumps[LUMP_BEHAVIOR])
					md.format = MAP_HEXEN;
				// If LEAFS, LIGHTS and MACROS exist, it's a doom 64 format map
				else if (existing_map_lumps[LUMP_LEAFS] && existing_map_lumps[LUMP_LIGHTS]
				         && existing_map_lumps[LUMP_MACROS])
					md.format = MAP_DOOM64;
				// Otherwise it's doom format
				else
					md.format = MAP_DOOM;

				// Add map info to the maps list
				maps.push_back(md);
			}
		}

		// Embedded WAD check (for Doom 64)
		if (entry->getType()->getFormat() == "archive_wad")
		{
			// Detect map format (probably kinda slow but whatever, no better way to do it really)
			Archive* tempwad = new WadArchive();
			tempwad->open(entry);
			vector<mapdesc_t> emaps = tempwad->detectMaps();
			if (emaps.size() > 0)
			{
				mapdesc_t md;
				md.head = entry;
				md.end = entry;
				md.archive = true;
				md.name = entry->getName(true).Upper();
				md.format = emaps[0].format;
				maps.push_back(md);
			}
			delete tempwad;
			entry->unlock();
		}

		// Not a UDMF or Doom/Hexen map lump, go to next lump
		entry = entry->nextEntry();
	}

	// Set all map header entries to ETYPE_MAP type
	for (size_t a = 0; a < maps.size(); a++)
		if (!maps[a].archive)
			maps[a].head->setType(EntryType::mapMarkerType());

	// Update entry map format hints
	for (unsigned a = 0; a < maps.size(); a++)
	{
		string format;
		if (maps[a].format == MAP_DOOM)
			format = "doom";
		else if (maps[a].format == MAP_DOOM64)
			format = "doom64";
		else if (maps[a].format == MAP_HEXEN)
			format = "hexen";
		else
			format = "udmf";

		ArchiveEntry* entry = maps[a].head;
		while (entry && entry != maps[a].end->nextEntry())
		{
			entry->exProp("MapFormat") = format;
			entry = entry->nextEntry();
		}
	}

	return maps;
}
Ejemplo n.º 16
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);
	}
}
Ejemplo n.º 17
0
/* ParseTreeNode::parse
 * Parses formatted text data. Current valid formatting is:
 * (type) child = value;
 * (type) child = value1, value2, ...;
 * (type) child = { value1, value2, ... }
 * (type) child { grandchild = value; etc... }
 * (type) child : inherited { ... }
 * All values are read as strings, but can be retrieved as string,
 * int, bool or float.
 *******************************************************************/
bool ParseTreeNode::parse(Tokenizer& tz)
{
    // Get first token
    string token = tz.getToken();

    // Keep parsing until final } is reached (or end of file)
    while (!(S_CMP(token, "}")) && !token.IsEmpty())
    {
        // Check for preprocessor stuff
        if (parser)
        {
            // #define
            if (S_CMPNOCASE(token, "#define"))
            {
                parser->define(tz.getToken());
                token = tz.getToken();
                continue;
            }

            // #if(n)def
            if (S_CMPNOCASE(token, "#ifdef") || S_CMPNOCASE(token, "#ifndef"))
            {
                bool test = true;
                if (S_CMPNOCASE(token, "#ifndef"))
                    test = false;
                string define = tz.getToken();
                if (parser->defined(define) == test)
                {
                    // Continue
                    token = tz.getToken();
                    continue;
                }
                else
                {
                    // Skip section
                    int skip = 0;
                    while (true)
                    {
                        token = tz.getToken();
                        if (S_CMPNOCASE(token, "#endif"))
                            skip--;
                        else if (S_CMPNOCASE(token, "#ifdef"))
                            skip++;
                        else if (S_CMPNOCASE(token, "#ifndef"))
                            skip++;

                        if (skip < 0)
                            break;
                        if (token.IsEmpty())
                        {
                            wxLogMessage("Error: found end of file within #if(n)def block");
                            break;
                        }
                    }

                    continue;
                }
            }

            // #include (ignore)
            if (S_CMPNOCASE(token, "#include"))
            {
                tz.skipToken();	// Skip include path
                token = tz.getToken();
                continue;
            }

            // #endif (ignore)
            if (S_CMPNOCASE(token, "#endif"))
            {
                token = tz.getToken();
                continue;
            }
        }

        // If it's a special character (ie not a valid name), parsing fails
        if (tz.isSpecialCharacter(token.at(0)))
        {
            wxLogMessage("Parsing error: Unexpected special character '%s' in %s (line %d)", CHR(token), CHR(tz.getName()), tz.lineNo());
            return false;
        }

        // So we have either a node or property name
        string name = token;

        // Check next token to determine what we're doing
        string next = tz.peekToken();

        // Check for type+name pair
        string type = "";
        if (next != "=" && next != "{" && next != ";" && next != ":")
        {
            type = name;
            name = tz.getToken();
            next = tz.peekToken();
        }

        // Assignment
        if (S_CMP(next, "="))
        {
            // Skip =
            tz.skipToken();

            // Create item node
            ParseTreeNode* child = (ParseTreeNode*)addChild(name);
            child->type = type;

            // Check type of assignment list
            token = tz.getToken();
            string list_end = ";";
            if (token == "{")
            {
                list_end = "}";
                token = tz.getToken();
            }

            // Parse until ; or }
            while (1)
            {
                // Check for list end
                if (S_CMP(token, list_end) && !tz.quotedString())
                    break;

                // Setup value
                Property value;

                // Detect value type
                if (tz.quotedString())					// Quoted string
                    value = token;
                else if (S_CMPNOCASE(token, "true"))	// Boolean (true)
                    value = true;
                else if (S_CMPNOCASE(token, "false"))	// Boolean (false)
                    value = false;
                else if (re_int1.Matches(token) ||		// Integer
                         re_int2.Matches(token))
                {
                    long val;
                    token.ToLong(&val);
                    value = (int)val;
                }
                else if (re_int3.Matches(token))  		// Hex (0xXXXXXX)
                {
                    long val;
                    token.ToLong(&val, 0);
                    value = (int)val;
                    //wxLogMessage("%s: %s is hex %d", CHR(name), CHR(token), value.getIntValue());
                }
                else if (re_float.Matches(token))  		// Floating point
                {
                    double val;
                    token.ToDouble(&val);
                    value = (double)val;
                    //LOG_MESSAGE(3, S_FMT("%s: %s is float %1.3f", CHR(name), CHR(token), val));
                }
                else									// Unknown, just treat as string
                    value = token;

                // Add value
                child->values.push_back(value);

                // Check for ,
                if (S_CMP(tz.peekToken(), ","))
                    tz.skipToken();	// Skip it
                else if (!(S_CMP(tz.peekToken(), list_end)))
                {
                    string t = tz.getToken();
                    string n = tz.getName();
                    wxLogMessage("Parsing error: Expected \",\" or \"%s\", got \"%s\" in %s (line %d)", CHR(list_end), CHR(t), CHR(n), tz.lineNo());
                    return false;
                }

                token = tz.getToken();
            }
        }

        // Child node
        else if (S_CMP(next, "{"))
        {
            // Add child node
            ParseTreeNode* child = (ParseTreeNode*)addChild(name);
            child->type = type;

            // Skip {
            tz.skipToken();

            // Parse child node
            if (!child->parse(tz))
                return false;
        }

        // Child node (with no values/children)
        else if (S_CMP(next, ";"))
        {
            // Add child node
            ParseTreeNode* child = (ParseTreeNode*)addChild(name);
            child->type = type;

            // Skip ;
            tz.skipToken();
        }

        // Child node + inheritance
        else if (S_CMP(next, ":"))
        {
            // Skip :
            tz.skipToken();

            // Read inherited name
            string inherit = tz.getToken();

            // Check for opening brace
            if (tz.checkToken("{"))
            {
                // Add child node
                ParseTreeNode* child = (ParseTreeNode*)addChild(name);
                child->type = type;

                // Set its inheritance
                child->inherit = inherit;

                // Parse child node
                if (!child->parse(tz))
                    return false;
            }
        }

        // Unexpected token
        else
        {
            wxLogMessage("Parsing error: \"%s\" unexpected in %s (line %d)", CHR(next), CHR(tz.getName()), tz.lineNo());
            return false;
        }

        // Continue parsing
        token = tz.getToken();
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	UI::setSplashProgressMessage("");

	return true;
}