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.
441 lines
13 KiB
441 lines
13 KiB
//-----------------------------------------------------------------------------
|
|
//
|
|
//
|
|
// File: dsnbuff.cpp
|
|
//
|
|
// Description: Implementation of CDSNBuffer... class that abstracts writes
|
|
// of DSN information to P2 file.
|
|
//
|
|
// Author: Mike Swafford (MikeSwa)
|
|
//
|
|
// History:
|
|
// 7/3/98 - MikeSwa Created
|
|
//
|
|
// Copyright (C) 1998 Microsoft Corporation
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "precomp.h"
|
|
|
|
//---[ CDSNBuffer::~CDSNBuffer ]-----------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Destructor for CDSNBuffer. Does NOT close file handle (caller is
|
|
// responisble for that).
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
// -
|
|
// History:
|
|
// 7/3/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CDSNBuffer::~CDSNBuffer()
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CDSNBuffer::~CDSNBuffer");
|
|
|
|
DebugTrace((LPARAM) this, "INFO: %d File writes needed by CDSNBuffer", m_cFileWrites);
|
|
|
|
//make sure we don't pass in 1 bit
|
|
if (m_overlapped.hEvent)
|
|
{
|
|
_VERIFY(CloseHandle((HANDLE) (((DWORD_PTR) m_overlapped.hEvent) & -2)));
|
|
}
|
|
TraceFunctLeave();
|
|
}
|
|
|
|
//---[ CDSNBuffer::HrInitialize ]----------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Initialize CDSNBuffer object.
|
|
// - Associates destination file handle with object (will not close it)
|
|
// - Creates an event for synchronizing file operations
|
|
// Parameters:
|
|
// hDestFile - Destination File Handle (must be opend with FILE_FLAG_OVERLAPPED)
|
|
// Returns:
|
|
// S_OK on success
|
|
// E_INVALIDARG if handle invalid is passed in
|
|
// E_FAIL if CreateEvent fails for an unknown reason
|
|
// History:
|
|
// 7/3/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDSNBuffer::HrInitialize(PFIO_CONTEXT pDestFile)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CDSNBuffer::HrInitialize");
|
|
HRESULT hr = S_OK;
|
|
|
|
_ASSERT(pDestFile);
|
|
|
|
if (!pDestFile)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Exit;
|
|
}
|
|
|
|
m_pDestFile = pDestFile;
|
|
|
|
//allow this to act as reset
|
|
m_overlapped.Offset = 0;
|
|
m_overlapped.OffsetHigh = 0;
|
|
m_cbOffset = 0;
|
|
m_cbFileSize = 0;
|
|
m_cFileWrites = 0;
|
|
|
|
m_overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (!m_overlapped.hEvent)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
ErrorTrace((LPARAM) this, "ERROR: Unable to create DSNBuffer event - hr 0x%08X", hr);
|
|
goto Exit;
|
|
}
|
|
|
|
//Set low bit stop ATQ completion routine from being called
|
|
m_overlapped.hEvent = ((HANDLE) (((DWORD_PTR) m_overlapped.hEvent) | 0x00000001));
|
|
|
|
Exit:
|
|
TraceFunctLeave();
|
|
return hr;
|
|
}
|
|
|
|
//---[ CDSNBuffer::HrWriteBuffer ]---------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Writes the given buffer, will call write file if needed
|
|
// Parameters:
|
|
// pbInputBuffer Buffer to write
|
|
// cbInputBuffer Number of bytes to write
|
|
// Returns:
|
|
// S_OK on success
|
|
// History:
|
|
// 7/3/98 - MikeSwa Created
|
|
// 10/21/98 - MikeSwa Updated to support resource conversion
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDSNBuffer::HrWriteBuffer(BYTE *pbInputBuffer, DWORD cbInputBuffer)
|
|
{
|
|
return HrPrivWriteBuffer(TRUE, pbInputBuffer, cbInputBuffer);
|
|
}
|
|
|
|
//---[ CDSNBuffer::HrWriteModifiedUnicodeString ]------------------------------
|
|
//
|
|
//
|
|
// IMPORTANT NOTE:
|
|
// This function replaces any whitespace characters in the input string
|
|
// with unicode whitespace (0x0020). Becaase fUTF7EncodeBuffer treats
|
|
// whitespace characters such as 0x3000 (Japanese whitespace) as a UTF7
|
|
// "separator", it will encode strings with such characters embedded as
|
|
// 2 separate UTF7 strings. By replacing these characters with 0x0020 we
|
|
// guarantee that the output UTF7 string is a single encoded string.
|
|
// Description:
|
|
// Writes a given NULL terminated Unicode string, and will call write file
|
|
// if needed. Converts to UTF7 encoding.
|
|
// Parameters:
|
|
// pwszString String to write
|
|
// Returns:
|
|
// S_OK on success
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDSNBuffer::HrWriteModifiedUnicodeString(LPWSTR pwszString)
|
|
{
|
|
DWORD i = 0;
|
|
DWORD cbLength = lstrlenW(pwszString);
|
|
|
|
_ASSERT(pwszString != NULL);
|
|
|
|
//Replace whitespace characters with
|
|
for(i = 0; i < cbLength; i++) {
|
|
if(iswspace(pwszString[i]))
|
|
pwszString[i] = L' ';
|
|
}
|
|
|
|
return HrPrivWriteBuffer(FALSE, (PBYTE) pwszString, cbLength * sizeof(WCHAR));
|
|
}
|
|
|
|
//---[ CDSNBuffer::HrPrivWriteBuffer ]-----------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Private function to handle writing UNICODE and ASCII buffers
|
|
// Parameters:
|
|
// fASCII TRUE if buffer is ASCII
|
|
// pbInputBuffer Buffer to write
|
|
// cbInputBuffer #of bytes to write
|
|
// Returns:
|
|
// S_OK on success
|
|
// Any errors returned from flushing buffer to disk
|
|
// History:
|
|
// 10/21/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDSNBuffer::HrPrivWriteBuffer(BOOL fASCII, BYTE *pbInputBuffer,
|
|
DWORD cbInputBuffer)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fDone = FALSE;
|
|
BYTE *pbCurrentInput = pbInputBuffer;
|
|
DWORD cbInputRead = 0;
|
|
DWORD cbTotalInputRead = 0;
|
|
DWORD cbOutputWritten = 0;
|
|
DWORD cTimesThruLoop = 0;
|
|
|
|
_ASSERT(NULL != m_pDestFile);
|
|
|
|
while (!fDone)
|
|
{
|
|
cTimesThruLoop++;
|
|
|
|
//the buffer can't be *that* large... this will hopfully catch infinite loops
|
|
_ASSERT(cTimesThruLoop < 100);
|
|
fDone = m_presconv->fConvertBuffer(fASCII, pbCurrentInput,
|
|
cbInputBuffer-cbTotalInputRead, m_pbFileBuffer+m_cbOffset,
|
|
DSN_BUFFER_SIZE - m_cbOffset, &cbOutputWritten,
|
|
&cbInputRead);
|
|
|
|
m_cbOffset += cbOutputWritten;
|
|
_ASSERT(m_cbOffset <= DSN_BUFFER_SIZE);
|
|
|
|
if (!fDone)
|
|
{
|
|
//Update vars passed to fConvertBuffer
|
|
cbTotalInputRead += cbInputRead;
|
|
pbCurrentInput += cbInputRead;
|
|
|
|
_ASSERT(cbTotalInputRead <= cbInputBuffer);
|
|
|
|
hr = HrWriteBufferToFile();
|
|
if (FAILED(hr))
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//---[ CDSNBuffer::HrWriteBufferToFile ]---------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Write the current buffer contents to the fils
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
// S_OK on success
|
|
// History:
|
|
// 7/3/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDSNBuffer::HrWriteBufferToFile()
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CDSNBuffer::HrWriteBufferToFile");
|
|
HRESULT hr = S_OK;
|
|
DWORD cbWritten = 0;
|
|
DWORD dwError = 0;
|
|
|
|
|
|
if (m_cbOffset) //there is stuff to write
|
|
{
|
|
//fix up overlapped
|
|
if (!WriteFile(m_pDestFile->m_hFile, m_pbFileBuffer, m_cbOffset, &cbWritten, &m_overlapped))
|
|
{
|
|
dwError = GetLastError();
|
|
if (ERROR_IO_PENDING != dwError)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
goto Exit;
|
|
}
|
|
|
|
//Wait for result, so we don't overwrite buffer and overlapped
|
|
if (!GetOverlappedResult(m_pDestFile->m_hFile, &m_overlapped, &cbWritten, TRUE))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
DebugTrace((LPARAM) this, "INFO: Async write pending for FIOContext 0x%08X", m_pDestFile);
|
|
}
|
|
|
|
_ASSERT(m_cbOffset == cbWritten);
|
|
m_cbOffset = 0;
|
|
m_cbFileSize += cbWritten;
|
|
m_overlapped.Offset += cbWritten;
|
|
m_cFileWrites++;
|
|
}
|
|
|
|
Exit:
|
|
TraceFunctLeave();
|
|
return hr;
|
|
}
|
|
|
|
//---[ CDSNBuffer::SeekForward ]-----------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Seeks buffers place in file forward specified number of bytes. Flushes
|
|
// Buffer in process of doing so.
|
|
// Parameters:
|
|
// cbBytesToSeek Number of bytes to seek forward
|
|
// pcbFileSize Returns old file size
|
|
// Returns:
|
|
// S_OK on succedd
|
|
// History:
|
|
// 7/6/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDSNBuffer::HrSeekForward(IN DWORD cbBytesToSeek,OUT DWORD *pcbFileSize)
|
|
{
|
|
_ASSERT(pcbFileSize);
|
|
HRESULT hr = HrWriteBufferToFile();
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
*pcbFileSize = m_cbFileSize;
|
|
|
|
m_cbFileSize += cbBytesToSeek;
|
|
m_overlapped.Offset += cbBytesToSeek;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//---[ CDSNBuffer::HrLoadResourceString ]--------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Encapsulates the functionality of LoadString... but allows you to
|
|
// specify a LangId, returns read only data
|
|
// Parameters:
|
|
// IN wResourceId ID of the resource
|
|
// IN LangId LangID to get resource for
|
|
// OUT pwszResource Read-only UNICODE resource (not NULL terminated)
|
|
// OUT pcbResource Size (in bytes) of UNICODE String
|
|
// Returns:
|
|
// S_OK on success
|
|
// HRESULTS from errors trying to get load resources
|
|
// History:
|
|
// 10/22/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDSNBuffer::HrLoadResourceString(WORD wResourceId, LANGID LangId,
|
|
LPWSTR *pwszResource, DWORD *pcbResource)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HINSTANCE hModule = GetModuleHandle(DSN_RESOUCE_MODULE_NAME);
|
|
HRSRC hResInfo = NULL;
|
|
HGLOBAL hResData = NULL;
|
|
WORD wStringIndex = wResourceId & 0x000F;
|
|
LPWSTR wszResData = NULL;
|
|
WCHAR wchLength = 0; //character representing current length
|
|
|
|
_ASSERT(pwszResource);
|
|
_ASSERT(pcbResource);
|
|
|
|
*pwszResource = NULL;
|
|
*pcbResource = NULL;
|
|
|
|
if (NULL == hModule)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
_ASSERT(0 && "Unable to load resource DLL");
|
|
goto Exit;
|
|
}
|
|
|
|
//Find handle to string table segment
|
|
hResInfo = FindResourceEx(hModule, RT_STRING,
|
|
MAKEINTRESOURCE(((WORD)((USHORT)wResourceId >> 4) + 1)),
|
|
LangId);
|
|
|
|
if (NULL == hResInfo)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
_ASSERT(0 && "Failed to find resource for requested LangId");
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
hResData = LoadResource(hModule, hResInfo);
|
|
|
|
if (NULL == hResData)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
//Get pointer to string table segement data
|
|
wszResData = (LPWSTR) LockResource(hResData);
|
|
|
|
if (NULL == wszResData)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
goto Exit;
|
|
}
|
|
|
|
//OK Now we have a pointer to the string table segment
|
|
//Lets use some code from LoadStringOrError to handle this
|
|
//There are 16 strings in a segment, which means we can look at
|
|
//The low 4 bits of the wResourceId (wStringIndex)
|
|
|
|
//String Table segment format
|
|
//PASCAL like string count first UTCHAR is count if TCHARs
|
|
//A zero length string (ie resource 0) is simply the WORD 0x0000...
|
|
//This loop handles both the same... when loop is done.
|
|
// wszResData - Ptr to UNICODE string
|
|
// wchLenght - Length of that string (in WCHARS)
|
|
while (TRUE)
|
|
{
|
|
wchLength = *((WCHAR *)wszResData++);
|
|
if (0 == wStringIndex--)
|
|
break;
|
|
// Step to start if next string...
|
|
wszResData += wchLength;
|
|
}
|
|
|
|
*pwszResource = wszResData;
|
|
*pcbResource = (DWORD) wchLength*sizeof(WCHAR);
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
//---[ CDSNBuffer::HrWriteResource ]-------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Gets resource for specified language ID, and dumps UNICODE to DSN
|
|
// content using current conversion context.
|
|
//
|
|
// It will assert if the resource cannot be found for the given language
|
|
// ID.
|
|
// Parameters:
|
|
// dwResourceID The resouce ID of the resource to get
|
|
// LandId The language ID to use
|
|
// Returns:
|
|
// S_OK on success
|
|
// History:
|
|
// 10/21/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDSNBuffer::HrWriteResource(WORD wResourceId, LANGID LangId)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR wszResource = NULL;
|
|
DWORD cbResource = NULL;
|
|
|
|
hr = HrLoadResourceString(wResourceId, LangId, &wszResource, &cbResource);
|
|
if (FAILED(hr))
|
|
{
|
|
_ASSERT(0 && "Unable to load resources");
|
|
//Fail silently in retail
|
|
hr = S_OK;
|
|
}
|
|
|
|
//OK... now we have everything we need to write the buffer
|
|
hr = HrPrivWriteBuffer(FALSE /*not ASCII */,
|
|
(BYTE *) wszResource, cbResource);
|
|
|
|
//$$REVIEW: Do we need to do any special cleanup here?
|
|
return hr;
|
|
}
|