/** * Load the extension pack descriptor from an XML document. * * @returns NULL on success, pointer to an error message on failure (caller * deletes it). * @param a_pDoc Pointer to the XML document. * @param a_pExtPackDesc Where to store the extension pack descriptor. */ static RTCString *vboxExtPackLoadDescFromDoc(xml::Document *a_pDoc, PVBOXEXTPACKDESC a_pExtPackDesc) { /* * Get the main element and check its version. */ const xml::ElementNode *pVBoxExtPackElm = a_pDoc->getRootElement(); if ( !pVBoxExtPackElm || strcmp(pVBoxExtPackElm->getName(), "VirtualBoxExtensionPack") != 0) return new RTCString("No VirtualBoxExtensionPack element"); RTCString strFormatVersion; if (!pVBoxExtPackElm->getAttributeValue("version", strFormatVersion)) return new RTCString("Missing format version"); if (!strFormatVersion.equals("1.0")) return &(new RTCString("Unsupported format version: "))->append(strFormatVersion); /* * Read and validate mandatory bits. */ const xml::ElementNode *pNameElm = pVBoxExtPackElm->findChildElement("Name"); if (!pNameElm) return new RTCString("The 'Name' element is missing"); const char *pszName = pNameElm->getValue(); if (!VBoxExtPackIsValidName(pszName)) return &(new RTCString("Invalid name: "))->append(pszName); const xml::ElementNode *pDescElm = pVBoxExtPackElm->findChildElement("Description"); if (!pDescElm) return new RTCString("The 'Description' element is missing"); const char *pszDesc = pDescElm->getValue(); if (!pszDesc || *pszDesc == '\0') return new RTCString("The 'Description' element is empty"); if (strpbrk(pszDesc, "\n\r\t\v\b") != NULL) return new RTCString("The 'Description' must not contain control characters"); const xml::ElementNode *pVersionElm = pVBoxExtPackElm->findChildElement("Version"); if (!pVersionElm) return new RTCString("The 'Version' element is missing"); const char *pszVersion = pVersionElm->getValue(); if (!pszVersion || *pszVersion == '\0') return new RTCString("The 'Version' element is empty"); if (!VBoxExtPackIsValidVersionString(pszVersion)) return &(new RTCString("Invalid version string: "))->append(pszVersion); uint32_t uRevision; if (!pVersionElm->getAttributeValue("revision", uRevision)) uRevision = 0; const char *pszEdition; if (!pVersionElm->getAttributeValue("edition", pszEdition)) pszEdition = ""; if (!VBoxExtPackIsValidEditionString(pszEdition)) return &(new RTCString("Invalid edition string: "))->append(pszEdition); const xml::ElementNode *pMainModuleElm = pVBoxExtPackElm->findChildElement("MainModule"); if (!pMainModuleElm) return new RTCString("The 'MainModule' element is missing"); const char *pszMainModule = pMainModuleElm->getValue(); if (!pszMainModule || *pszMainModule == '\0') return new RTCString("The 'MainModule' element is empty"); if (!VBoxExtPackIsValidModuleString(pszMainModule)) return &(new RTCString("Invalid main module string: "))->append(pszMainModule); /* * The VRDE module, optional. * Accept both none and empty as tokens of no VRDE module. */ const char *pszVrdeModule = NULL; const xml::ElementNode *pVrdeModuleElm = pVBoxExtPackElm->findChildElement("VRDEModule"); if (pVrdeModuleElm) { pszVrdeModule = pVrdeModuleElm->getValue(); if (!pszVrdeModule || *pszVrdeModule == '\0') pszVrdeModule = NULL; else if (!VBoxExtPackIsValidModuleString(pszVrdeModule)) return &(new RTCString("Invalid VRDE module string: "))->append(pszVrdeModule); } /* * Whether to show the license, optional. (presense is enough here) */ const xml::ElementNode *pShowLicenseElm = pVBoxExtPackElm->findChildElement("ShowLicense"); bool fShowLicense = pShowLicenseElm != NULL; /* * Parse plug-in descriptions (last because of the manual memory management). */ uint32_t cPlugIns = 0; PVBOXEXTPACKPLUGINDESC paPlugIns = NULL; RTCString *pstrRet = vboxExtPackLoadPlugInDescs(pVBoxExtPackElm, &cPlugIns, &paPlugIns); if (pstrRet) { RTMemFree(paPlugIns); return pstrRet; } /* * Everything seems fine, fill in the return values and return successfully. */ a_pExtPackDesc->strName = pszName; a_pExtPackDesc->strDescription = pszDesc; a_pExtPackDesc->strVersion = pszVersion; a_pExtPackDesc->strEdition = pszEdition; a_pExtPackDesc->uRevision = uRevision; a_pExtPackDesc->strMainModule = pszMainModule; a_pExtPackDesc->strVrdeModule = pszVrdeModule; a_pExtPackDesc->cPlugIns = cPlugIns; a_pExtPackDesc->paPlugIns = paPlugIns; a_pExtPackDesc->fShowLicense = fShowLicense; return NULL; }