653 lines
16 KiB
C++
653 lines
16 KiB
C++
|
//-----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Forms
|
||
|
// Copyright: (c) 1994-1995, Microsoft Corporation
|
||
|
// All rights Reserved.
|
||
|
// Information contained herein is Proprietary and Confidential.
|
||
|
//
|
||
|
// File CSTR.CXX
|
||
|
//
|
||
|
// Contents Class implementation for length prefix string class
|
||
|
//
|
||
|
// Classes CStr
|
||
|
//
|
||
|
// Maintained by Istvanc
|
||
|
//
|
||
|
//
|
||
|
// History:
|
||
|
// 5-22-95 kfl converted WCHAR to TCHAR
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#include "headers.hxx"
|
||
|
|
||
|
ANSIString::ANSIString(WCHAR *pchWide)
|
||
|
{
|
||
|
_pch = NULL;
|
||
|
|
||
|
Set(pchWide);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ANSIString::Set(WCHAR *pchWide)
|
||
|
{
|
||
|
int cch = wcslen(pchWide) + 1;
|
||
|
|
||
|
if (_pch)
|
||
|
delete _pch;
|
||
|
|
||
|
if (cch > 0)
|
||
|
{
|
||
|
_pch = new char[cch];
|
||
|
|
||
|
MemSetName(_pch, "ANSIString");
|
||
|
|
||
|
if (_pch)
|
||
|
{
|
||
|
WideCharToMultiByte(CP_ACP,
|
||
|
0,
|
||
|
pchWide,
|
||
|
-1,
|
||
|
_pch,
|
||
|
cch,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
_pch = NULL;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::Set, public
|
||
|
//
|
||
|
// Synopsis: Allocates memory for a string and initializes it from a given
|
||
|
// string.
|
||
|
//
|
||
|
// Arguments: [pch] -- String to initialize with. Can be NULL
|
||
|
// [uc] -- Number of characters to allocate.
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Notes: The total number of characters allocated is uc+1, to allow
|
||
|
// for a NULL terminator. If [pch] is NULL, then the string is
|
||
|
// uninitialized except for the NULL terminator, which is at
|
||
|
// character position [uc].
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::Set(LPCTSTR pch, UINT uc)
|
||
|
{
|
||
|
if (pch == _pch)
|
||
|
{
|
||
|
if (uc == Length())
|
||
|
return S_OK;
|
||
|
// when the ptrs are the same the length can only be
|
||
|
// different if the ptrs are NULL. this is a hack used
|
||
|
// internally to implement realloc type expansion
|
||
|
Assert(pch == NULL && _pch == NULL);
|
||
|
}
|
||
|
|
||
|
Free();
|
||
|
|
||
|
BYTE * p = new BYTE [sizeof(TCHAR) + sizeof(TCHAR) * uc + sizeof(UINT)];
|
||
|
if (p)
|
||
|
{
|
||
|
MemSetName(p, "CStr String");
|
||
|
|
||
|
*(UINT *)(p) = uc * sizeof(TCHAR);
|
||
|
_pch = (TCHAR *)(p + sizeof(UINT));
|
||
|
if (pch)
|
||
|
{
|
||
|
_tcsncpy(_pch, pch, uc);
|
||
|
}
|
||
|
|
||
|
((TCHAR *)_pch) [uc] = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::Set, public
|
||
|
//
|
||
|
// Synopsis: Allocates a string and initializes it
|
||
|
//
|
||
|
// Arguments: [pch] -- String to initialize from
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::Set(LPCTSTR pch)
|
||
|
{
|
||
|
RRETURN(Set(pch, pch ? _tcsclen(pch) : 0));
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::Set, public
|
||
|
//
|
||
|
// Synopsis: Allocates a string and initializes it
|
||
|
//
|
||
|
// Arguments: [cstr] -- String to initialize from
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::Set(const CStr &cstr)
|
||
|
{
|
||
|
RRETURN(Set(cstr, cstr.Length()));
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::TakeOwnership, public
|
||
|
//
|
||
|
// Synopsis: Takes the ownership of a string from another CStr class.
|
||
|
//
|
||
|
// Arguments: [cstr] -- Class to take string from
|
||
|
//
|
||
|
// Notes: This method just transfers a string from one CStr class to
|
||
|
// another. The class which is the source of the transfer has
|
||
|
// a NULL value at the end of the operation.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void
|
||
|
CStr::TakeOwnership(CStr &cstr)
|
||
|
{
|
||
|
_Free();
|
||
|
_pch = cstr._pch;
|
||
|
cstr._pch = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::SetBSTR, public
|
||
|
//
|
||
|
// Synopsis: Allocates a string and initializes it from a BSTR
|
||
|
//
|
||
|
// Arguments: [bstr] -- Initialization string
|
||
|
//
|
||
|
// Notes: This method is more efficient than Set(LPCWSTR pch) because
|
||
|
// of the length-prefix on BSTRs.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::SetBSTR(const BSTR bstr)
|
||
|
{
|
||
|
RRETURN(Set(bstr, bstr ? SysStringLen(bstr) : 0));
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::SetMultiByte, public
|
||
|
//
|
||
|
// Synopsis: Sets the string value from an MultiByte string
|
||
|
//
|
||
|
// Arguments: [pch] -- MultiByte string to convert to UNICODE
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::SetMultiByte(LPCSTR pch)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
DWORD dwLen;
|
||
|
|
||
|
dwLen = strlen(pch);
|
||
|
|
||
|
hr = Set(NULL, dwLen);
|
||
|
if (hr)
|
||
|
RRETURN(hr);
|
||
|
|
||
|
dwLen = MultiByteToWideChar(CP_ACP,
|
||
|
0,
|
||
|
pch,
|
||
|
dwLen,
|
||
|
_pch,
|
||
|
dwLen + 1);
|
||
|
|
||
|
if (dwLen == 0)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::GetMultiByte, public
|
||
|
//
|
||
|
// Synopsis: Gets the string value in MultiByte format
|
||
|
//
|
||
|
// Arguments: [pch] -- Place to put MultiByte string
|
||
|
// [cch] -- Size of buffer pch points to
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::GetMultiByte(LPSTR pch, UINT cch)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
DWORD dwLen = WideCharToMultiByte(CP_ACP,
|
||
|
0,
|
||
|
_pch,
|
||
|
-1,
|
||
|
pch,
|
||
|
cch,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (dwLen == 0)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::Length, public
|
||
|
//
|
||
|
// Synopsis: Returns the length of the string associated with this class
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
UINT
|
||
|
CStr::Length() const
|
||
|
{
|
||
|
if (_pch)
|
||
|
return (((UINT *)_pch) [-1]) / sizeof(TCHAR);
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::ReAlloc, public
|
||
|
//
|
||
|
// Synopsis: Reallocate the string to a different size buffer.
|
||
|
// The length of the string is not affected, but it is allocated
|
||
|
// within a larger (or maybe smaller) memory allocation.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::ReAlloc( UINT uc )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
TCHAR * pchOld;
|
||
|
UINT ubOld;
|
||
|
|
||
|
Assert(uc >= Length()); // Disallowed to allocate a too-short buffer.
|
||
|
|
||
|
if (uc)
|
||
|
{
|
||
|
pchOld = _pch; // Save pointer to old string.
|
||
|
_pch = 0; // Prevent Set from Freeing the string.
|
||
|
ubOld = pchOld ? // Save old length
|
||
|
*(UINT *) (((BYTE *)pchOld) - sizeof(UINT))
|
||
|
: 0;
|
||
|
|
||
|
hr = Set(pchOld, uc); // Alloc new; Copy old string.
|
||
|
if (hr)
|
||
|
{
|
||
|
_pch = pchOld;
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
*(UINT *)(((BYTE *)_pch) - sizeof(UINT)) = ubOld; // Restore length.
|
||
|
|
||
|
if (pchOld )
|
||
|
{
|
||
|
delete [] (((BYTE *)pchOld) - sizeof(UINT));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// else if uc == 0, then, since we have already checked that uc >= Length,
|
||
|
// length must == 0.
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::Append
|
||
|
//
|
||
|
// Synopsis: Append chars to the end of the string, reallocating & updating
|
||
|
// its length.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::Append(LPCTSTR pch, UINT uc)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
UINT ucOld, ucNew;
|
||
|
BYTE *p;
|
||
|
|
||
|
if (uc)
|
||
|
{
|
||
|
ucOld = Length();
|
||
|
ucNew = ucOld + uc;
|
||
|
hr = ReAlloc(ucNew);
|
||
|
if (hr)
|
||
|
goto Cleanup;
|
||
|
_tcsncpy(_pch + ucOld, pch, uc);
|
||
|
((TCHAR *)_pch) [ucNew] = 0;
|
||
|
p = ((BYTE*)_pch - sizeof(UINT));
|
||
|
*(UINT *)p = ucNew * sizeof(TCHAR);
|
||
|
}
|
||
|
Cleanup:
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT
|
||
|
CStr::Append(LPCTSTR pch)
|
||
|
{
|
||
|
RRETURN(Append(pch, pch ? _tcsclen(pch) : 0));
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::AppendMultiByte, public
|
||
|
//
|
||
|
// Synopsis: Append a multibyte string to the end,
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::AppendMultiByte(LPCSTR pch)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
UINT ucOld, ucNew, uc;
|
||
|
BYTE *p;
|
||
|
|
||
|
uc = strlen(pch);
|
||
|
|
||
|
if (uc)
|
||
|
{
|
||
|
ucOld = Length();
|
||
|
ucNew = ucOld + uc;
|
||
|
hr = ReAlloc(ucNew);
|
||
|
if (hr)
|
||
|
goto Cleanup;
|
||
|
|
||
|
uc = MultiByteToWideChar(CP_ACP,
|
||
|
0,
|
||
|
pch,
|
||
|
uc,
|
||
|
_pch + ucOld,
|
||
|
uc + 1);
|
||
|
if (uc == 0)
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
|
||
|
TraceTag((tagError, "CSTR: Fatal string conversion error %x", hr));
|
||
|
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
((TCHAR *)_pch) [ucNew] = 0;
|
||
|
p = ((BYTE*)_pch - sizeof(UINT));
|
||
|
*(UINT *)p = ucNew * sizeof(TCHAR);
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::SetLengthNoAlloc, public
|
||
|
//
|
||
|
// Synopsis: Sets the internal length of the string. Note. There is no
|
||
|
// verification that the length that is set is within the allocated
|
||
|
// range of the string. If the caller sets the length too large,
|
||
|
// this blasts a null byte into memory.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::SetLengthNoAlloc( UINT uc )
|
||
|
{
|
||
|
if (_pch)
|
||
|
{
|
||
|
BYTE * p = ( (BYTE *)_pch - sizeof(UINT));
|
||
|
*(UINT *)p = uc * sizeof(TCHAR); // Set the length prefix.
|
||
|
((TCHAR *)_pch) [uc] = 0; // Set null terminator
|
||
|
return S_OK;
|
||
|
}
|
||
|
else
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::AllocBSTR, public
|
||
|
//
|
||
|
// Synopsis: Allocates a BSTR and initializes it with the string that is
|
||
|
// associated with this class.
|
||
|
//
|
||
|
// Arguments: [pBSTR] -- Place to put new BSTR. This pointer should not
|
||
|
// be pointing to an existing BSTR.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CStr::AllocBSTR(BSTR *pBSTR) const
|
||
|
{
|
||
|
if (!_pch)
|
||
|
{
|
||
|
*pBSTR = 0;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
*pBSTR = SysAllocStringLen(*this, Length());
|
||
|
RRETURN(*pBSTR ? S_OK: E_OUTOFMEMORY);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::TrimTrailingWhitespace, public
|
||
|
//
|
||
|
// Synopsis: Removes any trailing whitespace in the string that is
|
||
|
// associated with this class.
|
||
|
//
|
||
|
// Arguments: None.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT CStr::TrimTrailingWhitespace()
|
||
|
{
|
||
|
if (!_pch)
|
||
|
return S_OK;
|
||
|
|
||
|
UINT ucNewLength = Length();
|
||
|
|
||
|
for ( ; ucNewLength > 0; ucNewLength-- )
|
||
|
{
|
||
|
if ( !_istspace( ((TCHAR *)_pch)[ ucNewLength - 1 ] ) )
|
||
|
break;
|
||
|
((TCHAR *)_pch)[ ucNewLength - 1 ] = (TCHAR) 0;
|
||
|
}
|
||
|
|
||
|
BYTE *p = ((BYTE*)_pch - sizeof(UINT));
|
||
|
*(UINT *)p = ucNewLength * sizeof(TCHAR);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::_Free, private
|
||
|
//
|
||
|
// Synopsis: Frees any memory held onto by this class.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void
|
||
|
CStr::_Free()
|
||
|
{
|
||
|
if (_pch )
|
||
|
{
|
||
|
delete [] (((BYTE *)_pch) - sizeof(UINT));
|
||
|
}
|
||
|
_pch=0;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::Clone
|
||
|
//
|
||
|
// Synopsis: Make copy of current string
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT
|
||
|
CStr::Clone(CStr **ppCStr) const
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
Assert(ppCStr);
|
||
|
*ppCStr = new CStr;
|
||
|
hr = *ppCStr?S_OK:E_OUTOFMEMORY;
|
||
|
if (hr)
|
||
|
goto Cleanup;
|
||
|
|
||
|
hr = THR( (*ppCStr)->Set(*this) );
|
||
|
|
||
|
Cleanup:
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::Compare
|
||
|
//
|
||
|
// Synopsis: Case insensitive comparison of 2 strings
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
BOOL
|
||
|
CStr::Compare (const CStr *pCStr) const
|
||
|
{
|
||
|
return (!_tcsicmp(*pCStr, *this));
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::ComputeCrc
|
||
|
//
|
||
|
// Synopsis: Computes a hash of the string.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
#pragma warning(disable:4305)
|
||
|
WORD
|
||
|
CStr::ComputeCrc() const
|
||
|
{
|
||
|
WORD wHash=0;
|
||
|
const TCHAR* pch;
|
||
|
int i;
|
||
|
|
||
|
pch=*this;
|
||
|
for(i = Length();i > 0;i--, pch++)
|
||
|
{
|
||
|
wHash = wHash << 7 ^ wHash >> (16-7) ^ (TCHAR)CharUpper((LPTSTR)((DWORD)(*pch)));
|
||
|
}
|
||
|
|
||
|
return wHash;
|
||
|
}
|
||
|
#pragma warning(default:4305)
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::Load
|
||
|
//
|
||
|
// Synopsis: Initializes the CStr from a stream
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT
|
||
|
CStr::Load(IStream * pstm)
|
||
|
{
|
||
|
DWORD cch;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = THR(pstm->Read(&cch, sizeof(DWORD), NULL));
|
||
|
if (hr)
|
||
|
goto Cleanup;
|
||
|
|
||
|
if (cch == 0xFFFFFFFF)
|
||
|
{
|
||
|
Free();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = THR(Set(NULL, cch));
|
||
|
if (hr)
|
||
|
goto Cleanup;
|
||
|
|
||
|
if (cch)
|
||
|
{
|
||
|
hr = THR(pstm->Read(_pch, cch * sizeof(TCHAR), NULL));
|
||
|
if (hr)
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::Save
|
||
|
//
|
||
|
// Synopsis: Writes the contents of the CStr to a stream
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
HRESULT
|
||
|
CStr::Save(IStream * pstm) const
|
||
|
{
|
||
|
DWORD cch = _pch ? Length() : 0xFFFFFFFF;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = THR(pstm->Write(&cch, sizeof(DWORD), NULL));
|
||
|
if (hr)
|
||
|
goto Cleanup;
|
||
|
|
||
|
if (cch && cch != 0xFFFFFFFF)
|
||
|
{
|
||
|
hr = THR(pstm->Write(_pch, cch * sizeof(TCHAR), NULL));
|
||
|
if (hr)
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
Cleanup:
|
||
|
RRETURN(hr);
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CStr::GetSaveSize
|
||
|
//
|
||
|
// Synopsis: Returns the number of bytes which will be written by
|
||
|
// CStr::Save
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
ULONG
|
||
|
CStr::GetSaveSize() const
|
||
|
{
|
||
|
return(sizeof(DWORD) + (_pch ? (Length() * sizeof(TCHAR)) : 0));
|
||
|
}
|
||
|
|