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