summaryrefslogtreecommitdiff
path: root/src/VBox/Main/xml/Settings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/xml/Settings.cpp')
-rw-r--r--src/VBox/Main/xml/Settings.cpp933
1 files changed, 744 insertions, 189 deletions
diff --git a/src/VBox/Main/xml/Settings.cpp b/src/VBox/Main/xml/Settings.cpp
index 8cb1e126..3520c9c7 100644
--- a/src/VBox/Main/xml/Settings.cpp
+++ b/src/VBox/Main/xml/Settings.cpp
@@ -54,7 +54,7 @@
*/
/*
- * Copyright (C) 2007-2012 Oracle Corporation
+ * Copyright (C) 2007-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -327,7 +327,9 @@ ConfigFileBase::ConfigFileBase(const com::Utf8Str *pstrFilename)
m->sv = SettingsVersion_v1_12;
else if (ulMinor == 13)
m->sv = SettingsVersion_v1_13;
- else if (ulMinor > 13)
+ else if (ulMinor == 14)
+ m->sv = SettingsVersion_v1_14;
+ else if (ulMinor > 14)
m->sv = SettingsVersion_Future;
}
else if (ulMajor > 1)
@@ -382,7 +384,9 @@ void ConfigFileBase::parseUUID(Guid &guid,
const Utf8Str &strUUID) const
{
guid = strUUID.c_str();
- if (guid.isEmpty())
+ if (guid.isZero())
+ throw ConfigFileError(this, NULL, N_("UUID \"%s\" has zero format"), strUUID.c_str());
+ else if (!guid.isValid())
throw ConfigFileError(this, NULL, N_("UUID \"%s\" has invalid format"), strUUID.c_str());
}
@@ -488,9 +492,8 @@ void ConfigFileBase::readExtraData(const xml::ElementNode &elmExtraData,
{
// <ExtraDataItem name="GUI/LastWindowPostion" value="97,88,981,858"/>
Utf8Str strName, strValue;
- if ( ((pelmExtraDataItem->getAttributeValue("name", strName)))
- && ((pelmExtraDataItem->getAttributeValue("value", strValue)))
- )
+ if ( pelmExtraDataItem->getAttributeValue("name", strName)
+ && pelmExtraDataItem->getAttributeValue("value", strValue) )
map[strName] = strValue;
else
throw ConfigFileError(this, pelmExtraDataItem, N_("Required ExtraDataItem/@name or @value attribute is missing"));
@@ -516,9 +519,8 @@ void ConfigFileBase::readUSBDeviceFilters(const xml::ElementNode &elmDeviceFilte
USBDeviceFilter flt;
flt.action = USBDeviceFilterAction_Ignore;
Utf8Str strAction;
- if ( (pelmLevel4Child->getAttributeValue("name", flt.strName))
- && (pelmLevel4Child->getAttributeValue("active", flt.fActive))
- )
+ if ( pelmLevel4Child->getAttributeValue("name", flt.strName)
+ && pelmLevel4Child->getAttributeValue("active", flt.fActive))
{
if (!pelmLevel4Child->getAttributeValue("vendorId", flt.strVendorId))
pelmLevel4Child->getAttributeValue("vendorid", flt.strVendorId); // used before 1.3
@@ -571,7 +573,7 @@ void ConfigFileBase::readMedium(MediaType t,
// <HardDisk uuid="{5471ecdb-1ddb-4012-a801-6d98e226868b}" location="/mnt/innotek-unix/vdis/Windows XP.vdi" format="VDI" type="Normal">
settings::Medium med;
Utf8Str strUUID;
- if (!(elmMedium.getAttributeValue("uuid", strUUID)))
+ if (!elmMedium.getAttributeValue("uuid", strUUID))
throw ConfigFileError(this, &elmMedium, N_("Required %s/@uuid attribute is missing"), elmMedium.getName());
parseUUID(med.uuid, strUUID);
@@ -664,14 +666,14 @@ void ConfigFileBase::readMedium(MediaType t,
}
if (med.strFormat.isEmpty()) // not set with 1.4 format above, or 1.4 Custom format?
- if (!(elmMedium.getAttributeValue("format", med.strFormat)))
+ if (!elmMedium.getAttributeValue("format", med.strFormat))
throw ConfigFileError(this, &elmMedium, N_("Required %s/@format attribute is missing"), elmMedium.getName());
- if (!(elmMedium.getAttributeValue("autoReset", med.fAutoReset)))
+ if (!elmMedium.getAttributeValue("autoReset", med.fAutoReset))
med.fAutoReset = false;
Utf8Str strType;
- if ((elmMedium.getAttributeValue("type", strType)))
+ if (elmMedium.getAttributeValue("type", strType))
{
// pre-1.4 used lower case, so make this case-insensitive
strType.toUpper();
@@ -696,13 +698,13 @@ void ConfigFileBase::readMedium(MediaType t,
if (m->sv < SettingsVersion_v1_4)
{
// DVD and floppy images before 1.4 had "src" attribute instead of "location"
- if (!(elmMedium.getAttributeValue("src", med.strLocation)))
+ if (!elmMedium.getAttributeValue("src", med.strLocation))
throw ConfigFileError(this, &elmMedium, N_("Required %s/@src attribute is missing"), elmMedium.getName());
fNeedsLocation = false;
}
- if (!(elmMedium.getAttributeValue("format", med.strFormat)))
+ if (!elmMedium.getAttributeValue("format", med.strFormat))
{
// DVD and floppy images before 1.11 had no format attribute. assign the default.
med.strFormat = "RAW";
@@ -716,7 +718,7 @@ void ConfigFileBase::readMedium(MediaType t,
if (fNeedsLocation)
// current files and 1.4 CustomHardDisk elements must have a location attribute
- if (!(elmMedium.getAttributeValue("location", med.strLocation)))
+ if (!elmMedium.getAttributeValue("location", med.strLocation))
throw ConfigFileError(this, &elmMedium, N_("Required %s/@location attribute is missing"), elmMedium.getName());
elmMedium.getAttributeValue("Description", med.strDescription); // optional
@@ -740,9 +742,8 @@ void ConfigFileBase::readMedium(MediaType t,
else if (pelmHDChild->nameEquals("Property"))
{
Utf8Str strPropName, strPropValue;
- if ( (pelmHDChild->getAttributeValue("name", strPropName))
- && (pelmHDChild->getAttributeValue("value", strPropValue))
- )
+ if ( pelmHDChild->getAttributeValue("name", strPropName)
+ && pelmHDChild->getAttributeValue("value", strPropValue) )
med.properties[strPropName] = strPropValue;
else
throw ConfigFileError(this, pelmHDChild, N_("Required HardDisk/Property/@name or @value attribute is missing"));
@@ -807,6 +808,47 @@ void ConfigFileBase::readMediaRegistry(const xml::ElementNode &elmMediaRegistry,
}
/**
+ * This is common version for reading NAT port forward rule in per-_machine's_adapter_ and
+ * per-network approaches.
+ * Note: this function doesn't in fill given list from xml::ElementNodesList, because there is conflicting
+ * declaration in ovmfreader.h.
+ */
+void ConfigFileBase::readNATForwardRuleList(const xml::ElementNode &elmParent, NATRuleList &llRules)
+{
+ xml::ElementNodesList plstRules;
+ elmParent.getChildElements(plstRules, "Forwarding");
+ for (xml::ElementNodesList::iterator pf = plstRules.begin(); pf != plstRules.end(); ++pf)
+ {
+ NATRule rule;
+ uint32_t port = 0;
+ (*pf)->getAttributeValue("name", rule.strName);
+ (*pf)->getAttributeValue("proto", (uint32_t&)rule.proto);
+ (*pf)->getAttributeValue("hostip", rule.strHostIP);
+ (*pf)->getAttributeValue("hostport", port);
+ rule.u16HostPort = port;
+ (*pf)->getAttributeValue("guestip", rule.strGuestIP);
+ (*pf)->getAttributeValue("guestport", port);
+ rule.u16GuestPort = port;
+ llRules.push_back(rule);
+ }
+}
+
+void ConfigFileBase::readNATLoopbacks(const xml::ElementNode &elmParent, NATLoopbackOffsetList &llLoopbacks)
+{
+ xml::ElementNodesList plstLoopbacks;
+ elmParent.getChildElements(plstLoopbacks, "Loopback4");
+ for (xml::ElementNodesList::iterator lo = plstLoopbacks.begin();
+ lo != plstLoopbacks.end(); ++lo)
+ {
+ NATHostLoopbackOffset loopback;
+ (*lo)->getAttributeValue("address", loopback.strLoopbackHostAddress);
+ (*lo)->getAttributeValue("offset", (uint32_t&)loopback.u32Offset);
+ llLoopbacks.push_back(loopback);
+ }
+}
+
+
+/**
* Adds a "version" attribute to the given XML element with the
* VirtualBox settings version (e.g. "1.10-linux"). Used by
* the XML format for the root element and by the OVF export
@@ -842,11 +884,15 @@ void ConfigFileBase::setVersionAttribute(xml::ElementNode &elm)
pcszVersion = "1.13";
break;
+ case SettingsVersion_v1_14:
+ pcszVersion = "1.14";
+ break;
+
case SettingsVersion_Future:
// can be set if this code runs on XML files that were created by a future version of VBox;
// in that case, downgrade to current version when writing since we can't write future versions...
- pcszVersion = "1.13";
- m->sv = SettingsVersion_v1_13;
+ pcszVersion = "1.14";
+ m->sv = SettingsVersion_v1_14;
break;
default:
@@ -1132,6 +1178,45 @@ void ConfigFileBase::buildMediaRegistry(xml::ElementNode &elmParent,
}
/**
+ * Serialize NAT port-forwarding rules in parent container.
+ * Note: it's responsibility of caller to create parent of the list tag.
+ * because this method used for serializing per-_mahine's_adapter_ and per-network approaches.
+ */
+void ConfigFileBase::buildNATForwardRuleList(xml::ElementNode &elmParent, const NATRuleList &natRuleList)
+{
+ for (NATRuleList::const_iterator r = natRuleList.begin();
+ r != natRuleList.end(); ++r)
+ {
+ xml::ElementNode *pelmPF;
+ pelmPF = elmParent.createChild("Forwarding");
+ if ((*r).strName.length())
+ pelmPF->setAttribute("name", (*r).strName);
+ pelmPF->setAttribute("proto", (*r).proto);
+ if ((*r).strHostIP.length())
+ pelmPF->setAttribute("hostip", (*r).strHostIP);
+ if ((*r).u16HostPort)
+ pelmPF->setAttribute("hostport", (*r).u16HostPort);
+ if ((*r).strGuestIP.length())
+ pelmPF->setAttribute("guestip", (*r).strGuestIP);
+ if ((*r).u16GuestPort)
+ pelmPF->setAttribute("guestport", (*r).u16GuestPort);
+ }
+}
+
+
+void ConfigFileBase::buildNATLoopbacks(xml::ElementNode &elmParent, const NATLoopbackOffsetList &natLoopbackOffsetList)
+{
+ for (NATLoopbackOffsetList::const_iterator lo = natLoopbackOffsetList.begin();
+ lo != natLoopbackOffsetList.end(); ++lo)
+ {
+ xml::ElementNode *pelmLo;
+ pelmLo = elmParent.createChild("Loopback4");
+ pelmLo->setAttribute("address", (*lo).strLoopbackHostAddress);
+ pelmLo->setAttribute("offset", (*lo).u32Offset);
+ }
+}
+
+/**
* Cleans up memory allocated by the internal XML parser. To be called by
* descendant classes when they're done analyzing the DOM tree to discard it.
*/
@@ -1213,9 +1298,8 @@ void MainConfigFile::readMachineRegistry(const xml::ElementNode &elmMachineRegis
{
MachineRegistryEntry mre;
Utf8Str strUUID;
- if ( ((pelmChild1->getAttributeValue("uuid", strUUID)))
- && ((pelmChild1->getAttributeValue("src", mre.strSettingsFile)))
- )
+ if ( pelmChild1->getAttributeValue("uuid", strUUID)
+ && pelmChild1->getAttributeValue("src", mre.strSettingsFile) )
{
parseUUID(mre.uuid, strUUID);
llMachines.push_back(mre);
@@ -1239,20 +1323,104 @@ void MainConfigFile::readDHCPServers(const xml::ElementNode &elmDHCPServers)
if (pelmServer->nameEquals("DHCPServer"))
{
DHCPServer srv;
- if ( (pelmServer->getAttributeValue("networkName", srv.strNetworkName))
- && (pelmServer->getAttributeValue("IPAddress", srv.strIPAddress))
- && (pelmServer->getAttributeValue("networkMask", srv.strIPNetworkMask))
- && (pelmServer->getAttributeValue("lowerIP", srv.strIPLower))
- && (pelmServer->getAttributeValue("upperIP", srv.strIPUpper))
- && (pelmServer->getAttributeValue("enabled", srv.fEnabled))
- )
+ if ( pelmServer->getAttributeValue("networkName", srv.strNetworkName)
+ && pelmServer->getAttributeValue("IPAddress", srv.strIPAddress)
+ && pelmServer->getAttributeValue("networkMask", srv.GlobalDhcpOptions[DhcpOpt_SubnetMask])
+ && pelmServer->getAttributeValue("lowerIP", srv.strIPLower)
+ && pelmServer->getAttributeValue("upperIP", srv.strIPUpper)
+ && pelmServer->getAttributeValue("enabled", srv.fEnabled) )
+ {
+ xml::NodesLoop nlOptions(*pelmServer, "Options");
+ const xml::ElementNode *options;
+ /* XXX: Options are in 1:1 relation to DHCPServer */
+
+ while ((options = nlOptions.forAllNodes()))
+ {
+ readDhcpOptions(srv.GlobalDhcpOptions, *options);
+ } /* end of forall("Options") */
+ xml::NodesLoop nlConfig(*pelmServer, "Config");
+ const xml::ElementNode *cfg;
+ while ((cfg = nlConfig.forAllNodes()))
+ {
+ com::Utf8Str strVmName;
+ uint32_t u32Slot;
+ cfg->getAttributeValue("vm-name", strVmName);
+ cfg->getAttributeValue("slot", u32Slot);
+ readDhcpOptions(srv.VmSlot2OptionsM[VmNameSlotKey(strVmName, u32Slot)], *cfg);
+ }
llDhcpServers.push_back(srv);
+ }
else
throw ConfigFileError(this, pelmServer, N_("Required DHCPServer/@networkName, @IPAddress, @networkMask, @lowerIP, @upperIP or @enabled attribute is missing"));
}
}
}
+void MainConfigFile::readDhcpOptions(DhcpOptionMap& map,
+ const xml::ElementNode& options)
+{
+ xml::NodesLoop nl2(options, "Option");
+ const xml::ElementNode *opt;
+ while ((opt = nl2.forAllNodes()))
+ {
+ DhcpOpt_T OptName;
+ com::Utf8Str OptValue;
+ opt->getAttributeValue("name", (uint32_t&)OptName);
+
+ if (OptName == DhcpOpt_SubnetMask)
+ continue;
+
+ opt->getAttributeValue("value", OptValue);
+
+ map.insert(std::map<DhcpOpt_T, Utf8Str>::value_type(OptName, OptValue));
+ } /* end of forall("Option") */
+
+}
+
+/**
+ * Reads in the <NATNetworks> chunk.
+ * @param elmNATNetworks
+ */
+void MainConfigFile::readNATNetworks(const xml::ElementNode &elmNATNetworks)
+{
+ xml::NodesLoop nl1(elmNATNetworks);
+ const xml::ElementNode *pelmNet;
+ while ((pelmNet = nl1.forAllNodes()))
+ {
+ if (pelmNet->nameEquals("NATNetwork"))
+ {
+ NATNetwork net;
+ if ( pelmNet->getAttributeValue("networkName", net.strNetworkName)
+ && pelmNet->getAttributeValue("enabled", net.fEnabled)
+ && pelmNet->getAttributeValue("network", net.strNetwork)
+ && pelmNet->getAttributeValue("ipv6", net.fIPv6)
+ && pelmNet->getAttributeValue("ipv6prefix", net.strIPv6Prefix)
+ && pelmNet->getAttributeValue("advertiseDefaultIPv6Route", net.fAdvertiseDefaultIPv6Route)
+ && pelmNet->getAttributeValue("needDhcp", net.fNeedDhcpServer) )
+ {
+ pelmNet->getAttributeValue("loopback6", net.u32HostLoopback6Offset);
+ const xml::ElementNode *pelmMappings;
+ if ((pelmMappings = pelmNet->findChildElement("Mappings")))
+ readNATLoopbacks(*pelmMappings, net.llHostLoopbackOffsetList);
+
+ const xml::ElementNode *pelmPortForwardRules4;
+ if ((pelmPortForwardRules4 = pelmNet->findChildElement("PortForwarding4")))
+ readNATForwardRuleList(*pelmPortForwardRules4,
+ net.llPortForwardRules4);
+
+ const xml::ElementNode *pelmPortForwardRules6;
+ if ((pelmPortForwardRules6 = pelmNet->findChildElement("PortForwarding6")))
+ readNATForwardRuleList(*pelmPortForwardRules6,
+ net.llPortForwardRules6);
+
+ llNATNetworks.push_back(net);
+ }
+ else
+ throw ConfigFileError(this, pelmNet, N_("Required NATNetwork/@networkName, @gateway, @network,@advertiseDefaultIpv6Route , @needDhcp or @enabled attribute is missing"));
+ }
+ }
+}
+
/**
* Constructor.
*
@@ -1286,6 +1454,7 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename)
if (pelmGlobalChild->nameEquals("SystemProperties"))
{
pelmGlobalChild->getAttributeValue("defaultMachineFolder", systemProperties.strDefaultMachineFolder);
+ pelmGlobalChild->getAttributeValue("LoggingLevel", systemProperties.strLoggingLevel);
pelmGlobalChild->getAttributeValue("defaultHardDiskFormat", systemProperties.strDefaultHardDiskFormat);
if (!pelmGlobalChild->getAttributeValue("VRDEAuthLibrary", systemProperties.strVRDEAuthLibrary))
// pre-1.11 used @remoteDisplayAuthLibrary instead
@@ -1294,6 +1463,8 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename)
pelmGlobalChild->getAttributeValue("defaultVRDEExtPack", systemProperties.strDefaultVRDEExtPack);
pelmGlobalChild->getAttributeValue("LogHistoryCount", systemProperties.ulLogHistoryCount);
pelmGlobalChild->getAttributeValue("autostartDatabasePath", systemProperties.strAutostartDatabasePath);
+ pelmGlobalChild->getAttributeValue("defaultFrontend", systemProperties.strDefaultFrontend);
+ pelmGlobalChild->getAttributeValue("exclusiveHwVirt", systemProperties.fExclusiveHwVirt);
}
else if (pelmGlobalChild->nameEquals("ExtraData"))
readExtraData(*pelmGlobalChild, mapExtraDataItems);
@@ -1313,6 +1484,8 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename)
{
if (pelmLevel4Child->nameEquals("DHCPServers"))
readDHCPServers(*pelmLevel4Child);
+ if (pelmLevel4Child->nameEquals("NATNetworks"))
+ readNATNetworks(*pelmLevel4Child);
}
}
else if (pelmGlobalChild->nameEquals("USBDeviceFilters"))
@@ -1341,7 +1514,7 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename)
"HostInterfaceNetworking-vboxnet0";
#endif
srv.strIPAddress = "192.168.56.100";
- srv.strIPNetworkMask = "255.255.255.0";
+ srv.GlobalDhcpOptions[DhcpOpt_SubnetMask] = "255.255.255.0";
srv.strIPLower = "192.168.56.101";
srv.strIPUpper = "192.168.56.254";
srv.fEnabled = true;
@@ -1349,12 +1522,25 @@ MainConfigFile::MainConfigFile(const Utf8Str *pstrFilename)
}
}
+void MainConfigFile::bumpSettingsVersionIfNeeded()
+{
+ if (m->sv < SettingsVersion_v1_14)
+ {
+ // VirtualBox 4.3 adds NAT networks.
+ if ( !llNATNetworks.empty())
+ m->sv = SettingsVersion_v1_14;
+ }
+}
+
+
/**
* Called from the IVirtualBox interface to write out VirtualBox.xml. This
* builds an XML DOM tree and writes it out to disk.
*/
void MainConfigFile::write(const com::Utf8Str strFilename)
{
+ bumpSettingsVersionIfNeeded();
+
m->strFilename = strFilename;
createStubDocument();
@@ -1384,17 +1570,110 @@ void MainConfigFile::write(const com::Utf8Str strFilename)
{
const DHCPServer &d = *it;
xml::ElementNode *pelmThis = pelmDHCPServers->createChild("DHCPServer");
+ DhcpOptConstIterator itOpt;
+ itOpt = d.GlobalDhcpOptions.find(DhcpOpt_SubnetMask);
+
pelmThis->setAttribute("networkName", d.strNetworkName);
pelmThis->setAttribute("IPAddress", d.strIPAddress);
- pelmThis->setAttribute("networkMask", d.strIPNetworkMask);
+ if (itOpt != d.GlobalDhcpOptions.end())
+ pelmThis->setAttribute("networkMask", itOpt->second);
pelmThis->setAttribute("lowerIP", d.strIPLower);
pelmThis->setAttribute("upperIP", d.strIPUpper);
pelmThis->setAttribute("enabled", (d.fEnabled) ? 1 : 0); // too bad we chose 1 vs. 0 here
+ /* We assume that if there're only 1 element it means that */
+ int cOpt = d.GlobalDhcpOptions.size();
+ /* We don't want duplicate validation check of networkMask here*/
+ if ( ( itOpt == d.GlobalDhcpOptions.end()
+ && cOpt > 0)
+ || cOpt > 1)
+ {
+ xml::ElementNode *pelmOptions = pelmThis->createChild("Options");
+ for (itOpt = d.GlobalDhcpOptions.begin();
+ itOpt != d.GlobalDhcpOptions.end();
+ ++itOpt)
+ {
+ if (itOpt->first == DhcpOpt_SubnetMask)
+ continue;
+
+ xml::ElementNode *pelmOpt = pelmOptions->createChild("Option");
+
+ if (!pelmOpt)
+ break;
+
+ pelmOpt->setAttribute("name", itOpt->first);
+ pelmOpt->setAttribute("value", itOpt->second);
+ }
+ } /* end of if */
+
+ if (d.VmSlot2OptionsM.size() > 0)
+ {
+ VmSlot2OptionsConstIterator itVmSlot;
+ DhcpOptConstIterator itOpt1;
+ for(itVmSlot = d.VmSlot2OptionsM.begin();
+ itVmSlot != d.VmSlot2OptionsM.end();
+ ++itVmSlot)
+ {
+ xml::ElementNode *pelmCfg = pelmThis->createChild("Config");
+ pelmCfg->setAttribute("vm-name", itVmSlot->first.VmName);
+ pelmCfg->setAttribute("slot", itVmSlot->first.Slot);
+
+ for (itOpt1 = itVmSlot->second.begin();
+ itOpt1 != itVmSlot->second.end();
+ ++itOpt1)
+ {
+ xml::ElementNode *pelmOpt = pelmCfg->createChild("Option");
+ pelmOpt->setAttribute("name", itOpt1->first);
+ pelmOpt->setAttribute("value", itOpt1->second);
+ }
+ }
+ } /* and of if */
+
+ }
+
+ xml::ElementNode *pelmNATNetworks;
+ /* don't create entry if no NAT networks are registered. */
+ if (!llNATNetworks.empty())
+ {
+ pelmNATNetworks = pelmNetserviceRegistry->createChild("NATNetworks");
+ for (NATNetworksList::const_iterator it = llNATNetworks.begin();
+ it != llNATNetworks.end();
+ ++it)
+ {
+ const NATNetwork &n = *it;
+ xml::ElementNode *pelmThis = pelmNATNetworks->createChild("NATNetwork");
+ pelmThis->setAttribute("networkName", n.strNetworkName);
+ pelmThis->setAttribute("network", n.strNetwork);
+ pelmThis->setAttribute("ipv6", n.fIPv6 ? 1 : 0);
+ pelmThis->setAttribute("ipv6prefix", n.strIPv6Prefix);
+ pelmThis->setAttribute("advertiseDefaultIPv6Route", (n.fAdvertiseDefaultIPv6Route)? 1 : 0);
+ pelmThis->setAttribute("needDhcp", (n.fNeedDhcpServer) ? 1 : 0);
+ pelmThis->setAttribute("enabled", (n.fEnabled) ? 1 : 0); // too bad we chose 1 vs. 0 here
+ if (n.llPortForwardRules4.size())
+ {
+ xml::ElementNode *pelmPf4 = pelmThis->createChild("PortForwarding4");
+ buildNATForwardRuleList(*pelmPf4, n.llPortForwardRules4);
+ }
+ if (n.llPortForwardRules6.size())
+ {
+ xml::ElementNode *pelmPf6 = pelmThis->createChild("PortForwarding6");
+ buildNATForwardRuleList(*pelmPf6, n.llPortForwardRules6);
+ }
+
+ if (n.llHostLoopbackOffsetList.size())
+ {
+ xml::ElementNode *pelmMappings = pelmThis->createChild("Mappings");
+ buildNATLoopbacks(*pelmMappings, n.llHostLoopbackOffsetList);
+
+ }
+ }
}
+
xml::ElementNode *pelmSysProps = pelmGlobal->createChild("SystemProperties");
if (systemProperties.strDefaultMachineFolder.length())
pelmSysProps->setAttribute("defaultMachineFolder", systemProperties.strDefaultMachineFolder);
+ if (systemProperties.strLoggingLevel.length())
+ pelmSysProps->setAttribute("LoggingLevel", systemProperties.strLoggingLevel);
if (systemProperties.strDefaultHardDiskFormat.length())
pelmSysProps->setAttribute("defaultHardDiskFormat", systemProperties.strDefaultHardDiskFormat);
if (systemProperties.strVRDEAuthLibrary.length())
@@ -1406,6 +1685,9 @@ void MainConfigFile::write(const com::Utf8Str strFilename)
pelmSysProps->setAttribute("LogHistoryCount", systemProperties.ulLogHistoryCount);
if (systemProperties.strAutostartDatabasePath.length())
pelmSysProps->setAttribute("autostartDatabasePath", systemProperties.strAutostartDatabasePath);
+ if (systemProperties.strDefaultFrontend.length())
+ pelmSysProps->setAttribute("defaultFrontend", systemProperties.strDefaultFrontend);
+ pelmSysProps->setAttribute("exclusiveHwVirt", systemProperties.fExclusiveHwVirt);
buildUSBDeviceFilters(*pelmGlobal->createChild("USBDeviceFilters"),
host.llUSBDeviceFilters,
@@ -1474,9 +1756,22 @@ bool BIOSSettings::operator==(const BIOSSettings &d) const
bool USBController::operator==(const USBController &u) const
{
return ( (this == &u)
- || ( (fEnabled == u.fEnabled)
- && (fEnabledEHCI == u.fEnabledEHCI)
- && (llDeviceFilters == u.llDeviceFilters)
+ || ( (strName == u.strName)
+ && (enmType == u.enmType)
+ )
+ );
+}
+
+/**
+ * Comparison operator. This gets called from MachineConfigFile::operator==,
+ * which in turn gets called from Machine::saveSettings to figure out whether
+ * machine settings have really changed and thus need to be written out to disk.
+ */
+bool USB::operator==(const USB &u) const
+{
+ return ( (this == &u)
+ || ( (llUSBControllers == u.llUSBControllers)
+ && (llDeviceFilters == u.llDeviceFilters)
)
);
}
@@ -1579,37 +1874,34 @@ bool GuestProperty::operator==(const GuestProperty &g) const
);
}
-// use a define for the platform-dependent default value of
-// hwvirt exclusivity, since we'll need to check that value
-// in bumpSettingsVersionIfNeeded()
-#if defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
- #define HWVIRTEXCLUSIVEDEFAULT false
-#else
- #define HWVIRTEXCLUSIVEDEFAULT true
-#endif
-
Hardware::Hardware()
: strVersion("1"),
fHardwareVirt(true),
- fHardwareVirtExclusive(HWVIRTEXCLUSIVEDEFAULT),
fNestedPaging(true),
fVPID(true),
+ fUnrestrictedExecution(true),
fHardwareVirtForce(false),
fSyntheticCpu(false),
+ fTripleFaultReset(false),
fPAE(false),
+ enmLongMode(HC_ARCH_BITS == 64 ? Hardware::LongMode_Enabled : Hardware::LongMode_Disabled),
cCPUs(1),
fCpuHotPlug(false),
fHPETEnabled(false),
ulCpuExecutionCap(100),
ulMemorySizeMB((uint32_t)-1),
+ graphicsControllerType(GraphicsControllerType_VBoxVGA),
ulVRAMSizeMB(8),
cMonitors(1),
fAccelerate3D(false),
fAccelerate2DVideo(false),
- ulVideoCaptureHorzRes(640),
- ulVideoCaptureVertRes(480),
+ ulVideoCaptureHorzRes(1024),
+ ulVideoCaptureVertRes(768),
+ ulVideoCaptureRate(512),
+ ulVideoCaptureFPS(25),
fVideoCaptureEnabled(false),
- strVideoCaptureFile("Test.webm"),
+ u64VideoCaptureScreens(UINT64_C(0xffffffffffffffff)),
+ strVideoCaptureFile(""),
firmwareType(FirmwareType_BIOS),
pointingHIDType(PointingHIDType_PS2Mouse),
keyboardHIDType(KeyboardHIDType_PS2Keyboard),
@@ -1655,13 +1947,15 @@ bool Hardware::operator==(const Hardware& h) const
|| ( (strVersion == h.strVersion)
&& (uuid == h.uuid)
&& (fHardwareVirt == h.fHardwareVirt)
- && (fHardwareVirtExclusive == h.fHardwareVirtExclusive)
&& (fNestedPaging == h.fNestedPaging)
&& (fLargePages == h.fLargePages)
&& (fVPID == h.fVPID)
+ && (fUnrestrictedExecution == h.fUnrestrictedExecution)
&& (fHardwareVirtForce == h.fHardwareVirtForce)
&& (fSyntheticCpu == h.fSyntheticCpu)
&& (fPAE == h.fPAE)
+ && (enmLongMode == h.enmLongMode)
+ && (fTripleFaultReset == h.fTripleFaultReset)
&& (cCPUs == h.cCPUs)
&& (fCpuHotPlug == h.fCpuHotPlug)
&& (ulCpuExecutionCap == h.ulCpuExecutionCap)
@@ -1670,14 +1964,18 @@ bool Hardware::operator==(const Hardware& h) const
&& (llCpuIdLeafs == h.llCpuIdLeafs)
&& (ulMemorySizeMB == h.ulMemorySizeMB)
&& (mapBootOrder == h.mapBootOrder)
+ && (graphicsControllerType == h.graphicsControllerType)
&& (ulVRAMSizeMB == h.ulVRAMSizeMB)
&& (cMonitors == h.cMonitors)
&& (fAccelerate3D == h.fAccelerate3D)
&& (fAccelerate2DVideo == h.fAccelerate2DVideo)
&& (fVideoCaptureEnabled == h.fVideoCaptureEnabled)
+ && (u64VideoCaptureScreens == h.u64VideoCaptureScreens)
&& (strVideoCaptureFile == h.strVideoCaptureFile)
&& (ulVideoCaptureHorzRes == h.ulVideoCaptureHorzRes)
&& (ulVideoCaptureVertRes == h.ulVideoCaptureVertRes)
+ && (ulVideoCaptureRate == h.ulVideoCaptureRate)
+ && (ulVideoCaptureFPS == h.ulVideoCaptureFPS)
&& (firmwareType == h.firmwareType)
&& (pointingHIDType == h.pointingHIDType)
&& (keyboardHIDType == h.keyboardHIDType)
@@ -1685,7 +1983,7 @@ bool Hardware::operator==(const Hardware& h) const
&& (fEmulatedUSBCardReader == h.fEmulatedUSBCardReader)
&& (vrdeSettings == h.vrdeSettings)
&& (biosSettings == h.biosSettings)
- && (usbController == h.usbController)
+ && (usbSettings == h.usbSettings)
&& (llNetworkAdapters == h.llNetworkAdapters)
&& (llSerialPorts == h.llSerialPorts)
&& (llParallelPorts == h.llParallelPorts)
@@ -1699,6 +1997,7 @@ bool Hardware::operator==(const Hardware& h) const
&& (strNotificationPatterns == h.strNotificationPatterns)
&& (ioSettings == h.ioSettings)
&& (pciAttachments == h.pciAttachments)
+ && (strDefaultFrontend == h.strDefaultFrontend)
)
);
}
@@ -1716,6 +2015,7 @@ bool AttachedDevice::operator==(const AttachedDevice &a) const
&& (fTempEject == a.fTempEject)
&& (fNonRotational == a.fNonRotational)
&& (fDiscard == a.fDiscard)
+ && (fHotPluggable == a.fHotPluggable)
&& (lPort == a.lPort)
&& (lDevice == a.lDevice)
&& (uuid == a.uuid)
@@ -2069,25 +2369,11 @@ void MachineConfigFile::readAttachedNetworkMode(const xml::ElementNode &elmMode,
pelmTFTP->getAttributeValue("boot-file", nic.nat.strTFTPBootFile);
pelmTFTP->getAttributeValue("next-server", nic.nat.strTFTPNextServer);
}
- xml::ElementNodesList plstNatPF;
- elmMode.getChildElements(plstNatPF, "Forwarding");
- for (xml::ElementNodesList::iterator pf = plstNatPF.begin(); pf != plstNatPF.end(); ++pf)
- {
- NATRule rule;
- uint32_t port = 0;
- (*pf)->getAttributeValue("name", rule.strName);
- (*pf)->getAttributeValue("proto", (uint32_t&)rule.proto);
- (*pf)->getAttributeValue("hostip", rule.strHostIP);
- (*pf)->getAttributeValue("hostport", port);
- rule.u16HostPort = port;
- (*pf)->getAttributeValue("guestip", rule.strGuestIP);
- (*pf)->getAttributeValue("guestport", port);
- rule.u16GuestPort = port;
- nic.nat.llRules.push_back(rule);
- }
+
+ readNATForwardRuleList(elmMode, nic.nat.llRules);
}
- else if ( (elmMode.nameEquals("HostInterface"))
- || (elmMode.nameEquals("BridgedInterface")))
+ else if ( elmMode.nameEquals("HostInterface")
+ || elmMode.nameEquals("BridgedInterface"))
{
enmAttachmentType = NetworkAttachmentType_Bridged;
@@ -2121,15 +2407,21 @@ void MachineConfigFile::readAttachedNetworkMode(const xml::ElementNode &elmMode,
if (pelmModeChild->nameEquals("Property"))
{
Utf8Str strPropName, strPropValue;
- if ( (pelmModeChild->getAttributeValue("name", strPropName))
- && (pelmModeChild->getAttributeValue("value", strPropValue))
- )
+ if ( pelmModeChild->getAttributeValue("name", strPropName)
+ && pelmModeChild->getAttributeValue("value", strPropValue) )
nic.genericProperties[strPropName] = strPropValue;
else
throw ConfigFileError(this, pelmModeChild, N_("Required GenericInterface/Property/@name or @value attribute is missing"));
}
}
}
+ else if (elmMode.nameEquals("NATNetwork"))
+ {
+ enmAttachmentType = NetworkAttachmentType_NATNetwork;
+
+ if (!elmMode.getAttributeValue("name", nic.strNATNetworkName)) // required network name
+ throw ConfigFileError(this, &elmMode, N_("Required NATNetwork/@name element is missing"));
+ }
else if (elmMode.nameEquals("VDE"))
{
enmAttachmentType = NetworkAttachmentType_Generic;
@@ -2391,7 +2683,6 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtEx")))
{
pelmCPUChild->getAttributeValue("enabled", hw.fHardwareVirt);
- pelmCPUChild->getAttributeValue("exclusive", hw.fHardwareVirtExclusive); // settings version 1.9
}
if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExNestedPaging")))
pelmCPUChild->getAttributeValue("enabled", hw.fNestedPaging);
@@ -2399,6 +2690,8 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
pelmCPUChild->getAttributeValue("enabled", hw.fLargePages);
if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExVPID")))
pelmCPUChild->getAttributeValue("enabled", hw.fVPID);
+ if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtExUX")))
+ pelmCPUChild->getAttributeValue("enabled", hw.fUnrestrictedExecution);
if ((pelmCPUChild = pelmHwChild->findChildElement("HardwareVirtForce")))
pelmCPUChild->getAttributeValue("enabled", hw.fHardwareVirtForce);
@@ -2411,8 +2704,19 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
else
pelmCPUChild->getAttributeValue("enabled", hw.fPAE);
+ bool fLongMode;
+ if ( (pelmCPUChild = pelmHwChild->findChildElement("LongMode"))
+ && pelmCPUChild->getAttributeValue("enabled", fLongMode) )
+ hw.enmLongMode = fLongMode ? Hardware::LongMode_Enabled : Hardware::LongMode_Disabled;
+ else
+ hw.enmLongMode = Hardware::LongMode_Legacy;
+
if ((pelmCPUChild = pelmHwChild->findChildElement("SyntheticCpu")))
pelmCPUChild->getAttributeValue("enabled", hw.fSyntheticCpu);
+
+ if ((pelmCPUChild = pelmHwChild->findChildElement("TripleFaultReset")))
+ pelmCPUChild->getAttributeValue("enabled", hw.fTripleFaultReset);
+
if ((pelmCPUChild = pelmHwChild->findChildElement("CpuIdTree")))
readCpuIdTree(*pelmCPUChild, hw.llCpuIdLeafs);
}
@@ -2478,6 +2782,8 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
hw.pointingHIDType = PointingHIDType_PS2Mouse;
else if (strHIDType == "ComboMouse")
hw.pointingHIDType = PointingHIDType_ComboMouse;
+ else if (strHIDType == "USBMultiTouch")
+ hw.pointingHIDType = PointingHIDType_USBMultiTouch;
else
throw ConfigFileError(this,
pelmHwChild,
@@ -2553,6 +2859,23 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
}
else if (pelmHwChild->nameEquals("Display"))
{
+ Utf8Str strGraphicsControllerType;
+ if (!pelmHwChild->getAttributeValue("controller", strGraphicsControllerType))
+ hw.graphicsControllerType = GraphicsControllerType_VBoxVGA;
+ else
+ {
+ strGraphicsControllerType.toUpper();
+ GraphicsControllerType_T type;
+ if (strGraphicsControllerType == "VBOXVGA")
+ type = GraphicsControllerType_VBoxVGA;
+ else if (strGraphicsControllerType == "VMSVGA")
+ type = GraphicsControllerType_VMSVGA;
+ else if (strGraphicsControllerType == "NONE")
+ type = GraphicsControllerType_Null;
+ else
+ throw ConfigFileError(this, pelmHwChild, N_("Invalid value '%s' in Display/@controller attribute"), strGraphicsControllerType.c_str());
+ hw.graphicsControllerType = type;
+ }
pelmHwChild->getAttributeValue("VRAMSize", hw.ulVRAMSizeMB);
if (!pelmHwChild->getAttributeValue("monitorCount", hw.cMonitors))
pelmHwChild->getAttributeValue("MonitorCount", hw.cMonitors); // pre-v1.5 variant
@@ -2560,14 +2883,16 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
pelmHwChild->getAttributeValue("Accelerate3D", hw.fAccelerate3D); // pre-v1.5 variant
pelmHwChild->getAttributeValue("accelerate2DVideo", hw.fAccelerate2DVideo);
}
- else if (pelmHwChild->nameEquals("VideoRecording"))
+ else if (pelmHwChild->nameEquals("VideoCapture"))
{
- pelmHwChild->getAttributeValue("enabled", hw.fVideoCaptureEnabled);
- pelmHwChild->getAttributeValue("file", hw.strVideoCaptureFile);
- pelmHwChild->getAttributeValue("horzRes", hw.ulVideoCaptureHorzRes);
- pelmHwChild->getAttributeValue("vertRes", hw.ulVideoCaptureVertRes);
+ pelmHwChild->getAttributeValue("enabled", hw.fVideoCaptureEnabled);
+ pelmHwChild->getAttributeValue("screens", hw.u64VideoCaptureScreens);
+ pelmHwChild->getAttributeValuePath("file", hw.strVideoCaptureFile);
+ pelmHwChild->getAttributeValue("horzRes", hw.ulVideoCaptureHorzRes);
+ pelmHwChild->getAttributeValue("vertRes", hw.ulVideoCaptureVertRes);
+ pelmHwChild->getAttributeValue("rate", hw.ulVideoCaptureRate);
+ pelmHwChild->getAttributeValue("fps", hw.ulVideoCaptureFPS);
}
-
else if (pelmHwChild->nameEquals("RemoteDisplay"))
{
pelmHwChild->getAttributeValue("enabled", hw.vrdeSettings.fEnabled);
@@ -2631,9 +2956,8 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
{
/* <Property name="TCP/Ports" value="3000-3002"/> */
Utf8Str strName, strValue;
- if ( ((pelmProperty->getAttributeValue("name", strName)))
- && ((pelmProperty->getAttributeValue("value", strValue)))
- )
+ if ( pelmProperty->getAttributeValue("name", strName)
+ && pelmProperty->getAttributeValue("value", strValue))
hw.vrdeSettings.mapProperties[strName] = strValue;
else
throw ConfigFileError(this, pelmProperty, N_("Required VRDE Property/@name or @value attribute is missing"));
@@ -2679,7 +3003,7 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
// legacy BIOS/IDEController (pre 1.7)
if ( (m->sv < SettingsVersion_v1_7)
- && ((pelmBIOSChild = pelmHwChild->findChildElement("IDEController")))
+ && (pelmBIOSChild = pelmHwChild->findChildElement("IDEController"))
)
{
StorageController sctl;
@@ -2702,22 +3026,75 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
strg.llStorageControllers.push_back(sctl);
}
}
- else if (pelmHwChild->nameEquals("USBController"))
+ else if ( (m->sv <= SettingsVersion_v1_14)
+ && pelmHwChild->nameEquals("USBController"))
{
- pelmHwChild->getAttributeValue("enabled", hw.usbController.fEnabled);
- pelmHwChild->getAttributeValue("enabledEhci", hw.usbController.fEnabledEHCI);
+ bool fEnabled = false;
+
+ pelmHwChild->getAttributeValue("enabled", fEnabled);
+ if (fEnabled)
+ {
+ /* Create OHCI controller with default name. */
+ USBController ctrl;
+
+ ctrl.strName = "OHCI";
+ ctrl.enmType = USBControllerType_OHCI;
+ hw.usbSettings.llUSBControllers.push_back(ctrl);
+ }
+
+ pelmHwChild->getAttributeValue("enabledEhci", fEnabled);
+ if (fEnabled)
+ {
+ /* Create OHCI controller with default name. */
+ USBController ctrl;
+
+ ctrl.strName = "EHCI";
+ ctrl.enmType = USBControllerType_EHCI;
+ hw.usbSettings.llUSBControllers.push_back(ctrl);
+ }
readUSBDeviceFilters(*pelmHwChild,
- hw.usbController.llDeviceFilters);
+ hw.usbSettings.llDeviceFilters);
}
- else if ( (m->sv < SettingsVersion_v1_7)
- && (pelmHwChild->nameEquals("SATAController"))
- )
+ else if (pelmHwChild->nameEquals("USB"))
+ {
+ const xml::ElementNode *pelmUSBChild;
+
+ if ((pelmUSBChild = pelmHwChild->findChildElement("Controllers")))
+ {
+ xml::NodesLoop nl2(*pelmUSBChild, "Controller");
+ const xml::ElementNode *pelmCtrl;
+
+ while ((pelmCtrl = nl2.forAllNodes()))
+ {
+ USBController ctrl;
+ com::Utf8Str strCtrlType;
+
+ pelmCtrl->getAttributeValue("name", ctrl.strName);
+
+ if (pelmCtrl->getAttributeValue("type", strCtrlType))
+ {
+ if (strCtrlType == "OHCI")
+ ctrl.enmType = USBControllerType_OHCI;
+ else if (strCtrlType == "EHCI")
+ ctrl.enmType = USBControllerType_EHCI;
+ else
+ throw ConfigFileError(this, pelmCtrl, N_("Invalid value '%s' for Controller/@type attribute"), strCtrlType.c_str());
+ }
+
+ hw.usbSettings.llUSBControllers.push_back(ctrl);
+ }
+ }
+
+ if ((pelmUSBChild = pelmHwChild->findChildElement("DeviceFilters")))
+ readUSBDeviceFilters(*pelmUSBChild, hw.usbSettings.llDeviceFilters);
+ }
+ else if ( m->sv < SettingsVersion_v1_7
+ && pelmHwChild->nameEquals("SATAController"))
{
bool f;
- if ( (pelmHwChild->getAttributeValue("enabled", f))
- && (f)
- )
+ if ( pelmHwChild->getAttributeValue("enabled", f)
+ && f)
{
StorageController sctl;
sctl.strName = "SATA Controller";
@@ -2734,15 +3111,15 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
else if (pelmHwChild->nameEquals("RTC"))
{
Utf8Str strLocalOrUTC;
- machineUserData.fRTCUseUTC = pelmHwChild->getAttributeValue("localOrUTC", strLocalOrUTC)
- && strLocalOrUTC == "UTC";
+ machineUserData.fRTCUseUTC = pelmHwChild->getAttributeValue("localOrUTC", strLocalOrUTC)
+ && strLocalOrUTC == "UTC";
}
- else if ( (pelmHwChild->nameEquals("UART"))
- || (pelmHwChild->nameEquals("Uart")) // used before 1.3
+ else if ( pelmHwChild->nameEquals("UART")
+ || pelmHwChild->nameEquals("Uart") // used before 1.3
)
readSerialPorts(*pelmHwChild, hw.llSerialPorts);
- else if ( (pelmHwChild->nameEquals("LPT"))
- || (pelmHwChild->nameEquals("Lpt")) // used before 1.3
+ else if ( pelmHwChild->nameEquals("LPT")
+ || pelmHwChild->nameEquals("Lpt") // used before 1.3
)
readParallelPorts(*pelmHwChild, hw.llParallelPorts);
else if (pelmHwChild->nameEquals("AudioAdapter"))
@@ -2844,7 +3221,9 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
hw.ioSettings.llBandwidthGroups.push_back(gr);
}
}
- } else if (pelmHwChild->nameEquals("HostPci")) {
+ }
+ else if (pelmHwChild->nameEquals("HostPci"))
+ {
const xml::ElementNode *pelmDevices;
if ((pelmDevices = pelmHwChild->findChildElement("Devices")))
@@ -2877,6 +3256,15 @@ void MachineConfigFile::readHardware(const xml::ElementNode &elmHardware,
pelmCardReader->getAttributeValue("enabled", hw.fEmulatedUSBCardReader);
}
}
+ else if (pelmHwChild->nameEquals("Frontend"))
+ {
+ const xml::ElementNode *pelmDefault;
+
+ if ((pelmDefault = pelmHwChild->findChildElement("Default")))
+ {
+ pelmDefault->getAttributeValue("type", hw.strDefaultFrontend);
+ }
+ }
}
if (hw.ulMemorySizeMB == (uint32_t)-1)
@@ -3099,6 +3487,7 @@ void MachineConfigFile::readStorageControllers(const xml::ElementNode &elmStorag
if (!pelmAttached->getAttributeValue("device", att.lDevice))
throw ConfigFileError(this, pelmImage, N_("Required AttachedDevice/@device attribute is missing"));
+ pelmAttached->getAttributeValue("hotpluggable", att.fHotPluggable);
pelmAttached->getAttributeValue("bandwidthGroup", att.strBwGroup);
sctl.llAttachedDevices.push_back(att);
}
@@ -3140,9 +3529,8 @@ void MachineConfigFile::readDVDAndFloppies_pre1_9(const xml::ElementNode &elmHar
const xml::ElementNode *pDriveChild;
Utf8Str strTmp;
- if ( ((pDriveChild = pelmHwChild->findChildElement("Image")))
- && (pDriveChild->getAttributeValue("uuid", strTmp))
- )
+ if ( (pDriveChild = pelmHwChild->findChildElement("Image")) != NULL
+ && pDriveChild->getAttributeValue("uuid", strTmp))
parseUUID(att.uuid, strTmp);
else if ((pDriveChild = pelmHwChild->findChildElement("HostDrive")))
pDriveChild->getAttributeValue("src", att.strHostDriveSrc);
@@ -3170,9 +3558,8 @@ void MachineConfigFile::readDVDAndFloppies_pre1_9(const xml::ElementNode &elmHar
else if (pelmHwChild->nameEquals("FloppyDrive"))
{
bool fEnabled;
- if ( (pelmHwChild->getAttributeValue("enabled", fEnabled))
- && (fEnabled)
- )
+ if ( pelmHwChild->getAttributeValue("enabled", fEnabled)
+ && fEnabled)
{
// create a new floppy controller and attach a floppy "attached device"
StorageController sctl;
@@ -3188,9 +3575,8 @@ void MachineConfigFile::readDVDAndFloppies_pre1_9(const xml::ElementNode &elmHar
const xml::ElementNode *pDriveChild;
Utf8Str strTmp;
- if ( ((pDriveChild = pelmHwChild->findChildElement("Image")))
- && (pDriveChild->getAttributeValue("uuid", strTmp))
- )
+ if ( (pDriveChild = pelmHwChild->findChildElement("Image"))
+ && pDriveChild->getAttributeValue("uuid", strTmp) )
parseUUID(att.uuid, strTmp);
else if ((pDriveChild = pelmHwChild->findChildElement("HostDrive")))
pDriveChild->getAttributeValue("src", att.strHostDriveSrc);
@@ -3296,17 +3682,26 @@ void MachineConfigFile::readGroups(const xml::ElementNode *pElmGroups, StringsLi
* contain a list of child snapshots; such lists are maintained in the
* Snapshot structure.
*
+ * @param curSnapshotUuid
+ * @param depth
* @param elmSnapshot
* @param snap
+ * @returns true if curSnapshotUuid is in this snapshot subtree, otherwise false
*/
-void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot,
+bool MachineConfigFile::readSnapshot(const Guid &curSnapshotUuid,
+ uint32_t depth,
+ const xml::ElementNode &elmSnapshot,
Snapshot &snap)
{
+ if (depth > SETTINGS_SNAPSHOT_DEPTH_MAX)
+ throw ConfigFileError(this, &elmSnapshot, N_("Maximum snapshot tree depth of %u exceeded"), depth);
+
Utf8Str strTemp;
if (!elmSnapshot.getAttributeValue("uuid", strTemp))
throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@uuid attribute is missing"));
parseUUID(snap.uuid, strTemp);
+ bool foundCurrentSnapshot = (snap.uuid == curSnapshotUuid);
if (!elmSnapshot.getAttributeValue("name", snap.strName))
throw ConfigFileError(this, &elmSnapshot, N_("Required Snapshot/@name attribute is missing"));
@@ -3332,13 +3727,11 @@ void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot,
{
if (pelmSnapshotChild->nameEquals("Description"))
snap.strDescription = pelmSnapshotChild->getValue();
- else if ( (m->sv < SettingsVersion_v1_7)
- && (pelmSnapshotChild->nameEquals("HardDiskAttachments"))
- )
+ else if ( m->sv < SettingsVersion_v1_7
+ && pelmSnapshotChild->nameEquals("HardDiskAttachments"))
readHardDiskAttachments_pre1_7(*pelmSnapshotChild, snap.storage);
- else if ( (m->sv >= SettingsVersion_v1_7)
- && (pelmSnapshotChild->nameEquals("StorageControllers"))
- )
+ else if ( m->sv >= SettingsVersion_v1_7
+ && pelmSnapshotChild->nameEquals("StorageControllers"))
readStorageControllers(*pelmSnapshotChild, snap.storage);
else if (pelmSnapshotChild->nameEquals("Snapshots"))
{
@@ -3348,9 +3741,15 @@ void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot,
{
if (pelmChildSnapshot->nameEquals("Snapshot"))
{
- Snapshot child;
- readSnapshot(*pelmChildSnapshot, child);
- snap.llChildSnapshots.push_back(child);
+ // Use the heap to reduce the stack footprint. Each
+ // recursion needs over 1K, and there can be VMs with
+ // deeply nested snapshots. The stack can be quite
+ // small, especially with XPCOM.
+ Snapshot *child = new Snapshot();
+ bool found = readSnapshot(curSnapshotUuid, depth + 1, *pelmChildSnapshot, *child);
+ foundCurrentSnapshot = foundCurrentSnapshot || found;
+ snap.llChildSnapshots.push_back(*child);
+ delete child;
}
}
}
@@ -3364,6 +3763,8 @@ void MachineConfigFile::readSnapshot(const xml::ElementNode &elmSnapshot,
readDebugging(elmSnapshot.findChildElement("Debugging"), &snap.debugging);
readAutostart(elmSnapshot.findChildElement("Autostart"), &snap.autostart);
// note: Groups exist only for Machine, not for Snapshot
+
+ return foundCurrentSnapshot;
}
const struct {
@@ -3430,9 +3831,8 @@ void MachineConfigFile::convertOldOSType_pre1_5(Utf8Str &str)
void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine)
{
Utf8Str strUUID;
- if ( (elmMachine.getAttributeValue("uuid", strUUID))
- && (elmMachine.getAttributeValue("name", machineUserData.strName))
- )
+ if ( elmMachine.getAttributeValue("uuid", strUUID)
+ && elmMachine.getAttributeValue("name", machineUserData.strName))
{
parseUUID(uuid, strUUID);
@@ -3441,7 +3841,6 @@ void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine)
Utf8Str str;
elmMachine.getAttributeValue("Description", machineUserData.strDescription);
-
elmMachine.getAttributeValue("OSType", machineUserData.strOsType);
if (m->sv < SettingsVersion_v1_5)
convertOldOSType_pre1_5(machineUserData.strOsType);
@@ -3461,6 +3860,8 @@ void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine)
if (elmMachine.getAttributeValue("aborted", fAborted))
fAborted = true;
+ elmMachine.getAttributeValue("icon", machineUserData.ovIcon);
+
// parse Hardware before the other elements because other things depend on it
const xml::ElementNode *pelmHardware;
if (!(pelmHardware = elmMachine.findChildElement("Hardware")))
@@ -3484,9 +3885,14 @@ void MachineConfigFile::readMachine(const xml::ElementNode &elmMachine)
readStorageControllers(*pelmMachineChild, storageMachine);
else if (pelmMachineChild->nameEquals("Snapshot"))
{
+ if (uuidCurrentSnapshot.isZero())
+ throw ConfigFileError(this, &elmMachine, N_("Snapshots present but required Machine/@currentSnapshot attribute is missing"));
+ bool foundCurrentSnapshot = false;
Snapshot snap;
// this will recurse into child snapshots, if necessary
- readSnapshot(*pelmMachineChild, snap);
+ foundCurrentSnapshot = readSnapshot(uuidCurrentSnapshot, 1, *pelmMachineChild, snap);
+ if (!foundCurrentSnapshot)
+ throw ConfigFileError(this, &elmMachine, N_("Snapshots present but none matches the UUID in the Machine/@currentSnapshot attribute"));
llFirstSnapshot.push_back(snap);
}
else if (pelmMachineChild->nameEquals("Description"))
@@ -3544,8 +3950,10 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
if (m->sv >= SettingsVersion_v1_4)
pelmHardware->setAttribute("version", hw.strVersion);
- if ( (m->sv >= SettingsVersion_v1_9)
- && (!hw.uuid.isEmpty())
+
+ if ((m->sv >= SettingsVersion_v1_9)
+ && !hw.uuid.isZero()
+ && hw.uuid.isValid()
)
pelmHardware->setAttribute("uuid", hw.uuid.toStringCurly());
@@ -3553,15 +3961,18 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
xml::ElementNode *pelmHwVirtEx = pelmCPU->createChild("HardwareVirtEx");
pelmHwVirtEx->setAttribute("enabled", hw.fHardwareVirt);
- if (m->sv >= SettingsVersion_v1_9)
- pelmHwVirtEx->setAttribute("exclusive", hw.fHardwareVirtExclusive);
pelmCPU->createChild("HardwareVirtExNestedPaging")->setAttribute("enabled", hw.fNestedPaging);
pelmCPU->createChild("HardwareVirtExVPID")->setAttribute("enabled", hw.fVPID);
+ pelmCPU->createChild("HardwareVirtExUX")->setAttribute("enabled", hw.fUnrestrictedExecution);
pelmCPU->createChild("PAE")->setAttribute("enabled", hw.fPAE);
+ if (m->sv >= SettingsVersion_v1_14 && hw.enmLongMode != Hardware::LongMode_Legacy)
+ pelmCPU->createChild("LongMode")->setAttribute("enabled", hw.enmLongMode == Hardware::LongMode_Enabled);
if (hw.fSyntheticCpu)
pelmCPU->createChild("SyntheticCpu")->setAttribute("enabled", hw.fSyntheticCpu);
+ if (hw.fTripleFaultReset)
+ pelmCPU->createChild("TripleFaultReset")->setAttribute("enabled", hw.fTripleFaultReset);
pelmCPU->setAttribute("count", hw.cCPUs);
if (hw.ulCpuExecutionCap != 100)
pelmCPU->setAttribute("executionCap", hw.ulCpuExecutionCap);
@@ -3642,12 +4053,13 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
switch (hw.pointingHIDType)
{
- case PointingHIDType_USBMouse: pcszHID = "USBMouse"; break;
- case PointingHIDType_USBTablet: pcszHID = "USBTablet"; break;
- case PointingHIDType_PS2Mouse: pcszHID = "PS2Mouse"; break;
- case PointingHIDType_ComboMouse: pcszHID = "ComboMouse"; break;
- case PointingHIDType_None: pcszHID = "None"; break;
- default: Assert(false); pcszHID = "PS2Mouse"; break;
+ case PointingHIDType_USBMouse: pcszHID = "USBMouse"; break;
+ case PointingHIDType_USBTablet: pcszHID = "USBTablet"; break;
+ case PointingHIDType_PS2Mouse: pcszHID = "PS2Mouse"; break;
+ case PointingHIDType_ComboMouse: pcszHID = "ComboMouse"; break;
+ case PointingHIDType_USBMultiTouch: pcszHID = "USBMultiTouch";break;
+ case PointingHIDType_None: pcszHID = "None"; break;
+ default: Assert(false); pcszHID = "PS2Mouse"; break;
}
pelmHID->setAttribute("Pointing", pcszHID);
@@ -3709,20 +4121,35 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
}
xml::ElementNode *pelmDisplay = pelmHardware->createChild("Display");
+ if (hw.graphicsControllerType != GraphicsControllerType_VBoxVGA)
+ {
+ const char *pcszGraphics;
+ switch (hw.graphicsControllerType)
+ {
+ case GraphicsControllerType_VBoxVGA: pcszGraphics = "VBoxVGA"; break;
+ case GraphicsControllerType_VMSVGA: pcszGraphics = "VMSVGA"; break;
+ default: /*case GraphicsControllerType_Null:*/ pcszGraphics = "None"; break;
+ }
+ pelmDisplay->setAttribute("controller", pcszGraphics);
+ }
pelmDisplay->setAttribute("VRAMSize", hw.ulVRAMSizeMB);
pelmDisplay->setAttribute("monitorCount", hw.cMonitors);
pelmDisplay->setAttribute("accelerate3D", hw.fAccelerate3D);
if (m->sv >= SettingsVersion_v1_8)
pelmDisplay->setAttribute("accelerate2DVideo", hw.fAccelerate2DVideo);
- xml::ElementNode *pelmVideoCapture = pelmHardware->createChild("VideoRecording");
+ xml::ElementNode *pelmVideoCapture = pelmHardware->createChild("VideoCapture");
- if (m->sv >= SettingsVersion_v1_12)
+ if (m->sv >= SettingsVersion_v1_14)
{
- pelmVideoCapture->setAttribute("enabled", hw.fVideoCaptureEnabled);
- pelmVideoCapture->setAttribute("file", hw.strVideoCaptureFile);
- pelmVideoCapture->setAttribute("horzRes", hw.ulVideoCaptureHorzRes);
- pelmVideoCapture->setAttribute("vertRes", hw.ulVideoCaptureVertRes);
+ pelmVideoCapture->setAttribute("enabled", hw.fVideoCaptureEnabled);
+ pelmVideoCapture->setAttribute("screens", hw.u64VideoCaptureScreens);
+ if (!hw.strVideoCaptureFile.isEmpty())
+ pelmVideoCapture->setAttributePath("file", hw.strVideoCaptureFile);
+ pelmVideoCapture->setAttribute("horzRes", hw.ulVideoCaptureHorzRes);
+ pelmVideoCapture->setAttribute("vertRes", hw.ulVideoCaptureVertRes);
+ pelmVideoCapture->setAttribute("rate", hw.ulVideoCaptureRate);
+ pelmVideoCapture->setAttribute("fps", hw.ulVideoCaptureFPS);
}
xml::ElementNode *pelmVRDE = pelmHardware->createChild("RemoteDisplay");
@@ -3861,7 +4288,8 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
pelmDVD->setAttribute("passthrough", att.fPassThrough);
if (att.fTempEject)
pelmDVD->setAttribute("tempeject", att.fTempEject);
- if (!att.uuid.isEmpty())
+
+ if (!att.uuid.isZero() && att.uuid.isValid())
pelmDVD->createChild("Image")->setAttribute("uuid", att.uuid.toStringCurly());
else if (att.strHostDriveSrc.length())
pelmDVD->createChild("HostDrive")->setAttribute("src", att.strHostDriveSrc);
@@ -3877,7 +4305,8 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
{
const AttachedDevice &att = sctl.llAttachedDevices.front();
pelmFloppy->setAttribute("enabled", true);
- if (!att.uuid.isEmpty())
+
+ if (!att.uuid.isZero() && att.uuid.isValid())
pelmFloppy->createChild("Image")->setAttribute("uuid", att.uuid.toStringCurly());
else if (att.strHostDriveSrc.length())
pelmFloppy->createChild("HostDrive")->setAttribute("src", att.strHostDriveSrc);
@@ -3893,13 +4322,68 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
throw ConfigFileError(this, NULL, N_("Internal error: cannot save more than one floppy drive with old settings format"));
}
- xml::ElementNode *pelmUSB = pelmHardware->createChild("USBController");
- pelmUSB->setAttribute("enabled", hw.usbController.fEnabled);
- pelmUSB->setAttribute("enabledEhci", hw.usbController.fEnabledEHCI);
+ if (m->sv < SettingsVersion_v1_14)
+ {
+ bool fOhciEnabled = false;
+ bool fEhciEnabled = false;
+ xml::ElementNode *pelmUSB = pelmHardware->createChild("USBController");
+
+ for (USBControllerList::const_iterator it = hardwareMachine.usbSettings.llUSBControllers.begin();
+ it != hardwareMachine.usbSettings.llUSBControllers.end();
+ ++it)
+ {
+ const USBController &ctrl = *it;
+
+ switch (ctrl.enmType)
+ {
+ case USBControllerType_OHCI:
+ fOhciEnabled = true;
+ break;
+ case USBControllerType_EHCI:
+ fEhciEnabled = true;
+ break;
+ default:
+ AssertMsgFailed(("Unknown USB controller type %d\n", ctrl.enmType));
+ }
+ }
+
+ pelmUSB->setAttribute("enabled", fOhciEnabled);
+ pelmUSB->setAttribute("enabledEhci", fEhciEnabled);
+
+ buildUSBDeviceFilters(*pelmUSB, hw.usbSettings.llDeviceFilters, false /* fHostMode */);
+ }
+ else
+ {
+ xml::ElementNode *pelmUSB = pelmHardware->createChild("USB");
+ xml::ElementNode *pelmCtrls = pelmUSB->createChild("Controllers");
+
+ for (USBControllerList::const_iterator it = hardwareMachine.usbSettings.llUSBControllers.begin();
+ it != hardwareMachine.usbSettings.llUSBControllers.end();
+ ++it)
+ {
+ const USBController &ctrl = *it;
+ com::Utf8Str strType;
+ xml::ElementNode *pelmCtrl = pelmCtrls->createChild("Controller");
- buildUSBDeviceFilters(*pelmUSB,
- hw.usbController.llDeviceFilters,
- false); // fHostMode
+ switch (ctrl.enmType)
+ {
+ case USBControllerType_OHCI:
+ strType = "OHCI";
+ break;
+ case USBControllerType_EHCI:
+ strType = "EHCI";
+ break;
+ default:
+ AssertMsgFailed(("Unknown USB controller type %d\n", ctrl.enmType));
+ }
+
+ pelmCtrl->setAttribute("name", ctrl.strName);
+ pelmCtrl->setAttribute("type", strType);
+ }
+
+ xml::ElementNode *pelmFilters = pelmUSB->createChild("DeviceFilters");
+ buildUSBDeviceFilters(*pelmFilters, hw.usbSettings.llDeviceFilters, false /* fHostMode */);
+ }
xml::ElementNode *pelmNetwork = pelmHardware->createChild("Network");
for (NetworkAdaptersList::const_iterator it = hw.llNetworkAdapters.begin();
@@ -3986,11 +4470,13 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
if (nic.mode != NetworkAttachmentType_Bridged)
buildNetworkXML(NetworkAttachmentType_Bridged, *pelmDisabledNode, false, nic);
if (nic.mode != NetworkAttachmentType_Internal)
- buildNetworkXML(NetworkAttachmentType_HostOnly, *pelmDisabledNode, false, nic);
+ buildNetworkXML(NetworkAttachmentType_Internal, *pelmDisabledNode, false, nic);
if (nic.mode != NetworkAttachmentType_HostOnly)
buildNetworkXML(NetworkAttachmentType_HostOnly, *pelmDisabledNode, false, nic);
if (nic.mode != NetworkAttachmentType_Generic)
buildNetworkXML(NetworkAttachmentType_Generic, *pelmDisabledNode, false, nic);
+ if (nic.mode != NetworkAttachmentType_NATNetwork)
+ buildNetworkXML(NetworkAttachmentType_NATNetwork, *pelmDisabledNode, false, nic);
buildNetworkXML(nic.mode, *pelmAdapter, true, nic);
}
}
@@ -4181,11 +4667,19 @@ void MachineConfigFile::buildHardwareXML(xml::ElementNode &elmParent,
if (m->sv >= SettingsVersion_v1_12)
{
xml::ElementNode *pelmEmulatedUSB = pelmHardware->createChild("EmulatedUSB");
- xml::ElementNode *pelmCardReader = pelmEmulatedUSB->createChild("CardReader");
+ xml::ElementNode *pelmCardReader = pelmEmulatedUSB->createChild("CardReader");
pelmCardReader->setAttribute("enabled", hw.fEmulatedUSBCardReader);
}
+ if ( m->sv >= SettingsVersion_v1_14
+ && !hw.strDefaultFrontend.isEmpty())
+ {
+ xml::ElementNode *pelmFrontend = pelmHardware->createChild("Frontend");
+ xml::ElementNode *pelmDefault = pelmFrontend->createChild("Default");
+ pelmDefault->setAttribute("type", hw.strDefaultFrontend);
+ }
+
xml::ElementNode *pelmGuest = pelmHardware->createChild("Guest");
pelmGuest->setAttribute("memoryBalloonSize", hw.ulMemoryBalloonSize);
@@ -4263,23 +4757,7 @@ void MachineConfigFile::buildNetworkXML(NetworkAttachmentType_T mode,
if (nic.nat.strTFTPNextServer.length())
pelmTFTP->setAttribute("next-server", nic.nat.strTFTPNextServer);
}
- for (NATRuleList::const_iterator rule = nic.nat.llRules.begin();
- rule != nic.nat.llRules.end(); ++rule)
- {
- xml::ElementNode *pelmPF;
- pelmPF = pelmNAT->createChild("Forwarding");
- if ((*rule).strName.length())
- pelmPF->setAttribute("name", (*rule).strName);
- pelmPF->setAttribute("proto", (*rule).proto);
- if ((*rule).strHostIP.length())
- pelmPF->setAttribute("hostip", (*rule).strHostIP);
- if ((*rule).u16HostPort)
- pelmPF->setAttribute("hostport", (*rule).u16HostPort);
- if ((*rule).strGuestIP.length())
- pelmPF->setAttribute("guestip", (*rule).strGuestIP);
- if ((*rule).u16GuestPort)
- pelmPF->setAttribute("guestport", (*rule).u16GuestPort);
- }
+ buildNATForwardRuleList(*pelmNAT, nic.nat.llRules);
break;
case NetworkAttachmentType_Bridged:
@@ -4313,6 +4791,11 @@ void MachineConfigFile::buildNetworkXML(NetworkAttachmentType_T mode,
}
break;
+ case NetworkAttachmentType_NATNetwork:
+ if (fEnabled || !nic.strNATNetworkName.isEmpty())
+ elmParent.createChild("NATNetwork")->setAttribute("name", nic.strNATNetworkName);
+ break;
+
default: /*case NetworkAttachmentType_Null:*/
break;
}
@@ -4348,7 +4831,7 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent,
if ( (m->sv < SettingsVersion_v1_9)
&& (sc.controllerType == StorageControllerType_I82078)
)
- // floppy controller already got written into <Hardware>/<FloppyController> in writeHardware()
+ // floppy controller already got written into <Hardware>/<FloppyController> in buildHardwareXML()
// for pre-1.9 settings
continue;
@@ -4443,6 +4926,9 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent,
pelmDevice->setAttribute("type", pcszType);
+ if (att.fHotPluggable)
+ pelmDevice->setAttribute("hotpluggable", att.fHotPluggable);
+
pelmDevice->setAttribute("port", att.lPort);
pelmDevice->setAttribute("device", att.lDevice);
@@ -4450,8 +4936,9 @@ void MachineConfigFile::buildStorageControllersXML(xml::ElementNode &elmParent,
pelmDevice->setAttribute("bandwidthGroup", att.strBwGroup);
// attached image, if any
- if ( !att.uuid.isEmpty()
- && ( att.deviceType == DeviceType_HardDisk
+ if (!att.uuid.isZero()
+ && att.uuid.isValid()
+ && (att.deviceType == DeviceType_HardDisk
|| !fSkipRemovableMedia
)
)
@@ -4547,12 +5034,18 @@ void MachineConfigFile::buildGroupsXML(xml::ElementNode *pElmParent, const Strin
* Writes a single snapshot into the DOM tree. Initially this gets called from MachineConfigFile::write()
* for the root snapshot of a machine, if present; elmParent then points to the <Snapshots> node under the
* <Machine> node to which <Snapshot> must be added. This may then recurse for child snapshots.
+ *
+ * @param depth
* @param elmParent
* @param snap
*/
-void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent,
+void MachineConfigFile::buildSnapshotXML(uint32_t depth,
+ xml::ElementNode &elmParent,
const Snapshot &snap)
{
+ if (depth > SETTINGS_SNAPSHOT_DEPTH_MAX)
+ throw ConfigFileError(this, NULL, N_("Maximum snapshot tree depth of %u exceeded"), SETTINGS_SNAPSHOT_DEPTH_MAX);
+
xml::ElementNode *pelmSnapshot = elmParent.createChild("Snapshot");
pelmSnapshot->setAttribute("uuid", snap.uuid.toStringCurly());
@@ -4584,7 +5077,7 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent,
++it)
{
const Snapshot &child = *it;
- buildSnapshotXML(*pelmChildren, child);
+ buildSnapshotXML(depth + 1, *pelmChildren, child);
}
}
}
@@ -4613,7 +5106,7 @@ void MachineConfigFile::buildSnapshotXML(xml::ElementNode &elmParent,
* that, if snapshots are present. Otherwise all snapshots are suppressed
* (when called from OVF).
*
- * -- BuildMachineXML_WriteVboxVersionAttribute: If set, add a settingsVersion
+ * -- BuildMachineXML_WriteVBoxVersionAttribute: If set, add a settingsVersion
* attribute to the machine tag with the vbox settings version. This is for
* the OVF export case in which we don't have the settings version set in
* the root element.
@@ -4637,7 +5130,7 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine,
uint32_t fl,
std::list<xml::ElementNode*> *pllElementsWithUuidAttributes)
{
- if (fl & BuildMachineXML_WriteVboxVersionAttribute)
+ if (fl & BuildMachineXML_WriteVBoxVersionAttribute)
// add settings version attribute to machine element
setVersionAttribute(elmMachine);
@@ -4654,8 +5147,10 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine,
&& !(fl & BuildMachineXML_SuppressSavedState)
)
elmMachine.setAttributePath("stateFile", strStateFile);
- if ( (fl & BuildMachineXML_IncludeSnapshots)
- && !uuidCurrentSnapshot.isEmpty())
+
+ if ((fl & BuildMachineXML_IncludeSnapshots)
+ && !uuidCurrentSnapshot.isZero()
+ && uuidCurrentSnapshot.isValid())
elmMachine.setAttribute("currentSnapshot", uuidCurrentSnapshot.toStringCurly());
if (machineUserData.strSnapshotFolder.length())
@@ -4665,6 +5160,10 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine,
elmMachine.setAttribute("lastStateChange", makeString(timeLastStateChange));
if (fAborted)
elmMachine.setAttribute("aborted", fAborted);
+ // Please keep the icon last so that one doesn't have to check if there
+ // is anything in the line after this very long attribute in the XML.
+ if (machineUserData.ovIcon.length())
+ elmMachine.setAttribute("icon", machineUserData.ovIcon);
if ( m->sv >= SettingsVersion_v1_9
&& ( machineUserData.fTeleporterEnabled
|| machineUserData.uTeleporterPort
@@ -4717,7 +5216,7 @@ void MachineConfigFile::buildMachineXML(xml::ElementNode &elmMachine,
if ( (fl & BuildMachineXML_IncludeSnapshots)
&& llFirstSnapshot.size())
- buildSnapshotXML(elmMachine, llFirstSnapshot.front());
+ buildSnapshotXML(1, elmMachine, llFirstSnapshot.front());
buildHardwareXML(elmMachine, hardwareMachine, storageMachine);
buildStorageControllersXML(elmMachine,
@@ -4842,6 +5341,69 @@ AudioDriverType_T MachineConfigFile::getHostDefaultAudioDriver()
*/
void MachineConfigFile::bumpSettingsVersionIfNeeded()
{
+ if (m->sv < SettingsVersion_v1_14)
+ {
+ // VirtualBox 4.3 adds default frontend setting, graphics controller
+ // setting, explicit long mode setting, video capturing and NAT networking.
+ if ( !hardwareMachine.strDefaultFrontend.isEmpty()
+ || hardwareMachine.graphicsControllerType != GraphicsControllerType_VBoxVGA
+ || hardwareMachine.enmLongMode != Hardware::LongMode_Legacy
+ || machineUserData.ovIcon.length() > 0
+ || hardwareMachine.fVideoCaptureEnabled)
+ {
+ m->sv = SettingsVersion_v1_14;
+ return;
+ }
+ NetworkAdaptersList::const_iterator netit;
+ for (netit = hardwareMachine.llNetworkAdapters.begin();
+ netit != hardwareMachine.llNetworkAdapters.end();
+ ++netit)
+ {
+ if (netit->mode == NetworkAttachmentType_NATNetwork)
+ {
+ m->sv = SettingsVersion_v1_14;
+ break;
+ }
+ }
+ }
+
+ if (m->sv < SettingsVersion_v1_14)
+ {
+ unsigned cOhciCtrls = 0;
+ unsigned cEhciCtrls = 0;
+ bool fNonStdName = false;
+
+ for (USBControllerList::const_iterator it = hardwareMachine.usbSettings.llUSBControllers.begin();
+ it != hardwareMachine.usbSettings.llUSBControllers.end();
+ ++it)
+ {
+ const USBController &ctrl = *it;
+
+ switch (ctrl.enmType)
+ {
+ case USBControllerType_OHCI:
+ cOhciCtrls++;
+ if (ctrl.strName != "OHCI")
+ fNonStdName = true;
+ break;
+ case USBControllerType_EHCI:
+ cEhciCtrls++;
+ if (ctrl.strName != "EHCI")
+ fNonStdName = true;
+ break;
+ default:
+ AssertMsgFailed(("Unknown USB controller type %d\n", ctrl.enmType));
+ }
+
+ /* Skip checking other controllers if the settings bump is necessary. */
+ if (cOhciCtrls > 1 || cEhciCtrls > 1 || fNonStdName)
+ {
+ m->sv = SettingsVersion_v1_14;
+ break;
+ }
+ }
+ }
+
if (m->sv < SettingsVersion_v1_13)
{
// VirtualBox 4.2 adds tracing, autostart, UUID in directory and groups.
@@ -4872,15 +5434,9 @@ void MachineConfigFile::bumpSettingsVersionIfNeeded()
if (m->sv < SettingsVersion_v1_12)
{
- // 4.1: Emulated USB devices.
- if (hardwareMachine.fEmulatedUSBCardReader)
- m->sv = SettingsVersion_v1_12;
- }
-
- if (m->sv < SettingsVersion_v1_12)
- {
- // VirtualBox 4.1 adds PCI passthrough.
- if (hardwareMachine.pciAttachments.size())
+ // VirtualBox 4.1 adds PCI passthrough and emulated USB Smart Card reader
+ if ( hardwareMachine.pciAttachments.size()
+ || hardwareMachine.fEmulatedUSBCardReader)
m->sv = SettingsVersion_v1_12;
}
@@ -5168,12 +5724,11 @@ void MachineConfigFile::bumpSettingsVersionIfNeeded()
// all the following require settings version 1.9
if ( (m->sv < SettingsVersion_v1_9)
&& ( (hardwareMachine.firmwareType >= FirmwareType_EFI)
- || (hardwareMachine.fHardwareVirtExclusive != HWVIRTEXCLUSIVEDEFAULT)
|| machineUserData.fTeleporterEnabled
|| machineUserData.uTeleporterPort
|| !machineUserData.strTeleporterAddress.isEmpty()
|| !machineUserData.strTeleporterPassword.isEmpty()
- || !hardwareMachine.uuid.isEmpty()
+ || (!hardwareMachine.uuid.isZero() && hardwareMachine.uuid.isValid())
)
)
m->sv = SettingsVersion_v1_9;
@@ -5212,7 +5767,7 @@ void MachineConfigFile::write(const com::Utf8Str &strFilename)
buildMachineXML(*pelmMachine,
MachineConfigFile::BuildMachineXML_IncludeSnapshots
| MachineConfigFile::BuildMachineXML_MediaRegistry,
- // but not BuildMachineXML_WriteVboxVersionAttribute
+ // but not BuildMachineXML_WriteVBoxVersionAttribute
NULL); /* pllElementsWithUuidAttributes */
// now go write the XML