ovfreader.cpp revision e64031e20c39650a7bc902a3e1aba613b9415dee
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * OVF reader declarations. Depends only on IPRT, including the iprt::MiniString
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * and IPRT XML classes.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2008-2009 Oracle Corporation
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * available from http://www.virtualbox.org. This file is free software;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * you can redistribute it and/or modify it under the terms of the GNU
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * General Public License (GPL) as published by the Free Software
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsyncusing namespace std;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsyncusing namespace iprt;
d5bf937d132098565e18a0d1fc408fb777c5e5b6vboxsyncusing namespace ovf;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync////////////////////////////////////////////////////////////////////////////////
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// OVF reader implemenation
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync////////////////////////////////////////////////////////////////////////////////
f7c0f913c4c22ee18059ff97055442566d0f14a1vboxsync * Constructor. This opens the given XML file and parses it. Throws lots of exceptions
f7c0f913c4c22ee18059ff97055442566d0f14a1vboxsync * on XML or OVF invalidity.
f7c0f913c4c22ee18059ff97055442566d0f14a1vboxsync * @param path
f7c0f913c4c22ee18059ff97055442566d0f14a1vboxsync const xml::ElementNode *pRootElem = m_doc.getRootElement();
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Root element in OVF file must be \"Envelope\"."));
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // OVF has the following rough layout:
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync -- <References> .... files referenced from other parts of the file, such as VMDK images
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync -- Metadata, comprised of several section commands
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync -- virtual machines, either a single <VirtualSystem>, or a <VirtualSystemCollection>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync -- optionally <Strings> for localization
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // get all "File" child elements of "References" section so we can look up files easily;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // first find the "References" sections so we can look up files
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync xml::ElementNodesList listFileElements; // receives all /Envelope/References/File nodes
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pReferencesElem = pRootElem->findChildElement("References")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync pReferencesElem->getChildElements(listFileElements, "File");
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // now go though the sections
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * Private helper method that goes thru the elements of the given "current" element in the OVF XML
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * and handles the contained child elements (which can be "Section" or "Content" elements).
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pcszPath Path spec of the XML file, for error messages.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pCurElem Element whose children are to be analyzed here.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsyncvoid OVFReader::LoopThruSections(const xml::ElementNode *pReferencesElem,
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if ( (!strcmp(pcszElemName, "NetworkSection"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync && (!strcmp(pcszTypeAttr, "ovf:NetworkSection_Type"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if ( (!strcmp(pcszElemName, "DeploymentOptionSection")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // child of VirtualSystemCollection -- TODO
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if ( (!strcmp(pcszElemName, "ResourceAllocationSection")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // child of VirtualSystemCollection -- TODO
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if ( (!strcmp(pcszElemName, "StartupSection")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // child of VirtualSystemCollection -- TODO
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync && (!strcmp(pcszTypeAttr, "ovf:VirtualSystem_Type"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if ( (!strcmp(pcszElemName, "VirtualSystemCollection"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync && (!strcmp(pcszTypeAttr, "ovf:VirtualSystemCollection_Type"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // TODO ResourceAllocationSection
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // recurse for this, since it has VirtualSystem elements as children
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * Private helper method that handles disk sections in the OVF XML.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * Gets called indirectly from IAppliance::read().
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pcszPath Path spec of the XML file, for error messages.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pSectionElem Section element for which this helper is getting called.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsyncvoid OVFReader::HandleDiskSection(const xml::ElementNode *pReferencesElem,
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // contains "Disk" child elements
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if (!(pelmDisk->getAttributeValue("diskId", pcszDiskId)))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!(pelmDisk->getAttributeValue("format", pcszFormat)))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!(pelmDisk->getAttributeValue("capacity", d.iCapacity)))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if (!(pelmDisk->getAttributeValue("populatedSize", d.iPopulatedSize)))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // optional
2c1d8cd8efdd4c486ff681135035d24111b03af8vboxsync // optional vbox:uuid attribute (if OVF was exported by VirtualBox != 3.2)
2c1d8cd8efdd4c486ff681135035d24111b03af8vboxsync pelmDisk->getAttributeValue("vbox:uuid", d.uuidVbox);
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if (pelmDisk->getAttributeValue("fileRef", pcszFileRef)) // optional
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // look up corresponding /References/File nodes (list built above)
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync && ((pFileElem = pReferencesElem->findChildElementFromId(pcszFileRef)))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // copy remaining values from file node then
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync const char *pcszHref;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if (!(pFileElem->getAttributeValue("href", pcszHref)))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!(pFileElem->getAttributeValue("size", d.iSize)))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // if (!(pFileElem->getAttributeValue("size", d.iChunkSize))) TODO
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if (pFileElem->getAttributeValue("compression", pcszCompression))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": missing or invalid attribute '%s' in 'File' element, line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": cannot find References/File element for ID '%s' referenced by 'Disk' element, line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": missing or invalid attribute '%s' in 'DiskSection' element, line %d"),
2c1d8cd8efdd4c486ff681135035d24111b03af8vboxsync // suggest a size in megabytes to help callers with progress reports
2c1d8cd8efdd4c486ff681135035d24111b03af8vboxsync d.ulSuggestedSizeMB = 10000; // assume 10 GB, this is for the progress bar only anyway
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * Private helper method that handles network sections in the OVF XML.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * Gets called indirectly from IAppliance::read().
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pcszPath Path spec of the XML file, for error messages.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pSectionElem Section element for which this helper is getting called.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsyncvoid OVFReader::HandleNetworkSection(const xml::ElementNode * /* pSectionElem */)
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // we ignore network sections for now
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// xml::NodesLoop loopNetworks(*pSectionElem, "Network");
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// const xml::Node *pelmNetwork;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// while ((pelmNetwork = loopNetworks.forAllNodes()))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// Network n;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// if (!(pelmNetwork->getAttributeValue("name", n.strNetworkName)))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// return setError(VBOX_E_FILE_ERROR,
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// tr("Error reading \"%s\": missing 'name' attribute in 'Network', line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// pcszPath,
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// pelmNetwork->getLineNumber());
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync// m->mapNetworks[n.strNetworkName] = n;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * Private helper method that handles a "VirtualSystem" element in the OVF XML.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * Gets called indirectly from IAppliance::read().
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pcszPath
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync * @param pContentElem
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsyncvoid OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSystem)
f7c0f913c4c22ee18059ff97055442566d0f14a1vboxsync // peek under the <VirtualSystem> node whether we have a <vbox:Machine> node;
f7c0f913c4c22ee18059ff97055442566d0f14a1vboxsync // that case case, the caller can completely ignore the OVF but only load the VBox machine XML
f7c0f913c4c22ee18059ff97055442566d0f14a1vboxsync vsys.pelmVboxMachine = pelmVirtualSystem->findChildElement("vbox", "Machine");
f7c0f913c4c22ee18059ff97055442566d0f14a1vboxsync // now look for real OVF
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync const xml::AttributeNode *pIdAttr = pelmVirtualSystem->findAttribute("id");
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync xml::NodesLoop loop(*pelmVirtualSystem); // all child elements
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync const xml::AttributeNode *pTypeAttr = pelmThis->findAttribute("type");
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync const char *pcszTypeAttr = (pTypeAttr) ? pTypeAttr->getValue() : "";
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync /* <EulaSection>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <Info ovf:msgid="6">License agreement for the Virtual System.</Info>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <License ovf:msgid="1">License terms can go in here.</License>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync </EulaSection> */
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmLicense = pelmThis->findChildElement("License")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync || (!strcmp(pcszTypeAttr, "ovf:ProductSection_Type"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync /* <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <Info>Meta-information about the installed software</Info>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <Product>VAtest</Product>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <Vendor>SUN Microsystems</Vendor>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <Version>10.0</Version>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <ProductUrl>http://blogs.sun.com/VirtualGuru</ProductUrl>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <VendorUrl>http://www.sun.com</VendorUrl>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync </Section> */
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmProduct = pelmThis->findChildElement("Product")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmVendor = pelmThis->findChildElement("Vendor")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmVersion = pelmThis->findChildElement("Version")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmProductUrl = pelmThis->findChildElement("ProductUrl")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmVendorUrl = pelmThis->findChildElement("VendorUrl")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if ( (!strcmp(pcszElemName, "VirtualHardwareSection"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync || (!strcmp(pcszTypeAttr, "ovf:VirtualHardwareSection_Type"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync const xml::ElementNode *pelmSystem, *pelmVirtualSystemType;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmSystem = pelmThis->findChildElement("System")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync /* <System>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <vssd:Description>Description of the virtual hardware section.</vssd:Description>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <vssd:ElementName>vmware</vssd:ElementName>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <vssd:InstanceID>1</vssd:InstanceID>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync </System>*/
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmVirtualSystemType = pelmSystem->findChildElement("VirtualSystemType")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync vsys.strVirtualSystemType = pelmVirtualSystemType->getValue();
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "Item"); // all "Item" child elements
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync while ((pelmItem = loopVirtualHardwareItems.forAllNodes()))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync xml::NodesLoop loopItemChildren(*pelmItem); // all child elements
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync while ((pelmItemChild = loopItemChildren.forAllNodes()))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync const char *pcszItemChildName = pelmItemChild->getName();
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "ElementName"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if ( (!strcmp(pcszItemChildName, "InstanceID"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "HostResource"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "ResourceType"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "OtherResourceType"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync i.strOtherResourceType = pelmItemChild->getValue();
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "ResourceSubType"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "AutomaticAllocation"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync i.fAutomaticAllocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "AutomaticDeallocation"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync i.fAutomaticDeallocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "AddressOnParent"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "AllocationUnits"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "VirtualQuantity"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "Reservation"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "ConsumerVisibility"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync i.strConsumerVisibility = pelmItemChild->getValue();
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (!strcmp(pcszItemChildName, "MappingBehavior"))
ad0efafe1c9e639fa7c26b9a956f20119031ca10vboxsync else if (!strcmp(pcszItemChildName, "BusNumber")) // seen in some old OVF, but it's not listed in the OVF specs
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": unknown element \"%s\" under Item element, line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // now go thru all hardware items and handle them according to their type;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // in this first loop we handle all items _except_ hard disk images,
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // which we'll handle in a second loop below
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // do some analysis
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync /* <rasd:Caption>1 virtual CPU</rasd:Caption>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Description>Number of virtual CPUs</rasd:Description>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ElementName>virtual CPU</rasd:ElementName>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:InstanceID>1</rasd:InstanceID>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceType>3</rasd:ResourceType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:VirtualQuantity>1</rasd:VirtualQuantity>*/
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": CPU count %RI64 is larger than %d, line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ( (i.strAllocationUnits == "MegaBytes") // found in OVF created by OVF toolkit
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync || (i.strAllocationUnits == "MB") // found in MS docs
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync || (i.strAllocationUnits == "byte * 2^20") // suggested by OVF spec DSP0243 page 21
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync vsys.ullMemorySize = i.ullVirtualQuantity * 1024 * 1024;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": Invalid allocation unit \"%s\" specified with memory size item, line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Caption>ideController0</rasd:Caption>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Description>IDE Controller</rasd:Description>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:InstanceId>5</rasd:InstanceId>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceType>5</rasd:ResourceType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Address>0</rasd:Address>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:BusNumber>0</rasd:BusNumber>
ad0efafe1c9e639fa7c26b9a956f20119031ca10vboxsync // if there is a numeric address tag for the IDE controller, use that;
ad0efafe1c9e639fa7c26b9a956f20119031ca10vboxsync // VMware uses "0" and "1" to keep the two OVF IDE controllers apart;
ad0efafe1c9e639fa7c26b9a956f20119031ca10vboxsync // otherwise use the "bus number" field which was specified in some old
ad0efafe1c9e639fa7c26b9a956f20119031ca10vboxsync // OVF files (but not the standard)
ad0efafe1c9e639fa7c26b9a956f20119031ca10vboxsync else if (i.strAddress == "2") // just to be sure, this doesn't seem to be used by VMware
d5bf937d132098565e18a0d1fc408fb777c5e5b6vboxsync case ResourceType_ParallelSCSIHBA: // 6 SCSI controller
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Caption>SCSI Controller 0 - LSI Logic</rasd:Caption>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Description>SCI Controller</rasd:Description>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ElementName>SCSI controller</rasd:ElementName>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:InstanceID>4</rasd:InstanceID>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceSubType>LsiLogic</rasd:ResourceSubType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceType>6</rasd:ResourceType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Caption>Ethernet adapter on 'Bridged'</rasd:Caption>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Connection>Bridged</rasd:Connection>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:InstanceID>6</rasd:InstanceID>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceType>10</rasd:ResourceType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceSubType>E1000</rasd:ResourceSubType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync OVF spec DSP 0243 page 21:
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync "For an Ethernet adapter, this specifies the abstract network connection name
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync for the virtual machine. All Ethernet adapters that specify the same abstract
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync network connection name within an OVF package shall be deployed on the same
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync network. The abstract network connection name shall be listed in the NetworkSection
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync at the outermost envelope level." */
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // only store the name
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync vsys.fHasFloppyDrive = true; // we have no additional information
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync /* <Item ovf:required="false">
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Caption>cdrom1</rasd:Caption>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:InstanceId>7</rasd:InstanceId>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceType>15</rasd:ResourceType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Parent>5</rasd:Parent>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:AddressOnParent>0</rasd:AddressOnParent>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // I tried to see what happens if I set an ISO for the CD-ROM in VMware Workstation,
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // but then the ovftool dies with "Device backing not supported". So I guess if
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // VMware can't export ISOs, then we don't need to be able to import them right now.
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync vsys.fHasCdromDrive = true; // we have no additional information
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // handled separately in second loop below
d5bf937d132098565e18a0d1fc408fb777c5e5b6vboxsync case ResourceType_OtherStorageDevice: // 20 SATA controller
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Description>SATA Controller</rasd:Description>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Caption>sataController0</rasd:Caption>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:InstanceID>4</rasd:InstanceID>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceType>20</rasd:ResourceType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceSubType>AHCI</rasd:ResourceSubType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Address>0</rasd:Address>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:BusNumber>0</rasd:BusNumber>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ( i.strCaption.startsWith("sataController", MiniString::CaseInsensitive)
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync && !i.strResourceSubType.compare("AHCI", MiniString::CaseInsensitive)
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": Host resource of type \"Other Storage Device (%d)\" is supported with SATA AHCI controllers only, line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync /* <Item ovf:required="false">
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Caption>usb</rasd:Caption>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Description>USB Controller</rasd:Description>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:InstanceId>3</rasd:InstanceId>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceType>23</rasd:ResourceType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Address>0</rasd:Address>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:BusNumber>0</rasd:BusNumber>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync vsys.fHasUsbController = true; // we have no additional information
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync /* <Item ovf:required="false">
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Caption>sound</rasd:Caption>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Description>Sound Card</rasd:Description>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:InstanceId>10</rasd:InstanceId>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceType>35</rasd:ResourceType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:AddressOnParent>3</rasd:AddressOnParent>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": Unknown resource type %d in hardware item, line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync } // end switch
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // now run through the items for a second time, but handle only
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // hard disk images; otherwise the code would fail if a hard
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // disk image appears in the OVF before its hard disk controller
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // do some analysis
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Caption>Harddisk 1</rasd:Caption>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Description>HD</rasd:Description>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ElementName>Hard Disk</rasd:ElementName>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:HostResource>ovf://disk/lamp</rasd:HostResource>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:InstanceID>5</rasd:InstanceID>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:Parent>4</rasd:Parent>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync <rasd:ResourceType>17</rasd:ResourceType>
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // look up the hard disk controller element whose InstanceID equals our Parent;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // this is how the connection is specified in OVF
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync ControllersMap::const_iterator it = vsys.mapControllers.find(i.ulParent);
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid parent %d, line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync //const HardDiskController &hdc = it->second;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // 123456789012345
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if (i.strHostResource.substr(0, 11) == "ovf://disk/")
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (i.strHostResource.substr(0, 10) == "ovf:/disk/")
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if (i.strHostResource.substr(0, 6) == "/disk/")
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync || (m_mapDisks.find(vd.strDiskId) == m_mapDisks.end())
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid host resource \"%s\", line %d"),
7622c238774f7797c2a216582f4efb84c4c082afvboxsync default: break;
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if ( (!strcmp(pcszElemName, "OperatingSystemSection"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync || (!strcmp(pcszTypeAttr, "ovf:OperatingSystemSection_Type"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync throw OVFLogicError(N_("Error reading \"%s\": missing or invalid 'ovf:id' attribute in operating system section element, line %d"),
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmCIMOSDescription = pelmThis->findChildElement("Description")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync vsys.strCimosDesc = pelmCIMOSDescription->getValue();
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync else if ( (!strcmp(pcszElemName, "AnnotationSection"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync || (!strcmp(pcszTypeAttr, "ovf:AnnotationSection_Type"))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync if ((pelmAnnotation = pelmThis->findChildElement("Annotation")))
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync // now create the virtual system
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync////////////////////////////////////////////////////////////////////////////////
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsync////////////////////////////////////////////////////////////////////////////////
d84b6107a8e797f41ac2d55bed97b02c91c742e8vboxsyncOVFLogicError::OVFLogicError(const char *aFormat, ...)