|
|
#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; }
|