You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
473 lines
14 KiB
473 lines
14 KiB
#include <windows.h>
|
|
#include <fusenetincludes.h>
|
|
#include <msxml2.h>
|
|
#include <stdio.h>
|
|
#include <md5.h>
|
|
#include "list.h"
|
|
#include "xmlutil.h"
|
|
|
|
|
|
class __declspec(uuid("f6d90f11-9c73-11d3-b32e-00c04f990bb4")) private_MSXML_DOMDocument30;
|
|
|
|
#define HASHLENGTH 32
|
|
#define HASHSTRINGLENGTH HASHLENGTH+1
|
|
#define SAFERELEASE(p) if ((p) != NULL) { (p)->Release(); (p) = NULL; };
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// FormatXML
|
|
// Called recursively.
|
|
// BUGBUG - t-peterf to document why selectNodes should not be used when
|
|
// adding nodes to an existing document.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT FormatXML(IXMLDOMDocument2 *pXMLDoc, IXMLDOMNode *pRootNode, LONG dwLevel)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMNode *pNode=NULL, *pNewNode=NULL;
|
|
IXMLDOMNode *pTextNode1=NULL, *pTextNode2=NULL;
|
|
CString sWhiteSpace1, sWhiteSpace2;
|
|
BOOL bHasChildren = FALSE;
|
|
int i = 0;
|
|
|
|
sWhiteSpace1.Assign(L"\n");
|
|
for (i = 0; i < (dwLevel-1); i++)
|
|
sWhiteSpace1.Append(L"\t");
|
|
|
|
sWhiteSpace2.Assign(L"\n");
|
|
for (i = 0; i < dwLevel; i++)
|
|
sWhiteSpace2.Append(L"\t");
|
|
|
|
hr = pRootNode->get_firstChild(&pNode);
|
|
while(pNode != NULL)
|
|
{
|
|
bHasChildren = TRUE;
|
|
|
|
// create whitespace with one extra tab.
|
|
if(FAILED(CreateXMLTextNode(pXMLDoc, sWhiteSpace2._pwz, &pTextNode2)))
|
|
goto exit;
|
|
|
|
VARIANT varRefNode;
|
|
VariantInit(&varRefNode);
|
|
varRefNode.vt = VT_UNKNOWN;
|
|
V_UNKNOWN(&varRefNode) = pNode;
|
|
|
|
if (FAILED(hr = pRootNode->insertBefore(pTextNode2, varRefNode, &pNewNode)))
|
|
goto exit;
|
|
SAFERELEASE(pNewNode);
|
|
SAFERELEASE(pTextNode2);
|
|
|
|
// Recursively call format on the node.
|
|
if (FAILED(FormatXML(pXMLDoc, pNode, dwLevel+1)))
|
|
goto exit;
|
|
|
|
pNode->get_nextSibling(&pNewNode);
|
|
|
|
SAFERELEASE(pNode);
|
|
pNode = pNewNode;
|
|
|
|
}
|
|
|
|
if (bHasChildren)
|
|
{
|
|
if(FAILED(CreateXMLTextNode(pXMLDoc, sWhiteSpace1._pwz, &pTextNode1)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = pRootNode->appendChild(pTextNode1, &pNewNode)))
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// GetAssemblyNode
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT GetAssemblyNode(IXMLDOMDocument2 *pXMLDoc, IXMLDOMNode **ppAssemblyNode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrtQueryString;
|
|
|
|
IXMLDOMNode *pAssemblyNode=NULL;
|
|
IXMLDOMNodeList *pNodeList = NULL;
|
|
LONG nNodes;
|
|
|
|
bstrtQueryString = ::SysAllocString(L"assembly");
|
|
if (!bstrtQueryString)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
if ((hr = pXMLDoc->selectNodes(bstrtQueryString, &pNodeList)) != S_OK)
|
|
goto exit;
|
|
|
|
hr = pNodeList->get_length(&nNodes);
|
|
if (nNodes > 1)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
|
|
goto exit;
|
|
}
|
|
|
|
if ((hr = pNodeList->get_item(0, &pAssemblyNode)) != S_OK)
|
|
{
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
|
|
*ppAssemblyNode=pAssemblyNode;
|
|
(*ppAssemblyNode)->AddRef();
|
|
|
|
exit:
|
|
if(bstrtQueryString)
|
|
::SysFreeString(bstrtQueryString);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// SetXMLElementAttribute
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CreatePatchManifest(List <LPWSTR> *pPatchedFiles, LPWSTR pwzPatchDir,
|
|
LPWSTR pwzSourceManifestPath, LPWSTR pwzDestManifestPath)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
IXMLDOMDocument2 *pXMLDoc = NULL;
|
|
IXMLDOMElement *pElement=NULL;
|
|
IXMLDOMNode *pNewNode=NULL, *pRoot=NULL, *pPatchNode = NULL, *pSourceAssemblyNode= NULL;
|
|
IAssemblyManifestImport *pSourceManImport = NULL;
|
|
IAssemblyIdentity *pSourceAssemblyId = NULL;
|
|
|
|
LISTNODE pos = NULL;
|
|
CString sPatchFileName, sDestAppBase;
|
|
LPWSTR pwzBuf=NULL;
|
|
BSTR bstrText;
|
|
|
|
sDestAppBase.Assign(pwzDestManifestPath);
|
|
sDestAppBase.RemoveLastElement();
|
|
sDestAppBase.Append(L"\\");
|
|
|
|
//Load the manifest
|
|
if(FAILED(hr = LoadXMLDocument(pwzDestManifestPath, &pXMLDoc)))
|
|
goto exit;
|
|
|
|
//Get the assemblyIdentity of the source assembly
|
|
if((hr = CreateAssemblyManifestImport(&pSourceManImport, pwzSourceManifestPath, NULL, 0)) != S_OK)
|
|
goto exit;
|
|
|
|
if((hr = pSourceManImport->GetAssemblyIdentity(&pSourceAssemblyId)) != S_OK)
|
|
goto exit;
|
|
SAFERELEASE(pSourceManImport);
|
|
|
|
//grab the first child(the only child) as the root node
|
|
if(FAILED(GetAssemblyNode(pXMLDoc, &pRoot)))
|
|
goto exit;
|
|
|
|
//create the Patch node
|
|
if(FAILED(hr = CreateXMLElement(pXMLDoc, L"Patch", &pElement)))
|
|
goto exit;
|
|
|
|
//append to the assembly (root) node
|
|
if (FAILED(hr = pRoot->appendChild((IXMLDOMNode *)pElement, &pPatchNode)))
|
|
goto exit;
|
|
SAFERELEASE(pElement);
|
|
|
|
//create the tempate assemblyIdentity node with blank attributes
|
|
if(FAILED(hr = CreateXMLElement(pXMLDoc, L"SourceAssembly", &pElement)))
|
|
goto exit;
|
|
|
|
//append to the patch node
|
|
if (FAILED(hr = pPatchNode->appendChild((IXMLDOMNode *)pElement, &pSourceAssemblyNode)))
|
|
goto exit;
|
|
SAFERELEASE(pElement);
|
|
|
|
//Create the source assemblyId and append the source assembly node
|
|
if(FAILED(hr = CreateXMLAssemblyIdElement(pXMLDoc, pSourceAssemblyId, &pElement)))
|
|
goto exit;
|
|
|
|
if (FAILED(hr = pSourceAssemblyNode->appendChild((IXMLDOMNode *)pElement, &pNewNode)))
|
|
goto exit;
|
|
SAFERELEASE(pElement);
|
|
SAFERELEASE(pNewNode);
|
|
|
|
//Add all the patchInfo node to the source assembly node
|
|
pos = pPatchedFiles->GetHeadPosition();
|
|
while (pos)
|
|
{
|
|
pwzBuf= pPatchedFiles->GetNext(pos);
|
|
|
|
pwzBuf += sDestAppBase._cc -1;
|
|
|
|
sPatchFileName.Assign(pwzPatchDir + sDestAppBase._cc -1);
|
|
sPatchFileName.Append(pwzBuf);
|
|
sPatchFileName.Append(L"._p");
|
|
|
|
if(FAILED(hr = CreateXMLElement(pXMLDoc, L"PatchInfo", &pElement)))
|
|
goto exit;
|
|
|
|
hr = SetXMLElementAttribute(pElement, L"file", pwzBuf);
|
|
hr = SetXMLElementAttribute(pElement, L"patchfile", sPatchFileName._pwz);
|
|
|
|
if (FAILED(hr = pSourceAssemblyNode->appendChild((IXMLDOMNode *)pElement, &pNewNode)))
|
|
goto exit;
|
|
SAFERELEASE(pElement);
|
|
SAFERELEASE(pNewNode);
|
|
}
|
|
|
|
|
|
hr = FormatXML(pXMLDoc, pRoot, 1);
|
|
hr = SaveXMLDocument(pXMLDoc, pwzDestManifestPath);
|
|
|
|
exit:
|
|
|
|
SAFERELEASE(pXMLDoc)
|
|
SAFERELEASE(pElement)
|
|
SAFERELEASE(pNewNode)
|
|
SAFERELEASE(pRoot)
|
|
SAFERELEASE(pPatchNode)
|
|
SAFERELEASE(pSourceAssemblyNode)
|
|
SAFERELEASE(pSourceManImport)
|
|
SAFERELEASE(pSourceAssemblyId);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// SaveXMLDocument
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT SaveXMLDocument(IXMLDOMDocument2 *pXMLDoc, LPWSTR pwzDocumentName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CString sDocumentName;
|
|
BSTR bstrFileName = NULL;
|
|
VARIANT varFileName;
|
|
|
|
// Save the manifest to a file
|
|
sDocumentName.Assign(pwzDocumentName);
|
|
|
|
bstrFileName = ::SysAllocString(sDocumentName._pwz);
|
|
if (!bstrFileName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
VariantInit(&varFileName);
|
|
varFileName.vt = VT_BSTR;
|
|
V_BSTR(&varFileName) = bstrFileName;
|
|
|
|
hr = pXMLDoc->save(varFileName);
|
|
|
|
exit:
|
|
if(bstrFileName)
|
|
::SysFreeString(bstrFileName);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//LoadXMLTemplate
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT LoadXMLDocument(LPWSTR pwzTemplatePath, IXMLDOMDocument2 **ppXMLDoc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMDocument2 *pXMLDoc=NULL;
|
|
VARIANT varFileName;
|
|
VARIANT_BOOL varBool;
|
|
BSTR bstrFileName;
|
|
|
|
bstrFileName = ::SysAllocString(pwzTemplatePath);
|
|
if (!bstrFileName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
VariantInit(&varFileName);
|
|
varFileName.vt = VT_BSTR;
|
|
V_BSTR(&varFileName) = bstrFileName;
|
|
|
|
if(FAILED(hr = CoCreateInstance(__uuidof(private_MSXML_DOMDocument30),
|
|
NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&pXMLDoc)))
|
|
goto exit;
|
|
|
|
// Load synchronously
|
|
if (FAILED(hr = pXMLDoc->put_async(VARIANT_FALSE)))
|
|
goto exit;
|
|
|
|
if ((hr = pXMLDoc->load(varFileName, &varBool)) != S_OK)
|
|
goto exit;
|
|
|
|
*ppXMLDoc=pXMLDoc;
|
|
(*ppXMLDoc)->AddRef();
|
|
|
|
exit:
|
|
if(bstrFileName)
|
|
::SysFreeString(bstrFileName);
|
|
SAFERELEASE(pXMLDoc);
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CreateXMLElement
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CreateXMLTextNode(IXMLDOMDocument2 *pXMLDoc, LPWSTR pwzText, IXMLDOMNode **ppNode)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMNode *pNode = NULL;
|
|
BSTR bstrText = NULL;
|
|
|
|
bstrText = ::SysAllocString(pwzText);
|
|
if (!bstrText)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
if(FAILED(pXMLDoc->createTextNode(bstrText, (IXMLDOMText**)&pNode)))
|
|
goto exit;
|
|
|
|
*ppNode = pNode;
|
|
(*ppNode)->AddRef();
|
|
|
|
exit:
|
|
if (bstrText)
|
|
::SysFreeString(bstrText);
|
|
|
|
SAFERELEASE (pNode);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CreateXMLElement
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CreateXMLElement(IXMLDOMDocument2 *pXMLDoc, LPWSTR pwzElementName,
|
|
IXMLDOMElement **ppElement)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
BSTR bstrElementName = NULL;
|
|
IXMLDOMElement *pElement = NULL;
|
|
IXMLDOMNode *pNode =NULL, *pNewNode = NULL;
|
|
|
|
bstrElementName = ::SysAllocString(pwzElementName);
|
|
if (!bstrElementName)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
// NOTENOTE - createElement doesn't append the node to the doc
|
|
// so we're just using pXMLDoc for convenience of calling create.
|
|
if(FAILED(hr = pXMLDoc->createElement(bstrElementName, &pElement)))
|
|
goto exit;
|
|
|
|
*ppElement = pElement;
|
|
(*ppElement)->AddRef();
|
|
|
|
exit:
|
|
|
|
if (bstrElementName)
|
|
::SysFreeString(bstrElementName);
|
|
|
|
SAFERELEASE(pNode);
|
|
SAFERELEASE(pNewNode);
|
|
SAFERELEASE(pElement);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// SetXMLElementAttribute
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT SetXMLElementAttribute(IXMLDOMElement *pElement, LPWSTR pwzAttributeName,
|
|
LPWSTR pwzAttributeValue)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
BSTR bstrAttributeName = NULL, bstrAttributeValue = NULL;
|
|
VARIANT varAttributeValue;
|
|
|
|
bstrAttributeName = ::SysAllocString(pwzAttributeName);
|
|
bstrAttributeValue = ::SysAllocString(pwzAttributeValue);
|
|
if (!bstrAttributeName || (!bstrAttributeValue && pwzAttributeValue))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
VariantInit(&varAttributeValue);
|
|
varAttributeValue.vt = VT_BSTR;
|
|
V_BSTR(&varAttributeValue) = bstrAttributeValue;
|
|
|
|
hr = pElement->setAttribute(bstrAttributeName, varAttributeValue);
|
|
|
|
exit:
|
|
|
|
if (bstrAttributeName)
|
|
::SysFreeString(bstrAttributeName);
|
|
|
|
if (bstrAttributeValue)
|
|
::SysFreeString(bstrAttributeValue);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CreateXMLAssemblyIdElement
|
|
/////////////////////////////////////////////////////////////////////////
|
|
HRESULT CreateXMLAssemblyIdElement(IXMLDOMDocument2 *pXMLDoc, IAssemblyIdentity *pAssemblyId,
|
|
IXMLDOMElement **ppElement)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMElement *pASMIdElement = NULL;
|
|
LPWSTR pwzBuf = NULL;
|
|
DWORD ccBuf = 0;
|
|
CString sBuffer;
|
|
|
|
LPWSTR rpwzAttrNames[6] =
|
|
{
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_TYPE,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PROCESSOR_ARCHITECTURE,
|
|
SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_LANGUAGE,
|
|
};
|
|
|
|
//Create assemblyIdentity Element
|
|
if(FAILED(hr=CreateXMLElement(pXMLDoc, L"assemblyIdentity", &pASMIdElement)))
|
|
goto exit;
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
// BUGBUG - eventually, when we add support for type the only guy which
|
|
// is optional is the public key token.
|
|
if (FAILED(hr = pAssemblyId->GetAttribute(rpwzAttrNames[i], &pwzBuf, &ccBuf))
|
|
&& hr != HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
|
|
goto exit;
|
|
else if (hr == S_OK)
|
|
{
|
|
sBuffer.TakeOwnership(pwzBuf, ccBuf);
|
|
hr = SetXMLElementAttribute(pASMIdElement, rpwzAttrNames[i], sBuffer._pwz);
|
|
}
|
|
else
|
|
hr = S_OK;
|
|
}
|
|
|
|
|
|
*ppElement = pASMIdElement;
|
|
(*ppElement)->AddRef();
|
|
|
|
|
|
exit:
|
|
SAFERELEASE(pASMIdElement);
|
|
|
|
return hr;
|
|
}
|
|
|