in XmlProfileParser/XmlProfileParser.cpp [76:287]
bool XmlProfileParser::ParseFile(const char *pszPath, Profile *pProfile, vector<Target> *pvSubstTargets, HMODULE hModule)
{
assert(pszPath != nullptr);
assert(pProfile != nullptr);
// import schema from the named resource
HRSRC hSchemaXmlResource = FindResource(hModule, L"DISKSPD.XSD", RT_HTML);
assert(hSchemaXmlResource != NULL);
HGLOBAL hSchemaXml = LoadResource(hModule, hSchemaXmlResource);
assert(hSchemaXml != NULL);
LPVOID pSchemaXml = LockResource(hSchemaXml);
assert(pSchemaXml != NULL);
// convert from utf-8 produced by the xsd authoring tool to utf-16
int cchSchemaXml = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pSchemaXml, -1, NULL, 0);
vector<WCHAR> vWideSchemaXml(cchSchemaXml);
int dwcchWritten = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pSchemaXml, -1, vWideSchemaXml.data(), cchSchemaXml);
UNREFERENCED_PARAMETER(dwcchWritten);
assert(dwcchWritten == cchSchemaXml);
// ... and finally, packed in a bstr for the loadXml interface
CComBSTR bSchemaXml(vWideSchemaXml.data());
bool fComInitialized = false;
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
fComInitialized = true;
CComPtr<IXMLDOMDocument2> spXmlDoc = nullptr;
CComPtr<IXMLDOMDocument2> spXmlSchema = nullptr;
CComPtr<IXMLDOMSchemaCollection2> spXmlSchemaColl = nullptr;
CComPtr<IXMLDOMParseError> spXmlParseError = nullptr;
// create com objects and decorate
hr = CoCreateInstance(__uuidof(DOMDocument60), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spXmlSchema));
if (SUCCEEDED(hr))
{
hr = spXmlSchema->put_async(VARIANT_FALSE);
}
if (SUCCEEDED(hr))
{
hr = spXmlSchema->setProperty(CComBSTR("ProhibitDTD"), CComVariant(VARIANT_FALSE));
}
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(__uuidof(XMLSchemaCache60), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spXmlSchemaColl));
}
if (SUCCEEDED(hr))
{
hr = spXmlSchemaColl->put_validateOnLoad(VARIANT_TRUE);
}
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(__uuidof(DOMDocument60), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spXmlDoc));
}
if (SUCCEEDED(hr))
{
hr = spXmlDoc->put_async(VARIANT_FALSE);
}
if (SUCCEEDED(hr))
{
hr = spXmlDoc->put_validateOnParse(VARIANT_TRUE);
}
if (SUCCEEDED(hr))
{
VARIANT_BOOL fvIsOk;
hr = spXmlSchema->loadXML(bSchemaXml, &fvIsOk);
if (FAILED(hr) || fvIsOk != VARIANT_TRUE)
{
hr = spXmlSchema->get_parseError(&spXmlParseError);
if (SUCCEEDED(hr))
{
ReportXmlError("schema", spXmlParseError);
}
hr = E_FAIL;
}
}
if (SUCCEEDED(hr))
{
CComVariant vXmlSchema(spXmlSchema);
CComBSTR bNull("");
hr = spXmlSchemaColl->add(bNull, vXmlSchema);
}
if (SUCCEEDED(hr))
{
CComVariant vSchemaCache(spXmlSchemaColl);
hr = spXmlDoc->putref_schemas(vSchemaCache);
}
if (SUCCEEDED(hr))
{
VARIANT_BOOL fvIsOk;
CComVariant vPath(pszPath);
hr = spXmlDoc->load(vPath, &fvIsOk);
if (FAILED(hr) || fvIsOk != VARIANT_TRUE)
{
hr = spXmlDoc->get_parseError(&spXmlParseError);
if (SUCCEEDED(hr))
{
ReportXmlError("profile", spXmlParseError);
}
hr = E_FAIL;
}
}
//
// XML has now passed basic schema validation. Bulld the target substitutions and parse the profile.
//
vector<pair<string, bool>> vSubsts;
if (pvSubstTargets)
{
for (auto target : *pvSubstTargets)
{
vSubsts.emplace_back(make_pair(target.GetPath(), false));
}
}
if (SUCCEEDED(hr))
{
bool b;
hr = _GetBool(spXmlDoc, "//Profile/Verbose", &b);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetVerbose(b);
}
}
if (SUCCEEDED(hr))
{
DWORD i;
hr = _GetDWORD(spXmlDoc, "//Profile/Progress", &i);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
pProfile->SetProgress(i);
}
}
if (SUCCEEDED(hr))
{
string sResultFormat;
hr = _GetString(spXmlDoc, "//Profile/ResultFormat", &sResultFormat);
if (SUCCEEDED(hr) && (hr != S_FALSE) && sResultFormat == "xml")
{
pProfile->SetResultsFormat(ResultsFormat::Xml);
}
}
if (SUCCEEDED(hr))
{
string sCreateFiles;
hr = _GetString(spXmlDoc, "//Profile/PrecreateFiles", &sCreateFiles);
if (SUCCEEDED(hr) && (hr != S_FALSE))
{
if (sCreateFiles == "UseMaxSize")
{
pProfile->SetPrecreateFiles(PrecreateFiles::UseMaxSize);
}
else if (sCreateFiles == "CreateOnlyFilesWithConstantSizes")
{
pProfile->SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantSizes);
}
else if (sCreateFiles == "CreateOnlyFilesWithConstantOrZeroSizes")
{
pProfile->SetPrecreateFiles(PrecreateFiles::OnlyFilesWithConstantOrZeroSizes);
}
else
{
hr = E_INVALIDARG;
}
}
}
if (SUCCEEDED(hr))
{
hr = _ParseEtw(spXmlDoc, pProfile);
}
if (SUCCEEDED(hr))
{
hr = _ParseTimeSpans(spXmlDoc, pProfile, vSubsts);
}
//
// Error on unused substitutions - user should ensure these match up.
//
// Note that no (zero) substitutions are OK at the point of parsing, which allows
// for -Rp forms on template profiles. Validation for executed profiles will occur
// later during common validation.
//
// Generate an error for each unused substitution.
//
if (SUCCEEDED(hr))
{
for (size_t i = 1; i <= vSubsts.size(); ++i)
{
if (!vSubsts[i - 1].second)
{
fprintf(stderr, "ERROR: unused template target substitution _%u -> %s - check profile\n", (int) i, vSubsts[i - 1].first.c_str());
hr = E_INVALIDARG;
}
}
}
}
if (fComInitialized)
{
CoUninitialize();
}
return SUCCEEDED(hr);
}