1
/* $Id: ovfreader.cpp $ */
4
* OVF reader declarations. Depends only on IPRT, including the iprt::MiniString
5
* and IPRT XML classes.
9
* Copyright (C) 2008-2009 Sun Microsystems, Inc.
11
* This file is part of VirtualBox Open Source Edition (OSE), as
12
* available from http://www.virtualbox.org. This file is free software;
13
* you can redistribute it and/or modify it under the terms of the GNU
14
* General Public License (GPL) as published by the Free Software
15
* Foundation, in version 2 as it comes in the "COPYING" file of the
16
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20
* Clara, CA 95054 USA or visit http://www.sun.com if you need
21
* additional information or have any questions.
24
#include "ovfreader.h"
29
////////////////////////////////////////////////////////////////////////////////
31
// OVF reader implemenation
33
////////////////////////////////////////////////////////////////////////////////
35
OVFReader::OVFReader(const MiniString &path)
38
xml::XmlFileParser parser;
40
parser.read(m_strPath,
43
const xml::ElementNode *pRootElem = doc.getRootElement();
44
if (pRootElem && strcmp(pRootElem->getName(), "Envelope"))
45
throw OVFLogicError(N_("Root element in OVF file must be \"Envelope\"."));
47
// OVF has the following rough layout:
49
-- <References> .... files referenced from other parts of the file, such as VMDK images
50
-- Metadata, comprised of several section commands
51
-- virtual machines, either a single <VirtualSystem>, or a <VirtualSystemCollection>
52
-- optionally <Strings> for localization
55
// get all "File" child elements of "References" section so we can look up files easily;
56
// first find the "References" sections so we can look up files
57
xml::ElementNodesList listFileElements; // receives all /Envelope/References/File nodes
58
const xml::ElementNode *pReferencesElem;
59
if ((pReferencesElem = pRootElem->findChildElement("References")))
60
pReferencesElem->getChildElements(listFileElements, "File");
62
// now go though the sections
63
LoopThruSections(pReferencesElem, pRootElem);
66
OVFReader::~OVFReader()
71
* Private helper method that goes thru the elements of the given "current" element in the OVF XML
72
* and handles the contained child elements (which can be "Section" or "Content" elements).
74
* @param pcszPath Path spec of the XML file, for error messages.
75
* @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
76
* @param pCurElem Element whose children are to be analyzed here.
79
void OVFReader::LoopThruSections(const xml::ElementNode *pReferencesElem,
80
const xml::ElementNode *pCurElem)
82
xml::NodesLoop loopChildren(*pCurElem);
83
const xml::ElementNode *pElem;
84
while ((pElem = loopChildren.forAllNodes()))
86
const char *pcszElemName = pElem->getName();
87
const char *pcszTypeAttr = "";
88
const xml::AttributeNode *pTypeAttr;
89
if ((pTypeAttr = pElem->findAttribute("type")))
90
pcszTypeAttr = pTypeAttr->getValue();
92
if ( (!strcmp(pcszElemName, "DiskSection"))
93
|| ( (!strcmp(pcszElemName, "Section"))
94
&& (!strcmp(pcszTypeAttr, "ovf:DiskSection_Type"))
98
HandleDiskSection(pReferencesElem, pElem);
100
else if ( (!strcmp(pcszElemName, "NetworkSection"))
101
|| ( (!strcmp(pcszElemName, "Section"))
102
&& (!strcmp(pcszTypeAttr, "ovf:NetworkSection_Type"))
106
HandleNetworkSection(pElem);
108
else if ( (!strcmp(pcszElemName, "DeploymentOptionSection")))
112
else if ( (!strcmp(pcszElemName, "Info")))
114
// child of VirtualSystemCollection -- TODO
116
else if ( (!strcmp(pcszElemName, "ResourceAllocationSection")))
118
// child of VirtualSystemCollection -- TODO
120
else if ( (!strcmp(pcszElemName, "StartupSection")))
122
// child of VirtualSystemCollection -- TODO
124
else if ( (!strcmp(pcszElemName, "VirtualSystem"))
125
|| ( (!strcmp(pcszElemName, "Content"))
126
&& (!strcmp(pcszTypeAttr, "ovf:VirtualSystem_Type"))
130
HandleVirtualSystemContent(pElem);
132
else if ( (!strcmp(pcszElemName, "VirtualSystemCollection"))
133
|| ( (!strcmp(pcszElemName, "Content"))
134
&& (!strcmp(pcszTypeAttr, "ovf:VirtualSystemCollection_Type"))
138
// TODO ResourceAllocationSection
140
// recurse for this, since it has VirtualSystem elements as children
141
LoopThruSections(pReferencesElem, pElem);
147
* Private helper method that handles disk sections in the OVF XML.
148
* Gets called indirectly from IAppliance::read().
150
* @param pcszPath Path spec of the XML file, for error messages.
151
* @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
152
* @param pSectionElem Section element for which this helper is getting called.
155
void OVFReader::HandleDiskSection(const xml::ElementNode *pReferencesElem,
156
const xml::ElementNode *pSectionElem)
158
// contains "Disk" child elements
159
xml::NodesLoop loopDisks(*pSectionElem, "Disk");
160
const xml::ElementNode *pelmDisk;
161
while ((pelmDisk = loopDisks.forAllNodes()))
164
const char *pcszBad = NULL;
165
const char *pcszDiskId;
166
const char *pcszFormat;
167
if (!(pelmDisk->getAttributeValue("diskId", pcszDiskId)))
169
else if (!(pelmDisk->getAttributeValue("format", pcszFormat)))
171
else if (!(pelmDisk->getAttributeValue("capacity", d.iCapacity)))
172
pcszBad = "capacity";
175
d.strDiskId = pcszDiskId;
176
d.strFormat = pcszFormat;
178
if (!(pelmDisk->getAttributeValue("populatedSize", d.iPopulatedSize)))
180
d.iPopulatedSize = -1;
182
const char *pcszFileRef;
183
if (pelmDisk->getAttributeValue("fileRef", pcszFileRef)) // optional
185
// look up corresponding /References/File nodes (list built above)
186
const xml::ElementNode *pFileElem;
188
&& ((pFileElem = pReferencesElem->findChildElementFromId(pcszFileRef)))
191
// copy remaining values from file node then
192
const char *pcszBadInFile = NULL;
193
const char *pcszHref;
194
if (!(pFileElem->getAttributeValue("href", pcszHref)))
195
pcszBadInFile = "href";
196
else if (!(pFileElem->getAttributeValue("size", d.iSize)))
197
d.iSize = -1; // optional
199
d.strHref = pcszHref;
201
// if (!(pFileElem->getAttributeValue("size", d.iChunkSize))) TODO
202
d.iChunkSize = -1; // optional
203
const char *pcszCompression;
204
if (pFileElem->getAttributeValue("compression", pcszCompression))
205
d.strCompression = pcszCompression;
208
throw OVFLogicError(N_("Error reading \"%s\": missing or invalid attribute '%s' in 'File' element, line %d"),
211
pFileElem->getLineNumber());
214
throw OVFLogicError(N_("Error reading \"%s\": cannot find References/File element for ID '%s' referenced by 'Disk' element, line %d"),
217
pelmDisk->getLineNumber());
222
throw OVFLogicError(N_("Error reading \"%s\": missing or invalid attribute '%s' in 'DiskSection' element, line %d"),
225
pelmDisk->getLineNumber());
227
m_mapDisks[d.strDiskId] = d;
232
* Private helper method that handles network sections in the OVF XML.
233
* Gets called indirectly from IAppliance::read().
235
* @param pcszPath Path spec of the XML file, for error messages.
236
* @param pSectionElem Section element for which this helper is getting called.
239
void OVFReader::HandleNetworkSection(const xml::ElementNode * /* pSectionElem */)
241
// we ignore network sections for now
243
// xml::NodesLoop loopNetworks(*pSectionElem, "Network");
244
// const xml::Node *pelmNetwork;
245
// while ((pelmNetwork = loopNetworks.forAllNodes()))
248
// if (!(pelmNetwork->getAttributeValue("name", n.strNetworkName)))
249
// return setError(VBOX_E_FILE_ERROR,
250
// tr("Error reading \"%s\": missing 'name' attribute in 'Network', line %d"),
252
// pelmNetwork->getLineNumber());
254
// m->mapNetworks[n.strNetworkName] = n;
259
* Private helper method that handles a "VirtualSystem" element in the OVF XML.
260
* Gets called indirectly from IAppliance::read().
263
* @param pContentElem
266
void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSystem)
270
const xml::AttributeNode *pIdAttr = pelmVirtualSystem->findAttribute("id");
272
vsys.strName = pIdAttr->getValue();
274
xml::NodesLoop loop(*pelmVirtualSystem); // all child elements
275
const xml::ElementNode *pelmThis;
276
while ((pelmThis = loop.forAllNodes()))
278
const char *pcszElemName = pelmThis->getName();
279
const xml::AttributeNode *pTypeAttr = pelmThis->findAttribute("type");
280
const char *pcszTypeAttr = (pTypeAttr) ? pTypeAttr->getValue() : "";
282
if ( (!strcmp(pcszElemName, "EulaSection"))
283
|| (!strcmp(pcszTypeAttr, "ovf:EulaSection_Type"))
287
<Info ovf:msgid="6">License agreement for the Virtual System.</Info>
288
<License ovf:msgid="1">License terms can go in here.</License>
291
const xml::ElementNode *pelmLicense;
292
if ((pelmLicense = pelmThis->findChildElement("License")))
293
vsys.strLicenseText = pelmLicense->getValue();
295
if ( (!strcmp(pcszElemName, "ProductSection"))
296
|| (!strcmp(pcszTypeAttr, "ovf:ProductSection_Type"))
299
/* <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
300
<Info>Meta-information about the installed software</Info>
301
<Product>VAtest</Product>
302
<Vendor>SUN Microsystems</Vendor>
303
<Version>10.0</Version>
304
<ProductUrl>http://blogs.sun.com/VirtualGuru</ProductUrl>
305
<VendorUrl>http://www.sun.com</VendorUrl>
307
const xml::ElementNode *pelmProduct;
308
if ((pelmProduct = pelmThis->findChildElement("Product")))
309
vsys.strProduct = pelmProduct->getValue();
310
const xml::ElementNode *pelmVendor;
311
if ((pelmVendor = pelmThis->findChildElement("Vendor")))
312
vsys.strVendor = pelmVendor->getValue();
313
const xml::ElementNode *pelmVersion;
314
if ((pelmVersion = pelmThis->findChildElement("Version")))
315
vsys.strVersion = pelmVersion->getValue();
316
const xml::ElementNode *pelmProductUrl;
317
if ((pelmProductUrl = pelmThis->findChildElement("ProductUrl")))
318
vsys.strProductUrl = pelmProductUrl->getValue();
319
const xml::ElementNode *pelmVendorUrl;
320
if ((pelmVendorUrl = pelmThis->findChildElement("VendorUrl")))
321
vsys.strVendorUrl = pelmVendorUrl->getValue();
323
else if ( (!strcmp(pcszElemName, "VirtualHardwareSection"))
324
|| (!strcmp(pcszTypeAttr, "ovf:VirtualHardwareSection_Type"))
327
const xml::ElementNode *pelmSystem, *pelmVirtualSystemType;
328
if ((pelmSystem = pelmThis->findChildElement("System")))
331
<vssd:Description>Description of the virtual hardware section.</vssd:Description>
332
<vssd:ElementName>vmware</vssd:ElementName>
333
<vssd:InstanceID>1</vssd:InstanceID>
334
<vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
335
<vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
337
if ((pelmVirtualSystemType = pelmSystem->findChildElement("VirtualSystemType")))
338
vsys.strVirtualSystemType = pelmVirtualSystemType->getValue();
341
xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "Item"); // all "Item" child elements
342
const xml::ElementNode *pelmItem;
343
while ((pelmItem = loopVirtualHardwareItems.forAllNodes()))
345
VirtualHardwareItem i;
347
i.ulLineNumber = pelmItem->getLineNumber();
349
xml::NodesLoop loopItemChildren(*pelmItem); // all child elements
350
const xml::ElementNode *pelmItemChild;
351
while ((pelmItemChild = loopItemChildren.forAllNodes()))
353
const char *pcszItemChildName = pelmItemChild->getName();
354
if (!strcmp(pcszItemChildName, "Description"))
355
i.strDescription = pelmItemChild->getValue();
356
else if (!strcmp(pcszItemChildName, "Caption"))
357
i.strCaption = pelmItemChild->getValue();
358
else if (!strcmp(pcszItemChildName, "ElementName"))
359
i.strElementName = pelmItemChild->getValue();
360
else if ( (!strcmp(pcszItemChildName, "InstanceID"))
361
|| (!strcmp(pcszItemChildName, "InstanceId"))
363
pelmItemChild->copyValue(i.ulInstanceID);
364
else if (!strcmp(pcszItemChildName, "HostResource"))
365
i.strHostResource = pelmItemChild->getValue();
366
else if (!strcmp(pcszItemChildName, "ResourceType"))
369
pelmItemChild->copyValue(ulType);
370
i.resourceType = (OVFResourceType_T)ulType;
372
else if (!strcmp(pcszItemChildName, "OtherResourceType"))
373
i.strOtherResourceType = pelmItemChild->getValue();
374
else if (!strcmp(pcszItemChildName, "ResourceSubType"))
375
i.strResourceSubType = pelmItemChild->getValue();
376
else if (!strcmp(pcszItemChildName, "AutomaticAllocation"))
377
i.fAutomaticAllocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
378
else if (!strcmp(pcszItemChildName, "AutomaticDeallocation"))
379
i.fAutomaticDeallocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
380
else if (!strcmp(pcszItemChildName, "Parent"))
381
pelmItemChild->copyValue(i.ulParent);
382
else if (!strcmp(pcszItemChildName, "Connection"))
383
i.strConnection = pelmItemChild->getValue();
384
else if (!strcmp(pcszItemChildName, "Address"))
385
i.strAddress = pelmItemChild->getValue();
386
else if (!strcmp(pcszItemChildName, "AddressOnParent"))
387
i.strAddressOnParent = pelmItemChild->getValue();
388
else if (!strcmp(pcszItemChildName, "AllocationUnits"))
389
i.strAllocationUnits = pelmItemChild->getValue();
390
else if (!strcmp(pcszItemChildName, "VirtualQuantity"))
391
pelmItemChild->copyValue(i.ullVirtualQuantity);
392
else if (!strcmp(pcszItemChildName, "Reservation"))
393
pelmItemChild->copyValue(i.ullReservation);
394
else if (!strcmp(pcszItemChildName, "Limit"))
395
pelmItemChild->copyValue(i.ullLimit);
396
else if (!strcmp(pcszItemChildName, "Weight"))
397
pelmItemChild->copyValue(i.ullWeight);
398
else if (!strcmp(pcszItemChildName, "ConsumerVisibility"))
399
i.strConsumerVisibility = pelmItemChild->getValue();
400
else if (!strcmp(pcszItemChildName, "MappingBehavior"))
401
i.strMappingBehavior = pelmItemChild->getValue();
402
else if (!strcmp(pcszItemChildName, "PoolID"))
403
i.strPoolID = pelmItemChild->getValue();
404
else if (!strcmp(pcszItemChildName, "BusNumber"))
405
pelmItemChild->copyValue(i.ulBusNumber);
407
throw OVFLogicError(N_("Error reading \"%s\": unknown element \"%s\" under Item element, line %d"),
414
vsys.mapHardwareItems[i.ulInstanceID] = i;
417
// now go thru all hardware items and handle them according to their type;
418
// in this first loop we handle all items _except_ hard disk images,
419
// which we'll handle in a second loop below
420
HardwareItemsMap::const_iterator itH;
421
for (itH = vsys.mapHardwareItems.begin();
422
itH != vsys.mapHardwareItems.end();
425
const VirtualHardwareItem &i = itH->second;
428
switch (i.resourceType)
430
case OVFResourceType_Processor: // 3
431
/* <rasd:Caption>1 virtual CPU</rasd:Caption>
432
<rasd:Description>Number of virtual CPUs</rasd:Description>
433
<rasd:ElementName>virtual CPU</rasd:ElementName>
434
<rasd:InstanceID>1</rasd:InstanceID>
435
<rasd:ResourceType>3</rasd:ResourceType>
436
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>*/
437
if (i.ullVirtualQuantity < UINT16_MAX)
438
vsys.cCPUs = (uint16_t)i.ullVirtualQuantity;
440
throw OVFLogicError(N_("Error reading \"%s\": CPU count %RI64 is larger than %d, line %d"),
442
i.ullVirtualQuantity,
447
case OVFResourceType_Memory: // 4
448
if ( (i.strAllocationUnits == "MegaBytes") // found in OVF created by OVF toolkit
449
|| (i.strAllocationUnits == "MB") // found in MS docs
450
|| (i.strAllocationUnits == "byte * 2^20") // suggested by OVF spec DSP0243 page 21
452
vsys.ullMemorySize = i.ullVirtualQuantity * 1024 * 1024;
454
throw OVFLogicError(N_("Error reading \"%s\": Invalid allocation unit \"%s\" specified with memory size item, line %d"),
456
i.strAllocationUnits.c_str(),
460
case OVFResourceType_IDEController: // 5
463
<rasd:Caption>ideController0</rasd:Caption>
464
<rasd:Description>IDE Controller</rasd:Description>
465
<rasd:InstanceId>5</rasd:InstanceId>
466
<rasd:ResourceType>5</rasd:ResourceType>
467
<rasd:Address>0</rasd:Address>
468
<rasd:BusNumber>0</rasd:BusNumber>
470
HardDiskController hdc;
471
hdc.system = HardDiskController::IDE;
472
hdc.idController = i.ulInstanceID;
473
hdc.strControllerType = i.strResourceSubType;
474
hdc.strAddress = i.strAddress;
475
hdc.ulBusNumber = i.ulBusNumber;
477
vsys.mapControllers[i.ulInstanceID] = hdc;
481
case OVFResourceType_ParallelSCSIHBA: // 6 SCSI controller
484
<rasd:Caption>SCSI Controller 0 - LSI Logic</rasd:Caption>
485
<rasd:Description>SCI Controller</rasd:Description>
486
<rasd:ElementName>SCSI controller</rasd:ElementName>
487
<rasd:InstanceID>4</rasd:InstanceID>
488
<rasd:ResourceSubType>LsiLogic</rasd:ResourceSubType>
489
<rasd:ResourceType>6</rasd:ResourceType>
491
HardDiskController hdc;
492
hdc.system = HardDiskController::SCSI;
493
hdc.idController = i.ulInstanceID;
494
hdc.strControllerType = i.strResourceSubType;
496
vsys.mapControllers[i.ulInstanceID] = hdc;
500
case OVFResourceType_EthernetAdapter: // 10
503
<rasd:Caption>Ethernet adapter on 'Bridged'</rasd:Caption>
504
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
505
<rasd:Connection>Bridged</rasd:Connection>
506
<rasd:InstanceID>6</rasd:InstanceID>
507
<rasd:ResourceType>10</rasd:ResourceType>
508
<rasd:ResourceSubType>E1000</rasd:ResourceSubType>
511
OVF spec DSP 0243 page 21:
512
"For an Ethernet adapter, this specifies the abstract network connection name
513
for the virtual machine. All Ethernet adapters that specify the same abstract
514
network connection name within an OVF package shall be deployed on the same
515
network. The abstract network connection name shall be listed in the NetworkSection
516
at the outermost envelope level." */
518
// only store the name
520
ea.strAdapterType = i.strResourceSubType;
521
ea.strNetworkName = i.strConnection;
522
vsys.llEthernetAdapters.push_back(ea);
526
case OVFResourceType_FloppyDrive: // 14
527
vsys.fHasFloppyDrive = true; // we have no additional information
530
case OVFResourceType_CDDrive: // 15
531
/* <Item ovf:required="false">
532
<rasd:Caption>cdrom1</rasd:Caption>
533
<rasd:InstanceId>7</rasd:InstanceId>
534
<rasd:ResourceType>15</rasd:ResourceType>
535
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
536
<rasd:Parent>5</rasd:Parent>
537
<rasd:AddressOnParent>0</rasd:AddressOnParent>
539
// I tried to see what happens if I set an ISO for the CD-ROM in VMware Workstation,
540
// but then the ovftool dies with "Device backing not supported". So I guess if
541
// VMware can't export ISOs, then we don't need to be able to import them right now.
542
vsys.fHasCdromDrive = true; // we have no additional information
545
case OVFResourceType_HardDisk: // 17
546
// handled separately in second loop below
549
case OVFResourceType_OtherStorageDevice: // 20 SATA controller
552
<rasd:Description>SATA Controller</rasd:Description>
553
<rasd:Caption>sataController0</rasd:Caption>
554
<rasd:InstanceID>4</rasd:InstanceID>
555
<rasd:ResourceType>20</rasd:ResourceType>
556
<rasd:ResourceSubType>AHCI</rasd:ResourceSubType>
557
<rasd:Address>0</rasd:Address>
558
<rasd:BusNumber>0</rasd:BusNumber>
560
if ( i.strCaption.startsWith("sataController", MiniString::CaseInsensitive)
561
&& !i.strResourceSubType.compare("AHCI", MiniString::CaseInsensitive)
564
HardDiskController hdc;
565
hdc.system = HardDiskController::SATA;
566
hdc.idController = i.ulInstanceID;
567
hdc.strControllerType = i.strResourceSubType;
569
vsys.mapControllers[i.ulInstanceID] = hdc;
572
throw OVFLogicError(N_("Error reading \"%s\": Host resource of type \"Other Storage Device (%d)\" is supported with SATA AHCI controllers only, line %d"),
574
OVFResourceType_OtherStorageDevice,
579
case OVFResourceType_USBController: // 23
580
/* <Item ovf:required="false">
581
<rasd:Caption>usb</rasd:Caption>
582
<rasd:Description>USB Controller</rasd:Description>
583
<rasd:InstanceId>3</rasd:InstanceId>
584
<rasd:ResourceType>23</rasd:ResourceType>
585
<rasd:Address>0</rasd:Address>
586
<rasd:BusNumber>0</rasd:BusNumber>
588
vsys.fHasUsbController = true; // we have no additional information
591
case OVFResourceType_SoundCard: // 35
592
/* <Item ovf:required="false">
593
<rasd:Caption>sound</rasd:Caption>
594
<rasd:Description>Sound Card</rasd:Description>
595
<rasd:InstanceId>10</rasd:InstanceId>
596
<rasd:ResourceType>35</rasd:ResourceType>
597
<rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
598
<rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
599
<rasd:AddressOnParent>3</rasd:AddressOnParent>
601
vsys.strSoundCardType = i.strResourceSubType;
605
throw OVFLogicError(N_("Error reading \"%s\": Unknown resource type %d in hardware item, line %d"),
612
// now run through the items for a second time, but handle only
613
// hard disk images; otherwise the code would fail if a hard
614
// disk image appears in the OVF before its hard disk controller
615
for (itH = vsys.mapHardwareItems.begin();
616
itH != vsys.mapHardwareItems.end();
619
const VirtualHardwareItem &i = itH->second;
622
switch (i.resourceType)
624
case OVFResourceType_HardDisk: // 17
627
<rasd:Caption>Harddisk 1</rasd:Caption>
628
<rasd:Description>HD</rasd:Description>
629
<rasd:ElementName>Hard Disk</rasd:ElementName>
630
<rasd:HostResource>ovf://disk/lamp</rasd:HostResource>
631
<rasd:InstanceID>5</rasd:InstanceID>
632
<rasd:Parent>4</rasd:Parent>
633
<rasd:ResourceType>17</rasd:ResourceType>
636
// look up the hard disk controller element whose InstanceID equals our Parent;
637
// this is how the connection is specified in OVF
638
ControllersMap::const_iterator it = vsys.mapControllers.find(i.ulParent);
639
if (it == vsys.mapControllers.end())
640
throw OVFLogicError(N_("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid parent %d, line %d"),
645
//const HardDiskController &hdc = it->second;
648
vd.idController = i.ulParent;
649
i.strAddressOnParent.toInt(vd.ulAddressOnParent);
652
if (i.strHostResource.substr(0, 11) == "ovf://disk/")
653
vd.strDiskId = i.strHostResource.substr(11);
654
else if (i.strHostResource.substr(0, 10) == "ovf:/disk/")
655
vd.strDiskId = i.strHostResource.substr(10);
656
else if (i.strHostResource.substr(0, 6) == "/disk/")
657
vd.strDiskId = i.strHostResource.substr(6);
659
if ( !(vd.strDiskId.length())
660
|| (m_mapDisks.find(vd.strDiskId) == m_mapDisks.end())
662
throw OVFLogicError(N_("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid host resource \"%s\", line %d"),
665
i.strHostResource.c_str(),
668
vsys.mapVirtualDisks[vd.strDiskId] = vd;
675
else if ( (!strcmp(pcszElemName, "OperatingSystemSection"))
676
|| (!strcmp(pcszTypeAttr, "ovf:OperatingSystemSection_Type"))
680
if (!(pelmThis->getAttributeValue("id", cimos64)))
681
throw OVFLogicError(N_("Error reading \"%s\": missing or invalid 'ovf:id' attribute in operating system section element, line %d"),
683
pelmThis->getLineNumber());
685
vsys.cimos = (CIMOSType_T)cimos64;
686
const xml::ElementNode *pelmCIMOSDescription;
687
if ((pelmCIMOSDescription = pelmThis->findChildElement("Description")))
688
vsys.strCimosDesc = pelmCIMOSDescription->getValue();
690
else if ( (!strcmp(pcszElemName, "AnnotationSection"))
691
|| (!strcmp(pcszTypeAttr, "ovf:AnnotationSection_Type"))
694
const xml::ElementNode *pelmAnnotation;
695
if ((pelmAnnotation = pelmThis->findChildElement("Annotation")))
696
vsys.strDescription = pelmAnnotation->getValue();
700
// now create the virtual system
701
m_llVirtualSystems.push_back(vsys);
704
////////////////////////////////////////////////////////////////////////////////
708
////////////////////////////////////////////////////////////////////////////////
710
OVFLogicError::OVFLogicError(const char *aFormat, ...)
714
va_start(args, aFormat);
715
RTStrAPrintfV(&pszNewMsg, aFormat, args);
717
RTStrFree(pszNewMsg);