WindowsXP-SP1/admin/activec/core/tstring.cpp
2020-09-30 16:53:49 +02:00

349 lines
8.9 KiB
C++

/*--------------------------------------------------------------------------*
*
* Microsoft Windows
* Copyright (C) Microsoft Corporation, 1992 - 1999
*
* File: tstring.h
*
* Contents: Implementation file for tstring
*
* History: 28-Oct-98 jeffro Created
*
*--------------------------------------------------------------------------*/
#include "tstring.h"
#include "stgio.h"
#include <atlbase.h>
#include <comutil.h>
#include "macros.h"
#include "countof.h"
/*+-------------------------------------------------------------------------*
* tstring::LoadString
*
*
*--------------------------------------------------------------------------*/
bool tstring::LoadString (HINSTANCE hInst, UINT nID)
{
#ifdef UNICODE
#define CHAR_FUDGE 1 // one TCHAR unused is good enough
#else
#define CHAR_FUDGE 2 // two BYTES unused for case of DBC last char
#endif
// try fixed buffer first (to avoid wasting space in the heap)
TCHAR szTemp[256];
int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
int nLen = ::LoadString(hInst, nID, szTemp, nCount);
if (nCount - nLen > CHAR_FUDGE)
*this = szTemp;
else
{
// try buffer size of 512, then larger size until entire string is retrieved
LPTSTR pszBuffer = NULL;
int nSize = 256;
do
{
nSize += 256;
delete[] pszBuffer;
pszBuffer = new TCHAR[nSize];
if (!pszBuffer)
{
return false; // Memory alloc failed.
}
nLen = ::LoadString(hInst, nID, pszBuffer, nSize);
} while (nSize - nLen <= CHAR_FUDGE);
*this = pszBuffer;
delete[] pszBuffer;
}
return (nLen > 0);
}
#ifndef UNICODE
/*+-------------------------------------------------------------------------*
* operator>>
*
* ANSI only: Extracts a string from a stream in Unicode format, then
* converts it to ANSI.
*--------------------------------------------------------------------------*/
IStream& operator>> (IStream& stm, tstring& str)
{
USES_CONVERSION;
std::wstring wstr;
stm >> wstr;
str = W2CA (wstr.data());
return (stm);
}
/*+-------------------------------------------------------------------------*
* operator<<
*
* ANSI only: Inserts a tstring into a stream in Unicode format.
*--------------------------------------------------------------------------*/
IStream& operator<< (IStream& stm, const tstring& str)
{
USES_CONVERSION;
return (stm << std::wstring (A2W (str.data())));
}
#endif // UNICODE
/*+-------------------------------------------------------------------------*
* CStringTableStringBase::CStringTableStringBase
*
*
*--------------------------------------------------------------------------*/
CStringTableStringBase::CStringTableStringBase (IStringTablePrivate* pstp)
: m_spStringTable (pstp),
m_id (eNoValue)
{
}
CStringTableStringBase::CStringTableStringBase (const CStringTableStringBase& other)
: m_spStringTable (other.m_spStringTable),
m_id (eNoValue)
{
Assign (other);
}
CStringTableStringBase::CStringTableStringBase (
IStringTablePrivate* pstp,
const tstring& str)
: m_spStringTable (pstp),
m_id (eNoValue),
m_str (str)
{
}
/*+-------------------------------------------------------------------------*
* CStringTableStringBase::operator=
*
*
*--------------------------------------------------------------------------*/
CStringTableStringBase& CStringTableStringBase::operator= (const CStringTableStringBase& other)
{
if (&other != this)
{
RemoveFromStringTable();
Assign (other);
}
return (*this);
}
CStringTableStringBase& CStringTableStringBase::operator= (const tstring& str)
{
/*
* string table operations are relatively expensive, so a string
* comparision before we do any string table stuff is warranted
*/
if (m_str != str)
{
RemoveFromStringTable();
/*
* copy the text, but delay committing to the string table
*/
m_str = str;
}
return (*this);
}
CStringTableStringBase& CStringTableStringBase::operator= (LPCTSTR psz)
{
return (operator= (tstring (psz)));
}
/*+-------------------------------------------------------------------------*
* CStringTableStringBase::Assign
*
*
*--------------------------------------------------------------------------*/
void CStringTableStringBase::Assign (const CStringTableStringBase& other)
{
ASSERT (m_id == eNoValue);
/*
* copy the other's value
*/
m_str = other.m_str;
/*
* if the source string is already committed to
* the string table, this one should be, too
*/
if (other.m_id != eNoValue)
CommitToStringTable ();
}
/*+-------------------------------------------------------------------------*
* CStringTableStringBase::~CStringTableStringBase
*
*
*--------------------------------------------------------------------------*/
CStringTableStringBase::~CStringTableStringBase ()
{
RemoveFromStringTable();
}
/*+-------------------------------------------------------------------------*
* CStringTableStringBase::CommitToStringTable
*
* Attaches the current string to the given string table
*--------------------------------------------------------------------------*/
MMC_STRING_ID CStringTableStringBase::CommitToStringTable () const
{
/*
* Commit the string if:
*
* 1. the string's not already in the string table, and
* 2. it's not empty, and
* 3. we have a string table
*/
if ((m_id == eNoValue) && !m_str.empty() && (m_spStringTable != NULL))
{
USES_CONVERSION;
m_spStringTable->AddString (T2CW (m_str.data()), &m_id, NULL);
}
return (m_id);
}
/*+-------------------------------------------------------------------------*
* CStringTableStringBase::RemoveFromStringTable
*
* Detaches the current string from the current string table.
*--------------------------------------------------------------------------*/
void CStringTableStringBase::RemoveFromStringTable () const
{
/*
* if we have a string ID from the current string table, delete it
*/
if (m_id != eNoValue)
{
/*
* shouldn't be removing a string from a string table unless
* we have already added it (and therefore obtained an interface)
*/
ASSERT (m_spStringTable != NULL);
m_spStringTable->DeleteString (m_id, NULL);
m_id = eNoValue;
}
}
/*+-------------------------------------------------------------------------*
* operator>>
*
*
*--------------------------------------------------------------------------*/
IStream& operator>> (IStream& stm, CStringTableStringBase& str)
{
str.RemoveFromStringTable();
stm >> str.m_id;
if (str.m_id != CStringTableStringBase::eNoValue)
{
try
{
USES_CONVERSION;
HRESULT hr;
ULONG cch;
if (str.m_spStringTable == NULL)
_com_issue_error (E_NOINTERFACE);
hr = str.m_spStringTable->GetStringLength (str.m_id, &cch, NULL);
THROW_ON_FAIL (hr);
// allow for NULL terminator
cch++;
std::auto_ptr<WCHAR> spszText (new (std::nothrow) WCHAR[cch]);
LPWSTR pszText = spszText.get();
if (pszText == NULL)
_com_issue_error (E_OUTOFMEMORY);
hr = str.m_spStringTable->GetString (str.m_id, cch, pszText, NULL, NULL);
THROW_ON_FAIL (hr);
str.m_str = W2T (pszText);
}
catch (_com_error& err)
{
ASSERT (false && "Caught _com_error");
str.m_id = CStringTableStringBase::eNoValue;
str.m_str.erase();
throw;
}
}
else
str.m_str.erase();
return (stm);
}
/*+-------------------------------------------------------------------------*
* operator<<
*
*
*--------------------------------------------------------------------------*/
IStream& operator<< (IStream& stm, const CStringTableStringBase& str)
{
str.CommitToStringTable();
#ifdef DBG
/*
* make sure CommitToStringTable really committed
*/
if (str.m_id != CStringTableStringBase::eNoValue)
{
WCHAR sz[256];
ASSERT (str.m_spStringTable != NULL);
HRESULT hr = str.m_spStringTable->GetString (str.m_id, countof(sz), sz, NULL, NULL);
ASSERT (SUCCEEDED(hr) && "Persisted a CStringTableString to a stream that's not in the string table");
}
#endif
stm << str.m_id;
return (stm);
}