📄 xpsarch.cpp
字号:
/*++
Copyright (c) 2005 Microsoft Corporation
All rights reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
File Name:
xpsarch.cpp
Abstract:
Implementation of the XPS archive class. This class is responsible for providing
an interface to clients that removes the potentially interleaved nature of an
XPS document. This allows clients to manipulate files using the parts full name
instead of having to worry about the semantics of interleaved parts.
--*/
#include "precomp.h"
#include "debug.h"
#include "globals.h"
#include "xdstring.h"
#include "xdexcept.h"
#include "xpsarch.h"
typedef HRESULT (*GetClassObject)(REFCLSID, REFIID, LPVOID FAR*);
static PCSTR szPartNameFormatString = "%s/[%i].piece";
static PCSTR szLastPartNameFormatString = "%s/[%i].last.piece";
//
// GUIDs for the archive handler
//
CONST GUID CLSID_PKArchiveHandler = {0x5a0f4115, 0xd4d3, 0x401e, {0x80, 0x71, 0xa4, 0x40, 0xd6, 0xd0, 0x70, 0x92}};
CONST GUID IID_IPKArchive = {0xbdbbdf56, 0xc742, 0x4efd, {0x80, 0x75, 0xaf, 0x2c, 0x7b, 0x24, 0x7f, 0x38}};
/*++
Routine Name:
CXPSArchive::CXPSArchive
Routine Description:
CXPSArchive class constructor
Arguments:
pReadStream - Pointer to the print read stream
pWriteStream - Pointer to the print write stream
Return Value:
None
Throws CXDException(HRESULT) on an error
--*/
CXPSArchive::CXPSArchive(
__in IPrintReadStream* pReadStream,
__in IPrintWriteStream* pWriteStream
) :
m_pWriteStream(pWriteStream),
m_pPkArchive(NULL),
m_hPkArch(NULL)
{
HRESULT hr = S_OK;
//
// Get the current directory to load the pk archive library
//
DWORD cchName = 0;
TCHAR* szFileName = new TCHAR[MAX_PATH];
if (SUCCEEDED(hr = CHECK_POINTER(szFileName, E_OUTOFMEMORY)))
{
cchName = GetModuleFileName(g_hInstance, szFileName, MAX_PATH);
if (cchName == 0)
{
hr = GetLastErrorAsHResult();
}
}
if (SUCCEEDED(hr) &&
cchName > 0)
{
//
// Remove the filespec
//
PathRemoveFileSpec(szFileName);
try
{
//
// Append the PK archive DLL name
//
CStringXD cstrPath(szFileName);
cstrPath += TEXT("\\pkarch.dll");
//
// Try to load the PK archive DLL
//
m_hPkArch = LoadLibrary(cstrPath);
}
catch (CXDException& e)
{
hr = e;
}
}
if (szFileName != NULL)
{
delete[] szFileName;
szFileName = NULL;
}
if (SUCCEEDED(hr))
{
//
// Get DllGetClassObject from the PK archive and instantiate the PK archive handler
//
if (m_hPkArch != NULL)
{
GetClassObject pfnGetClassObject = reinterpret_cast<GetClassObject>(GetProcAddress(m_hPkArch, "DllGetClassObject"));
if (SUCCEEDED(hr = CHECK_POINTER(pfnGetClassObject, E_NOINTERFACE)) &&
SUCCEEDED(hr = pfnGetClassObject(CLSID_PKArchiveHandler, IID_IPKArchive, reinterpret_cast<LPVOID*>(&m_pPkArchive))))
{
hr = CHECK_POINTER(m_pPkArchive, E_NOINTERFACE);
}
}
else
{
hr = E_NOINTERFACE;
}
}
//
// Initialise the IO streams
//
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = CHECK_POINTER(pReadStream, E_POINTER)) &&
SUCCEEDED(hr = CHECK_POINTER(m_pWriteStream, E_POINTER)) &&
SUCCEEDED(hr = m_pPkArchive->SetReadStream(pReadStream)) &&
SUCCEEDED(hr = m_pPkArchive->SetWriteStream(m_pWriteStream)))
{
//
// We can now process the read stream to create the file index
//
hr = m_pPkArchive->ProcessReadStream();
}
if (FAILED(hr))
{
throw CXDException(hr);
}
}
/*++
Routine Name:
CXPSArchive::~CXPSArchive
Routine Description:
CXPSArchive class destructor
Arguments:
None
Return Value:
None
--*/
CXPSArchive::~CXPSArchive()
{
if (m_pPkArchive != NULL)
{
m_pPkArchive->Close();
m_pPkArchive = NULL;
}
if (m_pWriteStream != NULL)
{
m_pWriteStream->Close();
}
if (m_hPkArch != NULL)
{
FreeLibrary(m_hPkArch);
}
}
/*++
Routine Name:
CXPSArchive::InitialiseFile
Routine Description:
This routine intialises the named file ready for processing
or sending on. This entails locating all the PK archive files
that constitute the XPS part.
Arguments:
szFileName - The name of the part to intialise
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CXPSArchive::InitialiseFile(
__in_z PCSTR szFileName
)
{
HRESULT hr = S_OK;
if (SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER)))
{
try
{
CStringXDA cstrFileName(szFileName);
//
// Open the file handler - if it is still in use this will fail
//
if (SUCCEEDED(hr = m_XpsFile.Open(szFileName)))
{
//
// Find the record or the parts comprising the record
//
hr = AddFile(szFileName);
}
else
{
RIP("File handler has not been closed correctly\n");
}
}
catch (CXDException& e)
{
hr = e;
}
}
ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND);
return hr;
}
/*++
Routine Name:
CXPSArchive::GetFileStream
Routine Description:
This routine retrieves the read stream for an XPS part.
Arguments:
szFileName - The name of the XPS part the stream is required for
ppFileStream - Pointer to an ISequentialStream pointer that recieves the stream
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CXPSArchive::GetFileStream(
__in_z PCSTR szFileName,
__deref_out ISequentialStream** ppFileStream
)
{
HRESULT hr = S_OK;
//
// Initialise the current XPS file
//
if (SUCCEEDED(hr = CHECK_POINTER(ppFileStream, E_POINTER)) &&
SUCCEEDED(hr = InitialiseFile(szFileName)))
{
//
// Query the XPS file for the file stream
//
*ppFileStream = NULL;
hr = m_XpsFile.QueryInterface(IID_ISequentialStream, reinterpret_cast<PVOID*>(ppFileStream));
}
ERR_ON_HR(hr);
return hr;
}
/*++
Routine Name:
CXPSArchive::CloseCurrent
Routine Description:
This routine closes the currently opened XPS file
Arguments:
None
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CXPSArchive::CloseCurrent(
VOID
)
{
return m_XpsFile.Close();
}
/*++
Routine Name:
CXPSArchive::SendCurrentFile
Routine Description:
This routine sends the current initialised file and requests the
PK archive handler compresses it according to the requested method
Arguments:
eCompType - The requested compression type
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CXPSArchive::SendCurrentFile(
__in ECompressionType eCompType
)
{
HRESULT hr = S_OK;
ULONG cb = 0;
PVOID pv = NULL;
PSTR pName = NULL;
//
// Get the data buffer and file name
//
if (SUCCEEDED(hr = m_XpsFile.GetBuffer(&pv, &cb)) &&
SUCCEEDED(hr = m_XpsFile.GetFileName(&pName)))
{
hr = SendFile(pName, pv, cb, eCompType);
}
ERR_ON_HR(hr);
return hr;
}
/*++
Routine Name:
CXPSArchive::SendCurrentFile
Routine Description:
This routine sends the current initialised file by requesting the
PK archive handler send the original constituent PK records
Arguments:
None
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CXPSArchive::SendCurrentFile(
VOID
)
{
HRESULT hr = S_OK;
XPSPartStack* pPartStack = NULL;
PSTR pName = NULL;
if (SUCCEEDED(hr = CHECK_POINTER(m_pPkArchive, E_NOINTERFACE)) &&
SUCCEEDED(hr = m_XpsFile.GetFileParts(&pPartStack)) &&
SUCCEEDED(hr = m_XpsFile.GetFileName(&pName)))
{
try
{
//
// Send all file parts on to the PK archive
//
if (!m_sentList[pName])
{
XPSPartStack::const_iterator iterParts = pPartStack->begin();
for (;
iterParts != pPartStack->end() && SUCCEEDED(hr);
iterParts++)
{
hr = m_pPkArchive->SendFile(iterParts->first);
}
if (SUCCEEDED(hr))
{
m_sentList[pName] = TRUE;
}
}
}
catch (exception& DBG_ONLY(e))
{
ERR(e.what());
hr = E_FAIL;
}
}
ERR_ON_HR(hr);
return hr;
}
/*++
Routine Name:
CXPSArchive::SendFile
Routine Description:
This routine sends a file defined by it's name and constituent data. The
routine passes the name and buffer to the PK archive handler to compress
and add to the archive.
Arguments:
szFileName - The name of the part
pBuffer - The buffer containing the part data
cbBuffer - The size of the data buffer
eCompType - The requested compression type
Return Value:
HRESULT
S_OK - On success
E_* - On error
--*/
HRESULT
CXPSArchive::SendFile(
__in_z PCSTR szFileName,
__in_bcount(cbBuffer) PVOID pBuffer,
__in ULONG cbBuffer,
__in ECompressionType eCompType
)
{
HRESULT hr = S_OK;
if (SUCCEEDED(hr = CHECK_POINTER(m_pPkArchive, E_NOINTERFACE)) &&
SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER)) &&
SUCCEEDED(hr = CHECK_POINTER(pBuffer, E_POINTER)))
{
if (eCompType == CompDeflated ||
eCompType == CompNone)
{
try
{
//
// Get the PK archive to compress and send the file on
//
if (!m_sentList[szFileName])
{
if (SUCCEEDED(hr = m_pPkArchive->SendFile(szFileName, pBuffer, cbBuffer, eCompType)))
{
m_sentList[szFileName] = TRUE;
}
}
}
catch (exception& DBG_ONLY(e))
{
ERR(e.what());
hr = E_FAIL;
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
}
ERR_ON_HR(hr);
return hr;
}
/*++
Routine Name:
CXPSArchive::AddFile
Routine Description:
This routine adds the PK file or constiuent PK files to the XPS file
ready for retrieval of the read stream. This hides the XPS piece handling
from the client which just adds the part by it's full un-interleaved name
Arguments:
szFileName - The name of the part
Return Value:
HRESULT
S_OK - On success
E_ELEMENT_NOT_FOUND - When part not present or badly formed in the container
E_* - On error
--*/
HRESULT
CXPSArchive::AddFile(
__in_z PCSTR szFileName
)
{
HRESULT hr = S_OK;
if (SUCCEEDED(hr = CHECK_POINTER(m_pPkArchive, E_NOINTERFACE)) &&
SUCCEEDED(hr = CHECK_POINTER(szFileName, E_POINTER)))
{
//
// Find the part or parts comprising the file
//
NameIndex* pNameIndex = NULL;
if (SUCCEEDED(hr = m_pPkArchive->GetNameIndex(&pNameIndex)))
{
try
{
NameIndex::const_iterator iterNameIndex = pNameIndex->find(szFileName);
if (iterNameIndex != pNameIndex->end())
{
//
// There is a single part
//
hr = m_XpsFile.AddFilePart(CStringXDA(szFileName), iterNameIndex->second);
}
else
{
//
// This could be a multipart interleaved file
//
UINT cPart = 0;
do
{
CStringXDA cstrPart;
cstrPart.Format(szPartNameFormatString, szFileName, cPart);
iterNameIndex = pNameIndex->find(cstrPart);
if (iterNameIndex != pNameIndex->end())
{
//
// We found the next part
//
hr = m_XpsFile.AddFilePart(CStringXDA(szFileName), iterNameIndex->second);
cPart++;
}
else
{
cstrPart.Format(szLastPartNameFormatString, szFileName, cPart);
iterNameIndex = pNameIndex->find(cstrPart);
if (iterNameIndex != pNameIndex->end())
{
//
// We found the last part
//
hr = m_XpsFile.AddFilePart(CStringXDA(szFileName), iterNameIndex->second);
cPart++;
break;
}
else
{
//
// The element is either not well constructed (i.e. missing a piece or the last
// part) or it does not exist
//
hr = E_ELEMENT_NOT_FOUND;
}
}
}
while (SUCCEEDED(hr));
}
}
catch (CXDException& e)
{
hr = e;
}
catch (exception& DBG_ONLY(e))
{
ERR(e.what());
hr = E_FAIL;
}
}
}
ERR_ON_HR_EXC(hr, E_ELEMENT_NOT_FOUND);
return hr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -