#if !defined(_WINDOWS_BCL_PURESTRING_H_INCLUDED_) #define _WINDOWS_BCL_PURESTRING_H_INCLUDED_ #pragma once /*++ Copyright (c) 2000 Microsoft Corporation Module Name: bcl_purestring.h Abstract: Abstract algorithms and definitions for a string class. Author: Michael Grier (MGrier) 2/6/2002 Revision History: --*/ #include namespace BCL { class CBaseString { }; template class CPureString; // // This is a pair of classes that manage buffers containing characters. // // We don't call it a "string class" because we want to have a more // pure model of a string (poolable non-mutable bodies); instead this is // a glorified "CHAR *" where as you do common operations the buffer // is resized appropriately. // // // Important note: // // This class will not be fully functional with the BCL CUnicodeCharTraits class // since here in the BCL, we can't take a position about case insensitive // behavior or memory allocation. // // Thus, this is clearly just a base class that needs to be specialized in // conjunction with other specializations of the char traits class(es) to be // usable. // // -mgrier (1/23/2002) // template class CPureString : public CBaseString { friend TTraits; friend typename TTraits::TAccessor; protected: typedef typename TTraits::TChar TChar; // e.g. WCHAR (alternately, CHAR) typedef typename TTraits::TNonNativeChar TNonNativeChar; // e.g. CHAR (alternately, WCHAR) typedef typename TTraits::TMetaChar TMetaChar; // e.g. ULONG for a UCS-4 character typedef typename TTraits::TMutableString TMutableString; // PWSTR typedef typename TTraits::TConstantString TConstantString; // PCWSTR typedef typename TTraits::TSizeT TSizeT; // SIZE_T typedef typename TTraits::TCallDisposition TCallDisposition; typedef typename TTraits::TPublicErrorReturnType TPublicErrorReturnType; typedef typename TTraits::TAccessor TAccessor; typedef typename TTraits::TCaseInsensitivityData TCaseInsensitivityData; typedef typename TTraits::TComparisonResult TComparisonResult; typedef typename TTraits::TEncodingDataIn TEncodingDataIn; typedef typename TTraits::TEncodingDataOut TEncodingDataOut; typedef typename TTraits::TDecodingDataIn TDecodingDataIn; typedef typename TTraits::TDecodingDataOut TDecodingDataOut; typedef typename TTraits::TMutableNonNativeString TMutableNonNativeString; typedef typename TTraits::TConstantNonNativeString TConstantNonNativeString; typedef typename TTraits::TConstantNonNativePair TConstantNonNativePair; typedef typename TTraits::TMutableNonNativePair TMutableNonNativePair; typedef typename TTraits::TConstantPair TConstantPair; typedef typename TTraits::TMutablePair TMutablePair; // You may not instantiate an instance of this class directly; you need to provide a derived // class which adds allocation/deallocation particulars. inline CPureString() { } // // Note that somewhat counter-intuitively, there is neither an assignment operator, // copy constructor or constructor taking a TConstantString. This is necessary // because such a constructor would need to perform a dynamic allocation // if the path passed in were longer than nInlineChars which could fail and // since we do not throw exceptions, constructors may not fail. Instead the caller // must just perform the default construction and then use the Assign() member // function, remembering of course to check its return status. // ~CPureString() { BCL_ASSERT(this->NoAccessors()); } inline void IntegrityCheck() const { TTraits::IntegrityCheck(this); } inline TCallDisposition __fastcall NoAccessorsCheck() const { return TTraits::NoAccessorsCheck(this); } inline bool AnyAccessors() const { return TTraits::AnyAccessors(this); } inline bool NoAccessors() const { return TTraits::NoAccessors(this); } inline TSizeT GetAccessorCount() const { return TTraits::GetAccessorCount(this); } inline TCallDisposition AttachAccessor(TAccessor *pAccessor) { return TTraits::AddAccessor(this, pAccessor); } inline void DetachAccessor(TAccessor *pAccessor) { TTraits::RemoveAccessor(this, pAccessor); } inline TConstantString GetBufferPtr() const { return TTraits::GetBufferPtr(this); } inline TSizeT GetBufferCch() const { return TTraits::GetBufferCch(this); } inline void SetBufferPointerAndCount(TMutableString psz, TSizeT cch) { TTraits::SetBufferPointerAndCount(this, psz, cch); } inline TSizeT GetStringCch() const { return TTraits::GetStringCch(this); } inline bool StringCchLegal(TSizeT cch) const { return TTraits::StringCchLegal(cch); } inline bool StringCchLegal(const TConstantPair &rpair) const { return TTraits::StringCchLegal(rpair.GetCount()); } inline TMutableString GetMutableBufferPtr() { return TTraits::GetMutableBufferPtr(this); } inline void SetStringCch(TSizeT cch) { TTraits::SetStringCch(this, cch); } // We make an explicit assumption here that the derived type holds a pair object for the // buffer length and pointer, but the "effective string length and pointer" aren't // stored together in a single pair object. (This would require having two copies of // the buffer pointer - one in the buffer pair and one in the string pair.) // // Instead we do not provide a mutable string pair operation; you can get a constant // string pair but almost certainly what you'll get back is a temporary object. inline const TConstantPair &BufferPair() const { return TTraits::BufferPair(this); } inline TMutablePair &MutableBufferPair() { return TTraits::MutableBufferPair(this); } inline TMutablePair GetMutableBufferPair() { return TTraits::MutableBufferPair(this); } // return a copy inline const TMutablePair GetOffsetMutableBufferPair(TSizeT cchOffset) { return TTraits::GetOffsetMutableBufferPair(this, cchOffset); } inline const TConstantPair GetStringPair() const { return TTraits::GetStringPair(this); } inline const TConstantString GetStringPtr() const { return TTraits::GetStringPair(this).GetPointer(); } template static inline bool IsValidParameter(const CConstantPointerAndCountPair &rpair) { return (rpair.GetPointer() != NULL) || (rpair.GetCount() == 0); } template static inline bool IsValidParameter(const CMutablePointerAndCountPair &rpair) { return (rpair.GetPointer() != NULL) || (rpair.GetCount() == 0); } static inline bool IsValidParameter(TChar ch) { return true; } static inline bool IsValidParameter(TConstantString psz) { return true; } static inline bool IsValidParameter(TMutableString psz) { return true; } static inline bool IsValidParameter(TConstantNonNativeString psz) { return true; } static inline bool IsValidParameter(TMutableNonNativeString psz) { return true; } template static inline TSizeT GetTemplateParameterBufferCch(const CConstantPointerAndCountPair &rpair) { return rpair.GetCount(); } template static inline TSizeT GetTemplateParameterBufferCch(const CMutablePointerAndCountPair &rpair) { return rpair.GetCount(); } inline TCallDisposition EnsureBufferLargeEnoughPreserve(TSizeT cch) { return TTraits::EnsureBufferLargeEnoughPreserve(this, cch); } inline TCallDisposition EnsureBufferLargeEnoughNoPreserve(TSizeT cch) { return TTraits::EnsureBufferLargeEnoughNoPreserve(this, cch); } template inline TCallDisposition ExpandBufferForInputPreserve(const TSomeInputType &rinput, TSizeT cchExtra, TSizeT &rcchString) { BCL_MAYFAIL_PROLOG TSizeT cch; TSizeT cchSum; rcchString = 0; BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_PARAMETER_CHECK(this->StringCchLegal(cchExtra)); BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rinput, cch)); BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(cchExtra, cch, cchSum)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cchSum)); rcchString = cch; BCL_MAYFAIL_EPILOG_INTERNAL } template inline TCallDisposition ExpandBufferForInputNoPreserve(const TSomeInputType &rinput, TSizeT cchExtra, TSizeT &rcchString) { BCL_MAYFAIL_PROLOG TSizeT cch; TSizeT cchSum; rcchString = 0; BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_PARAMETER_CHECK(this->StringCchLegal(cchExtra)); BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rinput, cch)); BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(cchExtra, cch, cchSum)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughNoPreserve(cchSum)); rcchString = cch; BCL_MAYFAIL_EPILOG_INTERNAL } template inline TPublicErrorReturnType __fastcall public_Assign( const TSomeInputType &rinput ) { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); this->IntegrityCheck(); TSizeT cch; // it would seem innocuous to allow assigns that don't resize the buffer to not // invalidate accessors, but that makes finding such bugs subject to even more // strenuous coverage problems than this simple error. The simple rule is that // you should not have an accessor attached to a string buffer when you use // any of member functions that may mutate the value. BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); BCL_IFCALLFAILED_EXIT(this->ExpandBufferForInputNoPreserve(rinput, 0, cch)); if (cch > 0) { TSizeT cchWritten; BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBuffer(this->MutableBufferPair(), rinput, cchWritten)); // cch was the buffer size we needed (including the trailing null); we don't need the trailing // null any more... this->SetStringCch(cch); } BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_AssignVa(TSomeConstantStringType pUnusedPrototype, TSizeT cStrings, va_list ap) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); TMutablePair pairCursor; TSizeT cch = 0; TSizeT i; va_list ap2 = ap; BCL_PARAMETER_CHECK(cStrings >= 0); // it would seem innocuous to allow assigns that don't resize the buffer to not // invalidate accessors, but that makes finding such bugs subject to even more // strenuous coverage problems than this simple error. The simple rule is that // you should not have an accessor attached to a string buffer when you use // any of member functions that may mutate the value. BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); for (i=0; i(cchArg); TSizeT cchRequired; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(TConstantPair(psz, cchThis), cchRequired)); BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(cch, cchRequired, cch)); } BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughNoPreserve(cch)); pairCursor.SetPointerAndCount(this->GetMutableBufferPtr(), cch); for (i=0; i(cchArg); BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBufferAndAdvanceCursor(pairCursor, TConstantPair(psz, cchThis))); } this->SetStringCch(cch); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_AssignArray(TSizeT cStrings, const TSomePairType *prgpairs) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); TMutablePair pairCursor; TSizeT cch = 0; TSizeT i; BCL_PARAMETER_CHECK(cStrings >= 0); // it would seem innocuous to allow assigns that don't resize the buffer to not // invalidate accessors, but that makes finding such bugs subject to even more // strenuous coverage problems than this simple error. The simple rule is that // you should not have an accessor attached to a string buffer when you use // any of member functions that may mutate the value. BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); for (i=0; iEnsureBufferLargeEnoughNoPreserve(cch)); pairCursor.SetPointerAndCount(this->GetMutableBufferPtr(), cch); for (i=0; iSetStringCch(cch); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_Assign( const TDecodingDataIn &rddi, const TSomeInputType &rinput, TDecodingDataOut &rddo ) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); SIZE_T cch; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rddi, rinput, rddo, cch)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughNoPreserve(cch)); BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBuffer(this->GetMutableBufferPair(), rddi, rinput, rddo)); this->SetStringCch(cch); BCL_MAYFAIL_EPILOG_PUBLIC } // Note: the sematics of the *Fill() functions is to try to get the // string to a particular length, not to add "n" instances of the // input. Thus you might use this to pad a string with dots to get to // a certain number of characters. If you want to work with repetitions // of the input, use the *Repeat() functions. template inline TPublicErrorReturnType public_AssignFill( const TSomeInputType &rinput, TSizeT cchResultantStringMaxLength, TSizeT &rcchExtra // if the length of rinput converted to the native buffer type // (think Unicode -> NonNative or vice versa) is not a multiple // of cchResultantStringMaxLength, the remainder is // returned here in rcchExtra. ) { BCL_MAYFAIL_PROLOG // TSizeT cchSum; TSizeT cchInput; TSizeT cchActual = 0; TSizeT cchExtra = 0; BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); if (cchResultantStringMaxLength > 0) { BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rinput, cchInput)); if (cchInput > 0) { TSizeT cRepetitions; TMutablePair pairCursor; cRepetitions = cchResultantStringMaxLength / cchInput; cchExtra = cchResultantStringMaxLength % cchInput; BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughNoPreserve(cchResultantStringMaxLength)); pairCursor = this->GetMutableBufferPair(); while (cRepetitions > 0) { BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBufferAndAdvanceCursor(pairCursor, rinput)); cRepetitions--; } cchActual = cchResultantStringMaxLength - cchExtra; } else { cchExtra = cchResultantStringMaxLength; } } this->SetStringCch(cchActual); rcchExtra = cchExtra; BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_AssignRepeat( const TSomeInputType &rinput, TSizeT cRepetitions ) { BCL_MAYFAIL_PROLOG TSizeT cchTotal = 0; BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); if (cRepetitions > 0) { TSizeT cchInput; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rinput, cchInput)); if (cchInput > 0) { TMutablePair pairCursor; BCL_IFCALLFAILED_EXIT(TTraits::MultiplyWithOverflowCheck(cchInput, cRepetitions, cchTotal)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughNoPreserve(cchTotal)); pairCursor = this->GetMutableBufferPair(); while (cRepetitions > 0) { BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBufferAndAdvanceCursor(pairCursor, rinput)); cRepetitions--; } } } this->SetStringCch(cchTotal); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_AppendVa(TSomeConstantStringType pUnusedPrototype, TSizeT cStrings, va_list ap) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); TMutablePair pairCursor; TSizeT cch = 0; TSizeT cchTemp; TSizeT i; va_list ap2 = ap; BCL_PARAMETER_CHECK(cStrings >= 0); // it would seem innocuous to allow assigns that don't resize the buffer to not // invalidate accessors, but that makes finding such bugs subject to even more // strenuous coverage problems than this simple error. The simple rule is that // you should not have an accessor attached to a string buffer when you use // any of member functions that may mutate the value. BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); for (i=0; i(cchArg); TSizeT cchRequired; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(TConstantPair(psz, cchThis), cchRequired)); BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(cch, cchRequired, cch)); } BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(cch, this->GetStringCch(), cch)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cch)); pairCursor.SetPointerAndCount(this->GetOffsetMutableBufferPtr(this->GetStringCch()), cch); for (i=0; i(cchArg); BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBufferAndAdvanceCursor(pairCursor, TConstantPair(psz, cchThis))); } this->SetStringCch(cch); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_Append( const TSomeInputType &rinput ) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); TSizeT cch; BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); BCL_IFCALLFAILED_EXIT(this->ExpandBufferForInputPreserve(rinput, this->GetStringCch(), cch)); if (cch > 0) { TSizeT cchWritten; BCL_IFCALLFAILED_EXIT( TTraits::CopyIntoBuffer( this->GetOffsetMutableBufferPair(this->GetStringCch()), rinput, cchWritten)); // We can assume that adding cch to the current string cch does not // overflow since ExpandBufferForInputPreserve would have had the same // overflow this->SetStringCch(this->GetStringCch() + cch); } BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_Append( const TDecodingDataIn &rddi, const TSomeInputType &rinput, TDecodingDataOut &rddo ) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); SIZE_T cch; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rddi, rinput, rddo, cch)); BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(cch, this->GetStringCch(), cch)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cch)); BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBuffer(this->GetOffsetMutableBufferPair(this->GetStringCch()), rddi, rinput, rddo)); this->SetStringCch(cch); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_AppendArray(TSizeT cStrings, const TSomeInputType *prginput) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); TMutablePair pairCursor; TSizeT cch = 0; TSizeT i; BCL_PARAMETER_CHECK((prginput != NULL) || (cStrings == 0)); BCL_PARAMETER_CHECK(cStrings >= 0); // it would seem innocuous to allow assigns that don't resize the buffer to not // invalidate accessors, but that makes finding such bugs subject to even more // strenuous coverage problems than this simple error. The simple rule is that // you should not have an accessor attached to a string buffer when you use // any of member functions that may mutate the value. BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); for (i=0; iGetStringCch(), cch)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cch)); pairCursor = this->GetOffsetMutableBufferPair(this->GetStringCch()); for (i=0; iSetStringCch(cch); BCL_MAYFAIL_EPILOG_PUBLIC } // Note: the sematics of the *Fill() functions is to try to get the // string to a particular length, not to add "n" instances of the // input. Thus you might use this to pad a string with dots to get to // a certain number of characters. If you want to work with repetitions // of the input, use the *Repeat() functions. template inline TPublicErrorReturnType public_AppendFill( const TSomeInputType &rinput, TSizeT cchResultantStringMaxLength, TSizeT &rcchExtra // if the length of rinput converted to the native buffer type // (think Unicode -> NonNative or vice versa) is not a multiple // of cchResultantStringMaxLength, the remainder is // returned here in rcchExtra. ) { BCL_MAYFAIL_PROLOG TSizeT cchInput; TSizeT cchExtra = 0; TSizeT cchString = this->GetStringCch(); TSizeT cchActual = cchString; BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); if (cchResultantStringMaxLength > cchString) { BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rinput, cchInput)); if (cchInput > 0) { TSizeT cRepetitions; TMutablePair pairBuffer; TSizeT cchAppendPartMaxLength = cchResultantStringMaxLength - cchString; cRepetitions = cchAppendPartMaxLength / cchInput; cchExtra = cchAppendPartMaxLength % cchInput; BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cchResultantStringMaxLength - cchExtra)); pairBuffer = this->GetOffsetMutableBufferPair(cchString); while (cRepetitions > 0) { BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBufferAndAdvanceCursor(pairBuffer, rinput)); cRepetitions--; } } else { // Zero input string; extra chars is simple diff (no // underflow since we already know that cchResultantStringMaxLength // is greater than cchString). cchExtra = cchResultantStringMaxLength - cchString; } cchActual = cchResultantStringMaxLength - cchExtra; } this->SetStringCch(cchActual); rcchExtra = cchExtra; BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_AppendRepeat( const TSomeInputType &rinput, TSizeT cRepetitions ) { BCL_MAYFAIL_PROLOG TSizeT cchString = this->GetStringCch(); TSizeT cchTotal = cchString; BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); if (cRepetitions > 0) { TSizeT cchInput; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rinput, cchInput)); if (cchInput > 0) { TMutablePair pairCursor; BCL_IFCALLFAILED_EXIT(TTraits::MultiplyWithOverflowCheck(cchInput, cRepetitions, cchTotal)); BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(cchTotal, cchString, cchTotal)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cchTotal)); pairCursor = this->GetOffsetMutableBufferPair(cchString); while (cRepetitions > 0) { BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBufferAndAdvanceCursor(pairCursor, rinput)); cRepetitions--; } } } this->SetStringCch(cchTotal); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_Prepend( const TSomeInputType &rinput ) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); TSizeT cchInput; BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); TSizeT cchSum; TSizeT cchWritten; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rinput, cchInput)); BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(this->GetStringCch(), cchInput, cchSum)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cchSum)); // Move current buffer "up" BCL::MoveBytes(this->GetMutableBufferPtr() + cchInput, this->GetBufferPtr(), this->GetStringCch() * sizeof(TChar)); // Copy from the source string into the buffer. BCL_IFCALLFAILED_EXIT( TTraits::CopyIntoBuffer( this->MutableBufferPair(), rinput, cchWritten)); this->SetStringCch(cchSum); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_Prepend( const TDecodingDataIn &rddi, const TSomeInputType &rinput, TDecodingDataOut &rddo ) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); SIZE_T cch; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(rddi, rinput, rddo, cch)); BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(cch, this->GetStringCch(), cch)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cch)); BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBuffer(this->GetMutableBufferPair(), rddi, rinput, rddo)); this->SetStringCch(cch); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_PrependArray(TSizeT cStrings, const TSomeInputType *prginput) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); TMutablePair pairCursor; TSizeT cch = 0; TSizeT i; TSizeT cchString = this->GetStringCch(); BCL_PARAMETER_CHECK((prginput != NULL) || (cStrings == 0)); BCL_PARAMETER_CHECK(cStrings >= 0); // it would seem innocuous to allow assigns that don't resize the buffer to not // invalidate accessors, but that makes finding such bugs subject to even more // strenuous coverage problems than this simple error. The simple rule is that // you should not have an accessor attached to a string buffer when you use // any of member functions that may mutate the value. BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); for (i=0; iEnsureBufferLargeEnoughPreserve(cch)); // Move current buffer "up" BCL::MoveBytes(this->GetMutableBufferPtr() + cchString, this->GetBufferPtr(), cchString * sizeof(TChar)); pairCursor = this->GetMutableBufferPair(); for (i=0; iSetStringCch(cch); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_CopyOut( const TEncodingDataIn &rddi, const TSomeOutputType &routput, TEncodingDataOut &rddo, TSizeT &rcchWritten ) const { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); TConstantPair pairString = this->GetStringPair(); TSizeT cchOriginal, cchToCopy, cchBufferWritten; BCL_PARAMETER_CHECK(this->IsValidParameter(routput)); cchOriginal = pairString.GetCount(); BCL_IFCALLFAILED_EXIT(TTraits::MapStringCchToBufferCch(cchOriginal, cchToCopy)); pairString.SetCount(cchToCopy); BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBuffer(routput, rddi, pairString, rddo, cchBufferWritten)); BCL_IFCALLFAILED_EXIT(TTraits::MapBufferCchToStringCch(cchBufferWritten, rcchWritten)); BCL_MAYFAIL_EPILOG_PUBLIC } inline TPublicErrorReturnType public_CopyOut( const TEncodingDataIn &rddi, TMutableNonNativeString &routput, TEncodingDataOut &rddo, TSizeT &rcchWritten ) const { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(routput)); BCL_IFCALLFAILED_EXIT(TTraits::AllocateAndCopyIntoBuffer(routput, rddi, this->GetStringPair(), rddo, rcchWritten)); BCL_MAYFAIL_EPILOG_PUBLIC } inline TPublicErrorReturnType public_CopyOut( const TMutablePair &routput, TSizeT &rcchWritten ) const { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); TConstantPair pairString = this->GetStringPair(); TSizeT cchOriginal; TSizeT cchToCopy; TSizeT cchBufferWritten; BCL_PARAMETER_CHECK(this->IsValidParameter(routput)); // Apply null termination length as applicable cchOriginal = pairString.GetCount(); BCL_IFCALLFAILED_EXIT(TTraits::MapStringCchToBufferCch(pairString.GetCount(), cchToCopy)); pairString.SetCount(cchToCopy); BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBuffer(routput, pairString, cchBufferWritten)); BCL_IFCALLFAILED_EXIT(TTraits::MapBufferCchToStringCch(cchBufferWritten, rcchWritten)); BCL_MAYFAIL_EPILOG_PUBLIC } inline TPublicErrorReturnType public_CopyOut( TMutableString &rstringout, TSizeT &rcchWritten ) const { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rstringout)); BCL_IFCALLFAILED_EXIT(TTraits::AllocateAndCopyIntoBuffer(rstringout, this->GetStringPair(), rcchWritten)); BCL_MAYFAIL_EPILOG_PUBLIC } inline VOID public_Clear(bool fFreeStorage = false) { this->IntegrityCheck(); // You can't free the storage if there's an attached accessor BCL_ASSERT(!fFreeStorage || this->NoAccessors()); if (this->NoAccessors()) { if (fFreeStorage) TTraits::DeallocateDynamicBuffer(this); this->SetStringCch(0); } } inline TPublicErrorReturnType public_UpperCase(const TCaseInsensitivityData &rcid) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_IFCALLFAILED_EXIT(TTraits::UpperCase(this, rcid)); BCL_MAYFAIL_EPILOG_PUBLIC } inline TPublicErrorReturnType public_LowerCase(const TCaseInsensitivityData &rcid) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_IFCALLFAILED_EXIT(TTraits::LowerCase(this, rcid)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_Compare( const TSomeInputType &rinput, TComparisonResult &rcrOut ) const { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::CompareStrings(this->GetStringPair(), rinput, rcrOut)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_CompareI( const TSomeInputType &rinput, const TCaseInsensitivityData &rcid, TComparisonResult &rcrOut ) const { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::CompareStringsI(this->GetStringPair(), rinput, rcid, rcrOut)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_Equals( const TSomeInputType &rinputCandidate, bool &rfMatches ) const { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rinputCandidate)); BCL_IFCALLFAILED_EXIT( TTraits::EqualStrings( this->GetStringPair(), rinputCandidate, rfMatches)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_EqualsI( const TSomeInputType &rinputCandidate, const TCaseInsensitivityData &rcid, bool &rfMatches ) const { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(this->IsValidParameter(rinputCandidate)); BCL_IFCALLFAILED_EXIT( TTraits::EqualStringsI( this->GetStringPair(), rinputCandidate, rcid, rfMatches)); BCL_MAYFAIL_EPILOG_PUBLIC } inline __int8 GetBufferCchAs_int8() const { this->IntegrityCheck(); if (this->GetBufferCch() > _I8_MAX) return _I8_MAX; return static_cast<__int8>(this->GetBufferCch()); } inline __int8 GetStringCchAs_int8() const { this->IntegrityCheck(); if (this->GetStringCch() > _I8_MAX) return _I8_MAX; return static_cast<__int8>(this->GetStringCch()); } inline unsigned __int8 GetBufferCchAs_unsigned_int8() const { this->IntegrityCheck(); if (this->GetBufferCch() > _UI8_MAX) return _UI8_MAX; return static_cast(this->GetBufferCch()); } inline unsigned __int8 GetStringCchAs_unsigned_int8() const { this->IntegrityCheck(); if (this->GetStringCch() > _UI8_MAX) return _UI8_MAX; return static_cast(this->GetStringCch()); } inline __int16 GetBufferCchAs_int16() const { this->IntegrityCheck(); if (this->GetBufferCch() > _I16_MAX) return _I16_MAX; return static_cast<__int16>(this->GetBufferCch()); } inline __int16 GetStringCchAs_int16() const { this->IntegrityCheck(); if (this->GetStringCch() > _I16_MAX) return _I16_MAX; return static_cast<__int16>(this->GetStringCch()); } inline unsigned __int16 GetBufferCchAs_unsigned_int16() const { this->IntegrityCheck(); if (this->GetBufferCch() > _UI16_MAX) return _UI16_MAX; return static_cast(this->GetBufferCch()); } inline unsigned __int16 GetStringCchAs_unsigned_int16() const { this->IntegrityCheck(); if (this->GetStringCch() > _UI16_MAX) return _UI16_MAX; return static_cast(this->GetStringCch()); } inline __int32 GetBufferCchAs_int32() const { this->IntegrityCheck(); if (this->GetBufferCch() > _I32_MAX) return _I32_MAX; return static_cast<__int32>(this->GetBufferCch()); } inline __int32 GetStringCchAs_int32() const { this->IntegrityCheck(); if (this->GetStringCch() > _I32_MAX) return _I32_MAX; return static_cast<__int32>(this->GetStringCch()); } inline unsigned __int32 GetBufferCchAs_unsigned_int32() const { this->IntegrityCheck(); if (this->GetBufferCch() > _UI32_MAX) return _UI32_MAX; return static_cast(this->GetBufferCch()); } inline unsigned __int32 GetStringCchAs_unsigned_int32() const { this->IntegrityCheck(); if (this->GetStringCch() > _UI32_MAX) return _UI32_MAX; return static_cast(this->GetStringCch()); } inline __int64 GetBufferCchAs_int64() const { this->IntegrityCheck(); if (this->GetBufferCch() > _I64_MAX) return _I64_MAX; return static_cast<__int64>(this->GetBufferCch()); } inline __int64 GetStringCchAs_int64() const { this->IntegrityCheck(); if (this->GetStringCch() > _I64_MAX) return _I64_MAX; return static_cast<__int64>(this->GetStringCch()); } inline unsigned __int64 GetBufferCchAs_unsigned_int64() const { this->IntegrityCheck(); if (this->GetBufferCch() > _UI64_MAX) return _UI64_MAX; return static_cast(this->GetBufferCch()); } inline unsigned __int64 GetStringCchAs_unsigned_int64() const { this->IntegrityCheck(); if (this->GetStringCch() > _UI64_MAX) return _UI64_MAX; return static_cast(this->GetStringCch()); } inline char GetBufferCchAs_char() const { this->IntegrityCheck(); if (this->GetBufferCch() > CHAR_MAX) return CHAR_MAX; return static_cast(this->GetBufferCch()); } inline char GetStringCchAs_char() const { this->IntegrityCheck(); if (this->GetStringCch() > CHAR_MAX) return CHAR_MAX; return static_cast(this->GetStringCch()); } inline unsigned char GetBufferCchAs_unsigned_char() const { this->IntegrityCheck(); if (this->GetBufferCch() > UCHAR_MAX) return UCHAR_MAX; return static_cast(this->GetBufferCch()); } inline unsigned char GetStringCchAs_unsigned_char() const { this->IntegrityCheck(); if (this->GetStringCch() > UCHAR_MAX) return UCHAR_MAX; return static_cast(this->GetStringCch()); } inline unsigned char GetBufferCchAs_signed_char() const { this->IntegrityCheck(); if (this->GetBufferCch() > SCHAR_MAX) return SCHAR_MAX; return static_cast(this->GetBufferCch()); } inline unsigned char GetStringCchAs_signed_char() const { this->IntegrityCheck(); if (this->GetStringCch() > SCHAR_MAX) return SCHAR_MAX; return static_cast(this->GetStringCch()); } inline short GetBufferCchAs_short() const { this->IntegrityCheck(); if (this->GetBufferCch() > SHRT_MAX) return SHRT_MAX; return static_cast(this->GetBufferCch()); } inline short GetStringCchAs_short() const { this->IntegrityCheck(); if (this->GetStringCch() > SHRT_MAX) return SHRT_MAX; return static_cast(this->GetStringCch()); } inline unsigned short GetBufferCchAs_unsigned_short() const { this->IntegrityCheck(); if (this->GetBufferCch() > USHRT_MAX) return USHRT_MAX; return static_cast(this->GetBufferCch()); } inline unsigned short GetStringCchAs_unsigned_short() const { this->IntegrityCheck(); if (this->GetStringCch() > USHRT_MAX) return USHRT_MAX; return static_cast(this->GetStringCch()); } inline int GetBufferCchAs_int() const { this->IntegrityCheck(); if (this->GetBufferCch() > INT_MAX) return INT_MAX; return static_cast(this->GetBufferCch()); } inline int GetStringCchAs_int() const { this->IntegrityCheck(); if (this->GetStringCch() > INT_MAX) return INT_MAX; return static_cast(this->GetStringCch()); } inline unsigned int GetBufferCchAs_unsigned_int() const { this->IntegrityCheck(); if (this->GetBufferCch() > UINT_MAX) return UINT_MAX; return static_cast(this->GetBufferCch()); } inline unsigned int GetStringCchAs_unsigned_int() const { this->IntegrityCheck(); if (this->GetStringCch() > UINT_MAX) return UINT_MAX; return static_cast(this->GetStringCch()); } inline long GetBufferCchAs_long() const { this->IntegrityCheck(); if (this->GetBufferCch() > LONG_MAX) return LONG_MAX; return static_cast(this->GetBufferCch()); } inline long GetStringCchAs_long() const { this->IntegrityCheck(); if (this->GetStringCch() > LONG_MAX) return LONG_MAX; return static_cast(this->GetStringCch()); } inline unsigned long GetBufferCchAs_unsigned_long() const { this->IntegrityCheck(); if (this->GetBufferCch() > ULONG_MAX) return ULONG_MAX; return static_cast(this->GetBufferCch()); } inline unsigned long GetStringCchAs_unsigned_long() const { this->IntegrityCheck(); if (this->GetStringCch() > ULONG_MAX) return ULONG_MAX; return static_cast(this->GetStringCch()); } inline TSizeT GetBufferCb() const { this->IntegrityCheck(); return this->GetBufferCch() * sizeof(TChar); } inline int GetBufferCbAs_int() const { this->IntegrityCheck(); if ((this->GetBufferCch() * sizeof(TChar)) > INT_MAX) return INT_MAX; return static_cast(this->GetBufferCch() * sizeof(TChar)); } inline unsigned long GetBufferCbAs_unsigned_long() const { this->IntegrityCheck(); if ((this->GetBufferCch() * sizeof(TChar)) > ULONG_MAX) return ULONG_MAX; return static_cast(this->GetBufferCch() * sizeof(TChar)); } inline unsigned long GetStringCbAs_unsigned_long() const { this->IntegrityCheck(); if ((this->GetStringCch() * sizeof(TChar)) > ULONG_MAX) return ULONG_MAX; return static_cast(this->GetStringCch() * sizeof(TChar)); } template inline TPublicErrorReturnType public_Span(const TSomeInputType &rinput, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::Span(this->GetStringPair(), rinput, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_SpanI(const TSomeInputType &rinput, const TCaseInsensitivityData &rcid, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::SpanI(this->GetStringPair(), rinput, rcid, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_ReverseSpan(const TSomeInputType &rinput, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::ReverseSpan(this->GetStringPair(), rinput, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_ReverseSpanI(const TSomeInputType &rinput, const TCaseInsensitivityData &rcid, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::ReverseSpanI(this->GetStringPair(), rinput, rcid, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_ComplementSpan(const TSomeInputType &rinput, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::ComplementSpan(this->GetStringPair(), rinput, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_ComplementSpanI(const TSomeInputType &rinput, const TCaseInsensitivityData &rcid, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::ComplementSpanI(this->GetStringPair(), rinput, rcid, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_ReverseComplementSpan(const TSomeInputType &rinput, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::ReverseComplementSpan(this->GetStringPair(), rinput, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_ReverseComplementSpanI(const TSomeInputType &rinput, const TCaseInsensitivityData &rcid, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::ReverseComplementSpanI(this->GetStringPair(), rinput, rcid, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_Contains(const TSomeInputType &rinput, bool &rfContainsCharacter) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::Contains(this->GetStringPair(), rinput, rfContainsCharacter)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_ContainsI(const TSomeInputType &rinput, const TCaseInsensitivityData &rcid, bool &rfContainsCharacter) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::ContainsI(this->GetStringPair(), rinput, rcid, rfContainsCharacter)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_FindFirst(const TSomeInputType &rinput, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::FindFirst(this->GetStringPair(), rinput, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_Count(const TSomeInputType &rinput, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::Count(this->GetStringPair(), rinput, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_FindLast(const TSomeInputType &rinput, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::FindLast(this->GetStringPair(), rinput, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_FindFirstI(const TSomeInputType &rinput, const TCaseInsensitivityData &rcid, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::FindFirstI(this->GetStringPair(), rinput, rcid, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_FindLastI(const TSomeInputType &rinput, const TCaseInsensitivityData &rcid, TSizeT &rich) const { BCL_MAYFAIL_PROLOG BCL_PARAMETER_CHECK(this->IsValidParameter(rinput)); BCL_IFCALLFAILED_EXIT(TTraits::FindLastI(this->GetStringPair(), rinput, rcid, rich)); BCL_MAYFAIL_EPILOG_PUBLIC } inline bool IsEmpty() const { return this->GetBufferPtr()[0] == 0; } template inline TPublicErrorReturnType public_EnsureTrailingChar(TSomeCharType ch) { BCL_MAYFAIL_PROLOG bool fDoAppend = false; this->IntegrityCheck(); // it would seem innocuous to allow assigns that don't resize the buffer to not // invalidate accessors, but that makes finding such bugs subject to even more // strenuous coverage problems than this simple error. The simple rule is that // you should not have an accessor attached to a string buffer when you use // any of member functions that may mutate the value. BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); if (this->GetStringCch() == 0) fDoAppend = true; else { bool fMatches = false; BCL_IFCALLFAILED_EXIT(TTraits::EqualsLastCharacter(this->GetBufferPtr(), this->GetStringCch(), ch, fMatches)); if (!fMatches) fDoAppend = true; } if (fDoAppend) { TSizeT cch; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(ch, cch)); if (cch > 1) { TSizeT cchTotal; BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(this->GetStringCch(), cch, cchTotal)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cchTotal)); // subtraction should only underflow if stringcch > buffercch which is bad anyways. BCL_INTERNAL_ERROR_CHECK(this->GetStringCch() <= this->GetBufferCch()); BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBuffer(this->GetBufferPtr()[this->GetStringCch()], this->GetBufferCch() - this->GetStringCch(), ch)); this->SetStringCch(cchTotal); } } BCL_MAYFAIL_EPILOG_PUBLIC } template inline TPublicErrorReturnType public_EnsureTrailingCharCaseInsensitive(TSomeCharType ch, const TCaseInsensitivityData &rcid) { BCL_MAYFAIL_PROLOG bool fDoAppend = false; this->IntegrityCheck(); // it would seem innocuous to allow assigns that don't resize the buffer to not // invalidate accessors, but that makes finding such bugs subject to even more // strenuous coverage problems than this simple error. The simple rule is that // you should not have an accessor attached to a string buffer when you use // any of member functions that may mutate the value. BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); if (this->GetStringCch() == 0) fDoAppend = true; else { bool fMatches = false; BCL_IFCALLFAILED_EXIT(TTraits::EqualsLastCharacterCaseInsensitive(this->GetBufferPtr(), this->GetStringCch(), ch, rcid, fMatches)); if (!fMatches) fDoAppend = true; } if (fDoAppend) { TSizeT cch; BCL_IFCALLFAILED_EXIT(TTraits::DetermineRequiredCharacters(ch, cch)); if (cch > 1) { TSizeT cchSum; BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(this->GetStringCch(), cch, cchSum)); BCL_IFCALLFAILED_EXIT(this->EnsureBufferLargeEnoughPreserve(cchSum)); BCL_INTERNAL_ERROR_CHECK(this->GetStringCch() <= this->GetBufferCch()); BCL_IFCALLFAILED_EXIT(TTraits::CopyIntoBuffer(this->GetBufferPtr()[this->GetStringCch()], this->GetBufferCch() - this->GetStringCch(), ch)); this->SetStringCch(cchSum); } } BCL_MAYFAIL_EPILOG_PUBLIC } inline TCallDisposition Left(TSizeT newLength) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_PARAMETER_CHECK(newLength <= this->GetStringCch()); BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); this->SetStringCch(newLength); BCL_MAYFAIL_EPILOG_INTERNAL } inline TPublicErrorReturnType public_Left(TSizeT newLength) { BCL_MAYFAIL_PROLOG BCL_IFCALLFAILED_EXIT(this->Left(newLength)); BCL_MAYFAIL_EPILOG_PUBLIC } inline TCallDisposition Right(TSizeT cchRightCount) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); BCL_PARAMETER_CHECK(cchRightCount <= this->GetStringCch()); if (cchRightCount < this->GetStringCch()) { BCL::MoveBytes( this->GetMutableBufferPtr(), &this->GetBufferPtr()[this->GetStringCch() - cchRightCount], cchRightCount * sizeof(TTraits::TChar)); this->SetStringCch(cchRightCount); } BCL_MAYFAIL_EPILOG_INTERNAL } TPublicErrorReturnType public_Right(TSizeT cchRightCount) { BCL_MAYFAIL_PROLOG this->IntegrityCheck(); BCL_IFCALLFAILED_EXIT(this->NoAccessorsCheck()); BCL_PARAMETER_CHECK(cchRightCount <= this->GetStringCch()); if (cchRightCount < this->GetStringCch()) { BCL::MoveBytes( this->GetMutableBufferPtr(), &this->GetBufferPtr()[this->GetStringCch() - cchRightCount], (cchRightCount + 1)*sizeof(TTraits::TChar)); this->SetStringCch(cchRightCount); } BCL_MAYFAIL_EPILOG_PUBLIC } TPublicErrorReturnType public_Mid(TSizeT ichStart, TSizeT cch) { BCL_MAYFAIL_PROLOG TSizeT cchSum; BCL_IFCALLFAILED_EXIT(TTraits::AddWithOverflowCheck(ichStart, cch, cchSum)); // It's not unreasonable to end up with a zero length string, so this is <=, not < BCL_PARAMETER_CHECK(cchSum <= this->GetStringCch()); BCL_IFCALLFAILED_EXIT(this->Right(this->GetStringCch() - ichStart)); BCL_IFCALLFAILED_EXIT(this->Left(cch)); BCL_MAYFAIL_EPILOG_PUBLIC } }; template class CPureStringAccessor { public: typedef CPureString TBuffer; typedef typename TTraits::TChar TChar; typedef typename TTraits::TCallDisposition TCallDisposition; typedef typename TTraits::TMutableString TMutableString; typedef typename TTraits::TConstantString TConstantString; typedef typename TTraits::TSizeT TSizeT; typedef typename TTraits::TPublicErrorReturnType TPublicErrorReturnType; typedef BCL::CMutablePointerAndCountPair TMutablePair; typedef BCL::CConstantPointerAndCountPair TConstantPair; CPureStringAccessor(TBuffer* pBuffer) : m_pStringBuffer(NULL) { this->Attach(pBuffer); } CPureStringAccessor() : m_pStringBuffer(NULL) { } ~CPureStringAccessor() { if (m_pStringBuffer != NULL) { m_pStringBuffer->SetStringCch(TTraits::NullTerminatedStringLengthWithLimit(this->GetBufferPtr(), this->GetBufferCch())); m_pStringBuffer->DetachAccessor(this); m_pStringBuffer = NULL; } } bool IsAttached() const { return (m_pStringBuffer != NULL); } inline TPublicErrorReturnType Attach(TBuffer *pBuffer) { BCL_MAYFAIL_PROLOG BCL_INTERNAL_ERROR_CHECK(!this->IsAttached()); BCL_IFCALLFAILED_EXIT(pBuffer->AttachAccessor(this)); m_pStringBuffer = pBuffer; BCL_MAYFAIL_EPILOG_PUBLIC } inline void Detach() { BCL_ASSERT (this->IsAttached()); if (this->IsAttached()) { m_pStringBuffer->SetStringCch(TTraits::NullTerminatedStringLengthWithLimit(this->GetBufferPtr(), this->GetBufferCch())); m_pStringBuffer->DetachAccessor(this); m_pStringBuffer = NULL; } } inline operator TMutableString() const { BCL_ASSERT(this->IsAttached()); return this->GetBufferPtr(); } inline typename TTraits::TMutableString GetBufferPtr() const { BCL_ASSERT(IsAttached()); return m_pStringBuffer->GetBufferPtr(); } inline TSizeT GetBufferCch() const { BCL_ASSERT(this->IsAttached()); return m_pStringBuffer->GetBufferCch(); } inline short GetBufferCchAs_short() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCch() > SHORT_MAX) return SHORT_MAX; return static_cast(this->GetBufferCch()) } inline unsigned short GetBufferCchAs_unsigned_short() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCch() > USHORT_MAX) return USHORT_MAX; return static_cast(this->GetBufferCch()) } inline int GetBufferCchAs_int() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCch() > INT_MAX) return INT_MAX; return static_cast(this->GetBufferCch()); } inline unsigned int GetBufferCchAs_unsigned_int() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCch() > UINT_MAX) return UINT_MAX; return static_cast(this->GetBufferCch()); } inline long GetBufferCchAs_long() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCch() > LONG_MAX) return LONG_MAX; return static_cast(this->GetBufferCch()); } inline unsigned long GetBufferCchAs_unsigned_long() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCch() > ULONG_MAX) return ULONG_MAX; return static_cast(this->GetBufferCch()); } inline TSizeT GetStringCch() const { BCL_ASSERT(this->IsAttached()); return TTraits::NullTerminatedStringLengthWithLimit(this->GetBufferPtr(), this->GetBufferCch()); } inline short GetStringCchAs_short() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCch() > SHORT_MAX) return SHORT_MAX; return static_cast(this->GetStringCch()) } inline unsigned short GetStringCchAs_unsigned_short() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCch() > USHORT_MAX) return USHORT_MAX; return static_cast(this->GetStringCch()) } inline int GetStringCchAs_int() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCch() > INT_MAX) return INT_MAX; return static_cast(this->GetStringCch()); } inline unsigned int GetStringCchAs_unsigned_int() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCch() > UINT_MAX) return UINT_MAX; return static_cast(this->GetStringCch()); } inline long GetStringCchAs_long() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCch() > LONG_MAX) return LONG_MAX; return static_cast(this->GetStringCch()); } inline unsigned long GetStringCchAs_unsigned_long() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCch() > ULONG_MAX) return ULONG_MAX; return static_cast(this->GetStringCch()); } inline TSizeT GetBufferCb() const { BCL_ASSERT(this->IsAttached()); return m_pStringBuffer->GetBufferCb(); } inline short GetBufferCbAs_short() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCb() > SHORT_MAX) return SHORT_MAX; return static_cast(this->GetBufferCb()) } inline unsigned short GetBufferCbAs_unsigned_short() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCb() > USHORT_MAX) return USHORT_MAX; return static_cast(this->GetBufferCb()) } inline int GetBufferCbAs_int() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCb() > INT_MAX) return INT_MAX; return static_cast(this->GetBufferCb()); } inline unsigned int GetBufferCbAs_unsigned_int() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCb() > UINT_MAX) return UINT_MAX; return static_cast(this->GetBufferCb()); } inline long GetBufferCbAs_long() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCb() > LONG_MAX) return LONG_MAX; return static_cast(this->GetBufferCb()); } inline unsigned long GetBufferCbAs_unsigned_long() const { BCL_ASSERT(this->IsAttached()); if (this->GetBufferCb() > ULONG_MAX) return ULONG_MAX; return static_cast(this->GetBufferCb()); } inline TSizeT GetStringCb() const { BCL_ASSERT(this->IsAttached()); return m_cch * sizeof(TChar); } inline short GetStringCbAs_short() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCb() > SHORT_MAX) return SHORT_MAX; return static_cast(this->GetStringCb()) } inline unsigned short GetStringCbAs_unsigned_short() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCb() > USHORT_MAX) return USHORT_MAX; return static_cast(this->GetStringCb()) } inline int GetStringCbAs_int() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCb() > INT_MAX) return INT_MAX; return static_cast(this->GetStringCb()); } inline unsigned int GetStringCbAs_unsigned_int() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCb() > UINT_MAX) return UINT_MAX; return static_cast(this->GetStringCb()); } inline long GetStringCbAs_long() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCb() > LONG_MAX) return LONG_MAX; return static_cast(this->GetStringCb()); } inline unsigned long GetStringCbAs_unsigned_long() const { BCL_ASSERT(this->IsAttached()); if (this->GetStringCb() > ULONG_MAX) return ULONG_MAX; return static_cast(this->GetStringCb()); } protected: TBuffer *m_pStringBuffer; TMutablePair m_pairBuffer; private: // // These two are to induce build breaks on people doing sb1 = sb2 // void operator=(const CPureStringAccessor &rOtherString); CPureStringAccessor(const CPureStringAccessor &r); }; }; // namespace BCL #endif // !defined(_WINDOWS_BCL_PURESTRING_H_INCLUDED_)