Blob Blame History Raw
From 6c58d8d7867ce39a4eb34d94bcc54b9f6969ba10 Mon Sep 17 00:00:00 2001
From: Julian Sikorski <belegdol+github@gmail.com>
Date: Fri, 8 Mar 2024 15:52:22 +0100
Subject: [PATCH 08/10] imp: Replaced custom XML parsing with QXmlStreamReader.
 (#42)

* Refactored machinelist.{cpp,h} to use QXmlStreamReader.
* Refactored softwarelist.cpp to use QXmlStreamReader.
* Refactored deviceconfigurator.cpp to QXmlStreamReader.
* Refactored romalyzer.cpp to QXmlStreamReader.
* Refactored qmc2main.cpp to QXmlStreamReader.
---
 src/deviceconfigurator.cpp |  88 +++--
 src/machinelist.cpp        | 639 ++++++++++++++++++-------------------
 src/machinelist.h          |   6 +-
 src/qmc2main.cpp           |  64 ++--
 src/romalyzer.cpp          |  99 +++---
 src/softwarelist.cpp       |  60 ++--
 6 files changed, 466 insertions(+), 490 deletions(-)

diff --git a/src/deviceconfigurator.cpp b/src/deviceconfigurator.cpp
index 6b06ebc4e..9b7b104a7 100644
--- a/src/deviceconfigurator.cpp
+++ b/src/deviceconfigurator.cpp
@@ -2006,57 +2006,55 @@ QString DeviceTreeXmlHandler::getXmlData(const QString &machine)
 
 QString DeviceTreeXmlHandler::lookupDescription(const QString &machine)
 {
-	QStringList xmlLines(qmc2MachineList->xmlDb()->xml(machine).split('\n'));
-	if ( xmlLines.count() > 1 ) {
-		int index = 0;
-		while ( index < xmlLines.count() && !xmlLines.at(index).startsWith("<description>") )
-			index++;
-		QString description(xmlLines.at(index));
-		description.remove("<description>").remove("</description>");
-		QTextDocument doc;
-		doc.setHtml(description);
-		return doc.toPlainText();
-	} else
-		return QString();
+	QXmlStreamReader xmlMachineEntry(qmc2MachineList->xmlDb()->xml(machine));
+	if ( xmlMachineEntry.readNextStartElement() ) {
+		if ( xmlMachineEntry.name() == "machine" ) {
+			while ( xmlMachineEntry.readNextStartElement() ) {
+				if ( xmlMachineEntry.name() == "description" ) {
+					QString description(xmlMachineEntry.readElementText());
+					QTextDocument doc;
+					doc.setHtml(description);
+					return doc.toPlainText();
+				} else
+					xmlMachineEntry.skipCurrentElement();
+			}
+		}
+	}
+	return QString();
 }
 
 QString DeviceTreeXmlHandler::lookupBiosOptions(const QString &machine, QStringList *bioses, QStringList *biosDescriptions)
 {
-	QStringList xmlLines(qmc2MachineList->xmlDb()->xml(machine).split('\n'));
-	if ( xmlLines.count() > 1 ) {
-		int index = 0;
-		QString defaultOption;
-		while ( index < xmlLines.count() ) {
-			if ( xmlLines.at(index).startsWith("<biosset ") ) {
-				QString name;
-				QString description;
-				int startIndex = xmlLines.at(index).indexOf("name=\"");
-				if ( startIndex >= 0 ) {
-					startIndex += 6;
-					int endIndex = xmlLines.at(index).indexOf("\"", startIndex);
-					name = xmlLines.at(index).mid(startIndex, endIndex - startIndex);
-				}
-				startIndex = xmlLines.at(index).indexOf("description=\"");
-				if ( startIndex >= 0 ) {
-					startIndex += 13;
-					int endIndex = xmlLines.at(index).indexOf("\"", startIndex);
-					description = xmlLines.at(index).mid(startIndex, endIndex - startIndex);
-					QTextDocument doc;
-					doc.setHtml(description);
-					description = doc.toPlainText();
-				}
-				if ( !name.isEmpty() && !description.isEmpty() ) {
-					bioses->append(name);
-					biosDescriptions->append(description);
-					if ( xmlLines.at(index).indexOf("default=\"yes\"") >= 0 )
-						defaultOption = name;
-				}
+	QXmlStreamReader xmlMachineEntry(qmc2MachineList->xmlDb()->xml(machine));
+	if ( xmlMachineEntry.readNextStartElement() ) {
+		if ( xmlMachineEntry.name() == "machine" ) {
+			QString defaultOption;
+			while ( xmlMachineEntry.readNextStartElement() ) {
+				if ( xmlMachineEntry.name() == "biosset" ) {
+					QString name;
+					QString description;
+					if ( xmlMachineEntry.attributes().hasAttribute("name") )
+						name = xmlMachineEntry.attributes().value("name").toString();
+					if ( xmlMachineEntry.attributes().hasAttribute("description") ) {
+						description = xmlMachineEntry.attributes().value("description").toString();
+						QTextDocument doc;
+						doc.setHtml(description);
+						description = doc.toPlainText();
+					}
+					if ( !name.isEmpty() && !description.isEmpty() ) {
+						bioses->append(name);
+						biosDescriptions->append(description);
+						if ( xmlMachineEntry.attributes().hasAttribute("default") && xmlMachineEntry.attributes().value("default").toString() == "yes" )
+							defaultOption = name;
+					}
+					xmlMachineEntry.skipCurrentElement();
+				} else
+					xmlMachineEntry.skipCurrentElement();
 			}
-			index++;
+			return defaultOption;
 		}
-		return defaultOption;
-	} else
-		return QString();
+	}
+	return QString();
 }
 
 bool FileChooserKeyEventFilter::eventFilter(QObject *obj, QEvent *event)
diff --git a/src/machinelist.cpp b/src/machinelist.cpp
index 4ccdc3c4b..7be2aa311 100644
--- a/src/machinelist.cpp
+++ b/src/machinelist.cpp
@@ -892,14 +892,10 @@ void MachineList::verify(bool currentOnly)
 	verifyProc->start(command, args, QIODevice::ReadOnly | QIODevice::Text);
 }
 
-QString MachineList::value(QString element, QString attribute, bool translate)
+QString MachineList::value(QXmlStreamReader &element, QString attribute, bool translate)
 {
-	QString attributePattern(" " + attribute + "=\"");
-	if ( element.contains(attributePattern) ) {
-		QString valueString(element.remove(0, element.indexOf(attributePattern) + attributePattern.length()));
-		valueString = valueString.remove(valueString.indexOf("\""), valueString.lastIndexOf(">")).replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">").replace("&quot;", "\"").replace("&apos;", "'");
-		if ( valueString == ">" )
-			return QString();
+	if ( element.attributes().hasAttribute(attribute) ) {
+		QString valueString(element.attributes().value(attribute).toString());
 		if ( translate )
 			return tr(valueString.toUtf8().constData());
 		else
@@ -908,7 +904,7 @@ QString MachineList::value(QString element, QString attribute, bool translate)
 		return QString();
 }
 
-void MachineList::insertAttributeItems(QTreeWidgetItem *parent, QString element, QStringList attributes, QStringList descriptions, bool translate)
+void MachineList::insertAttributeItems(QTreeWidgetItem *parent, QXmlStreamReader &element, QStringList attributes, QStringList descriptions, bool translate)
 {
 	QList<QTreeWidgetItem *> itemList;
 	for (int i = 0; i < attributes.count(); i++) {
@@ -923,7 +919,7 @@ void MachineList::insertAttributeItems(QTreeWidgetItem *parent, QString element,
 	parent->addChildren(itemList);
 }
 
-void MachineList::insertAttributeItems(QList<QTreeWidgetItem *> *itemList, QString element, QStringList attributes, QStringList descriptions, bool translate)
+void MachineList::insertAttributeItems(QList<QTreeWidgetItem *> *itemList, QXmlStreamReader &element, QStringList attributes, QStringList descriptions, bool translate)
 {
 	for (int i = 0; i < attributes.count(); i++) {
 		QString valueString(value(element, attributes.at(i), translate));
@@ -939,12 +935,7 @@ void MachineList::insertAttributeItems(QList<QTreeWidgetItem *> *itemList, QStri
 void MachineList::parseMachineDetail(QTreeWidgetItem *item)
 {
 	QString machineName(item->text(QMC2_MACHINELIST_COLUMN_NAME));
-	QStringList xmlLines(xmlDb()->xml(machineName).split("\n", QString::SkipEmptyParts));
-	if ( xmlLines.count() < 2 ) {
-		qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: couldn't find machine information for '%1'").arg(machineName));
-		return;
-	}
-	int gamePos = 1;
+	QXmlStreamReader xmlMachineEntry(xmlDb()->xml(machineName));
 	item->child(0)->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Updating"));
 	qmc2MainWindow->treeWidgetMachineList->viewport()->repaint();
 	qApp->processEvents();
@@ -955,259 +946,263 @@ void MachineList::parseMachineDetail(QTreeWidgetItem *item)
 
 	attributes << "name" << "sourcefile" << "isbios" << "isdevice" << "runnable" << "cloneof" << "romof" << "sampleof";
 	descriptions << tr("Name") << tr("Source file") << tr("Is BIOS?") << tr("Is device?") << tr("Runnable") << tr("Clone of") << tr("ROM of") << tr("Sample of");
-	element = xmlLines.at(gamePos - 1).simplified();
-	insertAttributeItems(&itemList, element, attributes, descriptions, true);
-	QString endMark("</machine>");
-
-	while ( !xmlLines.at(gamePos).contains(endMark) ) {
-		childItem = 0;
-		element = xmlLines.at(gamePos).simplified();
-		if ( element.contains("<year>") ) {
-			content = element.remove("<year>").remove("</year>");
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Year"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, content);
-		}
-		if ( element.contains("<manufacturer>") ) {
-			content = element.remove("<manufacturer>").remove("</manufacturer>");
-			content.replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">").replace("&quot;", "\"").replace("&apos;", "'");
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Manufacturer"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, content);
-		}
-		if ( element.contains("<rom ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("ROM"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
-			attributes.clear();
-			attributes << "bios" << "size" << "crc" << "sha1" << "merge" << "region" << "offset" << "status" << "optional";
-			descriptions.clear();
-			descriptions << tr("BIOS") << tr("Size") << tr("CRC") << tr("SHA-1") << tr("Merge") << tr("Region") << tr("Offset") << tr("Status") << tr("Optional");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-		}
-		if ( element.contains("<device_ref ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Device reference"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
-		}
-		if ( element.contains("<chip ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Chip"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
-			attributes.clear();
-			attributes << "tag" << "type" << "clock";
-			descriptions.clear();
-			descriptions << tr("Tag") << tr("Type") << tr("Clock");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-		}
-		if ( element.contains("<display ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Display"));
-			attributes.clear();
-			attributes << "type" << "rotate" << "flipx" << "width" << "height" << "refresh" << "pixclock" << "htotal" << "hbend" << "hbstart" << "vtotal" << "vbend" << "vbstart";
-			descriptions.clear();
-			descriptions << tr("Type") << tr("Rotate") << tr("Flip-X") << tr("Width") << tr("Height") << tr("Refresh") << tr("Pixel clock") << tr("H-Total") << tr("H-Bend") << tr("HB-Start") << tr("V-Total") << tr("V-Bend") << tr("VB-Start");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-		}
-		if ( element.contains("<sound ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Sound"));
-			attributes.clear();
-			attributes << "channels";
-			descriptions.clear();
-			descriptions << tr("Channels");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-		}
-		if ( element.contains("<input ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Input"));
-			attributes.clear();
-			attributes << "service" << "tilt" << "players" << "buttons" << "coins";
-			descriptions.clear();
-			descriptions << tr("Service") << tr("Tilt") << tr("Players") << tr("Buttons") << tr("Coins");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-			gamePos++;
-			while ( xmlLines.at(gamePos).contains("<control ") ) {
-				QString subElement(xmlLines.at(gamePos).simplified());
-				QTreeWidgetItem *nextChildItem = new QTreeWidgetItem(childItem);
-				nextChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Control"));
-				nextChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "type", true));
-				attributes.clear();
-				attributes << "minimum" << "maximum" << "sensitivity" << "keydelta" << "reverse" << "player" << "buttons" << "ways";
-				descriptions.clear();
-				descriptions << tr("Minimum") << tr("Maximum") << tr("Sensitivity") << tr("Key Delta") << tr("Reverse") << tr("Player") << tr("Buttons") << tr("Ways");
-				insertAttributeItems(nextChildItem, subElement, attributes, descriptions, true);
-				gamePos++;
-			}
-		}
-		if ( element.contains("<dipswitch ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("DIP switch"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name", true));
-			gamePos++;
-			while ( xmlLines.at(gamePos).contains("<dipvalue ") ) {
-				QString subElement(xmlLines.at(gamePos).simplified());
-				QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("DIP value"));
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", true));
-				attributes.clear();
-				attributes << "default";
-				descriptions.clear();
-				descriptions << tr("Default");
-				insertAttributeItems(secondChildItem, subElement, attributes, descriptions, true);
-				gamePos++;
-			}
-		}
-		if ( element.contains("<configuration ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Configuration"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name", true));
-			attributes.clear();
-			attributes << "tag" << "mask";
-			descriptions.clear();
-			descriptions << tr("Tag") << tr("Mask");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-			gamePos++;
-			while ( xmlLines.at(gamePos).contains("<confsetting ") ) {
-				QString subElement(xmlLines.at(gamePos).simplified());
-				QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Setting"));
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", true));
-				attributes.clear();
-				attributes << "value" << "default";
-				descriptions.clear();
-				descriptions << tr("Value") << tr("Default");
-				insertAttributeItems(secondChildItem, subElement, attributes, descriptions, true);
-				gamePos++;
-			}
-		}
-		if ( element.contains("<driver ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Driver"));
-			attributes.clear();
-			attributes << "status" << "emulation" << "color" << "sound" << "graphic" << "cocktail" << "protection" << "savestate" << "palettesize";
-			descriptions.clear();
-			descriptions << tr("Status") << tr("Emulation") << tr("Color") << tr("Sound") << tr("Graphic") << tr("Cocktail") << tr("Protection") << tr("Save state") << tr("Palette size");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-		}
-		if ( element.contains("<biosset ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("BIOS set"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
-			attributes.clear();
-			attributes << "description" << "default";
-			descriptions.clear();
-			descriptions << tr("Description") << tr("Default");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-		}
-		if ( element.contains("<sample ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Sample"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
-		}
-		if ( element.contains("<disk ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Disk"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
-			attributes.clear();
-			attributes << "md5" << "sha1" << "merge" << "region" << "index" << "status" << "optional";
-			descriptions.clear();
-			descriptions << tr("MD5") << tr("SHA-1") << tr("Merge") << tr("Region") << tr("Index") << tr("Status") << tr("Optional");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-		}
-		if ( element.contains("<adjuster ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Adjuster"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
-			attributes.clear();
-			attributes << "default";
-			descriptions.clear();
-			descriptions << tr("Default");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-		}
-		if ( element.contains("<softwarelist ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Software list"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
-			attributes.clear();
-			attributes << "status";
-			descriptions.clear();
-			descriptions << tr("Status");
-			insertAttributeItems(childItem, element, attributes, descriptions, true);
-		}
-		if ( element.contains("<category ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Category"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name", true));
-			gamePos++;
-			while ( xmlLines.at(gamePos).contains("<item ") ) {
-				QString subElement(xmlLines.at(gamePos).simplified());
-				QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Item"));
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", true));
-				attributes.clear();
-				attributes << "default";
-				descriptions.clear();
-				descriptions << tr("Default");
-				insertAttributeItems(secondChildItem, subElement, attributes, descriptions, true);
-				gamePos++;
-			}
-		}
-		if ( element.contains("<device ") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Device"));
-			childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "type", true));
-			attributes.clear();
-			attributes << "tag" << "mandatory" << "interface";
-			descriptions.clear();
-			descriptions << tr("Tag") << tr("Mandatory") << tr("Interface");
-			insertAttributeItems(childItem, element, attributes, descriptions, false);
-			gamePos++;
-			while ( xmlLines.at(gamePos).contains("<instance ") ) {
-				QString subElement(xmlLines.at(gamePos).simplified());
-				QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Instance"));
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", false));
-				attributes.clear();
-				attributes << "briefname";
-				descriptions.clear();
-				descriptions << tr("Brief name");
-				insertAttributeItems(secondChildItem, element, attributes, descriptions, false);
-				gamePos++;
-			}
-			while ( xmlLines.at(gamePos).contains("<extension ") ) {
-				QString subElement(xmlLines.at(gamePos).simplified());
-				QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Extension"));
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", false));
-				gamePos++;
-			}
-		}
-		if ( element.contains("<ramoption") ) {
-			childItem = new QTreeWidgetItem();
-			childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("RAM options"));
-			while ( xmlLines.at(gamePos).contains("<ramoption") ) {
-				QString subElement(xmlLines.at(gamePos).simplified());
-				QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Option"));
-				int fromIndex = subElement.indexOf('>') + 1;
-				int toIndex = subElement.indexOf('<', fromIndex);
-				QString ramOptionValue(subElement.mid(fromIndex, toIndex - fromIndex));
-				secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, ramOptionValue);
-				attributes.clear();
-				attributes << "default";
-				descriptions.clear();
-				descriptions << tr("Default");
-				insertAttributeItems(secondChildItem, subElement, attributes, descriptions, false);
-				gamePos++;
+
+	if ( xmlMachineEntry.readNextStartElement() ) {
+		if ( xmlMachineEntry.name() == "machine" ) {
+			insertAttributeItems(&itemList, xmlMachineEntry, attributes, descriptions, true);
+			while ( xmlMachineEntry.readNextStartElement() ) {
+				if ( xmlMachineEntry.name() == "year" ) {
+					content = xmlMachineEntry.readElementText();
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Year"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, content);
+				} else if ( xmlMachineEntry.name() =="manufacturer" ) {
+					content = xmlMachineEntry.readElementText();
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Manufacturer"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, content);
+				} else if ( xmlMachineEntry.name() == "rom" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("ROM"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name"));
+					attributes.clear();
+					attributes << "bios" << "size" << "crc" << "sha1" << "merge" << "region" << "offset" << "status" << "optional";
+					descriptions.clear();
+					descriptions << tr("BIOS") << tr("Size") << tr("CRC") << tr("SHA-1") << tr("Merge") << tr("Region") << tr("Offset") << tr("Status") << tr("Optional");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "device_ref" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Device reference"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name"));
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "chip") {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Chip"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name"));
+					attributes.clear();
+					attributes << "tag" << "type" << "clock";
+					descriptions.clear();
+					descriptions << tr("Tag") << tr("Type") << tr("Clock");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "display" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Display"));
+					attributes.clear();
+					attributes << "type" << "rotate" << "flipx" << "width" << "height" << "refresh" << "pixclock" << "htotal" << "hbend" << "hbstart" << "vtotal" << "vbend" << "vbstart";
+					descriptions.clear();
+					descriptions << tr("Type") << tr("Rotate") << tr("Flip-X") << tr("Width") << tr("Height") << tr("Refresh") << tr("Pixel clock") << tr("H-Total") << tr("H-Bend") << tr("HB-Start") << tr("V-Total") << tr("V-Bend") << tr("VB-Start");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "sound" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Sound"));
+					attributes.clear();
+					attributes << "channels";
+					descriptions.clear();
+					descriptions << tr("Channels");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "input" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Input"));
+					attributes.clear();
+					attributes << "service" << "tilt" << "players" << "buttons" << "coins";
+					descriptions.clear();
+					descriptions << tr("Service") << tr("Tilt") << tr("Players") << tr("Buttons") << tr("Coins");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					while ( xmlMachineEntry.readNextStartElement() ) {
+						if ( xmlMachineEntry.name() == "control" ) {
+							QTreeWidgetItem *nextChildItem = new QTreeWidgetItem(childItem);
+							nextChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Control"));
+							nextChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "type", true));
+							attributes.clear();
+							attributes << "minimum" << "maximum" << "sensitivity" << "keydelta" << "reverse" << "player" << "buttons" << "ways";
+							descriptions.clear();
+							descriptions << tr("Minimum") << tr("Maximum") << tr("Sensitivity") << tr("Key Delta") << tr("Reverse") << tr("Player") << tr("Buttons") << tr("Ways");
+							insertAttributeItems(nextChildItem, xmlMachineEntry, attributes, descriptions, true);
+							xmlMachineEntry.skipCurrentElement();
+						} else
+							xmlMachineEntry.skipCurrentElement();
+					}
+				} else if ( xmlMachineEntry.name() == "dipswitch") {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("DIP switch"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name", true));
+					while ( xmlMachineEntry.readNextStartElement() ) {
+						if ( xmlMachineEntry.name() == "dipvalue") {
+							QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("DIP value"));
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name", true));
+							attributes.clear();
+							attributes << "default";
+							descriptions.clear();
+							descriptions << tr("Default");
+							insertAttributeItems(secondChildItem, xmlMachineEntry, attributes, descriptions, true);
+							xmlMachineEntry.skipCurrentElement();
+						} else
+							xmlMachineEntry.skipCurrentElement();
+					}
+				} else if ( xmlMachineEntry.name() == "configuration" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Configuration"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name", true));
+					attributes.clear();
+					attributes << "tag" << "mask";
+					descriptions.clear();
+					descriptions << tr("Tag") << tr("Mask");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					while ( xmlMachineEntry.readNextStartElement() ) {
+						if ( xmlMachineEntry.name() == "confsetting" ) {
+							QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Setting"));
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name", true));
+							attributes.clear();
+							attributes << "value" << "default";
+							descriptions.clear();
+							descriptions << tr("Value") << tr("Default");
+							insertAttributeItems(secondChildItem, xmlMachineEntry, attributes, descriptions, true);
+							xmlMachineEntry.skipCurrentElement();
+						} else
+							xmlMachineEntry.skipCurrentElement();
+					}
+				} else if ( xmlMachineEntry.name() == "driver" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Driver"));
+					attributes.clear();
+					attributes << "status" << "emulation" << "color" << "sound" << "graphic" << "cocktail" << "protection" << "savestate" << "palettesize";
+					descriptions.clear();
+					descriptions << tr("Status") << tr("Emulation") << tr("Color") << tr("Sound") << tr("Graphic") << tr("Cocktail") << tr("Protection") << tr("Save state") << tr("Palette size");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "biosset" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("BIOS set"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name"));
+					attributes.clear();
+					attributes << "description" << "default";
+					descriptions.clear();
+					descriptions << tr("Description") << tr("Default");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "sample" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Sample"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name"));
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "disk" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Disk"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name"));
+					attributes.clear();
+					attributes << "md5" << "sha1" << "merge" << "region" << "index" << "status" << "optional";
+					descriptions.clear();
+					descriptions << tr("MD5") << tr("SHA-1") << tr("Merge") << tr("Region") << tr("Index") << tr("Status") << tr("Optional");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "adjuster" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Adjuster"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name"));
+					attributes.clear();
+					attributes << "default";
+					descriptions.clear();
+					descriptions << tr("Default");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "softwarelist" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Software list"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name"));
+					attributes.clear();
+					attributes << "status";
+					descriptions.clear();
+					descriptions << tr("Status");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, true);
+					xmlMachineEntry.skipCurrentElement();
+				} else if ( xmlMachineEntry.name() == "category" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Category"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name", true));
+					while ( xmlMachineEntry.readNextStartElement() ) {
+						if ( xmlMachineEntry.name() == "item" ) {
+							QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Item"));
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name", true));
+							attributes.clear();
+							attributes << "default";
+							descriptions.clear();
+							descriptions << tr("Default");
+							insertAttributeItems(secondChildItem, xmlMachineEntry, attributes, descriptions, true);
+							xmlMachineEntry.skipCurrentElement();
+						} else
+							xmlMachineEntry.skipCurrentElement();
+					}
+				} else if ( xmlMachineEntry.name() == "device" ) {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Device"));
+					childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "type", true));
+					attributes.clear();
+					attributes << "tag" << "mandatory" << "interface";
+					descriptions.clear();
+					descriptions << tr("Tag") << tr("Mandatory") << tr("Interface");
+					insertAttributeItems(childItem, xmlMachineEntry, attributes, descriptions, false);
+					while ( xmlMachineEntry.readNextStartElement() ) {
+						if ( xmlMachineEntry.name() == "instance" ) {
+							QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Instance"));
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name", false));
+							attributes.clear();
+							attributes << "briefname";
+							descriptions.clear();
+							descriptions << tr("Brief name");
+							insertAttributeItems(secondChildItem, xmlMachineEntry, attributes, descriptions, false);
+							xmlMachineEntry.skipCurrentElement();
+						} else if ( xmlMachineEntry.name() == "extension" ) {
+							QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Extension"));
+							secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(xmlMachineEntry, "name", false));
+							xmlMachineEntry.skipCurrentElement();
+						} else
+							xmlMachineEntry.skipCurrentElement();
+					}
+				} else if ( xmlMachineEntry.name() == "ramoption") {
+					childItem = new QTreeWidgetItem();
+					childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("RAM options"));
+					QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
+					secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Option"));
+					attributes.clear();
+					attributes << "default";
+					descriptions.clear();
+					descriptions << tr("Default");
+					insertAttributeItems(secondChildItem, xmlMachineEntry, attributes, descriptions, false);
+					QString ramOptionValue = xmlMachineEntry.readElementText();
+					secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, ramOptionValue);
+					while ( xmlMachineEntry.readNextStartElement() ) {
+						if (  xmlMachineEntry.name() == "ramoption" ) {
+							QTreeWidgetItem *anotherSecondChildItem = new QTreeWidgetItem(childItem);
+							anotherSecondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Option"));
+							attributes.clear();
+							attributes << "default";
+							descriptions.clear();
+							descriptions << tr("Default");
+							insertAttributeItems(anotherSecondChildItem, xmlMachineEntry, attributes, descriptions, false);
+							QString ramOptionValue = xmlMachineEntry.readElementText();
+							anotherSecondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, ramOptionValue);
+						}
+					}
+				} else
+					xmlMachineEntry.skipCurrentElement();
+				if ( childItem )
+					itemList.append(childItem);
 			}
