|
|
/*++
Copyright (c) Microsoft Corporation
Module Name:
fusionbuffer.h
Abstract:
Author:
Revision History:
--*/ #if !defined(FUSION_INC_FUSIONBUFFER_H_INCLUDED_)
#define FUSION_INC_FUSIONBUFFER_H_INCLUDED_
#pragma once
#include <stdio.h>
#include <limits.h>
#include "arrayhelp.h"
#include "smartref.h"
#include "returnstrategy.h"
#include "fusionstring.h"
#include "fusiontrace.h"
#include "fusionchartraits.h"
// avoid circular reference to Util.h
BOOL FusionpIsPathSeparator(WCHAR ch); BOOL FusionpIsDriveLetter(WCHAR ch);
//
// This header file defines the Fusion character string buffer class.
// The purpose of this class is to encapsulate common activities that
// callers want to do with character string buffers and handle it in
// a generic fashion. A principle tenet of this class is that it is
// not a string class, although one could consider building a string
// class upon it.
//
// The buffer maintains a certain amount of storage within the buffer
// object itself, and if more storage is required, a buffer is
// dynamically allocated from a heap.
//
//
// Like the STL string class, we use a helper class called a "character
// traits" class to provide the actual code to manipulate character string
// buffers with a specific encoding.
//
// All the members are inline static and with normal optimization turned
// on, the C++ compiler generates code that fully meets expectations.
//
//
// We provide two implementations: one for Unicode strings, and another
// template class for MBCS strings. The code page of the string is a
// template parameter for the MBCS string, so without any extra storage
// wasted per-instance, code can separately handle MBCS strings which
// are expected to be in the thread-default windows code page (CP_THREAD_ACP),
// process-default windows code page (CP_ACP) or even a particular code
// page (e.g. CP_UTF8).
//
//
// This template class uses a number of non-type template parameters to
// control things like growth algorithms etc. As a result there are
// many comparisons of template parameters against well-known constant
// values, for which the compiler generates warning C4127. We'll turn that
// warning off.
//
#pragma warning(disable:4127)
#pragma warning(disable:4284)
#if !defined(FUSION_DEFAULT_STRINGBUFFER_CHARS)
#define FUSION_DEFAULT_STRINGBUFFER_CHARS (MAX_PATH)
#endif
#if !defined(FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS)
#define FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS (8)
#endif
#if !defined(FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS)
#define FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS (64)
#endif
#if !defined(FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS)
#define FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS (128)
#endif
enum EIfNoExtension { eAddIfNoExtension, eDoNothingIfNoExtension, eErrorIfNoExtension };
enum ECaseConversionDirection { eConvertToUpperCase, eConvertToLowerCase };
enum EPreserveContents { ePreserveBufferContents, eDoNotPreserveBufferContents };
template <typename TCharTraits> class CGenericStringBufferAccessor;
template <typename TCharTraits> class CGenericBaseStringBuffer { friend TCharTraits; friend CGenericStringBufferAccessor<TCharTraits>;
//
// These two are to induce build breaks on people doing sb1 = sb2
//
CGenericBaseStringBuffer& operator=(PCWSTR OtherString); CGenericBaseStringBuffer& operator=(CGenericBaseStringBuffer &rOtherString);
public: typedef typename TCharTraits::TChar TChar; typedef typename TCharTraits::TMutableString TMutableString; typedef typename TCharTraits::TConstantString TConstantString; typedef CGenericStringBufferAccessor<TCharTraits> TAccessor;
inline static TChar NullCharacter() { return TCharTraits::NullCharacter(); } inline static bool IsNullCharacter(TChar ch) { return TCharTraits::IsNullCharacter(ch); } inline static TChar PreferredPathSeparator() { return TCharTraits::PreferredPathSeparator(); } inline static TConstantString PreferredPathSeparatorString() { return TCharTraits::PreferredPathSeparatorString(); } inline static TConstantString PathSeparators() { return TCharTraits::PathSeparators(); } inline static bool IsPathSeparator(TChar ch) { return TCharTraits::IsPathSeparator(ch); } inline static TConstantString DotString() { return TCharTraits::DotString(); } inline static SIZE_T DotStringCch() { return TCharTraits::DotStringCch(); } inline static TChar DotChar() { return TCharTraits::DotChar(); }
protected: // You may not instantiate an instance of this class directly; you need to provide a derived
// class which adds allocation/deallocation particulars.
CGenericBaseStringBuffer() : m_prgchBuffer(NULL), m_cchBuffer(0), m_cAttachedAccessors(0), m_cch(0) { }
//
// 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.
//
~CGenericBaseStringBuffer() { ASSERT_NTC(m_cAttachedAccessors == 0); }
inline void IntegrityCheck() const { #if DBG
ASSERT_NTC(m_cch < m_cchBuffer); #endif // DBG
}
// Derived constructors should call this to get the initial buffer pointers set up.
inline void InitializeInlineBuffer() { ASSERT_NTC(m_prgchBuffer == NULL); ASSERT_NTC(m_cchBuffer == 0);
m_prgchBuffer = this->GetInlineBuffer(); m_cchBuffer = this->GetInlineBufferCch(); }
VOID AttachAccessor(TAccessor *) { ::InterlockedIncrement(&m_cAttachedAccessors); }
VOID DetachAccessor(TAccessor *) { ::InterlockedDecrement(&m_cAttachedAccessors); }
virtual BOOL Win32AllocateBuffer(SIZE_T cch, TMutableString &rpsz) const = 0; virtual VOID DeallocateBuffer(TMutableString sz) const = 0; virtual TMutableString GetInlineBuffer() const = 0; virtual SIZE_T GetInlineBufferCch() const = 0;
public:
BOOL Win32Assign(PCWSTR psz, SIZE_T cchIn) { FN_PROLOG_WIN32
ASSERT(static_cast<SSIZE_T>(cchIn) >= 0);
this->IntegrityCheck();
SIZE_T cchIncludingTrailingNull;
// 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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(psz, cchIn, cchIncludingTrailingNull));
// Only force the buffer to be dynamically grown if the new contents do not
// fit in the old buffer.
if (cchIncludingTrailingNull > m_cchBuffer) IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(cchIncludingTrailingNull));
IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(m_prgchBuffer, m_cchBuffer, psz, cchIn));
ASSERT(cchIncludingTrailingNull <= m_cchBuffer); ASSERT((cchIncludingTrailingNull == 0) || this->IsNullCharacter(m_prgchBuffer[cchIncludingTrailingNull - 1]));
// cch was the buffer size we needed (including the trailing null); we don't need the trailing
// null any more...
m_cch = cchIncludingTrailingNull - 1;
FN_EPILOG }
BOOL Win32Assign(PCSTR psz, SIZE_T cchIn) { FN_PROLOG_WIN32
ASSERT(static_cast<SSIZE_T>(cchIn) >= 0);
this->IntegrityCheck();
SIZE_T cchIncludingTrailingNull;
// 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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(psz, cchIn, cchIncludingTrailingNull));
// Only force the buffer to be dynamically grown if the new contents do not
// fit in the old buffer.
if (cchIncludingTrailingNull > m_cchBuffer) IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(cchIncludingTrailingNull));
IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(m_prgchBuffer, m_cchBuffer, psz, cchIn));
ASSERT(cchIncludingTrailingNull <= m_cchBuffer); ASSERT((cchIncludingTrailingNull == 0) || this->IsNullCharacter(m_prgchBuffer[cchIncludingTrailingNull - 1]));
// cch was the buffer size we needed (including the trailing null); we don't need the trailing
// null any more...
m_cch = cchIncludingTrailingNull - 1;
FN_EPILOG }
BOOL Win32Assign(const UNICODE_STRING* NtString) { return Win32Assign(NtString->Buffer, RTL_STRING_GET_LENGTH_CHARS(NtString)); }
BOOL Win32Assign(const ANSI_STRING* NtString) { return Win32Assign(NtString->Buffer, RTL_STRING_GET_LENGTH_CHARS(NtString)); }
BOOL Win32Append(const UNICODE_STRING* NtString) { return this->Win32Append(NtString->Buffer, RTL_STRING_GET_LENGTH_CHARS(NtString)); }
BOOL Win32AppendPathElement(const UNICODE_STRING* NtString) { return this->Win32AppendPathElement(NtString->Buffer, RTL_STRING_GET_LENGTH_CHARS(NtString)); }
BOOL Win32Assign(const CGenericBaseStringBuffer &r) { return this->Win32Assign(r, r.Cch()); }
BOOL Win32AssignWVa(SIZE_T cStrings, va_list ap) { this->IntegrityCheck();
BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
TMutableString pszCursor; SIZE_T cchIncludingTrailingNull = 1; // leave space for trailing null...
SIZE_T cchTemp = 0; SIZE_T i = 0; va_list ap2 = ap;
// 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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
for (i=0; i<cStrings; i++) { PCWSTR psz = va_arg(ap, PCWSTR); INT cchArg = va_arg(ap, INT); SIZE_T cchThis = (cchArg < 0) ? ((psz != NULL) ? ::wcslen(psz) : 0) : static_cast<SIZE_T>(cchArg); SIZE_T cchRequired;
IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(psz, cchThis, cchRequired));
ASSERT((cchRequired != 0) || (cchThis == 0));
cchIncludingTrailingNull += (cchRequired - 1); }
IFW32FALSE_EXIT(this->Win32ResizeBuffer(cchIncludingTrailingNull, eDoNotPreserveBufferContents));
pszCursor = m_prgchBuffer; cchTemp = cchIncludingTrailingNull;
for (i=0; i<cStrings; i++) { PCWSTR psz = va_arg(ap2, PCWSTR); INT cchArg = va_arg(ap2, INT); SIZE_T cchThis = (cchArg < 0) ? ((psz != NULL) ? ::wcslen(psz) : 0) : static_cast<SIZE_T>(cchArg);
IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBufferAndAdvanceCursor(pszCursor, cchTemp, psz, cchThis)); }
*pszCursor++ = this->NullCharacter();
ASSERT(cchTemp == 1); ASSERT(static_cast<SIZE_T>(pszCursor - m_prgchBuffer) == cchIncludingTrailingNull);
m_cch = (cchIncludingTrailingNull - 1);
FN_EPILOG }
BOOL Win32AssignW(ULONG cStrings, ...) { this->IntegrityCheck();
BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); va_list ap;
va_start(ap, cStrings);
IFW32FALSE_EXIT(this->Win32AssignWVa(cStrings, ap));
fSuccess = TRUE; Exit: va_end(ap);
return fSuccess; }
BOOL Win32AssignFill(TChar ch, SIZE_T cch) { FN_PROLOG_WIN32
TMutableString Cursor;
ASSERT(static_cast<SSIZE_T>(cch) >= 0);
IFW32FALSE_EXIT(this->Win32ResizeBuffer(cch + 1, eDoNotPreserveBufferContents)); Cursor = m_prgchBuffer;
while (cch > 0) { *Cursor++ = ch; cch--; }
*Cursor = NullCharacter();
m_cch = (Cursor - m_prgchBuffer);
FN_EPILOG }
BOOL Win32Append(PCWSTR sz, SIZE_T cchIn) { this->IntegrityCheck();
BOOL fSuccess = FALSE;
ASSERT_NTC(static_cast<SSIZE_T>(cchIn) >= 0);
SIZE_T cchIncludingTrailingNull; // note that cch will include space for a tailing null character
// 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.
ASSERT_NTC(m_cAttachedAccessors == 0);
if (!TCharTraits::Win32DetermineRequiredCharacters(sz, cchIn, cchIncludingTrailingNull)) goto Exit;
// Bypass all this junk if the string to append is empty.
if (cchIncludingTrailingNull > 1) { if (!this->Win32ResizeBufferPreserveContentsInternal(m_cch + cchIncludingTrailingNull)) goto Exit;
if (!TCharTraits::Win32CopyIntoBuffer(&m_prgchBuffer[m_cch], m_cchBuffer - m_cch, sz, cchIn)) goto Exit;
m_cch += (cchIncludingTrailingNull - 1); }
fSuccess = TRUE; Exit: return fSuccess; }
BOOL Win32Append(PCSTR sz, SIZE_T cchIn) { this->IntegrityCheck();
BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
ASSERT(static_cast<SSIZE_T>(cchIn) >= 0);
SIZE_T cchIncludingTrailingNull;
// 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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(sz, cchIn, cchIncludingTrailingNull));
// Bypass all this junk if the string to append is empty.
if (cchIncludingTrailingNull > 1) { IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + cchIncludingTrailingNull)); IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(&m_prgchBuffer[m_cch], m_cchBuffer - m_cch, sz, cchIn)); m_cch += (cchIncludingTrailingNull - 1);
this->IntegrityCheck(); }
FN_EPILOG }
BOOL Win32Append(const CGenericBaseStringBuffer &r) { return this->Win32Append(r, r.Cch()); } BOOL Win32Append(WCHAR wch) { WCHAR rgwch[1] = { wch }; return this->Win32Append(rgwch, 1); }
BOOL Win32AppendFill(TChar ch, SIZE_T cch) { FN_PROLOG_WIN32
ASSERT(static_cast<SSIZE_T>(cch) >= 0);
TMutableString Cursor;
IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + cch + 1)); Cursor = m_prgchBuffer + m_cch;
while (cch > 0) { *Cursor++ = ch; cch--; }
*Cursor = NullCharacter();
m_cch = Cursor - m_prgchBuffer;
FN_EPILOG }
BOOL Win32Prepend(const CGenericBaseStringBuffer& other ) { return this->Win32Prepend(other, other.Cch()); }
BOOL Win32Prepend(TConstantString sz, SIZE_T cchIn) { this->IntegrityCheck();
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
ASSERT(static_cast<SSIZE_T>(cchIn) >= 0);
SIZE_T cchIncludingTrailingNull; // note that cch will include space for a tailing null character
// 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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
if ( m_cch == 0 ) { IFW32FALSE_EXIT(this->Win32Assign(sz, cchIn)); } else { //
// Enlarge the buffer, move the current data to past where the new data will need
// to go, copy in the new data, and place the trailing null.
//
TChar SavedChar = m_prgchBuffer[0];
IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(sz, cchIn, cchIncludingTrailingNull)); IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + cchIncludingTrailingNull));
// Move current buffer "up"
MoveMemory(m_prgchBuffer + ( cchIncludingTrailingNull - 1), m_prgchBuffer, (m_cch + 1) * sizeof(TChar));
// Copy from the source string into the buffer.
IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer( this->m_prgchBuffer, this->m_cchBuffer, sz, cchIn));
m_prgchBuffer[cchIncludingTrailingNull - 1] = SavedChar; m_cch += cchIncludingTrailingNull - 1; } FN_EPILOG }
BOOL Win32Prepend(TChar ch) { FN_PROLOG_WIN32
IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + 1 + 1));
// move buffer ahead, including null
MoveMemory(m_prgchBuffer + 1, m_prgchBuffer, (m_cch + 1) * sizeof(TChar)); m_prgchBuffer[0] = ch; m_cch++;
FN_EPILOG }
operator TConstantString() const { this->IntegrityCheck(); return m_prgchBuffer; }
inline VOID Clear(bool fFreeStorage = false) { FN_TRACE();
this->IntegrityCheck();
// You can't free the storage if there's an attached accessor
ASSERT(!fFreeStorage || m_cAttachedAccessors == 0);
if (fFreeStorage && (m_cAttachedAccessors == 0)) { if (m_prgchBuffer != NULL) { const TMutableString pszInlineBuffer = this->GetInlineBuffer();
if (m_prgchBuffer != pszInlineBuffer) { this->DeallocateBuffer(m_prgchBuffer); m_prgchBuffer = pszInlineBuffer; m_cchBuffer = this->GetInlineBufferCch(); } } }
if (m_prgchBuffer != NULL) m_prgchBuffer[0] = this->NullCharacter();
m_cch = 0; }
BOOL Win32ConvertCase( ECaseConversionDirection direction ) { #if !FUSION_WIN
return FALSE; #else
FN_PROLOG_WIN32
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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
TMutableString Cursor = m_prgchBuffer;
for ( ULONG ul = 0; ul < this->Cch(); ul++ ) { if ( direction == eConvertToUpperCase ) *Cursor = RtlUpcaseUnicodeChar(*Cursor); else *Cursor = RtlDowncaseUnicodeChar(*Cursor);
Cursor++; }
FN_EPILOG #endif
}
BOOL Win32Compare(TConstantString szCandidate, SIZE_T cchCandidate, StringComparisonResult &rscrOut, bool fCaseInsensitive) const { this->IntegrityCheck(); BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); IFW32FALSE_EXIT(TCharTraits::Win32CompareStrings(rscrOut, m_prgchBuffer, m_cch, szCandidate, cchCandidate, fCaseInsensitive)); FN_EPILOG }
BOOL Win32Equals(TConstantString szCandidate, SIZE_T cchCandidate, bool &rfMatches, bool fCaseInsensitive) const { this->IntegrityCheck();
BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
IFW32FALSE_EXIT( TCharTraits::Win32EqualStrings( rfMatches, m_prgchBuffer, m_cch, szCandidate, cchCandidate, fCaseInsensitive)); FN_EPILOG }
BOOL Win32Equals(const CGenericBaseStringBuffer &r, bool &rfMatches, bool fCaseInsensitive) const { return this->Win32Equals(r, r.Cch(), rfMatches, fCaseInsensitive); }
SIZE_T GetBufferCch() const { this->IntegrityCheck(); return m_cchBuffer; } INT GetBufferCchAsINT() const { this->IntegrityCheck(); if (m_cchBuffer > INT_MAX) return INT_MAX; return static_cast<INT>(m_cchBuffer); } DWORD GetBufferCchAsDWORD() const { this->IntegrityCheck(); if (m_cchBuffer > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cchBuffer); } DWORD GetCchAsDWORD() const { this->IntegrityCheck(); if (m_cch > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cch); } INT GetCchAsINT() const { this->IntegrityCheck(); if (m_cch > INT_MAX) return INT_MAX; return static_cast<INT>(m_cch); } UINT GetCchAsUINT() const { this->IntegrityCheck(); if (m_cch > UINT_MAX) return UINT_MAX; return static_cast<UINT>(m_cch); }
SIZE_T GetBufferCb() const { this->IntegrityCheck(); return m_cchBuffer * sizeof(TChar); } INT GetBufferCbAsINT() const { this->IntegrityCheck(); if ((m_cchBuffer * sizeof(TChar)) > INT_MAX) return INT_MAX; return static_cast<INT>(m_cchBuffer * sizeof(TChar)); } DWORD GetBufferCbAsDWORD() const { this->IntegrityCheck(); if ((m_cchBuffer * sizeof(TChar)) > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cchBuffer * sizeof(TChar)); } DWORD GetCbAsDWORD() const { this->IntegrityCheck(); if ((m_cch * sizeof(TChar)) > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cch * sizeof(TChar)); } INT GetCbAsINT() const { this->IntegrityCheck(); if ((m_cch * sizeof(TChar)) > INT_MAX) return INT_MAX; return static_cast<INT>(m_cch * sizeof(TChar)); } UINT GetCbAsUINT() const { this->IntegrityCheck(); if ((m_cch * sizeof(TChar)) > UINT_MAX) return UINT_MAX; return static_cast<UINT>(m_cch * sizeof(TChar)); }
bool ContainsCharacter(WCHAR wch) const { this->IntegrityCheck(); return TCharTraits::ContainsCharacter(m_prgchBuffer, m_cch, wch); }
BOOL Win32ResizeBuffer( SIZE_T cch, EPreserveContents epc ) { FN_PROLOG_WIN32
this->IntegrityCheck();
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0); PARAMETER_CHECK((epc == ePreserveBufferContents) || (epc == eDoNotPreserveBufferContents));
if (cch > m_cchBuffer) { TMutableString prgchBufferNew = NULL;
IFW32FALSE_EXIT(this->Win32AllocateBuffer(cch, prgchBufferNew));
if (epc == ePreserveBufferContents) { // We assume that the buffer is/was null-terminated.
IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(prgchBufferNew, cch, m_prgchBuffer, m_cch)); } else { m_prgchBuffer[0] = this->NullCharacter(); m_cch = 0; }
if ((m_prgchBuffer != NULL) && (m_prgchBuffer != this->GetInlineBuffer())) this->DeallocateBuffer(m_prgchBuffer);
m_prgchBuffer = prgchBufferNew; m_cchBuffer = cch; }
FN_EPILOG }
BOOL Win32Format(TConstantString pszFormat, ...) { this->IntegrityCheck();
va_list args; va_start(args, pszFormat); BOOL f = this->Win32FormatV(pszFormat, args); va_end(args); return f; }
BOOL Win32FormatAppend(TConstantString pszFormat, ...) { this->IntegrityCheck();
va_list args; va_start(args, pszFormat); BOOL f = Win32FormatAppendV(pszFormat, args); va_end(args); return f; }
BOOL Win32FormatV(TConstantString pszFormat, va_list args) { BOOL fSuccess = FALSE; this->Clear(); fSuccess = Win32FormatAppendV(pszFormat, args); return fSuccess; }
BOOL Win32FormatAppendV(TConstantString pszFormat, va_list args) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); SIZE_T cchRequiredBufferSize = 0; INT i = 0;
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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
m_prgchBuffer[m_cchBuffer - 1] = this->NullCharacter(); i = TCharTraits::FormatV(m_prgchBuffer + m_cch, m_cchBuffer - 1 - m_cch, pszFormat, args); ASSERT(m_prgchBuffer[m_cchBuffer - 1] == NullCharacter()); fSuccess = (i >= 0); if ( fSuccess ) m_cch += i; else { //
// Sprintf doesn't touch last error. The fn tracer
// will fail an assertion if we return false but FusionpGetLastWin32Error()==NOERROR
//
ORIGINATE_WIN32_FAILURE_AND_EXIT(snwprintf_MaybeBufferTooSmall, ERROR_INVALID_PARAMETER); } Exit: return fSuccess; }
SIZE_T Cch() const { this->IntegrityCheck(); return this->m_cch; }
BOOL IsEmpty() const { this->IntegrityCheck(); const BOOL fResult = (this->m_prgchBuffer[0] == this->NullCharacter()); #if DBG
//
// We should probably reverse how we compute the result in
// retail vs. what we assert. That would be one pointer
// deref instead of two in retail; not worth churn right now.
// - JayKrell, June 2002.
//
if (fResult) { ASSERT_NTC(this->m_cch == 0); } #endif
return fResult; }
WCHAR GetLastCharUnsafe() const { ASSERT_NTC(!this->IsEmpty()); return this->m_prgchBuffer[this->m_cch - 1]; }
BOOL Win32EnsureTrailingChar(WCHAR ch) { this->IntegrityCheck();
BOOL fSuccess = FALSE;
// 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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
if ((m_cch == 0) || (m_prgchBuffer[m_cch - 1] != ch)) { IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + 1 + 1)); m_prgchBuffer[m_cch++] = ch; m_prgchBuffer[m_cch] = this->NullCharacter(); }
fSuccess = TRUE; Exit: return fSuccess; }
BOOL Win32EnsureTrailingPathSeparator() { this->IntegrityCheck();
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
// 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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
if ((m_cch == 0) || !TCharTraits::IsPathSeparator(m_prgchBuffer[m_cch - 1])) { IFW32FALSE_EXIT(this->Win32ResizeBufferPreserveContentsInternal(m_cch + 1 + 1)); m_prgchBuffer[m_cch++] = this->PreferredPathSeparator(); m_prgchBuffer[m_cch] = this->NullCharacter(); }
fSuccess = TRUE; Exit: return fSuccess; }
BOOL Win32AppendPathElement(PCWSTR pathElement, SIZE_T cchPathElement) { this->IntegrityCheck();
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
// 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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
IFW32FALSE_EXIT(this->Win32EnsureTrailingPathSeparator()); IFW32FALSE_EXIT(this->Win32Append(pathElement, cchPathElement));
fSuccess = TRUE; Exit: return fSuccess; }
BOOL Win32AppendPathElement(const CGenericBaseStringBuffer &r) { return this->Win32AppendPathElement(r, r.Cch()); }
BOOL Win32AppendPathElement(PCSTR pathElement, SIZE_T cchPathElement) { this->IntegrityCheck();
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
// 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.
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
IFW32FALSE_EXIT(this->Win32EnsureTrailingPathSeparator()); IFW32FALSE_EXIT(this->Win32Append(pathElement, cchPathElement));
fSuccess = TRUE; Exit: return fSuccess; }
BOOL Left(SIZE_T newLength) { this->IntegrityCheck();
ASSERT_NTC(newLength <= m_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.
// Note also that while the current implementation does not change the buffer
// pointer, this is just a shortcut in the implementation; if a call to Left()
// were to make the string short enough to fit in the inline buffer, we should
// copy it to the inline buffer and deallocate the dynamic one.
ASSERT_NTC(m_cAttachedAccessors == 0);
if (m_cchBuffer > newLength) { m_prgchBuffer[newLength] = this->NullCharacter(); }
m_cch = newLength;
this->IntegrityCheck();
return TRUE; }
TConstantString Begin() const { this->IntegrityCheck(); return m_prgchBuffer; }
TConstantString End() const { this->IntegrityCheck(); return &m_prgchBuffer[m_cch]; }
// should factor this for reuse in CchWithoutLastPathElement
SIZE_T CchWithoutTrailingPathSeparators() const { this->IntegrityCheck(); // Until GetLength is constant time, optimize its use..
SIZE_T length = m_cch; if (length > 0) { length -= ::StringReverseSpan(&*m_prgchBuffer, &*m_prgchBuffer + length, TCharTraits::PathSeparators()); } return length; }
BOOL RestoreNextPathElement() { SIZE_T index;
this->IntegrityCheck();
index = m_cch; m_prgchBuffer[index++] = L'\\'; // replace trailing NULL with '\'
while ((index < m_cchBuffer) && (!this->IsNullCharacter(m_prgchBuffer[index]))) { if (::FusionpIsPathSeparator(m_prgchBuffer[index])) { this->Left(index); return TRUE; }
index++; }
return FALSE; }
bool HasTrailingPathSeparator() const { FN_TRACE();
this->IntegrityCheck();
if ((m_cch != 0) && TCharTraits::IsPathSeparator(m_prgchBuffer[m_cch - 1])) return true;
return false; }
BOOL Win32RemoveTrailingPathSeparators() { 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.
// Note also that while the current implementation does not change the buffer
// pointer, this is just a shortcut in the implementation; if a call to Left()
// were to make the string short enough to fit in the inline buffer, we should
// copy it to the inline buffer and deallocate the dynamic one.
ASSERT_NTC(m_cAttachedAccessors == 0);
while ((m_cch != 0) && TCharTraits::IsPathSeparator(m_prgchBuffer[m_cch - 1])) m_cch--;
m_prgchBuffer[m_cch] = this->NullCharacter();
this->IntegrityCheck();
return TRUE; }
BOOL Right( SIZE_T cchRightCount ) { this->IntegrityCheck();
ASSERT_NTC(m_cAttachedAccessors == 0); ASSERT_NTC(cchRightCount <= m_cch);
if (cchRightCount < m_cch) { ::MoveMemory( m_prgchBuffer, &m_prgchBuffer[m_cch - cchRightCount], (cchRightCount + 1)*sizeof(TCharTraits::TChar)); m_cch = cchRightCount; } this->IntegrityCheck();
return TRUE; }
BOOL RemoveLeadingPathSeparators() { this->IntegrityCheck(); BOOL fSuccess = this->Right(m_cch - wcsspn(m_prgchBuffer, TCharTraits::PathSeparators())); this->IntegrityCheck(); return fSuccess; }
BOOL Win32StripToLastPathElement() { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0); this->IntegrityCheck(); IFW32FALSE_EXIT(this->Right(m_cch - this->CchWithoutLastPathElement())); IFW32FALSE_EXIT(this->RemoveLeadingPathSeparators()); fSuccess = TRUE; Exit: this->IntegrityCheck(); return fSuccess; }
BOOL Win32GetFirstPathElement( CGenericBaseStringBuffer &sbDestination, BOOL bRemoveAsWell = FALSE ) { FN_PROLOG_WIN32
this->IntegrityCheck();
IFW32FALSE_EXIT( sbDestination.Win32Assign( m_prgchBuffer, this->CchOfFirstPathElement() ) ); sbDestination.RemoveLeadingPathSeparators();
if ( bRemoveAsWell ) IFW32FALSE_EXIT(this->Win32RemoveFirstPathElement());
this->IntegrityCheck();
FN_EPILOG }
BOOL Win32GetFirstPathElement( CGenericBaseStringBuffer &sbDestination ) const { BOOL bSuccess = FALSE;
this->IntegrityCheck();
if ( sbDestination.Win32Assign( m_prgchBuffer, CchOfFirstPathElement() ) ) { sbDestination.RemoveLeadingPathSeparators(); bSuccess = TRUE; }
return bSuccess; }
BOOL Win32StripToFirstPathElement() { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0); this->IntegrityCheck();
IFW32FALSE_EXIT(this->Left(this->CchOfFirstPathElement())); IFW32FALSE_EXIT(this->RemoveLeadingPathSeparators());
fSuccess = TRUE; Exit: this->IntegrityCheck(); return fSuccess; }
BOOL Win32RemoveFirstPathElement() { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
this->IntegrityCheck(); INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
IFW32FALSE_EXIT(this->Right(this->CchWithoutFirstPathElement())); IFW32FALSE_EXIT(this->RemoveLeadingPathSeparators()); fSuccess = TRUE; Exit: this->IntegrityCheck(); return fSuccess; }
SIZE_T CchOfFirstPathElement() const { return Cch() - CchWithoutFirstPathElement(); }
SIZE_T CchWithoutFirstPathElement() const { this->IntegrityCheck();
SIZE_T cch = m_cch;
//
// We just look for the first path element, which can also be the drive
// letter!
//
if ( cch != 0 ) { cch -= wcscspn( m_prgchBuffer, PathSeparators() ); }
return cch; }
BOOL Win32GetLastPathElement(CGenericBaseStringBuffer &sbDestination) const { BOOL bSuccess = FALSE; FN_TRACE_WIN32(bSuccess); this->IntegrityCheck(); sbDestination.IntegrityCheck(); IFW32FALSE_EXIT(sbDestination.Win32Assign(m_prgchBuffer, m_cch)); IFW32FALSE_EXIT(sbDestination.Win32StripToLastPathElement()); bSuccess = TRUE; Exit: this->IntegrityCheck(); sbDestination.IntegrityCheck(); return bSuccess; }
SIZE_T CchWithoutLastPathElement() const { this->IntegrityCheck();
// Paths are assumed to be
// "\\machine\share"
// or
// "x:\"
// Worry about alternate NTFS streams at a later date.
// Worry about NT paths at a later date.
// Worry about URLs at a later date.
const SIZE_T length = m_cch; SIZE_T newLength = length; if (length > 0) { if ((length == 3) && (m_prgchBuffer[1] == ':') && ::FusionpIsPathSeparator(m_prgchBuffer[2]) && ::FusionpIsDriveLetter(m_prgchBuffer[0])) { // c:\ => empty string
newLength = 0; } else { // Remove trailing path seperators here, in the future when it is not risky.
//newLength -= ::StringReverseSpan(&*m_prgchBuffer, &*m_prgchBuffer + newLength, PathSeparators());
newLength -= ::StringReverseComplementSpan(&*m_prgchBuffer, &*m_prgchBuffer + newLength, PathSeparators()); newLength -= ::StringReverseSpan(&*m_prgchBuffer, &*m_prgchBuffer + newLength, PathSeparators()); if ((newLength == 2) && // "c:"
(length >= 4) && // "c:\d"
(m_prgchBuffer[1] == ':') && ::FusionpIsPathSeparator(m_prgchBuffer[2]) && ::FusionpIsDriveLetter(m_prgchBuffer[0])) { ++newLength; // put back the slash in "c:\"
} } } return newLength; }
BOOL Win32RemoveLastPathElement() { BOOL fSuccess = FALSE; FN_TRACE_WIN32( fSuccess );
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.
// Note also that while the current implementation does not change the buffer
// pointer, this is just a shortcut in the implementation; if a call to Left()
// were to make the string short enough to fit in the inline buffer, we should
// copy it to the inline buffer and deallocate the dynamic one.
ASSERT_NTC(m_cAttachedAccessors == 0);
IFW32FALSE_EXIT(this->Left(this->CchWithoutLastPathElement()));
fSuccess = TRUE; Exit: this->IntegrityCheck(); return fSuccess; }
BOOL Win32ClearPathExtension() { //
// Replace the final '.' with a \0 to clear the path extension
//
BOOL fSuccess = FALSE; FN_TRACE_WIN32( fSuccess );
this->IntegrityCheck();
TMutableString dot = 0;
const TMutableString end = End();
IFW32FALSE_EXIT(TCharTraits::Win32ReverseFind(dot, m_prgchBuffer, m_cch, this->DotChar(), false));
if((dot != end) && (dot != NULL)) { *dot = this->NullCharacter(); m_cch = (dot - m_prgchBuffer); }
fSuccess = TRUE; Exit: this->IntegrityCheck(); return fSuccess; }
BOOL Win32GetPathExtension(CGenericBaseStringBuffer<TCharTraits> &destination) const { this->IntegrityCheck();
BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
SIZE_T cchExtension;
const TConstantString start = Begin(); const TConstantString end = End();
cchExtension = ::StringReverseComplementSpan( &(*start), &(*end), L"." ); IFW32FALSE_EXIT(destination.Win32Assign( static_cast<PCWSTR>(*this) + ( m_cch - cchExtension ), cchExtension));
fSuccess = TRUE;
Exit: return fSuccess; }
// newExtension can start with a dot or not
BOOL Win32ChangePathExtension(PCWSTR newExtension, SIZE_T cchExtension, EIfNoExtension e) { this->IntegrityCheck();
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
TMutableString end = 0; TMutableString dot = 0;
INTERNAL_ERROR_CHECK(m_cAttachedAccessors == 0);
PARAMETER_CHECK((e == eAddIfNoExtension) || (e == eDoNothingIfNoExtension) || (e == eErrorIfNoExtension));
if ((cchExtension != 0) && (newExtension[0] == L'.')) { cchExtension--; newExtension++; }
// the use of append when we know where the end of the string is inefficient
end = this->End();
IFW32FALSE_EXIT(TCharTraits::Win32ReverseFind(dot, m_prgchBuffer, m_cch, this->DotChar(), false));
// Found the end of the string, or Win32ReverseFind didn't find the dot anywhere...
if ((dot == end) || (dot == NULL)) { switch (e) { case eAddIfNoExtension: IFW32FALSE_EXIT(this->Win32Append(this->DotString(), 1)); IFW32FALSE_EXIT(this->Win32Append(newExtension, cchExtension)); break;
case eDoNothingIfNoExtension: break;
case eErrorIfNoExtension: ORIGINATE_WIN32_FAILURE_AND_EXIT(MissingExtension, ERROR_BAD_PATHNAME); } } else { ++dot; IFW32FALSE_EXIT(this->Left(dot - this->Begin())); IFW32FALSE_EXIT(this->Win32Append(newExtension, cchExtension)); }
fSuccess = TRUE; Exit: this->IntegrityCheck(); return fSuccess; }
BOOL Win32ChangePathExtension(const UNICODE_STRING* NtString, EIfNoExtension e) { return Win32ChangePathExtension( NtString->Buffer, RTL_STRING_GET_LENGTH_CHARS(NtString), e); }
BOOL Win32CopyStringOut(LPWSTR sz, ULONG *pcch) const { FN_PROLOG_WIN32
this->IntegrityCheck();
SIZE_T cwchRequired = 0;
PARAMETER_CHECK(pcch != NULL);
IFW32FALSE_EXIT(TCharTraits::Win32DetermineRequiredCharacters(m_prgchBuffer, m_cch, cwchRequired));
if ((*pcch) < cwchRequired) { *pcch = static_cast<DWORD>(cwchRequired); ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER); }
IFW32FALSE_EXIT(TCharTraits::Win32CopyIntoBuffer(sz, *pcch, m_prgchBuffer, m_cch));
FN_EPILOG }
//
// This function is rather special purpose in that several design choices are not
// implemented as parameters. In particular, the pcbBytesWritten is assumed to
// accumulate a number (thus it's updated by adding the number of bytes written to
// it rather than just setting it to the count of bytes written).
//
// It also writes 0 bytes into the buffer is the string is zero length; if the string
// is not zero length, it writes the string including a trailing null.
//
inline BOOL Win32CopyIntoBuffer( PWSTR *ppszCursor, SIZE_T *pcbBuffer, SIZE_T *pcbBytesWritten, PVOID pvBase, ULONG *pulOffset, ULONG *pulLength ) const { this->IntegrityCheck();
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
PWSTR pszCursor = NULL; SSIZE_T dptr = 0; SIZE_T cbRequired = 0; SIZE_T cch = 0;
if (pulOffset != NULL) *pulOffset = 0;
if (pulLength != NULL) *pulLength = 0;
PARAMETER_CHECK(pcbBuffer != NULL); PARAMETER_CHECK(ppszCursor != NULL);
pszCursor = *ppszCursor; dptr = ((SSIZE_T) pszCursor) - ((SSIZE_T) pvBase);
// If they're asking for an offset or length and the cursor is too far from the base,
// fail.
PARAMETER_CHECK((pulOffset == NULL) || (dptr <= ULONG_MAX));
cch = m_cch;
cbRequired = (cch != 0) ? ((cch + 1) * sizeof(WCHAR)) : 0;
if ((*pcbBuffer) < cbRequired) { ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER); goto Exit; }
if (cbRequired > ULONG_MAX) { ::FusionpSetLastWin32Error(ERROR_INSUFFICIENT_BUFFER); goto Exit; }
CopyMemory(pszCursor, static_cast<PCWSTR>(*this), cbRequired);
if (pulOffset != NULL) { if (cbRequired != 0) *pulOffset = (ULONG) dptr; }
if (pulLength != NULL) { if (cbRequired == 0) *pulLength = 0; else { *pulLength = (ULONG) (cbRequired - sizeof(WCHAR)); } }
*pcbBytesWritten += cbRequired; *pcbBuffer -= cbRequired;
*ppszCursor = (PWSTR) (((ULONG_PTR) pszCursor) + cbRequired);
fSuccess = TRUE;
Exit: return fSuccess; }
protected: BOOL __fastcall Win32ResizeBufferPreserveContentsInternal( SIZE_T cch ) { // Note: this function is performance-sensitive, so we do not use the normal
// tracing infrastucture here
if (cch > m_cchBuffer) { TMutableString prgchBufferNew = NULL;
if (!this->Win32AllocateBuffer(cch, prgchBufferNew)) return FALSE;
// We assume that the buffer is/was null-terminated.
if (!TCharTraits::Win32CopyIntoBuffer(prgchBufferNew, cch, m_prgchBuffer, m_cch)) { this->DeallocateBuffer(prgchBufferNew); return FALSE; }
if ((m_prgchBuffer != NULL) && (m_prgchBuffer != this->GetInlineBuffer())) this->DeallocateBuffer(m_prgchBuffer);
m_prgchBuffer = prgchBufferNew; m_cchBuffer = cch; }
return TRUE; }
TMutableString Begin() { this->IntegrityCheck(); /* CopyBeforeWrite() */ return m_prgchBuffer; }
TMutableString End() { this->IntegrityCheck(); return &m_prgchBuffer[m_cch]; }
LONG m_cAttachedAccessors; TChar *m_prgchBuffer; SIZE_T m_cchBuffer; SIZE_T m_cch; // current length of string
};
template <typename TCharTraits> class CGenericStringBufferAccessor { public: typedef CGenericBaseStringBuffer<TCharTraits> TBuffer; typedef typename CGenericBaseStringBuffer<TCharTraits>::TChar TChar;
CGenericStringBufferAccessor(TBuffer* pBuffer = NULL) : m_pBuffer(NULL), m_pszBuffer(NULL), m_cchBuffer(NULL) { if (pBuffer != NULL) { Attach(pBuffer); } }
~CGenericStringBufferAccessor() { if (m_pBuffer != NULL) { m_pBuffer->m_cch = TCharTraits::NullTerminatedStringLength(m_pszBuffer); m_pBuffer->DetachAccessor(this); m_pBuffer = NULL; m_pszBuffer = NULL; m_cchBuffer = 0; } }
bool IsAttached() const { return (m_pBuffer != NULL); }
static TChar NullCharacter() { return TCharTraits::NullCharacter(); }
void Attach(TBuffer *pBuffer) { FN_TRACE();
// NTRAID#NTBUG9 - 586534 - 2002/03/26 - xiaoyuw
// should be changed to be INTERNAL_ERROR_CHECK
//
ASSERT(!this->IsAttached());
if (!this->IsAttached()) { pBuffer->AttachAccessor(this);
m_pBuffer = pBuffer; m_pszBuffer = m_pBuffer->m_prgchBuffer; m_cchBuffer = m_pBuffer->m_cchBuffer; } }
void Detach() { FN_TRACE();
// NTRAID#NTBUG9 - 586534 - 2002/03/26 - xiaoyuw
// should be changed to be INTERNAL_ERROR_CHECK
//
ASSERT (IsAttached());
if (IsAttached()) { ASSERT(m_pszBuffer == m_pBuffer->m_prgchBuffer);
m_pBuffer->m_cch = TCharTraits::NullTerminatedStringLength(m_pszBuffer); m_pBuffer->DetachAccessor(this);
m_pBuffer = NULL; m_pszBuffer = NULL; m_cchBuffer = 0; } else { ASSERT(m_pszBuffer == NULL); ASSERT(m_cchBuffer == 0); } }
operator typename TCharTraits::TMutableString() const { ASSERT_NTC(this->IsAttached()); return m_pszBuffer; }
SIZE_T Cch() const { ASSERT_NTC(this->IsAttached()); return (m_pszBuffer != NULL) ? ::wcslen(m_pszBuffer) : 0; }
typename TCharTraits::TMutableString GetBufferPtr() const { ASSERT_NTC(IsAttached()); return m_pszBuffer; }
SIZE_T GetBufferCch() const { ASSERT_NTC(this->IsAttached()); return m_cchBuffer; } INT GetBufferCchAsINT() const { ASSERT_NTC(this->IsAttached()); if (m_cchBuffer > INT_MAX) return INT_MAX; return static_cast<INT>(m_cchBuffer); } UINT GetBufferCchAsUINT() const { ASSERT_NTC(this->IsAttached()); if (m_cchBuffer > UINT_MAX) return UINT_MAX; return static_cast<UINT>(m_cchBuffer); } DWORD GetBufferCchAsDWORD() const { ASSERT_NTC(this->IsAttached()); if (m_cchBuffer > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cchBuffer); } DWORD GetCchAsDWORD() const { ASSERT_NTC(this->IsAttached()); if (m_cch > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cch); }
// NTRAID#NTBUG9 - 586534 - 2002/03/26 - xiaoyuw
// (1) overflow of the result of m_cchBuffer * sizeof(TChar)
// (2) calls GetXXXAsDWORD need to check whether the return value is DWORDMAX, if so, stop;
SIZE_T GetBufferCb() const { ASSERT_NTC(this->IsAttached()); return m_cchBuffer * sizeof(*m_pszBuffer); } INT GetBufferCbAsINT() const { ASSERT_NTC(this->IsAttached()); if ((m_cchBuffer * sizeof(TChar)) > INT_MAX) return INT_MAX; return static_cast<INT>(m_cchBuffer * sizeof(TChar)); } DWORD GetBufferCbAsDWORD() const { ASSERT_NTC(this->IsAttached()); if ((m_cchBuffer * sizeof(TChar)) > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cchBuffer * sizeof(TChar)); } DWORD GetCbAsDWORD() const { ASSERT_NTC(this->IsAttached()); if ((m_cch * sizeof(TChar)) > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cch * sizeof(TChar)); }
protected: TBuffer *m_pBuffer; typename TCharTraits::TMutableString m_pszBuffer; SIZE_T m_cchBuffer; };
template <SIZE_T nInlineChars, typename TCharTraits> class CGenericStringBuffer : public CGenericBaseStringBuffer<TCharTraits> { typedef CGenericBaseStringBuffer<TCharTraits> Base;
protected: BOOL Win32AllocateBuffer(SIZE_T cch, TMutableString &rpsz) const { // You shouldn't be doing this if the required buffer size is small enough to be inline...
ASSERT_NTC(cch > nInlineChars);
rpsz = NULL;
TCharTraits::TMutableString String = NULL; String = reinterpret_cast<TCharTraits::TMutableString>(::FusionpHeapAllocEx( FUSION_DEFAULT_PROCESS_HEAP(), 0, cch * sizeof(TCharTraits::TChar), "<string buffer>", __FILE__, __LINE__, 0)); // fusion heap allocation flags
if (String == NULL) { ::FusionpSetLastWin32Error(FUSION_WIN32_ALLOCFAILED_ERROR); return FALSE; }
rpsz = String; return TRUE; }
VOID DeallocateBuffer(TMutableString sz) const { VERIFY_NTC(::FusionpHeapFree(FUSION_DEFAULT_PROCESS_HEAP(), 0, sz)); }
TMutableString GetInlineBuffer() const { return const_cast<TMutableString>(m_rgchInlineBuffer); } SIZE_T GetInlineBufferCch() const { return nInlineChars; }
void Initialize() { m_rgchInlineBuffer[0] = this->NullCharacter(); Base::InitializeInlineBuffer(); } void Cleanup() { if (m_prgchBuffer != m_rgchInlineBuffer) { this->DeallocateBuffer(m_prgchBuffer); } m_prgchBuffer = NULL; m_cchBuffer = 0; }
public: void Reinitialize() { Cleanup(); Initialize(); } CGenericStringBuffer() { Initialize(); } ~CGenericStringBuffer() { Cleanup(); }
protected: TChar m_rgchInlineBuffer[nInlineChars];
private: CGenericStringBuffer(const CGenericStringBuffer &); // intentionally not implemented
void operator =(const CGenericStringBuffer &); // intentionally not implemented
};
template <SIZE_T nInlineChars, typename TCharTraits> class CGenericHeapStringBuffer : public CGenericBaseStringBuffer<TCharTraits> { // friend CGenericBaseStringBuffer<TCharTraits>;
typedef CGenericBaseStringBuffer<TCharTraits> Base;
protected: BOOL Win32AllocateBuffer(SIZE_T cch, TMutableString &rpsz) const { // You shouldn't be doing this if the required buffer size is small enough to be inline...
ASSERT_NTC(cch > nInlineChars);
rpsz = NULL;
TCharTraits::TMutableString String = NULL; String = reinterpret_cast<TCharTraits::TMutableString>(::FusionpHeapAllocEx( m_hHeap, dwDefaultWin32HeapAllocFlags, cch * sizeof(TCharTraits::TChar), "<string buffer>", __FILE__, __LINE__, 0)) // fusion heap allocation flags
if (String == NULL) { ::FusionpSetLastWin32Error(FUSION_WIN32_ALLOCFAILED_ERROR); return FALSE; }
rpsz = String; return TRUE; }
VOID DeallocateBuffer(TMutableString sz) const { VERIFY_NTC(::FusionpHeapFree(m_hHeap, dwDefaultWin32HeapFreeFlags, sz)); }
TMutableString GetInlineBuffer() const { return m_rgchInlineBuffer; } SIZE_T GetInlineBufferCch() const { return nInlineChars; }
public: CGenericHeapStringBuffer(HANDLE hHeap) : m_hHeap(hHeap) { m_rgchInlineBuffer[0] = this->NullCharacter(); Base::InitializeInlineBuffer(); }
~CGenericHeapStringBuffer() { ASSERT(m_cchBuffer == 0); ASSERT(m_prgchBuffer == NULL); }
protected: HANDLE m_hHeap; TChar m_rgchInlineBuffer[nInlineChars]; };
typedef CGenericStringBufferAccessor<CUnicodeCharTraits> CUnicodeStringBufferAccessor;
typedef CGenericBaseStringBuffer<CUnicodeCharTraits> CUnicodeBaseStringBuffer;
typedef CGenericStringBuffer<FUSION_DEFAULT_STRINGBUFFER_CHARS, CUnicodeCharTraits> CUnicodeStringBuffer; typedef CGenericHeapStringBuffer<FUSION_DEFAULT_STRINGBUFFER_CHARS, CUnicodeCharTraits> CUnicodeHeapStringBuffer;
typedef CGenericStringBuffer<FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS, CUnicodeCharTraits> CTinyUnicodeStringBuffer; typedef CGenericHeapStringBuffer<FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS, CUnicodeCharTraits> CTinyUnicodeHeapStringBuffer;
typedef CGenericStringBuffer<FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS, CUnicodeCharTraits> CSmallUnicodeStringBuffer; typedef CGenericHeapStringBuffer<FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS, CUnicodeCharTraits> CSmallUnicodeHeapStringBuffer;
typedef CGenericStringBuffer<FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS, CUnicodeCharTraits> CMediumUnicodeStringBuffer; typedef CGenericHeapStringBuffer<FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS, CUnicodeCharTraits> CMediumUnicodeHeapStringBuffer;
typedef CGenericStringBufferAccessor<CANSICharTraits> CANSIStringBufferAccessor;
typedef CGenericBaseStringBuffer<CANSICharTraits> CANSIBaseStringBuffer;
typedef CGenericStringBuffer<FUSION_DEFAULT_STRINGBUFFER_CHARS, CANSICharTraits> CANSIStringBuffer; typedef CGenericHeapStringBuffer<FUSION_DEFAULT_STRINGBUFFER_CHARS, CANSICharTraits> CANSIHeapStringBuffer;
typedef CGenericStringBuffer<FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS, CANSICharTraits> CTinyANSIStringBuffer; typedef CGenericHeapStringBuffer<FUSION_DEFAULT_TINY_STRINGBUFFER_CHARS, CANSICharTraits> CTinyANSIHeapStringBuffer;
typedef CGenericStringBuffer<FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS, CANSICharTraits> CSmallANSIStringBuffer; typedef CGenericHeapStringBuffer<FUSION_DEFAULT_SMALL_STRINGBUFFER_CHARS, CANSICharTraits> CSmallANSIHeapStringBuffer;
typedef CGenericStringBuffer<FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS, CANSICharTraits> CMediumANSIStringBuffer; typedef CGenericHeapStringBuffer<FUSION_DEFAULT_MEDIUM_STRINGBUFFER_CHARS, CANSICharTraits> CMediumANSIHeapStringBuffer;
typedef CUnicodeBaseStringBuffer CBaseStringBuffer; typedef CUnicodeStringBuffer CStringBuffer; typedef CUnicodeHeapStringBuffer CHeapStringBuffer;
typedef CUnicodeStringBufferAccessor CStringBufferAccessor;
typedef CTinyUnicodeStringBuffer CTinyStringBuffer; typedef CTinyUnicodeHeapStringBuffer CTinyHeapStringBuffer;
typedef CSmallUnicodeStringBuffer CSmallStringBuffer; typedef CSmallUnicodeHeapStringBuffer CSmallHeapStringBuffer;
typedef CMediumUnicodeStringBuffer CMediumStringBuffer; typedef CMediumUnicodeHeapStringBuffer CMediumHeapStringBuffer;
template <typename T1, typename T2> inline HRESULT HashTableCompareKey(T1 t1, T2 *pt2, bool &rfMatch);
template <> inline HRESULT HashTableCompareKey(PCWSTR sz, CUnicodeStringBuffer *pbuff, bool &rfMatch) { HRESULT hr = NOERROR; SIZE_T cchKey = (sz != NULL) ? ::wcslen(sz) : 0;
rfMatch = false;
if (!pbuff->Win32Equals(sz, cchKey, rfMatch, false)) { hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error()); goto Exit; }
hr = NOERROR; Exit: return hr; }
template <> inline HRESULT HashTableCompareKey(PCSTR sz, CANSIStringBuffer *pbuff, bool &rfMatch) { HRESULT hr = NOERROR; SIZE_T cchKey = ::strlen(sz);
rfMatch = false;
if (!pbuff->Win32Equals(sz, cchKey, rfMatch, false)) { hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error()); goto Exit; }
hr = NOERROR; Exit: return hr; }
//
// Support for CFusionArrays of strings
//
template<> inline BOOL FusionWin32CopyContents<CStringBuffer>( CStringBuffer &rDestination, const CStringBuffer &rSource ) { return rDestination.Win32Assign(rSource); }
inline BOOL FusionWin32CopyContents( CStringBuffer &rDestination, const CBaseStringBuffer &rSource ) { return rDestination.Win32Assign(rSource); }
#endif
|