467 lines
12 KiB
C++
467 lines
12 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
pcmwriter.cpp
|
||
|
|
||
|
Abstract:
|
||
|
implementation of Precompiled manifest writer
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Xiaoyu Wu (xiaoyuw) June 2000
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "stdinc.h"
|
||
|
#include "pcm.h"
|
||
|
#include "nodefactory.h"
|
||
|
//helper APIs
|
||
|
HRESULT CPrecompiledManifestWriter::SetFactory(IXMLNodeFactory *pNodeFactory)
|
||
|
{
|
||
|
if (! pNodeFactory)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
m_pNodeFactory = pNodeFactory;
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
HRESULT CPrecompiledManifestWriter::Close()
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
if (m_pFileStream)
|
||
|
hr = m_pFileStream->Close(m_ulRecordCount, m_usMaxNodeCount);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
HRESULT CPrecompiledManifestWriter::Initialize(PCWSTR pcmFileName)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
CStringBuffer buffFileName;
|
||
|
|
||
|
if ( ! pcmFileName )
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
hr = buffFileName.Assign(pcmFileName, ::wcslen(pcmFileName));
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
// Initialize() is assumed to be called only once
|
||
|
if (m_pFileStream != NULL){
|
||
|
::FusionpDbgPrintEx(
|
||
|
FUSION_DBG_LEVEL_ERROR,
|
||
|
"SXS.DLL: %S is called more than once\n", __FUNCTION__);
|
||
|
|
||
|
return E_UNEXPECTED;
|
||
|
}
|
||
|
|
||
|
m_pFileStream = new CPrecompiledManifestWriterStream;
|
||
|
if ( !m_pFileStream )
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
hr = m_pFileStream->SetSink(buffFileName);
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr = WritePCMHeader();
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr= NOERROR;
|
||
|
|
||
|
Exit:
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
|
||
|
// we assume that this pStream is initialized by using SetSink....
|
||
|
HRESULT CPrecompiledManifestWriter::SetWriterStream(CPrecompiledManifestWriterStream * pSinkedStream)
|
||
|
{
|
||
|
if ( ! pSinkedStream )
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
ASSERT(pSinkedStream->IsSinkedStream() == TRUE);
|
||
|
|
||
|
m_pFileStream = pSinkedStream;
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
// write helper APIs
|
||
|
HRESULT CPrecompiledManifestWriter::GetPCMRecordSize(XML_NODE_INFO ** ppNodeInfo, USHORT iNodeCount, ULONG * pSize)
|
||
|
{
|
||
|
ULONG ulSize = 0 ;
|
||
|
XML_NODE_INFO *pNode = NULL;
|
||
|
USHORT i = 0 ;
|
||
|
ULONG ulSingleRecordSize = offsetof(XML_NODE_INFO, pNode);
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
if ( pSize)
|
||
|
*pSize = 0 ;
|
||
|
|
||
|
if ((!pSize) || (!ppNodeInfo) || (!*ppNodeInfo))
|
||
|
return E_INVALIDARG;
|
||
|
// validate ppNodeInfo
|
||
|
for (i=0;i<iNodeCount;i++)
|
||
|
if (!ppNodeInfo[i])
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*pSize = 0;
|
||
|
for ( i=0; i < iNodeCount; i++){
|
||
|
pNode = ppNodeInfo[i];
|
||
|
ASSERT(pNode);
|
||
|
//ulSize += ulSingleRecordSize = sizeof(XML_NODE_INFO)- sizeof(PVOID) - sizeof(PVOID);
|
||
|
ulSize += ulSingleRecordSize = offsetof(XML_NODE_INFO, pNode);
|
||
|
ulSize += pNode->ulLen * sizeof(WCHAR);
|
||
|
}
|
||
|
if ( pSize)
|
||
|
*pSize = ulSize;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CPrecompiledManifestWriter::WritePCMHeader()
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
PCMHeader pcmHeader;
|
||
|
|
||
|
pcmHeader.iVersion = 1;
|
||
|
pcmHeader.ulRecordCount = 0 ;
|
||
|
pcmHeader.usMaxNodeCount = 0 ;
|
||
|
|
||
|
hr = m_pFileStream->WriteWithDelay((PVOID)&(pcmHeader), sizeof(PCMHeader), NULL);
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
hr = NOERROR;
|
||
|
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CPrecompiledManifestWriter::WritePCMRecordHeader(PCM_RecordHeader * pHeader)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(m_pFileStream);
|
||
|
if ( ! pHeader)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
hr = m_pFileStream->WriteWithDelay((PVOID)(pHeader), sizeof(PCM_RecordHeader), NULL);
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
inline void FromXMLNodeToPCMXMLNode(PCM_XML_NODE_INFO *pPCMNode, XML_NODE_INFO *pNode)
|
||
|
{
|
||
|
ASSERT(pPCMNode && pNode);
|
||
|
|
||
|
pPCMNode->dwSize = pNode->dwSize;
|
||
|
pPCMNode->dwType = pNode->dwType ;
|
||
|
pPCMNode->dwSubType = pNode->dwSubType ;
|
||
|
pPCMNode->fTerminal = pNode->fTerminal ;
|
||
|
pPCMNode->ulLen = pNode->ulLen ;
|
||
|
pPCMNode->ulNsPrefixLen = pNode->ulNsPrefixLen ;
|
||
|
pPCMNode->offset = 0 ;
|
||
|
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
HRESULT CPrecompiledManifestWriter::WritePCMXmlNodeInfo(XML_NODE_INFO ** ppNodeInfo, USHORT iNodeCount, RECORD_TYPE_PRECOMP_MANIFEST typeID, PVOID param)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
ULONG offset ;
|
||
|
USHORT i;
|
||
|
PCM_XML_NODE_INFO pcmNode;
|
||
|
XML_NODE_INFO * pNode = NULL ;
|
||
|
USHORT uTextAddr;
|
||
|
USHORT uTextOffset;
|
||
|
ULONG cbWritten;
|
||
|
LPWSTR *ppText = NULL;
|
||
|
ULONG *pcbLen = NULL;
|
||
|
LPWSTR pstr;
|
||
|
ULONG ulLen;
|
||
|
|
||
|
if ((!ppNodeInfo) || (!*ppNodeInfo))
|
||
|
return E_INVALIDARG;
|
||
|
if (!((typeID == ENDCHILDREN_PRECOMP_MANIFEST) || (typeID == BEGINCHILDREN_PRECOMP_MANIFEST) ||
|
||
|
(typeID == CREATENODE_PRECOMP_MANIFEST)))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if (!m_pFileStream)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
//uTextAddr = sizeof(PCM_RecordHeader) + NodeCount * sizeof(PCM_XML_NODE_INFO);
|
||
|
// RecordHeader is read before the boby(XML_NODE_INFO) is read
|
||
|
uTextAddr = iNodeCount * sizeof(PCM_XML_NODE_INFO);
|
||
|
uTextOffset = 0;
|
||
|
|
||
|
|
||
|
if (typeID == ENDCHILDREN_PRECOMP_MANIFEST) // param1 is fEmpty;
|
||
|
uTextAddr += sizeof(BOOL);
|
||
|
else if (typeID == CREATENODE_PRECOMP_MANIFEST) // param1 = linenumber
|
||
|
uTextAddr += sizeof(ULONG);
|
||
|
|
||
|
if ( iNodeCount == 1) { // for BeginChildren and EndChildren
|
||
|
ppText = &pstr;
|
||
|
pcbLen = &ulLen;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ppText = FUSION_NEW_ARRAY(LPWSTR, iNodeCount);
|
||
|
if (!ppText) {
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
pcbLen = FUSION_NEW_ARRAY(ULONG, iNodeCount);
|
||
|
if (!pcbLen ){
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto Exit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// write all records
|
||
|
for (i=0; i<iNodeCount; i++) {
|
||
|
pNode = ppNodeInfo[i];
|
||
|
if (!pNode) {
|
||
|
hr = E_FAIL;
|
||
|
goto Exit;
|
||
|
}
|
||
|
ppText[i] = (LPWSTR)(pNode->pwcText) ;
|
||
|
pcbLen[i] = pNode->ulLen * sizeof(WCHAR);
|
||
|
|
||
|
//pPCMNode = static_cast<PCM_XML_NODE_INFO *>(pNode);
|
||
|
FromXMLNodeToPCMXMLNode(&pcmNode, pNode); // void function
|
||
|
pcmNode.offset = uTextAddr + uTextOffset;
|
||
|
uTextAddr = uTextAddr + uTextOffset;
|
||
|
uTextOffset = (USHORT)pcmNode.ulLen * sizeof(WCHAR) ;
|
||
|
|
||
|
hr = m_pFileStream->WriteWithDelay((PVOID)&pcmNode, sizeof(PCM_XML_NODE_INFO), &cbWritten);
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if ( typeID == ENDCHILDREN_PRECOMP_MANIFEST) // write fEmpty into the file
|
||
|
hr = m_pFileStream->WriteWithDelay(param, sizeof(BOOL), &cbWritten);
|
||
|
else if ( typeID == CREATENODE_PRECOMP_MANIFEST)
|
||
|
hr = m_pFileStream->WriteWithDelay(param, sizeof(ULONG), &cbWritten);
|
||
|
|
||
|
// write texts in all records
|
||
|
for (i=0; i<iNodeCount; i++) {
|
||
|
hr = m_pFileStream->WriteWithDelay((PVOID)ppText[i], (ULONG)pcbLen[i], &cbWritten);
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
Exit :
|
||
|
|
||
|
if ((ppText) && (ppText != &pstr))
|
||
|
FUSION_DELETE_ARRAY(ppText);
|
||
|
|
||
|
if ( (pcbLen) && ( pcbLen != &ulLen))
|
||
|
FUSION_DELETE_ARRAY(pcbLen);
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// write APIs
|
||
|
HRESULT CPrecompiledManifestWriter::WritePrecompiledManifestRecord(RECORD_TYPE_PRECOMP_MANIFEST typeID,
|
||
|
PVOID pData, USHORT NodeCount, PVOID param)
|
||
|
{
|
||
|
HRESULT hr=NOERROR;
|
||
|
PCM_RecordHeader pcmHeader;
|
||
|
XML_NODE_INFO ** apNodeInfo = NULL ;
|
||
|
|
||
|
|
||
|
if (!pData)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
// validate typeID and param
|
||
|
if ((typeID == ENDCHILDREN_PRECOMP_MANIFEST) || (typeID == CREATENODE_PRECOMP_MANIFEST)){
|
||
|
if (!param)
|
||
|
return E_INVALIDARG;
|
||
|
}else if (typeID != BEGINCHILDREN_PRECOMP_MANIFEST)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
apNodeInfo = (XML_NODE_INFO **)pData;
|
||
|
|
||
|
pcmHeader.typeID = typeID;
|
||
|
hr = GetPCMRecordSize(apNodeInfo, NodeCount, &pcmHeader.RecordSize) ; // the size contains each string's length
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
if (typeID == ENDCHILDREN_PRECOMP_MANIFEST) // param1 is fEmpty;
|
||
|
pcmHeader.RecordSize += sizeof(BOOL);
|
||
|
else if (typeID == CREATENODE_PRECOMP_MANIFEST) // param1 is Current Line number
|
||
|
pcmHeader.RecordSize += sizeof(ULONG);
|
||
|
|
||
|
pcmHeader.NodeCount = NodeCount;
|
||
|
|
||
|
hr = WritePCMRecordHeader(&pcmHeader);
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr = WritePCMXmlNodeInfo(apNodeInfo, NodeCount, typeID, param);
|
||
|
if (FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
m_ulRecordCount ++ ;
|
||
|
if ( NodeCount > m_usMaxNodeCount )
|
||
|
m_usMaxNodeCount = NodeCount;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// IUnknown
|
||
|
ULONG CPrecompiledManifestWriter::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement((LONG*) &m_cRef);
|
||
|
}
|
||
|
|
||
|
ULONG CPrecompiledManifestWriter::Release()
|
||
|
{
|
||
|
ULONG lRet = InterlockedDecrement ((PLONG)&m_cRef);
|
||
|
if (!lRet)
|
||
|
FUSION_DELETE_SINGLETON(this);
|
||
|
return lRet;
|
||
|
}
|
||
|
|
||
|
HRESULT CPrecompiledManifestWriter::QueryInterface(REFIID riid, LPVOID *ppv)
|
||
|
{
|
||
|
if (riid == __uuidof(this))
|
||
|
{
|
||
|
*ppv = this;
|
||
|
}
|
||
|
else if (riid == IID_IUnknown
|
||
|
|| riid == IID_IXMLNodeFactory)
|
||
|
{
|
||
|
*ppv = static_cast<IXMLNodeFactory*> (this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppv = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// IXMLNodeFactory methods:
|
||
|
HRESULT CPrecompiledManifestWriter::NotifyEvent(IXMLNodeSource *pSource, XML_NODEFACTORY_EVENT iEvt)
|
||
|
{
|
||
|
ASSERT(m_pNodeFactory);
|
||
|
// no hr-canonicalization is needed because these two nodefactories are supposed to return the correct range of values
|
||
|
return m_pNodeFactory->NotifyEvent(pSource, iEvt);
|
||
|
}
|
||
|
|
||
|
HRESULT CPrecompiledManifestWriter::BeginChildren(IXMLNodeSource *pSource, XML_NODE_INFO *pNodeInfo)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
ASSERT(m_pNodeFactory);
|
||
|
hr = m_pNodeFactory->BeginChildren(pSource, pNodeInfo);
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
// write pcm file
|
||
|
hr = WritePrecompiledManifestRecord(BEGINCHILDREN_PRECOMP_MANIFEST,
|
||
|
&pNodeInfo, 1, NULL);
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CPrecompiledManifestWriter::EndChildren(IXMLNodeSource *pSource, BOOL fEmpty, XML_NODE_INFO *pNodeInfo)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
ASSERT(m_pNodeFactory);
|
||
|
hr = m_pNodeFactory->EndChildren(pSource, fEmpty, pNodeInfo);
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
// write pcm file
|
||
|
hr = WritePrecompiledManifestRecord(ENDCHILDREN_PRECOMP_MANIFEST, &pNodeInfo, 1, &fEmpty);
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CPrecompiledManifestWriter::Error(IXMLNodeSource *pSource, HRESULT hrErrorCode, USHORT cNumRecs, XML_NODE_INFO **apNodeInfo)
|
||
|
{
|
||
|
ASSERT(m_pNodeFactory);
|
||
|
// no hr-canonicalization is needed because these two nodefactories are supposed to return the correct range of values
|
||
|
return m_pNodeFactory->Error(pSource, hrErrorCode, cNumRecs, apNodeInfo);
|
||
|
}
|
||
|
|
||
|
HRESULT CPrecompiledManifestWriter::CreateNode(IXMLNodeSource *pSource, PVOID pNodeParent, USHORT cNumRecs, XML_NODE_INFO **apNodeInfo)
|
||
|
{
|
||
|
ULONG ulLineNumber ;
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
ASSERT(m_pNodeFactory);
|
||
|
if ( ! m_pNodeFactory)
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
hr = m_pNodeFactory->CreateNode(pSource, pNodeParent, cNumRecs, apNodeInfo);
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
ulLineNumber = pSource->GetLineNumber();
|
||
|
hr = WritePrecompiledManifestRecord(CREATENODE_PRECOMP_MANIFEST,
|
||
|
apNodeInfo, cNumRecs, &ulLineNumber);
|
||
|
if ( FAILED(hr))
|
||
|
goto Exit;
|
||
|
|
||
|
hr = NOERROR;
|
||
|
Exit:
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CPrecompiledManifestWriter::Initialize(PACTCTXGENCTX ActCtxGenCtx, PASSEMBLY Assembly,
|
||
|
PACTCTXCTB_ASSEMBLY_CONTEXT AssemblyContext)
|
||
|
{
|
||
|
HRESULT hr = NOERROR;
|
||
|
FN_TRACE_HR(hr);
|
||
|
|
||
|
CSmartRef<CNodeFactory> pNodeFactory;
|
||
|
|
||
|
if (! m_pNodeFactory) {
|
||
|
pNodeFactory = new CNodeFactory;
|
||
|
if (!pNodeFactory) {
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
m_pNodeFactory = pNodeFactory;
|
||
|
}
|
||
|
else {
|
||
|
hr = pNodeFactory.QueryInterfaceFrom(m_pNodeFactory);
|
||
|
ASSERT(SUCCEEDED(hr));
|
||
|
}
|
||
|
|
||
|
IFW32FALSE_EXIT(pNodeFactory->Initialize(ActCtxGenCtx, Assembly, AssemblyContext));
|
||
|
|
||
|
IFCOMFAILED_EXIT(this->SetWriterStream(reinterpret_cast<CPrecompiledManifestWriterStream*>(AssemblyContext->pcmWriterStream));
|
||
|
|
||
|
// this must be called in order for later use
|
||
|
IFCOMFAILED_EXIT(this->WritePCMHeader());
|
||
|
|
||
|
FN_EPILOG
|
||
|
}
|