windows-nt/Source/XPSP1/NT/base/win32/fusion/sxs/pcmreader.cpp

628 lines
15 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++ /*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
pcmreader.cpp
Abstract:
implementation of PrecompiledManifestReader
Author:
Xiaoyu Wu (xiaoyuw) June 2000
Revision History:
--*/
#include "stdinc.h"
#include "pcm.h"
/* main function of this class
pwcText in XML_NODE_INFO is not allocated in the code because we use file mapping
*/
HRESULT
CPrecompiledManifestReader::InvokeNodeFactory(PCWSTR pcmFileName, IXMLNodeFactory * pXMLNodeFactory)
{
HRESULT hr = NOERROR;
PCMHeader pcmHeader;
PCM_RecordHeader pcmRecordHeader;
typedef XML_NODE_INFO* PXML_NODE_INFO;
PXML_NODE_INFO* ppNodes = NULL; // array of PXML_NODE_INFO
XML_NODE_INFO* pXMLData = NULL;
ULONG i, j;
BOOL fEmpty = FALSE;
if ((!pcmFileName) || (!pXMLNodeFactory))
return E_INVALIDARG;
hr = OpenForRead(pcmFileName);
if (FAILED(hr))
goto Exit;
hr = ReadPCMHeader(&pcmHeader);
if (FAILED(hr))
goto Exit;
if ( pcmHeader.iVersion != 1) { // wrong version number
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS.DLL: Wrong Version of Precompiled manifest file %S in %S()\n", pcmFileName, __FUNCTION__);
hr = E_FAIL;
goto Exit;
}
// by allocate the maximum PXML_NODE_INFO, this space would be reused
ppNodes = FUSION_NEW_ARRAY(PXML_NODE_INFO, pcmHeader.usMaxNodeCount);
if (!ppNodes) {
hr = E_OUTOFMEMORY;
goto Exit;
}
pXMLData = FUSION_NEW_ARRAY(XML_NODE_INFO, pcmHeader.usMaxNodeCount);
if (!pXMLData){
hr = E_OUTOFMEMORY;
goto Exit;
}
memset(pXMLData, 0, sizeof(XML_NODE_INFO)*pcmHeader.usMaxNodeCount);
// setup the pointer array and data
for (i=0;i<pcmHeader.usMaxNodeCount; i++)
ppNodes[i] = &pXMLData[i];
for ( i=0; i<pcmHeader.ulRecordCount; i++) {
hr = ReadPCMRecordHeader(&pcmRecordHeader);
if (FAILED(hr))
goto Exit;
switch(pcmRecordHeader.typeID) {
case ENDCHILDREN_PRECOMP_MANIFEST :
hr = ReadPCMRecord(ppNodes, &pcmRecordHeader, &fEmpty); // fEmpty would be set
break;
case CREATENODE_PRECOMP_MANIFEST :
hr = ReadPCMRecord(ppNodes, &pcmRecordHeader, NULL); // m_ulLineNumber would be Set
break;
case BEGINCHILDREN_PRECOMP_MANIFEST :
hr = ReadPCMRecord(ppNodes, &pcmRecordHeader, NULL);
break;
default:
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS.DLL: %S() failed for invalid typeID in PCM Record", __FUNCTION__);
hr = E_UNEXPECTED;
} // end of swtich
if (FAILED(hr))
goto Exit;
switch (pcmRecordHeader.typeID){
case CREATENODE_PRECOMP_MANIFEST:
hr = pXMLNodeFactory->CreateNode(this, NULL, (USHORT)(pcmRecordHeader.NodeCount), ppNodes);
// "this" is passed in CreateNode because it has implemented IXMLNodeSource
break;
case BEGINCHILDREN_PRECOMP_MANIFEST:
hr = pXMLNodeFactory->BeginChildren(NULL, *ppNodes);
break;
case ENDCHILDREN_PRECOMP_MANIFEST :
hr = pXMLNodeFactory->EndChildren(NULL, fEmpty, *ppNodes);
break;
default:
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS.DLL: %S() failed for invalid typeID in PCM Record", __FUNCTION__);
hr = E_UNEXPECTED;
break;
}// end of switch
if ( FAILED(hr))
goto Exit;
} // end of for
hr = Close();
if ( FAILED(hr))
goto Exit;
hr = NOERROR;
Exit:
if (pXMLData)
{
FUSION_DELETE_ARRAY(pXMLData);
pXMLData = NULL;
}
if (ppNodes)
{
FUSION_DELETE_ARRAY(ppNodes);
ppNodes = NULL;
}
return hr;
}
// helper functions
HRESULT
CPrecompiledManifestReader::ReadPCMHeader(PCMHeader* pHeader)
{
HRESULT hr = NOERROR;
if ( ! pHeader )
return E_INVALIDARG;
ASSERT(m_lpMapAddress);
hr = this->Read((PVOID)pHeader, sizeof(PCMHeader), NULL);
if ( FAILED(hr))
goto Exit;
if ( pHeader->iVersion != 1 ){ // wrong file header, stop
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS.DLL: Wrong Version of Precompiled manifest file in %S()\n", __FUNCTION__);
hr = E_UNEXPECTED;
goto Exit;
}
hr = NOERROR;
Exit:
return hr;
}
HRESULT
CPrecompiledManifestReader::ReadPCMRecordHeader(PCM_RecordHeader * pHeader)
{
HRESULT hr = NOERROR;
if (!pHeader)
return E_INVALIDARG;
ASSERT(m_lpMapAddress);
return this->Read((PVOID)pHeader, sizeof(PCM_RecordHeader), NULL);
}
inline void FromPCMXMLNodeToXMLNode(XML_NODE_INFO * pNode, PCM_XML_NODE_INFO * pPCMNode)
{
ASSERT(pNode && pPCMNode);
pNode->dwSize = pPCMNode->dwSize;
pNode->dwType = pPCMNode->dwType;
pNode->dwSubType = pPCMNode->dwSubType;
pNode->fTerminal = pPCMNode->fTerminal;
pNode->ulLen = pPCMNode->ulLen;
pNode->ulNsPrefixLen= pPCMNode->ulNsPrefixLen;
pNode->pwcText = NULL;
return;
}
HRESULT
CPrecompiledManifestReader::ReadPCMRecord(XML_NODE_INFO ** ppNodes,
PCM_RecordHeader * pRecordHeader, PVOID param)
{
HRESULT hr = NOERROR;
ULONG i, strOffset;
PVOID pData, ptr;
PCM_XML_NODE_INFO pcmNode;
if ( !ppNodes || !pRecordHeader)
return E_INVALIDARG;
// point to the data in the mapped file
pData = (BYTE *)m_lpMapAddress + m_dwFilePointer;
switch (pRecordHeader->typeID){
default:
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS.DLL: %S() failed for invalid typeID in PCM Record", __FUNCTION__);
hr = E_UNEXPECTED;
goto Exit;
break;
case CREATENODE_PRECOMP_MANIFEST:
memcpy(PVOID(&m_ulLineNumberFromCreateNodeRecord), (BYTE *)pData + pRecordHeader->NodeCount * sizeof(PCM_XML_NODE_INFO), sizeof(ULONG));
break;
case BEGINCHILDREN_PRECOMP_MANIFEST:
break;
case ENDCHILDREN_PRECOMP_MANIFEST :
ASSERT(param);
memcpy(param, (BYTE *)pData + pRecordHeader->NodeCount * sizeof(PCM_XML_NODE_INFO), sizeof(BOOL));
break;
} // end of switch
ptr = pData;
for (i=0; i< pRecordHeader->NodeCount; i++) {
//memcpy((PVOID)ppNodes[i], ptr, sizeof(PCM_XML_NODE_INFO));
memcpy((PVOID)&pcmNode, ptr, sizeof(PCM_XML_NODE_INFO));
FromPCMXMLNodeToXMLNode(ppNodes[i], &pcmNode); // void func
// reset pwcText
strOffset=pcmNode.offset;
ppNodes[i]->pwcText = (WCHAR*)((BYTE *)pData + strOffset);
ppNodes[i]->pNode = NULL;
ppNodes[i]->pReserved = NULL;
ptr = (BYTE *)ptr + sizeof(PCM_XML_NODE_INFO);
}
// reset the pointer of file
m_dwFilePointer += pRecordHeader->RecordSize;
hr = NOERROR;
Exit:
return hr;
}
HRESULT
CPrecompiledManifestReader::Close()
{
HRESULT hr = NOERROR;
if (m_lpMapAddress)
if ( ! ::UnmapViewOfFile(m_lpMapAddress)) {
// continue the close process even hr is not NOERROR
hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
}
if (m_hFileMapping != INVALID_HANDLE_VALUE)
if ( ! ::CloseHandle(m_hFileMapping)) {
// UnmapViewOfFile is done successfully
if ( hr == NOERROR )
hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
}
if (m_hFile != INVALID_HANDLE_VALUE)
if ( ! ::CloseHandle(m_hFile)) {
// UnmapViewOfFile and CloseHandle(filemapping) is done successfully
if ( hr == NOERROR )
hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
}
if ( FAILED(hr))
goto Exit;
this->Reset();
hr = NOERROR;
Exit:
return hr;
}
VOID CPrecompiledManifestReader::Reset()
{
m_lpMapAddress = NULL;
m_hFileMapping = INVALID_HANDLE_VALUE;
m_hFile = INVALID_HANDLE_VALUE;
m_dwFilePointer = 0;
return;
}
HRESULT
CPrecompiledManifestReader::OpenForRead(
PCWSTR pszPath,
DWORD dwShareMode,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes
)
{
HRESULT hr = NOERROR;
if (pszPath == NULL)
return E_INVALIDARG;
if (m_hFile != INVALID_HANDLE_VALUE){
hr = E_UNEXPECTED;
goto Exit;
}
m_hFile = ::CreateFileW(
pszPath,
GENERIC_READ,
dwShareMode,
NULL,
dwCreationDisposition,
dwFlagsAndAttributes,
NULL);
if (m_hFile == INVALID_HANDLE_VALUE){
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS.DLL: %S() failed; GetLastError() = %d\n", __FUNCTION__, ::FusionpGetLastWin32Error());
hr = E_UNEXPECTED;
goto Exit;
}
m_dwFileSize = GetFileSize(m_hFile, NULL);
if ( m_dwFileSize== INVALID_FILE_SIZE ) {
::FusionpDbgPrintEx(
FUSION_DBG_LEVEL_ERROR,
"SXS.DLL: %S() call GetFileSize failed, GetLastError() = %d\n", __FUNCTION__, ::FusionpGetLastWin32Error());
hr = E_UNEXPECTED;
goto Exit;
}
// open filemapping
ASSERT(m_hFileMapping == INVALID_HANDLE_VALUE);
if (m_hFileMapping != INVALID_HANDLE_VALUE){
hr = E_UNEXPECTED;
goto Exit;
}
m_hFileMapping = ::CreateFileMappingW(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (m_hFileMapping == INVALID_HANDLE_VALUE){
hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
goto Exit;
}
// map view of file
ASSERT(m_lpMapAddress == NULL);
if ( m_lpMapAddress ) {
hr = E_UNEXPECTED;
goto Exit;
}
m_lpMapAddress = MapViewOfFile(m_hFileMapping, FILE_MAP_READ, 0, 0, 0); // mpa the whole file
if (!m_lpMapAddress) {
hr = E_FAIL;
goto Exit;
}
hr = NOERROR;
Exit:
if ( FAILED(hr))
Close();
return hr;
}
// IStream methods:
HRESULT
CPrecompiledManifestReader::Read(void *pv, ULONG cb, ULONG *pcbRead)
{
DWORD dwData;
ULONG cbRead;
if (pcbRead)
*pcbRead = 0;
if (!pv)
return E_INVALIDARG;
if ( m_dwFilePointer >= m_dwFileSize ) // read at the file end
return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF);
dwData = m_dwFileSize - m_dwFilePointer;
cbRead = (cb <= dwData) ? cb : dwData;
memcpy(pv, (BYTE *)m_lpMapAddress + m_dwFilePointer, cbRead);
m_dwFilePointer += cbRead;
if (pcbRead)
*pcbRead = cbRead;
return NOERROR;
}
HRESULT
CPrecompiledManifestReader::Write(void const *pv, ULONG cb, ULONG *pcbWritten)
{
if (pcbWritten)
*pcbWritten = 0;
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
{
if (plibNewPosition)
plibNewPosition->QuadPart = 0;
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::SetSize(ULARGE_INTEGER libNewSize)
{
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
{
if (pcbWritten)
pcbWritten->QuadPart = 0;
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::Commit(DWORD grfCommitFlags)
{
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::Revert()
{
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
{
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
{
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::Clone(IStream **ppIStream)
{
if ( ppIStream )
*ppIStream = NULL;
ASSERT(FALSE);
return E_NOTIMPL;
}
// IXMLNodeSource methods, only GetLineNumber are implemented got PCM purpose
HRESULT
CPrecompiledManifestReader::SetFactory(IXMLNodeFactory *pNodeFactory)
{
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::GetFactory(IXMLNodeFactory** ppNodeFactory)
{
if (ppNodeFactory)
*ppNodeFactory = NULL;
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::Abort(BSTR bstrErrorInfo)
{
ASSERT(FALSE);
return E_NOTIMPL;
}
ULONG
CPrecompiledManifestReader::GetLineNumber(void)
{
ASSERT(m_ulLineNumberFromCreateNodeRecord != (ULONG)-1);
ULONG tmp = m_ulLineNumberFromCreateNodeRecord;
// do not reset it to be (-1) because the caller may call this function more than once
//m_ulLineNumberFromCreateNodeRecord = (ULONG)-1;
return tmp;
}
ULONG
CPrecompiledManifestReader::GetLinePosition(void)
{
ASSERT(FALSE);
return ULONG(-1);
}
ULONG
CPrecompiledManifestReader::GetAbsolutePosition(void)
{
ASSERT(FALSE);
return ULONG(-1);
}
HRESULT
CPrecompiledManifestReader::GetLineBuffer(const WCHAR **ppwcBuf, ULONG *pulLen, ULONG *pulStartPos)
{
if (ppwcBuf)
*ppwcBuf = NULL;
if (pulLen)
* pulLen = 0;
if (pulStartPos)
*pulStartPos = NULL;
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::GetLastError(void)
{
ASSERT(FALSE);
return E_NOTIMPL;
}
HRESULT
CPrecompiledManifestReader::GetErrorInfo(BSTR *pbstrErrorInfo)
{
ASSERT(FALSE);
return E_NOTIMPL;
}
ULONG
CPrecompiledManifestReader::GetFlags()
{
ASSERT(FALSE);
return ULONG(-1);
}
HRESULT
CPrecompiledManifestReader::GetURL(const WCHAR **ppwcBuf)
{
if (ppwcBuf)
*ppwcBuf = NULL;
ASSERT(FALSE);
return E_NOTIMPL;
}
// IUnknown method implementation
ULONG
CPrecompiledManifestReader::AddRef()
{
ULONG ulResult = ::InterlockedIncrement((LONG *) &m_cRef);
return ulResult;
}
ULONG
CPrecompiledManifestReader::Release()
{
ULONG ulResult = ::InterlockedDecrement((LONG *) &m_cRef);
if (ulResult == 0 )
{
FUSION_DELETE_SINGLETON(this);
}
return ulResult;
}
HRESULT
CPrecompiledManifestReader::QueryInterface(REFIID riid, LPVOID *ppvObj)
{
HRESULT hr = NOERROR;
IUnknown *pIUnknown = NULL;
if (ppvObj != NULL)
*ppvObj = NULL;
if (ppvObj == NULL){
hr = E_POINTER;
goto Exit;
}
if (riid == __uuidof(this))
*ppvObj = this;
else if ((riid == IID_IUnknown) ||
(riid == IID_ISequentialStream) ||
(riid == IID_IStream))
pIUnknown = static_cast<IStream *>(this);
else if ( riid == IID_IXMLNodeSource )
pIUnknown = static_cast<IXMLNodeSource *>(this);
else
{
hr = E_NOINTERFACE;
goto Exit;
}
AddRef();
if (pIUnknown != NULL)
*ppvObj = pIUnknown;
hr = NOERROR;
Exit:
return hr;
}