880 lines
25 KiB
C++
880 lines
25 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 2000.
|
||
|
//
|
||
|
// File: V A L I D A T I O N M A N A G E R . C P P
|
||
|
//
|
||
|
// Contents: Validates device host inputs
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: mbend 9 Oct 2000
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include "uhbase.h"
|
||
|
#include "ValidationManager.h"
|
||
|
#include "uhutil.h"
|
||
|
#include "ncstring.h"
|
||
|
#include "validate.h"
|
||
|
#include "uhcommon.h"
|
||
|
|
||
|
// Functions declarationc
|
||
|
HRESULT HrValidateDevice(
|
||
|
IXMLDOMNodePtr & pNodeDevice,
|
||
|
CUString & strErrorString);
|
||
|
|
||
|
CValidationManager::CValidationManager ()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CValidationManager::~CValidationManager ()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
HRESULT HrGetDocumentAndRootNode(
|
||
|
BSTR bstrTemplate,
|
||
|
IXMLDOMDocumentPtr & pDoc,
|
||
|
IXMLDOMNodePtr & pRootNode)
|
||
|
{
|
||
|
TraceTag(ttidValidate, "HrGetDocumentAndRootNode");
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// Load document and fetch needed items
|
||
|
hr = HrLoadDocument(bstrTemplate, pDoc);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pRootNode.HrAttach(pDoc);
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrGetDocumentAndRootNode");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
struct PresenceItem
|
||
|
{
|
||
|
const wchar_t * m_szName;
|
||
|
bool m_bEmpty;
|
||
|
bool m_bSuffix;
|
||
|
bool m_bOptional;
|
||
|
LONG m_cchMax;
|
||
|
};
|
||
|
|
||
|
// m_szName EMPTY SUFFIX OPTONAL CCH
|
||
|
// ----------------------------------------------------------
|
||
|
const PresenceItem g_arpiDeviceItems[] =
|
||
|
{
|
||
|
{L"deviceType", false, true, false, 64},
|
||
|
{L"friendlyName", false, false, false, 64},
|
||
|
{L"manufacturer", false, false, false, 64},
|
||
|
{L"manufacturerURL", false, false, true, -1},
|
||
|
{L"modelDescription", false, false, true, 128},
|
||
|
{L"modelName", false, false, false, 32},
|
||
|
{L"modelNumber", false, false, true, 32},
|
||
|
{L"modelURL", false, false, true, -1},
|
||
|
{L"serialNumber", false, false, true, 64},
|
||
|
{L"UDN", false, false, false, -1},
|
||
|
{L"UPC", false, false, true, 12},
|
||
|
};
|
||
|
|
||
|
const long c_nDeviceItems = celems(g_arpiDeviceItems);
|
||
|
|
||
|
PresenceItem g_arpiServiceItems[] =
|
||
|
{
|
||
|
{L"serviceType", false, true, false, 64},
|
||
|
{L"serviceId", false, true, false, 64},
|
||
|
{L"SCPDURL", false, false, false, -1},
|
||
|
{L"controlURL", true, false, false, -1},
|
||
|
{L"eventSubURL", true, false, false, -1},
|
||
|
};
|
||
|
|
||
|
const long c_nServiceItems = celems(g_arpiServiceItems);
|
||
|
|
||
|
PresenceItem g_arpiIconItems[] =
|
||
|
{
|
||
|
{L"mimetype", false, false, false, -1},
|
||
|
{L"width", false, false, false, -1},
|
||
|
{L"height", false, false, false, -1},
|
||
|
{L"depth", false, false, false, -1},
|
||
|
{L"url", false, false, false, -1},
|
||
|
};
|
||
|
|
||
|
const long c_nIconItems = celems(g_arpiIconItems);
|
||
|
|
||
|
PresenceItem g_arpiRootItems[] =
|
||
|
{
|
||
|
{L"/root/specVersion", false, false, false, -1},
|
||
|
};
|
||
|
|
||
|
const long c_nRootItems = celems(g_arpiRootItems);
|
||
|
|
||
|
HRESULT HrValidateSufixes(IXMLDOMNodePtr & pNode,
|
||
|
const wchar_t * szName,
|
||
|
LONG cchMax,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
DWORD ctok = 0;
|
||
|
LPCWSTR pchText;
|
||
|
CUString strText;
|
||
|
IXMLDOMNodePtr pNodeItem;
|
||
|
|
||
|
// This function validates the serviceType, deviceType, and serviceId
|
||
|
// elements in the following way:
|
||
|
// Each of these is of the form: urn:domain-name:keyword:SUFFIX:version
|
||
|
// Since they all follow the same format (which currently we DO NOT
|
||
|
// validate), we can make an assumption that the 4th token (SUFFIX) is the
|
||
|
// one that we need to validate. The validation is strictly as according
|
||
|
// to UPnP architecture 1.0 where this suffix must be <= 64 characters in
|
||
|
// length.
|
||
|
//
|
||
|
|
||
|
hr = HrSelectNode(szName, pNode, pNodeItem);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrGetNodeText(pNodeItem, strText);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
pchText = strText.GetBuffer();
|
||
|
while (*pchText)
|
||
|
{
|
||
|
if (*pchText == L':')
|
||
|
{
|
||
|
ctok++;
|
||
|
pchText++;
|
||
|
|
||
|
if (ctok == 3)
|
||
|
{
|
||
|
// Fourth token is the one we need to examine
|
||
|
LONG cch = 0;
|
||
|
|
||
|
while (*pchText && *pchText != L':')
|
||
|
{
|
||
|
pchText++;
|
||
|
cch++;
|
||
|
}
|
||
|
|
||
|
// ISSUE-2000/11/29-danielwe: We don't yet
|
||
|
// validate the format of the suffix
|
||
|
//
|
||
|
|
||
|
if (cch > cchMax)
|
||
|
{
|
||
|
hr = strErrorString.HrPrintf(
|
||
|
WszLoadString(_Module.GetResourceInstance(),
|
||
|
IDS_SUFFIX_TOO_LONG),
|
||
|
strText);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_SUFFIX_TOO_LONG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pchText++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrValidateSufixes(%S)",
|
||
|
strErrorString.GetLength() ? strErrorString.GetBuffer(): L"Unspecified");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrValidatePresenceItems(
|
||
|
IXMLDOMNodePtr & pNode,
|
||
|
long nPresenceItems,
|
||
|
const PresenceItem * arPresenceItems,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
for(long n = 0; n < nPresenceItems && SUCCEEDED(hr); ++n)
|
||
|
{
|
||
|
AssertSz(FImplies(arPresenceItems[n].m_bEmpty,
|
||
|
arPresenceItems[n].m_cchMax == -1),
|
||
|
"Empty elements mean there shouldn't be a size to verify "
|
||
|
"against! Fix the array above!");
|
||
|
|
||
|
if(arPresenceItems[n].m_bEmpty)
|
||
|
{
|
||
|
hr = HrIsNodePresentOnceAndEmpty(arPresenceItems[n].m_szName, pNode);
|
||
|
if(S_OK != hr)
|
||
|
{
|
||
|
hr = strErrorString.HrPrintf(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_EMPTY_NODE_NOT_PRESENT),
|
||
|
arPresenceItems[n].m_szName);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_REQUIRED_ELEMENT_ERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (!arPresenceItems[n].m_bSuffix)
|
||
|
{
|
||
|
hr = HrIsNodePresentOnceAndNotEmpty(arPresenceItems[n].m_szName, pNode);
|
||
|
if(S_OK != hr)
|
||
|
{
|
||
|
if (UPNP_E_DUPLICATE_NOT_ALLOWED == hr)
|
||
|
{
|
||
|
// Didn't find the item and it's not optional
|
||
|
hr = strErrorString.HrPrintf(
|
||
|
WszLoadString(_Module.GetResourceInstance(),
|
||
|
IDS_DUPLICATES_NOT_ALLOWED),
|
||
|
arPresenceItems[n].m_szName);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_DUPLICATE_NOT_ALLOWED;
|
||
|
}
|
||
|
}
|
||
|
else if (!arPresenceItems[n].m_bOptional)
|
||
|
{
|
||
|
// Didn't find the item and it's not optional
|
||
|
hr = strErrorString.HrPrintf(
|
||
|
WszLoadString(_Module.GetResourceInstance(),
|
||
|
IDS_NON_EMPTY_NODE_NOT_PRESENT),
|
||
|
arPresenceItems[n].m_szName);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_REQUIRED_ELEMENT_ERROR;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Element was optional
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
else if (arPresenceItems[n].m_cchMax != -1)
|
||
|
{
|
||
|
// Check length if one is specified
|
||
|
//
|
||
|
hr = HrIsNodeOfValidLength(arPresenceItems[n].m_szName, pNode,
|
||
|
arPresenceItems[n].m_cchMax);
|
||
|
if(S_FALSE == hr)
|
||
|
{
|
||
|
hr = strErrorString.HrPrintf(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_ELEMENT_VALUE_TOO_LONG),
|
||
|
arPresenceItems[n].m_szName);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_VALUE_TOO_LONG;
|
||
|
}
|
||
|
}
|
||
|
else if (arPresenceItems[n].m_bOptional && (FAILED(hr)))
|
||
|
{
|
||
|
// If item was optional, forget any errors
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (arPresenceItems[n].m_bSuffix && arPresenceItems[n].m_cchMax != -1)
|
||
|
{
|
||
|
hr = HrValidateSufixes(pNode, arPresenceItems[n].m_szName,
|
||
|
arPresenceItems[n].m_cchMax,
|
||
|
strErrorString);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrValidatePresenceItems(%S)",
|
||
|
strErrorString.GetLength() ? strErrorString.GetBuffer(): L"Unspecified");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrValidateDeviceService(
|
||
|
IXMLDOMNodePtr & pNodeService,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
hr = HrValidatePresenceItems(pNodeService, c_nServiceItems, g_arpiServiceItems, strErrorString);
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrValidateDeviceService");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrCheckForDuplicatesInList(
|
||
|
IXMLDOMNodeListPtr & pNodeList,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
CUArray<CUString> arstrValues;
|
||
|
while(SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMNodePtr pNode;
|
||
|
HRESULT hrTemp = pNodeList->nextNode(pNode.AddressOf());
|
||
|
if(S_OK != hrTemp)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
CUString strText;
|
||
|
hr = HrGetNodeText(pNode, strText);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
long nIndex = 0;
|
||
|
hrTemp = arstrValues.HrFind(strText, nIndex);
|
||
|
if(S_OK == hrTemp)
|
||
|
{
|
||
|
// We found a duplicate
|
||
|
hr = strErrorString.HrPrintf(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_DUPLICATES_NOT_ALLOWED),
|
||
|
strText.GetBuffer());
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_DUPLICATE_NOT_ALLOWED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = arstrValues.HrPushBack(strText);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrCheckForDuplicatesInList");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrValidateDeviceServices(
|
||
|
IXMLDOMNodePtr & pNodeDevice,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// serviceList is required and must contain a service
|
||
|
BOOL bServiceNotPresent = TRUE;
|
||
|
|
||
|
HRESULT hrTemp = HrIsNodePresentOnce(L"serviceList", pNodeDevice);
|
||
|
if(S_OK == hrTemp)
|
||
|
{
|
||
|
IXMLDOMNodeListPtr pNodeList;
|
||
|
hrTemp = HrSelectNodes(L"serviceList/service", pNodeDevice, pNodeList);
|
||
|
if(S_OK == hrTemp)
|
||
|
{
|
||
|
while(SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMNodePtr pNode;
|
||
|
hrTemp = pNodeList->nextNode(pNode.AddressOf());
|
||
|
if(S_OK != hrTemp)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// We have a service
|
||
|
bServiceNotPresent = FALSE;
|
||
|
|
||
|
hr = HrValidateDeviceService(pNode, strErrorString);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Make sure all ServiceId's are unique
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
pNodeList.Release();
|
||
|
hrTemp = HrSelectNodes(L"serviceList/service/serviceId", pNodeDevice, pNodeList);
|
||
|
if(S_OK == hrTemp)
|
||
|
{
|
||
|
hr = HrCheckForDuplicatesInList(pNodeList, strErrorString);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(bServiceNotPresent)
|
||
|
{
|
||
|
hr = strErrorString.HrAssign(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_SERVICE_MISSING));
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_INVALID_SERVICE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrValidateDeviceServices");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrValidateDeviceIcon(
|
||
|
IXMLDOMNodePtr & pNodeIcon,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
hr = HrValidatePresenceItems(pNodeIcon, c_nIconItems, g_arpiIconItems, strErrorString);
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrValidateDeviceIcon");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrValidateDeviceIcons(
|
||
|
IXMLDOMNodePtr & pNodeDevice,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
HRESULT hrTemp = HrIsNodePresentOnce(L"iconList", pNodeDevice);
|
||
|
if(S_OK == hrTemp)
|
||
|
{
|
||
|
BOOL fGotAnIcon = FALSE;
|
||
|
|
||
|
IXMLDOMNodeListPtr pNodeList;
|
||
|
hrTemp = HrSelectNodes(L"iconList/icon", pNodeDevice, pNodeList);
|
||
|
if(S_OK == hrTemp)
|
||
|
{
|
||
|
while(SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMNodePtr pNode;
|
||
|
hrTemp = pNodeList->nextNode(pNode.AddressOf());
|
||
|
if(S_OK != hrTemp)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
fGotAnIcon = TRUE;
|
||
|
hr = HrValidateDeviceIcon(pNode, strErrorString);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!fGotAnIcon)
|
||
|
{
|
||
|
hr = strErrorString.HrAssign(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_ICON_MISSING));
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_INVALID_ICON;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrValidateDeviceIcons");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrValidateDeviceChildren(
|
||
|
IXMLDOMNodePtr & pNodeDevice,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
BOOL fGotADevice = FALSE;
|
||
|
|
||
|
HRESULT hrTemp = HrIsNodePresentOnce(L"deviceList", pNodeDevice);
|
||
|
if(S_OK == hrTemp)
|
||
|
{
|
||
|
IXMLDOMNodeListPtr pNodeList;
|
||
|
hrTemp = HrSelectNodes(L"deviceList/device", pNodeDevice, pNodeList);
|
||
|
if(S_OK == hrTemp)
|
||
|
{
|
||
|
while(SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMNodePtr pNode;
|
||
|
hrTemp = pNodeList->nextNode(pNode.AddressOf());
|
||
|
if(S_OK != hrTemp)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
fGotADevice = TRUE;
|
||
|
hr = HrValidateDevice(pNode, strErrorString);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!fGotADevice)
|
||
|
{
|
||
|
hr = strErrorString.HrAssign(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_DEVICE_MISSING));
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_INVALID_DOCUMENT;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrValidateDeviceChildren");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrValidateDevice(
|
||
|
IXMLDOMNodePtr & pNodeDevice,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
TraceTag(ttidValidate, "HrValidateDevice");
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
hr = HrValidatePresenceItems(pNodeDevice, c_nDeviceItems, g_arpiDeviceItems, strErrorString);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrValidateDeviceServices(pNodeDevice, strErrorString);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrValidateDeviceIcons(pNodeDevice, strErrorString);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrValidateDeviceChildren(pNodeDevice, strErrorString);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrValidateDevice");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT HrValidateUDNs(
|
||
|
IXMLDOMNodePtr & pNodeDevice,
|
||
|
CUString & strErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
IXMLDOMNodeListPtr pNodeList;
|
||
|
hr = HrSelectNodes(L"//UDN", pNodeDevice, pNodeList);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrCheckForDuplicatesInList(pNodeList, strErrorString);
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "HrValidateUDNs");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
HRESULT HrValidateDevice(
|
||
|
IXMLDOMNodePtr & pNodeDevice)
|
||
|
{
|
||
|
TraceTag(ttidValidate, "");
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "");
|
||
|
return hr;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// IUPnPValidationManager methods
|
||
|
|
||
|
STDMETHODIMP CValidationManager::ValidateDescriptionDocument(
|
||
|
/*[in]*/ BSTR bstrTemplate,
|
||
|
/*[out, string]*/ wchar_t ** pszErrorString)
|
||
|
{
|
||
|
CHECK_POINTER(bstrTemplate);
|
||
|
CHECK_POINTER(pszErrorString);
|
||
|
HRESULT hr = S_OK;
|
||
|
CUString strErrorString;
|
||
|
*pszErrorString = NULL;
|
||
|
|
||
|
IXMLDOMDocumentPtr pDoc;
|
||
|
IXMLDOMNodePtr pRootNode;
|
||
|
|
||
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrGetDocumentAndRootNode(bstrTemplate, pDoc, pRootNode);
|
||
|
}
|
||
|
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrValidatePresenceItems(pRootNode, c_nRootItems, g_arpiRootItems, strErrorString);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrIsNodePresentOnce(L"/root/device", pRootNode);
|
||
|
if(S_OK == hr)
|
||
|
{
|
||
|
hr = HrIsNodePresentOnce(L"/root/URLBase", pRootNode);
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
hr = HrValidateUDNs(pRootNode, strErrorString);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMNodePtr pNodeDevice;
|
||
|
hr = HrSelectNode(L"/root/device", pRootNode, pNodeDevice);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = HrValidateDevice(pNodeDevice, strErrorString);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = strErrorString.HrAssign(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_URLBASE_PRESENT));
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_REQUIRED_ELEMENT_ERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = strErrorString.HrAssign(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_ROOT_DEVICE_MISSING));
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_REQUIRED_ELEMENT_ERROR;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Let's make sure the root namespace is according to spec
|
||
|
//
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMNodePtr pNodeRootSub;
|
||
|
|
||
|
hr = HrSelectNode(L"/root", pRootNode, pNodeRootSub);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
BSTR bstrUri;
|
||
|
|
||
|
hr = pNodeRootSub->get_namespaceURI(&bstrUri);
|
||
|
if (S_OK != hr || lstrcmpi(bstrUri,
|
||
|
L"urn:schemas-upnp-org:device-1-0"))
|
||
|
{
|
||
|
hr = strErrorString.HrPrintf(
|
||
|
WszLoadString(_Module.GetResourceInstance(),
|
||
|
IDS_INVALID_ROOT_NAMESPACE),
|
||
|
bstrUri);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_INVALID_ROOT_NAMESPACE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
if(strErrorString.GetLength())
|
||
|
{
|
||
|
strErrorString.HrGetCOM(pszErrorString);
|
||
|
}
|
||
|
}
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "CValidationManager::ValidateDescriptionDocument(%S)",
|
||
|
*pszErrorString ? *pszErrorString : L"Unspecified");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CValidationManager::ValidateServiceDescription(
|
||
|
/*[in, string]*/ const wchar_t * szFullPath,
|
||
|
/*[out, string]*/ wchar_t ** pszErrorString)
|
||
|
{
|
||
|
CHECK_POINTER(szFullPath);
|
||
|
CHECK_POINTER(pszErrorString);
|
||
|
HRESULT hr = S_OK;
|
||
|
CUString strErrorString;
|
||
|
*pszErrorString = NULL;
|
||
|
|
||
|
BSTR bstrPath;
|
||
|
IXMLDOMDocumentPtr pDoc;
|
||
|
|
||
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
bstrPath = SysAllocString(szFullPath);
|
||
|
}
|
||
|
|
||
|
if (bstrPath)
|
||
|
{
|
||
|
hr = HrLoadDocumentFromFile(bstrPath, pDoc);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMElementPtr pxdeSDRoot;
|
||
|
|
||
|
hr = pDoc->get_documentElement(pxdeSDRoot.AddressOf());
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
hr = HrValidateServiceDescription(pxdeSDRoot, pszErrorString);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = strErrorString.HrPrintf(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_INVALID_XML),
|
||
|
szFullPath);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_INVALID_XML;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SysFreeString(bstrPath);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
if(strErrorString.GetLength())
|
||
|
{
|
||
|
strErrorString.HrGetCOM(pszErrorString);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "CValidationManager::ValidateServiceDescription(%S)",
|
||
|
*pszErrorString ? *pszErrorString : L"Unspecified");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CValidationManager::ValidateServiceDescriptions(const wchar_t * szResourcePath,
|
||
|
IXMLDOMNodePtr pRootNode,
|
||
|
wchar_t ** pszErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
IXMLDOMNodeListPtr pNodeList;
|
||
|
|
||
|
// Select all of the SCPDURL nodes in the description document
|
||
|
hr = HrSelectNodes(L"//device/serviceList/service/SCPDURL",
|
||
|
pRootNode, pNodeList);
|
||
|
|
||
|
while (S_OK == hr)
|
||
|
{
|
||
|
IXMLDOMNodePtr pNode;
|
||
|
CUString strUrl;
|
||
|
|
||
|
hr = pNodeList->nextNode(pNode.AddressOf());
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
hr = HrGetNodeText(pNode, strUrl);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CUString strFullPath;
|
||
|
|
||
|
hr = HrMakeFullPath(szResourcePath, strUrl, strFullPath);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = ValidateServiceDescription(strFullPath,
|
||
|
pszErrorString);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// normalize error code
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "CValidationManager::ValidateServiceDescriptions(%S)",
|
||
|
*pszErrorString ? *pszErrorString : L"Unspecified");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CValidationManager::ValidateIconFiles(const wchar_t * szResourcePath,
|
||
|
IXMLDOMNodePtr pRootNode,
|
||
|
wchar_t ** pszErrorString)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
IXMLDOMNodeListPtr pNodeList;
|
||
|
CUString strErrorString;
|
||
|
|
||
|
// Select all of the SCPDURL nodes in the description document
|
||
|
hr = HrSelectNodes(L"//device/iconList/icon/url", pRootNode, pNodeList);
|
||
|
while (S_OK == hr)
|
||
|
{
|
||
|
IXMLDOMNodePtr pNode;
|
||
|
CUString strUrl;
|
||
|
|
||
|
hr = pNodeList->nextNode(pNode.AddressOf());
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
hr = HrGetNodeText(pNode, strUrl);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CUString strFullPath;
|
||
|
|
||
|
hr = HrMakeFullPath(szResourcePath, strUrl, strFullPath);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (!FFileExists((LPTSTR)strFullPath.GetBuffer(), FALSE))
|
||
|
{
|
||
|
hr = strErrorString.HrPrintf(
|
||
|
WszLoadString(_Module.GetResourceInstance(), IDS_INVALID_ICON),
|
||
|
strFullPath);
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = UPNP_E_INVALID_ICON;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(FAILED(hr))
|
||
|
{
|
||
|
if(strErrorString.GetLength())
|
||
|
{
|
||
|
strErrorString.HrGetCOM(pszErrorString);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
// normalize error code
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "CValidationManager::ValidateIconFiles(%S)",
|
||
|
*pszErrorString ? *pszErrorString : L"Unspecified");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CValidationManager::ValidateDescriptionDocumentAndReferences(
|
||
|
/*[in]*/ BSTR bstrTemplate,
|
||
|
/*[in, string]*/ const wchar_t * szResourcePath,
|
||
|
/*[out, string]*/ wchar_t ** pszErrorString)
|
||
|
{
|
||
|
CHECK_POINTER(bstrTemplate);
|
||
|
CHECK_POINTER(szResourcePath);
|
||
|
CHECK_POINTER(pszErrorString);
|
||
|
HRESULT hr = S_OK;
|
||
|
*pszErrorString = NULL;
|
||
|
|
||
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = ValidateDescriptionDocument(bstrTemplate, pszErrorString);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
IXMLDOMDocumentPtr pDoc;
|
||
|
IXMLDOMNodePtr pRootNode;
|
||
|
|
||
|
hr = HrGetDocumentAndRootNode(bstrTemplate, pDoc, pRootNode);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = ValidateServiceDescriptions(szResourcePath, pRootNode,
|
||
|
pszErrorString);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = ValidateIconFiles(szResourcePath, pRootNode,
|
||
|
pszErrorString);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidValidate, FAL, hr, FALSE, "CValidationManager::ValidateDescriptionDocumentAndReferences(%S)",
|
||
|
*pszErrorString ? *pszErrorString : L"Unspecified");
|
||
|
return hr;
|
||
|
}
|
||
|
|