-			if ( xmlLines.at(gamePos).contains(endMark) )
-				gamePos--;
+		} else {
+			qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: couldn't find machine information for '%1'").arg(machineName));
+			return;
 		}
-		gamePos++;
-		if ( childItem )
-			itemList.append(childItem);
 	}
+
 	qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(false);
 	delete item->takeChild(0);
 	item->addChildren(itemList);
@@ -1548,26 +1543,21 @@ void MachineList::parse()
 			machineListDb()->beginTransaction();
 			int pendingDbUpdates = 0;
 			for (qint64 rowCounter = 1; rowCounter <= xmlRowCount && !qmc2LoadingInterrupted; rowCounter++) {
-				QStringList xmlLines(xmlDb()->xml(rowCounter).split(lineSplitChar, QString::SkipEmptyParts));
-				for (int lineCounter = 0; lineCounter < xmlLines.count() && !qmc2LoadingInterrupted; lineCounter++) {
-					while ( lineCounter < xmlLines.count() && !xmlLines.at(lineCounter).contains("<description>") )
-						lineCounter++;
-					if ( !qmc2LoadingInterrupted && lineCounter < xmlLines.count() ) {
-						QString machineElement(xmlLines.at(lineCounter - 1).simplified());
-						if ( !machineElement.contains(" name=\"") )
-							continue;
-						bool isBIOS = value(machineElement, "isbios").compare("yes") == 0;
-						bool isDev = value(machineElement, "isdevice").compare("yes") == 0;
-						QString machineName(value(machineElement, "name"));
+				QXmlStreamReader xmlMachineEntry(xmlDb()->xml(rowCounter));
+				if ( xmlMachineEntry.readNextStartElement() && !qmc2LoadingInterrupted ) {
+					if ( xmlMachineEntry.name() == "machine" ) {
+						bool isBIOS = value(xmlMachineEntry, "isbios").compare("yes") == 0;
+						bool isDev = value(xmlMachineEntry, "isdevice").compare("yes") == 0;
+						QString machineName(value(xmlMachineEntry, "name"));
 						if ( machineName.isEmpty() ) {
-							qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: name attribute empty on XML line %1 (set will be ignored!) -- please inform MAME developers and include the offending output from -listxml").arg(lineCounter + 2));
+							qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: name attribute empty on XML line %1 (set will be ignored!) -- please inform MAME developers and include the offending output from -listxml").arg(xmlMachineEntry.lineNumber()));
 							qApp->processEvents();
 							continue;
 						}
-						QString machineSource(value(machineElement, "sourcefile"));
-						QString machineCloneOf(value(machineElement, "cloneof"));
-						QString descriptionElement(xmlLines.at(lineCounter).simplified());
-						QString machineDescription(descriptionElement.remove("<description>").remove("</description>").replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">").replace("&quot;", "\"").replace("&apos;", "'"));
+						QString machineSource(value(xmlMachineEntry, "sourcefile"));
+						QString machineCloneOf(value(xmlMachineEntry, "cloneof"));
+						QString descriptionElement;
+						QString machineDescription;
 						MachineListItem *machineItem = new MachineListItem();
 						qmc2MachineListItemHash.insert(machineName, machineItem);
 						machineItem->setFlags(MachineListItem::defaultItemFlags);
@@ -1576,37 +1566,39 @@ void MachineList::parse()
 							hiddenItemHash.insert(machineItem, true);
 						// find year & manufacturer and determine ROM/CHD requirements
 						bool endMachine = false;
-						int i = lineCounter;
+
 						QString machineYear(trQuestionMark), machineManufacturer(trQuestionMark), machinePlayers(trQuestionMark), machineDrvStat(trQuestionMark);
 						bool yearFound = false, manufacturerFound = false, hasROMs = false, hasCHDs = false, playersFound = false, statusFound = false;
-						QString endMark("</machine>");
-						while ( !endMachine ) {
-							QString xmlLine(xmlLines.at(i));
-							if ( xmlLine.contains("<year>") ) {
-								machineYear = xmlLine.simplified().remove("<year>").remove("</year>");
+						while ( xmlMachineEntry.readNextStartElement() && !endMachine ) {
+							if ( xmlMachineEntry.name() == "description" ) {
+								machineDescription = xmlMachineEntry.readElementText();
+							} else if ( xmlMachineEntry.name() == "year" ) {
+								machineYear = xmlMachineEntry.readElementText();
 								yearFound = true;
-							} else if ( xmlLine.contains("<manufacturer>") ) {
-								machineManufacturer = xmlLine.simplified().remove("<manufacturer>").remove("</manufacturer>").replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">").replace("&quot;", "\"").replace("&apos;", "'");
+							} else if ( xmlMachineEntry.name() == "manufacturer" ) {
+								machineManufacturer = xmlMachineEntry.readElementText();
 								manufacturerFound = true;
-							} else if ( xmlLine.contains("<rom name") ) {
+							} else if ( xmlMachineEntry.name() == "rom" ) {
 								hasROMs = true;
-							} else if ( xmlLine.contains("<disk name") ) {
+								xmlMachineEntry.skipCurrentElement();
+							} else if ( xmlMachineEntry.name() == "disk" ) {
 								hasCHDs = true;
-							} else if ( xmlLine.contains("<input players") ) {
-								int playersPos = xmlLine.indexOf("input players=\"") + 15;
-								if ( playersPos >= 0 ) {
-									machinePlayers = xmlLine.mid(playersPos, xmlLine.indexOf("\"", playersPos) - playersPos);
+								xmlMachineEntry.skipCurrentElement();
+							} else if ( xmlMachineEntry.name() == "input" ) {
+								if ( xmlMachineEntry.attributes().hasAttribute("players") ) {
+									machinePlayers = xmlMachineEntry.attributes().value("players").toString();
 									playersFound = true;
 								}
-							} else if ( xmlLine.contains("<driver status") ) {
-								int statusPos = xmlLine.indexOf("driver status=\"") + 15;
-								if ( statusPos >= 0 ) {
-									machineDrvStat = xmlLine.mid(statusPos, xmlLine.indexOf("\"", statusPos) - statusPos);
+								xmlMachineEntry.skipCurrentElement();
+							} else if ( xmlMachineEntry.name() == "driver" ) {
+								if ( xmlMachineEntry.attributes().hasAttribute("status") ) {
+									machineDrvStat = xmlMachineEntry.attributes().value("status").toString();
 									statusFound = true;
 								}
-							}
-							endMachine = xmlLine.contains(endMark) || (yearFound && manufacturerFound && hasROMs && hasCHDs && playersFound && statusFound);
-							i++;
+								xmlMachineEntry.skipCurrentElement();
+							} else
+								xmlMachineEntry.skipCurrentElement();
+							endMachine = yearFound && manufacturerFound && hasROMs && hasCHDs && playersFound && statusFound;
 						}
 						if ( machineCloneOf.isEmpty() ) {
 							if ( !hierarchyHash.contains(machineName) )
@@ -2544,28 +2536,29 @@ void MachineList::verifyFinished(int exitCode, QProcess::ExitStatus exitStatus)
 				QTreeWidgetItem *versionItem = qmc2VersionItemHash.value(machineName);
 				// there are quite a number of sets in MAME that don't require any ROMs... many/most device-sets in particular
 				bool romRequired = true;
-				int xmlCounter = 0;
-				QStringList xmlLines(xmlDb()->xml(machineName).split("\n", QString::SkipEmptyParts));
-				if ( xmlLines.count() > 0 ) {
-					int romCounter = 0;
-					int chdCounter = 0;
-					bool endFound = false;
-					QString endMark = "</machine>";
-					while ( !endFound && xmlCounter < xmlLines.count() ) {
-						if ( xmlLines.at(xmlCounter).contains("<rom name=\"") ) {
-							romCounter++;
-							endFound = true;
-						} else if ( xmlLines.at(xmlCounter).contains("<disk name=\"") ) {
-							chdCounter++;
-							endFound = true;
-						} else if ( xmlLines.at(xmlCounter).contains(endMark) )
-							endFound = true;
-						xmlCounter++;
+				QXmlStreamReader xmlMachineEntry(xmlDb()->xml(machineName));
+				if ( xmlMachineEntry.readNextStartElement() ) {
+					if ( xmlMachineEntry.name() == "machine" ) {
+						int romCounter = 0;
+						int chdCounter = 0;
+						bool endFound = false;
+						while ( xmlMachineEntry.readNextStartElement() && !endFound ) {
+							if ( xmlMachineEntry.name() == "rom" ) {
+								romCounter++;
+								endFound = true;
+								xmlMachineEntry.skipCurrentElement();
+							} else if ( xmlMachineEntry.name() == "disk" ) {
+								chdCounter++;
+								endFound = true;
+								xmlMachineEntry.skipCurrentElement();
+							} else
+								xmlMachineEntry.skipCurrentElement();
+						}
+						if ( romCounter == 0 && chdCounter > 0 )
+							romRequired = true;
+						else
+							romRequired = (romCounter > 0);
 					}
-					if ( romCounter == 0 && chdCounter > 0 )
-						romRequired = true;
-					else
-						romRequired = (romCounter > 0);
 				}
 				if ( romItem && hierarchyItem ) {
 					if ( romStateCache.isOpen() ) {
diff --git a/src/machinelist.h b/src/machinelist.h
index 8a4eee1e0..944ee88d0 100644
--- a/src/machinelist.h
+++ b/src/machinelist.h
@@ -132,11 +132,11 @@ class MachineList : public QObject
 		void verifyReadyReadStandardOutput();
 
 		// internal methods
-		QString value(QString, QString, bool translate = false);
+		QString value(QXmlStreamReader &, QString, bool translate = false);
 		void parse();
 		void parseMachineDetail(QTreeWidgetItem *);
-		void insertAttributeItems(QTreeWidgetItem *, QString, QStringList, QStringList, bool translate = false);
-		void insertAttributeItems(QList<QTreeWidgetItem *> *itemList, QString element, QStringList attributes, QStringList descriptions, bool translate = false);
+		void insertAttributeItems(QTreeWidgetItem *, QXmlStreamReader &, QStringList, QStringList, bool translate = false);
+		void insertAttributeItems(QList<QTreeWidgetItem *> *itemList, QXmlStreamReader &element, QStringList attributes, QStringList descriptions, bool translate = false);
 		void enableWidgets(bool enable = true);
 		void disableWidgets() { enableWidgets(false); }
 		void filter(bool initial = false);
diff --git a/src/qmc2main.cpp b/src/qmc2main.cpp
index ec16009b2..e24fe89d6 100644
--- a/src/qmc2main.cpp
+++ b/src/qmc2main.cpp
@@ -4631,44 +4631,36 @@ QStringList &MainWindow::getXmlChoices(const QString &machineName, const QString
 		return xmlChoices;
 	if ( defaultChoice )
 		defaultChoice->clear();
-	QStringList xmlLines(qmc2MachineList->xmlDb()->xml(machineName).split('\n', QString::SkipEmptyParts));
-	QString defaultYes("default=\"yes\"");
-	QString defaultOne("default=\"1\"");
-	int i = 0;
-	while ( i < xmlLines.count() ) {
-		QString xmlLine(xmlLines.at(i++).simplified());
-		int index = xmlLine.indexOf('<' + optionElement);
-		if ( index >= 0 ) {
-			if ( optionAttribute.isEmpty() ) {
-				index = xmlLine.indexOf('>', index);
-				if ( index >= 0 ) {
-					xmlLine.remove(0, index + 1);
-					bool isDefaultChoice = false;
-					if ( defaultChoice && (xmlLine.indexOf(defaultYes) >= 0 || xmlLine.indexOf(defaultOne) >= 0 || defaultChoice->isEmpty()) )
-						isDefaultChoice = true;
-					xmlLine.replace("</" + optionElement + '>', "");
-					QTextDocument doc;
-					doc.setHtml(xmlLine);
-					xmlLine = doc.toPlainText();
-					xmlChoices << xmlLine;
-					if ( isDefaultChoice )
-						*defaultChoice = xmlLine;
-				}
-			} else {
-				QString prefix(optionAttribute + "=\"");
-				index = xmlLine.indexOf(prefix);
-				if ( index >= 0 ) {
-					xmlLine.remove(0, index + prefix.length());
-					index = xmlLine.indexOf('\"');
-					if ( index >= 0 ) {
+	QXmlStreamReader xmlMachineEntry(qmc2MachineList->xmlDb()->xml(machineName));
+	QString defaultYes("yes");
+	QString defaultOne("1");
+	if ( xmlMachineEntry.readNextStartElement() ) {
+		if ( xmlMachineEntry.name() == "machine" ) {
+			while ( xmlMachineEntry.readNextStartElement() ) {
+				if ( xmlMachineEntry.name() == optionElement ) {
+					if ( optionAttribute.isEmpty() ) {
+						bool isDefaultChoice = false;
+						if ( defaultChoice && (xmlMachineEntry.attributes().hasAttribute("default") && xmlMachineEntry.attributes().value("default").toString() == defaultYes || xmlMachineEntry.attributes().value("default").toString() == defaultOne || defaultChoice->isEmpty()) )
+							isDefaultChoice = true;
 						QTextDocument doc;
-						doc.setHtml(xmlLine.left(index));
-						QString choice = doc.toPlainText();
-						xmlChoices << choice;
-						if ( defaultChoice && (xmlLine.indexOf(defaultYes) >= 0 || xmlLine.indexOf(defaultOne) >= 0 || defaultChoice->isEmpty()) )
-							*defaultChoice = choice;
+						doc.setHtml(xmlMachineEntry.readElementText());
+						QString xmlLine = doc.toPlainText();
+						xmlChoices << xmlLine;
+						if ( isDefaultChoice )
+							*defaultChoice = xmlLine;
+					} else {
+						if ( xmlMachineEntry.attributes().hasAttribute(optionAttribute) ) {
+							QTextDocument doc;
+							doc.setHtml(xmlMachineEntry.attributes().value(optionAttribute).toString());
+							QString choice = doc.toPlainText();
+							xmlChoices << choice;
+							if ( defaultChoice && (xmlMachineEntry.attributes().hasAttribute("default") && xmlMachineEntry.attributes().value("default").toString() == defaultYes || xmlMachineEntry.attributes().value("default").toString() == defaultOne || defaultChoice->isEmpty()) )
+								*defaultChoice = choice;
+							xmlMachineEntry.skipCurrentElement();
+						}
 					}
-				}
+				} else
+					xmlMachineEntry.skipCurrentElement();
 			}
 		}
 	}
diff --git a/src/romalyzer.cpp b/src/romalyzer.cpp
index ddb5b0b38..902db6ed7 100644
--- a/src/romalyzer.cpp
+++ b/src/romalyzer.cpp
@@ -2753,18 +2753,15 @@ void ROMAlyzer::on_pushButtonChecksumWizardSearch_clicked()
 	lineEditSets->setEnabled(false);
 	labelStatus->setText(tr("Check-sum search"));
 
-	QString hashStartString;
-	int hashStartOffset;
+	QString hashAttribute;
 	switch ( comboBoxChecksumWizardHashType->currentIndex() ) {
 		case QMC2_ROMALYZER_CSF_HASHTYPE_CRC:
-			hashStartString = "crc=\"";
-			hashStartOffset = 5;
+			hashAttribute = "crc";
 			break;
 
 		default:
 		case QMC2_ROMALYZER_CSF_HASHTYPE_SHA1:
-			hashStartString = "sha1=\"";
-			hashStartOffset = 6;
+			hashAttribute = "sha1";
 			break;
 	}
 
@@ -2775,29 +2772,28 @@ void ROMAlyzer::on_pushButtonChecksumWizardSearch_clicked()
 				int progressCount = 0, updateCount = 0;
 				foreach (QString list, uniqueSoftwareLists) {
 					foreach (QString set, qmc2MainWindow->swlDb->uniqueSoftwareSets(list)) {
-						QStringList xmlLines(qmc2MainWindow->swlDb->xml(list, set).split('\n', QString::SkipEmptyParts));
-						for (int i = 0; i < xmlLines.count(); i++) {
-							QString xmlLine(xmlLines.at(i));
-							int hashIndex = xmlLine.indexOf(hashStartString);
-							if ( hashIndex >= 0 ) {
-								int hashPos = hashIndex + hashStartOffset;
-								QString currentChecksum(xmlLine.mid(hashPos, xmlLine.indexOf('\"', hashPos) - hashPos).toLower());
-								if ( currentChecksum.compare(searchedChecksum) == 0 ) {
-									int fileNamePos;
-									QString fileType;
-									if ( xmlLine.startsWith("<disk name=\"") ) {
-										fileType = tr("CHD");
-										fileNamePos = xmlLine.indexOf("<disk name=\"") + 12;
-									} else {
-										fileType = tr("ROM");
-										fileNamePos = xmlLine.indexOf("<rom name=\"") + 11;
-									}
-									QString fileName(xmlLine.mid(fileNamePos, xmlLine.indexOf('\"', fileNamePos) - fileNamePos));
-									QTreeWidgetItem *item = new QTreeWidgetItem(treeWidgetChecksumWizardSearchResult);
-									item->setText(QMC2_ROMALYZER_CSF_COLUMN_ID, list + ":" + set);
-									item->setText(QMC2_ROMALYZER_CSF_COLUMN_FILENAME, fileName.replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">").replace("&quot;", "\"").replace("&apos;", "'"));
-									item->setText(QMC2_ROMALYZER_CSF_COLUMN_TYPE, fileType);
-									item->setText(QMC2_ROMALYZER_CSF_COLUMN_STATUS, tr("unknown"));
+						QXmlStreamReader xmlMachineEntry(qmc2MainWindow->swlDb->xml(list, set));
+						if ( xmlMachineEntry.readNextStartElement() ) {
+							if ( xmlMachineEntry.name() == "machine" ) {
+								while ( xmlMachineEntry.readNextStartElement() ) {
+									if ( xmlMachineEntry.attributes().hasAttribute(hashAttribute) ) {
+										QString currentChecksum(xmlMachineEntry.attributes().value(hashAttribute).toString().toLower());
+										if ( currentChecksum.compare(searchedChecksum) == 0 ) {
+											QString fileType;
+											if ( xmlMachineEntry.name() == "disk" )
+												fileType = tr("CHD");
+											else
+												fileType = tr("ROM");
+											QString fileName(xmlMachineEntry.attributes().value("name").toString());
+											QTreeWidgetItem *item = new QTreeWidgetItem(treeWidgetChecksumWizardSearchResult);
+											item->setText(QMC2_ROMALYZER_CSF_COLUMN_ID, list + ":" + set);
+											item->setText(QMC2_ROMALYZER_CSF_COLUMN_FILENAME, fileName);
+											item->setText(QMC2_ROMALYZER_CSF_COLUMN_TYPE, fileType);
+											item->setText(QMC2_ROMALYZER_CSF_COLUMN_STATUS, tr("unknown"));
+										}
+										xmlMachineEntry.skipCurrentElement();
+									} else
+										xmlMachineEntry.skipCurrentElement();
 								}
 							}
 						}
@@ -2820,29 +2816,28 @@ void ROMAlyzer::on_pushButtonChecksumWizardSearch_clicked()
 					qApp->processEvents();
 				}
 				QString currentMachine(qmc2MainWindow->treeWidgetMachineList->topLevelItem(i)->text(QMC2_MACHINELIST_COLUMN_NAME));
-				QStringList xmlLines(qmc2MachineList->xmlDb()->xml(currentMachine).split('\n', QString::SkipEmptyParts));
-				for (int j = 0; j < xmlLines.count(); j++) {
-					QString xmlLine(xmlLines.at(j));
-					int hashIndex = xmlLine.indexOf(hashStartString);
-					if ( hashIndex >= 0 ) {
-						int hashPos = hashIndex + hashStartOffset;
-						QString currentChecksum(xmlLine.mid(hashPos, xmlLine.indexOf('\"', hashPos) - hashPos).toLower());
-						if ( currentChecksum.compare(searchedChecksum) == 0 ) {
-							int fileNamePos;
-							QString fileType;
-							if ( xmlLine.startsWith("<disk name=\"") ) {
-								fileType = tr("CHD");
-								fileNamePos = xmlLine.indexOf("<disk name=\"") + 12;
-							} else {
-								fileType = tr("ROM");
-								fileNamePos = xmlLine.indexOf("<rom name=\"") + 11;
-							}
-							QString fileName(xmlLine.mid(fileNamePos, xmlLine.indexOf('\"', fileNamePos) - fileNamePos));
-							QTreeWidgetItem *item = new QTreeWidgetItem(treeWidgetChecksumWizardSearchResult);
-							item->setText(QMC2_ROMALYZER_CSF_COLUMN_ID, currentMachine);
-							item->setText(QMC2_ROMALYZER_CSF_COLUMN_FILENAME, fileName.replace("&amp;", "&").replace("&lt;", "<").replace("&gt;", ">").replace("&quot;", "\"").replace("&apos;", "'"));
-							item->setText(QMC2_ROMALYZER_CSF_COLUMN_TYPE, fileType);
-							item->setText(QMC2_ROMALYZER_CSF_COLUMN_STATUS, tr("unknown"));
+				QXmlStreamReader xmlMachineEntry(qmc2MachineList->xmlDb()->xml(currentMachine));
+				if ( xmlMachineEntry.readNextStartElement() ) {
+					if ( xmlMachineEntry.name() == "machine" ) {
+						while ( xmlMachineEntry.readNextStartElement() ) {
+							if ( xmlMachineEntry.attributes().hasAttribute(hashAttribute) ) {
+								QString currentChecksum(xmlMachineEntry.attributes().value(hashAttribute).toString().toLower());
+								if ( currentChecksum.compare(searchedChecksum) == 0 ) {
+									QString fileType;
+									if ( xmlMachineEntry.name() == "disk" )
+										fileType = tr("CHD");
+									else
+										fileType = tr("ROM");
+									QString fileName(xmlMachineEntry.attributes().value("name").toString());
+									QTreeWidgetItem *item = new QTreeWidgetItem(treeWidgetChecksumWizardSearchResult);
+									item->setText(QMC2_ROMALYZER_CSF_COLUMN_ID, currentMachine);
+									item->setText(QMC2_ROMALYZER_CSF_COLUMN_FILENAME, fileName);
+									item->setText(QMC2_ROMALYZER_CSF_COLUMN_TYPE, fileType);
+									item->setText(QMC2_ROMALYZER_CSF_COLUMN_STATUS, tr("unknown"));
+								}
+								xmlMachineEntry.skipCurrentElement();
+							} else
+								xmlMachineEntry.skipCurrentElement();
 						}
 					}
 				}
diff --git a/src/softwarelist.cpp b/src/softwarelist.cpp
index 99f806da4..13c1f0f55 100644
--- a/src/softwarelist.cpp
+++ b/src/softwarelist.cpp
@@ -1012,6 +1012,7 @@ QString &SoftwareList::lookupMountDevice(QString device, QString deviceInterface
 	QStringList xmlLines(qmc2MachineList->xmlDb()->xml(systemName).split('\n', QString::SkipEmptyParts));
 	QStringList *xmlData = &xmlLines;
 	QStringList dynamicXmlData;
+	QXmlStreamReader xmlMachineEntry(qmc2MachineList->xmlDb()->xml(systemName));
 	if ( comboBoxDeviceConfiguration->currentIndex() > 0 ) {
 		qmc2Config->beginGroup(QMC2_EMULATOR_PREFIX + QString("Configuration/Devices/%1/%2").arg(systemName).arg(comboBoxDeviceConfiguration->currentText()));
 		QStringList instances(qmc2Config->value("Instances").toStringList());
@@ -1047,37 +1048,34 @@ QString &SoftwareList::lookupMountDevice(QString device, QString deviceInterface
 #endif
 	}
 
-	int i = 0;
-	while ( i < xmlData->count() && !xmlData->at(i).contains("</machine>") ) {
-		QString line(xmlData->at(i++).simplified());
-		if ( line.startsWith("<device type=\"") ) {
-			int startIndex = line.indexOf("interface=\"");
-			int endIndex = -1;
-			QString devName;
-			if ( startIndex >= 0 ) {
-				startIndex += 11;
-				endIndex = line.indexOf("\"", startIndex);
-				QStringList devInterfaces(line.mid(startIndex, endIndex - startIndex).split(',', QString::SkipEmptyParts));
-				line = xmlData->at(i++).simplified();
-				startIndex = line.indexOf("briefname=\"");
-				if ( startIndex >= 0 ) {
-					startIndex += 11;
-					endIndex = line.indexOf("\"", startIndex);
-					devName = line.mid(startIndex, endIndex - startIndex);
-				}
-				if ( !devName.isEmpty() )
-					foreach (QString devIf, devInterfaces)
-						deviceInstanceHash[devIf] << devName;
-			} else {
-				line = xmlData->at(i++).simplified();
-				startIndex = line.indexOf("briefname=\"");
-				if ( startIndex >= 0 ) {
-					startIndex += 11;
-					endIndex = line.indexOf("\"", startIndex);
-					devName = line.mid(startIndex, endIndex - startIndex);
-				}
-				if ( !devName.isEmpty() )
-					deviceInstanceHash[devName] << devName;
+	if ( xmlMachineEntry.readNextStartElement() ) {
+		if ( xmlMachineEntry.name() == "machine" ) {
+			while ( xmlMachineEntry.readNextStartElement() ) {
+				if ( xmlMachineEntry.name() == "device" && xmlMachineEntry.attributes().hasAttribute("type") ) {
+					QString devName;
+					if ( xmlMachineEntry.attributes().hasAttribute("interface") ) {
+						QStringList devInterfaces(xmlMachineEntry.attributes().value("interface").toString().split(',', QString::SkipEmptyParts));
+						while ( xmlMachineEntry.readNextStartElement() ) {
+							if ( xmlMachineEntry.name() == "instance" && xmlMachineEntry.attributes().hasAttribute("briefname") ) {
+								devName = xmlMachineEntry.attributes().value("briefname").toString();
+								if ( !devName.isEmpty() )
+									foreach (QString devIf, devInterfaces)
+										deviceInstanceHash[devIf] << devName;
+							}
+							xmlMachineEntry.skipCurrentElement();
+						}
+					} else {
+						while ( xmlMachineEntry.readNextStartElement() ) {
+							if ( xmlMachineEntry.name() == "instance" && xmlMachineEntry.attributes().hasAttribute("briefname") ) {
+								devName = xmlMachineEntry.attributes().value("briefname").toString();
+								if ( !devName.isEmpty() )
+									deviceInstanceHash[devName] << devName;
+							}
+							xmlMachineEntry.skipCurrentElement();
+						}
+					}
+				} else
+					xmlMachineEntry.skipCurrentElement();
 			}
 		}
 	}
-- 
2.44.0