|
|
//
// rdpfstore.cpp
//
// Implementation of CRdpFileStore, implements ISettingsStore
//
// CRdpFileStore implements a persistent settings store for
// ts client settings.
//
//
// Copyright(C) Microsoft Corporation 2000
// Author: Nadim Abdo (nadima)
//
//
// Notes for improvement:
// Can add a hash lookup table to speedup FindRecord.
// (FindRecord is called at least once for each property that
// is read/written during OpenStore/SaveStore operations)
// Most files contain maybe 5-10 records so speeding up
// the find is probably not that important.
//
// Copyright(C) Microsoft Corporation 2000
// Author: Nadim Abdo (nadima)
//
#include "stdafx.h"
#define TRC_GROUP TRC_GROUP_UI
#define TRC_FILE "rdpfstore.cpp"
#include <atrcapi.h>
#include "rdpfstore.h"
#include "autil.h" //for StringToBinary/BinaryToString
//
// Index values must match RDPF_RECTYPE_*
//
LPCTSTR g_szTypeCodeMap[] = { TEXT(":i:"), //RDPF_RECTYPE_UINT
TEXT(":s:"), //RDPF_RECTYPE_SZ
TEXT(":b:") //RDPF_RECTYPE_BINARY
};
CRdpFileStore::CRdpFileStore() { _cRef = 1; _fReadOnly = FALSE; _fOpenForRead = FALSE; _fOpenForWrite = FALSE; _fIsDirty = FALSE; _pRecordListHead= NULL; _pRecordListTail= NULL; _szFileName[0] = 0; }
CRdpFileStore::~CRdpFileStore() { DeleteRecords(); }
ULONG __stdcall CRdpFileStore::AddRef() { DC_BEGIN_FN("AddRef"); ULONG cref = InterlockedIncrement(&_cRef); TRC_ASSERT(cref > 0, (TB,_T("AddRef: cref is not > 0!"))); DC_END_FN(); return cref; }
ULONG __stdcall CRdpFileStore::Release() { DC_BEGIN_FN("Release"); TRC_ASSERT(_cRef > 0, (TB,_T("AddRef: cref is not > 0!"))); ULONG cref = InterlockedDecrement(&_cRef); if(0 == cref) { TRC_DBG((TB,_T("CRdpFileStore::Release deleting object"))); delete this; } DC_END_FN(); return cref; }
STDMETHODIMP CRdpFileStore::QueryInterface(REFIID iid, void** p) { UNREFERENCED_PARAMETER(iid); UNREFERENCED_PARAMETER(p); return E_NOTIMPL; }
//
// OpenStore
// opens the RDP file, creating one if one doesn't exist
// The file existed it is parsed and readied for fast queries
//
// parameters:
// szStoreMoniker - path to file
// bReadyOnly - specifies if file is to be opened readonly
//
BOOL CRdpFileStore::OpenStore(LPCTSTR szStoreMoniker, BOOL bReadOnly) { DC_BEGIN_FN("OpenStore");
TRC_ASSERT(szStoreMoniker, (TB, _T("szStoreMoniker parameter is NULL"))); if(szStoreMoniker) { _fReadOnly = bReadOnly; HRESULT hr = StringCchCopy(_szFileName, SIZECHAR(_szFileName), szStoreMoniker); if (FAILED(hr)) { TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr)); memset(_szFileName, 0, sizeof(_szFileName)); return FALSE; }
//
// Open the file, creating it if it doesn't exist
//
//
// First try to open existing for rw
//
if (ERR_SUCCESS == _fs.OpenForRead( (LPTSTR)szStoreMoniker)) { _fOpenForRead = _fs.IsOpenForRead(); _fOpenForWrite = !bReadOnly; } else { TRC_DBG((TB, _T("OpenStore could not _tfopen: %s."), szStoreMoniker)); return FALSE; } ParseFile(); } else { return FALSE; }
DC_END_FN(); return TRUE; }
//
// CommitStore
// commits the in memory representation of the file to the store
// this overwrites any existing contents in the file.
//
// File MUST have been opened with OpenStore
//
BOOL CRdpFileStore::CommitStore() { DC_BEGIN_FN("CommitStore"); PRDPF_RECORD node = NULL; TCHAR szBuf[LINEBUF_SIZE]; int ret;
if(_fOpenForWrite) { if(_fs.IsOpenForRead() || _fs.IsOpenForWrite()) { _fs.Close(); } //Reopen for write, nuking previous contents
//Open as binary to allow UNICODE output
if(ERR_SUCCESS == _fs.OpenForWrite(_szFileName, TRUE)) { node = _pRecordListHead; while(node) { if(RecordToString(node, szBuf, LINEBUF_SIZE)) { ret = _fs.Write(szBuf); if(ERR_SUCCESS != ret) { TRC_ABORT((TB,_T("Error writing to _fs: %d"),ret)); return FALSE; } } else { return FALSE; } node = node->pNext; } return TRUE; } else { TRC_ERR((TB,_T("OpenForWrite failed on file:%s"),_szFileName)); return FALSE; } } else { TRC_ERR((TB,_T("Files was not opened for write:%s"),_szFileName)); return FALSE; }
DC_END_FN(); }
//
// CloseStore
// Closes the file, does NOT do a commit.
//
BOOL CRdpFileStore::CloseStore() { DC_BEGIN_FN("CloseStore"); if(_fs.IsOpenForRead() || _fs.IsOpenForWrite()) { if(ERR_SUCCESS == _fs.Close()) { _fReadOnly = FALSE; _fOpenForRead = FALSE; _fOpenForWrite = FALSE; return TRUE; } else { return FALSE; } } else { return FALSE; } DC_END_FN(); }
BOOL CRdpFileStore::IsOpenForRead() { return _fOpenForRead; }
BOOL CRdpFileStore::IsOpenForWrite() { return _fOpenForWrite; }
BOOL CRdpFileStore::IsDirty() { return _fIsDirty; }
BOOL CRdpFileStore::SetDirtyFlag(BOOL bIsDirty) { _fIsDirty = bIsDirty; return _fIsDirty; }
//
// Typed read/write functions
//
BOOL CRdpFileStore::ReadString(LPCTSTR szName, LPTSTR szDefault, LPTSTR szOutBuf, UINT strLen) { PRDPF_RECORD node = NULL; HRESULT hr; DC_BEGIN_FN("ReadString");
TRC_ASSERT(szName && szDefault && szOutBuf && strLen, (TB,_T("Invalid params to ReadString"))); if(szName && szDefault && szOutBuf && strLen) { node = FindRecord(szName); if(node && node->recType == RDPF_RECTYPE_SZ) { hr = StringCchCopy(szOutBuf, strLen, node->u.szVal); if (SUCCEEDED(hr)) { return TRUE; } else { TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr)); return FALSE; } } else { //Fill with default
hr = StringCchCopy(szOutBuf, strLen, szDefault); if (SUCCEEDED(hr)) { return TRUE; } else { TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr)); return FALSE; } } } else { return FALSE; }
DC_END_FN(); }
//
// Writes a string to the store
// params
// szName - key name
// szDefault - default value (if writing default settings gets deleted)
// szValue - value to write out
// fIgnoreDefault - if set then always write ignoring szDefault
//
BOOL CRdpFileStore::WriteString(LPCTSTR szName, LPTSTR szDefault, LPTSTR szValue, BOOL fIgnoreDefault) { DC_BEGIN_FN("WriteString"); TRC_ASSERT(szName && szValue, (TB,_T("Invalid params to WriteString"))); if(szName && szValue) { if(szDefault && !fIgnoreDefault && !_tcscmp(szDefault,szValue)) { //
// Don't write out defaults
//
PRDPF_RECORD node = FindRecord(szName); if(node) { return DeleteRecord(node); } return TRUE; } else { BOOL bRet = InsertRecord(szName, RDPF_RECTYPE_SZ, szValue); return bRet; } } else { return FALSE; }
DC_END_FN(); }
BOOL CRdpFileStore::ReadBinary(LPCTSTR szName, PBYTE pOutBuf, UINT cbBufLen) { PRDPF_RECORD node = NULL; DC_BEGIN_FN("ReadBinary");
TRC_ASSERT(szName && pOutBuf && cbBufLen, (TB,_T("Invalid params to ReadBinary"))); if(szName && pOutBuf && cbBufLen) { node = FindRecord(szName); if(node && node->recType == RDPF_RECTYPE_BINARY) { if(node->dwBinValLen <= cbBufLen) { memcpy(pOutBuf, node->u.pBinVal, node->dwBinValLen); return TRUE; } else { TRC_ERR((TB,_T("Insufficient space in outbuf buf"))); return FALSE; } } else { return FALSE; } } else { return FALSE; }
DC_END_FN(); }
BOOL CRdpFileStore::WriteBinary(LPCTSTR szName,PBYTE pBuf, UINT cbBufLen) { DC_BEGIN_FN("WriteInt");
TRC_ASSERT(szName && pBuf, (TB,_T("Invalid params to WriteBinary")));
if(!cbBufLen) { return TRUE; }
if(szName && pBuf) { BOOL bRet = InsertBinaryRecord(szName, pBuf, (DWORD)cbBufLen); return bRet; } else { return FALSE; }
DC_END_FN(); }
BOOL CRdpFileStore::ReadInt(LPCTSTR szName, UINT defaultVal, PUINT pval) { PRDPF_RECORD node = NULL; DC_BEGIN_FN("ReadInt");
TRC_ASSERT(szName && pval, (TB,_T("Invalid params to ReadInt"))); if(szName && pval) { node = FindRecord(szName); if(node && node->recType == RDPF_RECTYPE_UINT) { *pval = node->u.iVal; return TRUE; } else { *pval = defaultVal; return TRUE; } } else { return FALSE; }
DC_END_FN(); }
//
// Writes an int to the store
// params
// szName - key name
// defaultVal - default value (if writing default settings gets deleted)
// val - value to write out
// fIgnoreDefault - if set then always write ignoring szDefault
//
BOOL CRdpFileStore::WriteInt(LPCTSTR szName, UINT defaultVal, UINT val, BOOL fIgnoreDefault) { DC_BEGIN_FN("WriteInt");
TRC_ASSERT(szName, (TB,_T("Invalid params to WriteInt"))); if(szName) { if(!fIgnoreDefault && defaultVal == val) { //
// Don't write out default
//
PRDPF_RECORD node = FindRecord(szName); if(node) { return DeleteRecord(node); } return TRUE; } else { BOOL bRet = InsertIntRecord(szName, val); return bRet; } } else { return FALSE; }
DC_END_FN(); }
BOOL CRdpFileStore::ReadBool(LPCTSTR szName, UINT defaultVal, PBOOL pbVal) { DC_BEGIN_FN("ReadBool"); UINT val; TRC_ASSERT(szName && pbVal, (TB,_T("Invalid params to ReadBool"))); if(szName && pbVal) { if(ReadInt(szName, defaultVal, &val)) { *pbVal = (BOOL)val; return TRUE; } } else { return FALSE; }
DC_END_FN(); return TRUE; }
//
// Writes a bool to the store
// params
// szName - key name
// defaultVal - default value (if writing default settings gets deleted)
// bVal - value to write out
// fIgnoreDefault - if set then always write ignoring szDefault
//
BOOL CRdpFileStore::WriteBool(LPCTSTR szName, UINT defaultVal,BOOL bVal, BOOL fIgnoreDefault) { DC_BEGIN_FN("WriteBool"); UINT iVal = bVal; BOOL bRet = WriteInt( szName, defaultVal, iVal, fIgnoreDefault); return bRet;
DC_END_FN(); }
//
// ParseFile
// parses the _hFile into a reclist and associated namemap hash
//
BOOL CRdpFileStore::ParseFile() { DC_BEGIN_FN("ParseFile"); TRC_ASSERT(_fs.IsOpenForRead(), (TB,_T("Can't ParseFile on a closed FS"))); if(!_fs.IsOpenForRead()) { return FALSE; }
//
// Nuke any current in-memory state
//
DeleteRecords();
//
// Parse the file line by line into a RDPF_RECORD list
//
TCHAR szBuf[LINEBUF_SIZE]; while(ERR_SUCCESS == _fs.ReadNextLine(szBuf, sizeof(szBuf))) { if(!InsertRecordFromLine(szBuf)) { TRC_DBG((TB,_T("Parse error, aborting file parse"))); return FALSE; } }
_fs.Close();
DC_END_FN(); return TRUE; }
//
// InsertRecordFromLine
// parses szLine into a record and adds to the record list
//
BOOL CRdpFileStore::InsertRecordFromLine(LPTSTR szLine) { DC_BEGIN_FN("InsertRecordFromLine"); TCHAR szNameField[LINEBUF_SIZE]; UINT typeCode; TCHAR szValueField[LINEBUF_SIZE]; BOOL fParseOk = FALSE;
memset(szNameField,0,sizeof(szNameField)); memset(szValueField,0,sizeof(szValueField)); fParseOk = ParseLine(szLine, &typeCode, szNameField, szValueField);
TRC_DBG((TB,_T("Parsed line into fields- name:'%s', value:'%s', typecode:'%d'"), szNameField, szValueField, typeCode));
TRC_ASSERT(IS_VALID_RDPF_TYPECODE(typeCode), (TB,_T("typeCode %d is invalid"), typeCode)); if(IS_VALID_RDPF_TYPECODE(typeCode)) { //Create a new record for this line
//and insert it into the reclist
if(typeCode == RDPF_RECTYPE_UNPARSED) { //Unparsed line: Value is the whole line. Name ignored
HRESULT hr = StringCchCopy(szValueField, SIZECHAR(szValueField), szLine); if (FAILED(hr)) { TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr)); return FALSE; } } //names are always lower case
if(InsertRecord(_tcslwr(szNameField), typeCode, szValueField)) { return TRUE; } else { return FALSE; } } else { //
// Invalid typecode
//
return FALSE; }
DC_END_FN(); return TRUE; }
//
// ParseLine
// parses the lines into tokens, returns false
// if the line does not match the expected format
//
// params
// szLine - line to parse
// pTypeCode - [OUT] typecode
// szNameField - [OUT] name field. (must be at least LINEBUF_SIZE)
// szValueField - [OUT] value field. (must be at least LINEBUF_SIZE)
//
//
BOOL CRdpFileStore::ParseLine(LPTSTR szLine, PUINT pTypeCode, LPTSTR szNameField, LPTSTR szValueField) { PTCHAR szWrite = NULL; TCHAR szTypeCode; INT writeCount = 0; DC_BEGIN_FN("ParseLine");
//
// Try to parse the line, if unable to parse it return
// false.
//
// Format is "fieldname:szTypeCode:value"
// e.g "server:s:localhost"
//
// szTypeCodes are:
// s - string
// i - UINT
// b - binary blob (encoded)
//
TRC_ASSERT(szLine, (TB,_T("szLine is null"))); TRC_ASSERT(pTypeCode, (TB,_T("pTypeCode is null"))); TRC_ASSERT(szNameField, (TB,_T("szNameField is null"))); TRC_ASSERT(szValueField, (TB,_T("szValueField is null"))); if(szLine && pTypeCode && szNameField && szValueField) { //
// parse the whole line in one pass
// goto used on error case to avoid horrible nesting
//
PTCHAR sz = szLine; while(*sz && *sz == TCHAR(' ')) sz++; //eat leading whitespace
if(!*sz) { goto parse_error; } //Copy field 1
PTCHAR szWrite = szNameField; writeCount = 0; while(*sz && *sz != TCHAR(':')) { *szWrite++ = *sz++; if(++writeCount > LINEBUF_SIZE) { TRC_ERR((TB,_T("Field1 exceeds max size. size: %d"), writeCount)); goto parse_error; } } *szWrite = NULL;
if(*sz != TCHAR(':')) { goto parse_error; sz++; } sz++; //eat ':'
while(*sz && *sz == TCHAR(' ')) sz++; //eat whitespace
if( *sz ) { szTypeCode = isupper(*sz) ? #ifndef OS_WINCE
_tolower(*sz++) #else
towlower(*sz++) #endif
: *sz++; switch(szTypeCode) { case TCHAR('s'): *pTypeCode = RDPF_RECTYPE_SZ; break; case TCHAR('i'): *pTypeCode = RDPF_RECTYPE_UINT; break; case TCHAR('b'): *pTypeCode = RDPF_RECTYPE_BINARY; break; default: TRC_ERR((TB,_T("Invalid szTypeCode in szLine '%s'"), szLine)); *pTypeCode = RDPF_RECTYPE_UNPARSED; goto parse_error; break; } } else { TRC_ERR((TB,_T("Invalid szTypeCode in szLine '%s'"), szLine)); goto parse_error; } while(*sz && *sz == TCHAR(' ')) sz++; //eat whitespace
if(*sz != TCHAR(':')) { goto parse_error; } sz++; //eat ':'
while(*sz && *sz == TCHAR(' ')) sz++; //eat leading whitespace
//rest of line is field3
szWrite = szValueField; writeCount = 0; while(*sz && *sz != TCHAR('\n')) { *szWrite++ = *sz++; if(++writeCount > LINEBUF_SIZE) { TRC_ERR((TB,_T("Field1 exceeds max size. size: %d"), writeCount)); goto parse_error; } } *szWrite = NULL; return TRUE; }
parse_error: TRC_ERR((TB,_T("Parse error in line"))); //Add an unknown record..it will be persisted back out to
//the file (it could be from a newer file version)
*pTypeCode = RDPF_RECTYPE_UNPARSED; DC_END_FN(); return FALSE; }
//
// InsertRecord
// inserts new record, modifies existing record
// if one exists with the same name field
//
BOOL CRdpFileStore::InsertRecord(LPCTSTR szName, UINT TypeCode, LPCTSTR szValue) { DC_BEGIN_FN("InsertRecord");
TRC_ASSERT(IS_VALID_RDPF_TYPECODE(TypeCode), (TB,_T("typeCode %d is invalid"), TypeCode)); TRC_ASSERT(szName && szValue, (TB,_T("Invalid szName or szValue"))); if(szName && szValue) { PRDPF_RECORD node; node = FindRecord(szName); if(node) { if(node->recType == TypeCode) { //
// Existing record found, modify it's contents
// first free any allocated memory in the current
// node.
//
switch(TypeCode) { case RDPF_RECTYPE_SZ: { if(node->u.szVal) { LocalFree(node->u.szVal); } } break; case RDPF_RECTYPE_BINARY: { if(node->u.pBinVal) { LocalFree(node->u.pBinVal); } } break; case RDPF_RECTYPE_UNPARSED: { if(node->u.szUnparsed) { LocalFree(node->u.szUnparsed); } } break; default: { return FALSE; } break; }
//
// Set the node value from the typecode
//
if(SetNodeValue(node, TypeCode, szValue)) { return TRUE; } } else { //
// dup record of differing type
//
TRC_ASSERT(FALSE,(TB,_T("found duplicate record of differing type"))); return FALSE; } } else { PRDPF_RECORD node = NewRecord(szName, TypeCode); if(node) { if(SetNodeValue(node, TypeCode, szValue)) { //Append the node to the end of the reclist
if(AppendRecord(node)) { return TRUE; } } } return FALSE; } }
DC_END_FN(); return FALSE; }
//
// Sets node value based on a typecode
// this coaxes the value from the string form
//
// This function is the generic version that accepts the value as a string
// parameter. Automatic conversion are done to the appropriate type.
//
inline BOOL CRdpFileStore::SetNodeValue(PRDPF_RECORD pNode, RDPF_RECTYPE TypeCode, LPCTSTR szValue) { DC_BEGIN_FN("SetNodeValue");
TRC_ASSERT(pNode && szValue && IS_VALID_RDPF_TYPECODE(TypeCode), (TB,_T("Invalid SetNodeValue params"))); if(pNode && szValue) { switch(TypeCode) { case RDPF_RECTYPE_UINT: { pNode->u.iVal = _ttol(szValue); return TRUE; } break; case RDPF_RECTYPE_SZ: { pNode->u.szVal = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)*(_tcslen(szValue)+1)); if(pNode->u.szVal) { _tcscpy(pNode->u.szVal,szValue); return TRUE; } else { return FALSE; } } break; case RDPF_RECTYPE_BINARY: { //Convert from string form to actual binary bits
UINT strLen = _tcslen(szValue); DWORD dwLen = 0;
//
// First get the buffer length
// (binaryToString returns the wrong length when the
// null parameter is passed in).
dwLen = (strLen >> 1) + 2;
pNode->u.pBinVal = (PBYTE) LocalAlloc(LPTR, dwLen); if(!pNode->u.pBinVal) { TRC_ERR((TB,_T("Failed to alloc %d bytes"), dwLen)); return FALSE; } memset(pNode->u.pBinVal,0,dwLen); //
// Do the conversion
//
if(!CUT::BinarytoString( strLen, (LPTSTR)szValue, (PBYTE)pNode->u.pBinVal, &dwLen)) { TRC_ERR((TB,_T("BinaryToString conversion failed"))); return FALSE; } pNode->dwBinValLen = dwLen; } break; case RDPF_RECTYPE_UNPARSED: { pNode->u.szUnparsed = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)*(_tcslen(szValue)+1)); if(pNode->u.szUnparsed) { _tcscpy(pNode->u.szUnparsed,szValue); return TRUE; } else { return FALSE; } } break; default: { return FALSE; } break; } } else { return FALSE; }
DC_END_FN(); return TRUE; }
//
// Inserts an int record (RDPF_RECTYPE_UINT)
// modifies existing record if one is found
//
BOOL CRdpFileStore::InsertIntRecord(LPCTSTR szName, UINT value) { DC_BEGIN_FN("InsertIntRecord");
TRC_ASSERT(szName, (TB,_T("Invalid szName"))); if(szName) { PRDPF_RECORD node; node = FindRecord(szName); if(node) { if(node->recType == RDPF_RECTYPE_UINT) { //
// Existing record found, modify it's contents
//
node->u.iVal = value; return TRUE; } else { //
// dup record of differing type
//
TRC_ASSERT(FALSE,(TB,_T("found duplicate record of differing type"))); return FALSE; } } else { PRDPF_RECORD node = NewRecord(szName, RDPF_RECTYPE_UINT); if(node) { node->u.iVal = value; //Append the node to the end of the reclist
if(AppendRecord(node)) { return TRUE; } } return FALSE; } } else { return FALSE; }
DC_END_FN(); }
//
// Insert a binary buffer record (RDPF_RECTYPE_BINARY)
// modifies existing record if one found
//
BOOL CRdpFileStore::InsertBinaryRecord(LPCTSTR szName, PBYTE pBuf, DWORD dwLen) { DC_BEGIN_FN("InsertBinaryRecord");
TRC_ASSERT(szName && pBuf && dwLen, (TB,_T("Invalid szName or pBuf"))); if(szName) { PRDPF_RECORD node; node = FindRecord(szName); if(node) { if(node->recType == RDPF_RECTYPE_BINARY) { //
// Existing record found, modify its contents
//
if(node->u.pBinVal) { LocalFree(node->u.pBinVal); }
node->u.pBinVal = (PBYTE) LocalAlloc(LPTR, dwLen); if(node->u.pBinVal) { memcpy(node->u.pBinVal, pBuf, dwLen); node->dwBinValLen = dwLen; return TRUE; } else { return FALSE; }
return TRUE; } else { //
// dup record of differing type
//
TRC_ASSERT(FALSE,(TB,_T("found duplicate record of differing type"))); return FALSE; } } else { PRDPF_RECORD node = NewRecord(szName, RDPF_RECTYPE_BINARY); if(node) { node->u.pBinVal = (PBYTE) LocalAlloc(LPTR, dwLen); if(node->u.pBinVal) { memcpy(node->u.pBinVal, pBuf, dwLen); node->dwBinValLen = dwLen; if(AppendRecord(node)) { return TRUE; } else { return FALSE; } } else { return FALSE; }
} return FALSE; } } else { return FALSE; }
DC_END_FN(); }
//
// A worker function to make life easier in RecordToString. This function
// takes a source string, cats it to a destination string, and then appends
// a carriage return and line-feed.
//
HRESULT StringCchCatCRLF(LPTSTR pszDest, size_t cchDest, LPCTSTR pszSrc) { HRESULT hr = E_FAIL; DC_BEGIN_FN("StringCchCatCRLF");
hr = StringCchCat(pszDest, cchDest, pszSrc); if (FAILED(hr)) { DC_QUIT; } hr = StringCchCat(pszDest, cchDest, _T("\r\n")); if (FAILED(hr)) { DC_QUIT; }
DC_EXIT_POINT: DC_END_FN();
return hr; }
//
// Flatten a record to a string (szBuf) using format:
// name:type:value\r\n
//
BOOL CRdpFileStore::RecordToString(PRDPF_RECORD pNode, LPTSTR szBuf, UINT strLen) { DC_BEGIN_FN("RecordToString"); TRC_ASSERT(pNode && szBuf && strLen, (TB,_T("Invalid parameters to RecordToString"))); TCHAR szTemp[LINEBUF_SIZE]; INT lenRemain = strLen; HRESULT hr;
if(pNode && szBuf && strLen) { TRC_ASSERT(IS_VALID_RDPF_TYPECODE(pNode->recType), (TB,_T("Invalid typecode %d"),pNode->recType));
if(pNode->recType != RDPF_RECTYPE_UNPARSED) { // Space for name field, typecode, two delimiters and a NULL.
lenRemain -= _tcslen(pNode->szName) + 4; if(lenRemain >= 0) { hr = StringCchPrintf(szBuf, strLen, _T("%s%s"), pNode->szName, g_szTypeCodeMap[pNode->recType]); if (FAILED(hr)) { TRC_ERR((TB, _T("String printf failed: hr = 0x%x"), hr)); return FALSE; }
switch(pNode->recType) { case RDPF_RECTYPE_UINT: { _stprintf(szTemp,TEXT("%d"),pNode->u.iVal); // Need space for a "\r\n" sequence.
lenRemain -= _tcslen(szTemp) + 2; if(lenRemain >= 0) { hr = StringCchCatCRLF(szBuf, strLen, szTemp); if (FAILED(hr)) { TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr)); return FALSE; } return TRUE; } else { return FALSE; } } break;
case RDPF_RECTYPE_SZ: { // Need space for a "\r\n" sequence.
lenRemain -= _tcslen(pNode->u.szVal) + 2; if(lenRemain >= 0) { hr = StringCchCatCRLF(szBuf, strLen, pNode->u.szVal); if (FAILED(hr)) { TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr)); return FALSE; } return TRUE; } else { return FALSE; } } break;
case RDPF_RECTYPE_BINARY: { DWORD dwLen; //
// Convert the binary buffer to string form
//
//
// First get the buffer length
//
if(!CUT::StringtoBinary( pNode->dwBinValLen, (PBYTE)pNode->u.pBinVal, NULL, &dwLen)) { TRC_ERR((TB, _T("Failed to get StringtoBinary buffer len"))); return FALSE; } lenRemain -= dwLen; if(lenRemain >= 0 && dwLen < LINEBUF_SIZE) { //
// Do the conversion
//
if(CUT::StringtoBinary( pNode->dwBinValLen, (PBYTE)pNode->u.pBinVal, (LPTSTR) szTemp, &dwLen)) { //String to binary appends two trailing
//'0' characters. get rid of them.
szTemp[dwLen-2] = NULL;
hr = StringCchCatCRLF(szBuf, strLen, szTemp); if (FAILED(hr)) { TRC_ERR((TB, _T("String concatenation failed: hr = 0x%x"), hr)); return FALSE; } return TRUE; } else { TRC_ERR((TB,_T("StringtoBinary conversion failed"))); return FALSE; } } else { return FALSE; } } break; } return FALSE; } else { return FALSE; } } else { //Unparsed record, just splat the value
hr = StringCchCopy(szBuf, strLen, pNode->u.szUnparsed); if (SUCCEEDED(hr)) { return TRUE; } else { TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr)); return FALSE; } } } else { return FALSE; }
DC_END_FN(); }
//
// Search the record list
// for the first record with the given name
//
PRDPF_RECORD CRdpFileStore::FindRecord(LPCTSTR szName) { DC_BEGIN_FN("FindRecord");
if(szName && _pRecordListHead) { TCHAR szCmpName[RDPF_NAME_LEN]; HRESULT hr = StringCchCopy(szCmpName, SIZECHAR(szCmpName), szName); if (FAILED(hr)) { TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr)); return NULL; } _tcslwr(szCmpName);
PRDPF_RECORD node = _pRecordListHead; while(node) { if(!_tcscmp(szCmpName, node->szName)) { return node; } node=node->pNext; } return NULL; } else { return NULL; } DC_END_FN(); }
//
// Append record to the end of the record list
// for a record with the given name
//
BOOL CRdpFileStore::AppendRecord(PRDPF_RECORD node) { DC_BEGIN_FN("AppendRecord"); if(node) { node->pNext = NULL; if(_pRecordListHead && _pRecordListTail) { node->pPrev = _pRecordListTail; _pRecordListTail->pNext= node; _pRecordListTail = node; return TRUE; } else { _pRecordListHead = _pRecordListTail = node; node->pPrev = NULL; return TRUE; } } else { return FALSE; } DC_END_FN(); }
//
// Create a new record with name szName
//
PRDPF_RECORD CRdpFileStore::NewRecord(LPCTSTR szName, UINT TypeCode) { DC_BEGIN_FN("NewRecord"); PRDPF_RECORD node = NULL;
if(szName) { //Need to insert new node
node = (PRDPF_RECORD)LocalAlloc(LPTR, sizeof(RDPF_RECORD)); if(node) { node->recType = TypeCode; HRESULT hr = StringCchCopy(node->szName, SIZECHAR(node->szName), szName); if (FAILED(hr)) { TRC_ERR((TB, _T("String copy failed: hr = 0x%x"), hr)); return NULL; } _tcslwr(node->szName); node->pPrev= node->pNext= NULL; } }
DC_END_FN(); return node; }
//
// DeleteRecords
// deletes and resets all inmemory record structures
//
BOOL CRdpFileStore::DeleteRecords() { DC_BEGIN_FN("DeleteRecords"); PRDPF_RECORD node = _pRecordListHead; PRDPF_RECORD prev; while(node) { prev = node; node = node->pNext;
switch(prev->recType) { case RDPF_RECTYPE_SZ: LocalFree(prev->u.szVal); break; case RDPF_RECTYPE_BINARY: LocalFree(prev->u.pBinVal); break; case RDPF_RECTYPE_UNPARSED: LocalFree(prev->u.szUnparsed); break; } LocalFree(prev); } _pRecordListHead = NULL; _pRecordListTail = NULL;
DC_END_FN(); return TRUE; }
inline BOOL CRdpFileStore::DeleteRecord(PRDPF_RECORD node) { DC_BEGIN_FN("DeleteRecord");
TRC_ASSERT(node,(TB,_T("node is null")));
if(node) { if(_pRecordListTail == node) { _pRecordListTail = node->pPrev; } if(_pRecordListHead == node) { _pRecordListHead = node->pNext; }
if(node->pPrev) { node->pPrev->pNext = node->pNext; } if(node->pNext) { node->pNext->pPrev = node->pPrev; }
switch(node->recType) { case RDPF_RECTYPE_SZ: LocalFree(node->u.szVal); break; case RDPF_RECTYPE_BINARY: LocalFree(node->u.pBinVal); break; case RDPF_RECTYPE_UNPARSED: LocalFree(node->u.szUnparsed); break; } LocalFree(node); return TRUE; } else { return FALSE; }
DC_END_FN(); return FALSE; }
BOOL CRdpFileStore::DeleteValueIfPresent(LPCTSTR szName) { DC_BEGIN_FN("DeleteValueIfPresent"); TRC_ASSERT(szName,(TB,_T("szName is null"))); if(szName) { PRDPF_RECORD node = FindRecord(szName); if(node) { return DeleteRecord(node); } else { return TRUE; } } else { return FALSE; }
DC_END_FN(); }
//
// Initialize to a NULL store that is readable
//
BOOL CRdpFileStore::SetToNullStore() { DC_BEGIN_FN("SetToNullStore"); DeleteRecords(); _fOpenForRead = TRUE; _fOpenForWrite = TRUE; DC_END_FN(); return TRUE; }
//
// Return TRUE if the record is present
//
BOOL CRdpFileStore::IsValuePresent(LPTSTR szName) { DC_BEGIN_FN("IsValuePresent");
if(szName) { PRDPF_RECORD node = FindRecord(szName); if(node) { return TRUE; } else { return FALSE; } } else { return FALSE; }
DC_END_FN(); }
DWORD CRdpFileStore::GetDataLength(LPCTSTR szName) { if(szName) { PRDPF_RECORD node = FindRecord(szName); if(node) { switch (node->recType) { case RDPF_RECTYPE_UINT: return sizeof(UINT); break; case RDPF_RECTYPE_SZ: return _tcslen(node->u.szVal) * sizeof(TCHAR); break; case RDPF_RECTYPE_BINARY: return node->dwBinValLen; break; default: return 0; } } else { return 0; } } else { return 0; } }
|