/*--------------------------------------------------------------------------* * * 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 #include #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 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); }