/*++ Copyright (c) 2000 Microsoft Corporation Module Name: FusionString.h Abstract: Stuff to futz with everybody's favorite type, generally templatized to work on char, wchar_t, or anything else; occasionally templatized to work on arbitrary STL style [begin, end) sequences. Also stuff particularly for NT's UNICODE_STRING. To be merged with CFusionBuffer.h. Author: Jay M. Krell (a-JayK) May 2000 Revision History: --*/ #pragma once #include #include "fusionntdll.h" //#include "fusionalgorithm.h" class CUnicodeCharTraits; template class CGenericBaseStringBuffer; int FusionpCompareStrings( PCWSTR sz1, SIZE_T cch1, PCWSTR sz2, SIZE_T cch2, bool fCaseInsensitive ); inline bool FusionpEqualStrings( PCWSTR sz1, SIZE_T cch1, PCWSTR sz2, SIZE_T cch2, bool fCaseInsensitive ) { return ((cch1 == cch2) && (FusionpCompareStrings(sz1, cch1, sz2, cch2, fCaseInsensitive) == 0)); } int FusionpCompareStrings( const CGenericBaseStringBuffer &rbuff1, PCWSTR psz2, SIZE_T cch2, bool fCaseInsensitive ); int FusionpCompareStrings( PCWSTR psz1, SIZE_T cch1, const CGenericBaseStringBuffer &rbuff2, bool fCaseInsensitive ); int FusionpCompareStrings( const CGenericBaseStringBuffer &rbuff1, const CGenericBaseStringBuffer &rbuff2, bool fCaseInsensitive ); int FusionpCompareStrings( PCSTR sz1, SIZE_T cch1, PCSTR sz2, SIZE_T cch2, bool fCaseInsensitive ); #if !defined(FUSION_CANONICAL_CASE_IS_UPPER) #define FUSION_CANONICAL_CASE_IS_UPPER 1 #endif // !defined(FUSION_CANONICAL_CASE_IS_UPPER) #if FUSION_CANONICAL_CASE_IS_UPPER inline WCHAR FusionpCanonicalizeUnicodeChar(WCHAR wch) { return ::FusionpRtlUpcaseUnicodeChar(wch); } #else inline WCHAR FusionpCanonicalizeUnicodeChar(WCHAR wch) { return ::FusionpRtlDowncaseUnicodeChar(wch); } #endif inline int FusionpStrCmpI( PCWSTR psz1, PCWSTR psz2 ) { return ::FusionpCompareStrings( psz1, (psz1 != NULL) ? ::wcslen(psz1) : 0, psz2, (psz2 != NULL) ? ::wcslen(psz2) : 0, true); } /*----------------------------------------------------------------------------- StringLength is a generic name for getting the length, in count of characters, of various kinds of strings -----------------------------------------------------------------------------*/ inline SIZE_T StringLength(LPCSTR psz) { return ::strlen(psz); } inline SIZE_T StringLength(LPCWSTR psz) { return ::wcslen(psz); } #if defined(NT_INCLUDED) // { { inline SIZE_T StringLength(const UNICODE_STRING* s) { return s->Length / sizeof(*s->Buffer); } inline SIZE_T StringLength(const ANSI_STRING* s) { return s->Length / sizeof(*s->Buffer); } /* perhaps half backed, like UNICODE_STRING itself, should probably call these CContantUnicodeString or CUnicodeStringNoFree, to indicate they do no allocation or deallocation .. .. darn, really just need to merge this with existing FusionBuffer... */ #define CONSTANT_UNICODE_STRING(x) \ { \ /* the subtraction is to not count the terminal nul */ \ static_cast(sizeof(x) - sizeof((x)[0])), \ static_cast(sizeof(x) - sizeof((x)[0])), \ const_cast(x) \ } extern const UNICODE_STRING g_strEmptyUnicodeString; class CUnicodeString : public UNICODE_STRING { public: ~CUnicodeString() { } CUnicodeString(PCWSTR buffer, SIZE_T length) { this->Buffer = const_cast(buffer); // Careful! this->Length = static_cast(length * sizeof(*Buffer)); this->MaximumLength = this->Length; } CUnicodeString(PCWSTR buffer) { this->Buffer = const_cast(buffer); this->Length = static_cast(::wcslen(buffer) * sizeof(*Buffer)); this->MaximumLength = this->Length; } operator const UNICODE_STRING *() const { return this; } void operator=(PCWSTR buffer) { this->Buffer = const_cast(buffer); // Careful! this->Length = static_cast(::wcslen(buffer) * sizeof(*Buffer)); this->MaximumLength = this->Length; } void Sync() { this->Length = static_cast(::wcslen(Buffer) * sizeof(*Buffer)); } int FormatV(PCWSTR pszFormat, va_list args) { // note that vsnprintf doesn't nul terminate if there isn't room, // it squeezes the nul out in favor of an additional character, // we work around this by telling it one char less, and by always // putting a nul at the end int cchMaximumLength = this->MaximumLength / sizeof(*Buffer); this->Buffer[cchMaximumLength - 1] = 0; int i = _vsnwprintf(this->Buffer, cchMaximumLength - 1, pszFormat, args); if (i >= 0) { this->Buffer[i] = 0; this->Length = static_cast(i * sizeof(*Buffer)); } return i; } int Format(PCWSTR pszFormat, ...) { va_list args; va_start(args, pszFormat); int i = FormatV(pszFormat, args); va_end(args); return i; } //protected: CUnicodeString() { this->Buffer = L""; this->Length = sizeof(*Buffer); this->MaximumLength = this->Length; } private: // deliberately not implemented CUnicodeString(const CUnicodeString&); void operator=(const CUnicodeString&); }; template class CUnicodeStringN : public CUnicodeString { public: ~CUnicodeStringN() { } CUnicodeStringN() { this->Buffer = m_rgchBuffer; this->Length = 0; this->MaximumLength = sizeof(m_rgchBuffer); m_rgchBuffer[0] = 0; m_rgchBuffer[N-1] = 0; } WCHAR m_rgchBuffer[N]; private: // deliberately not implemented CUnicodeStringN(const CUnicodeStringN&); void operator=(const CUnicodeStringN&); }; #endif // } } /*----------------------------------------------------------------------------- genericized name for strchr and wcschr -----------------------------------------------------------------------------*/ //template const Char* StringFindChar(const Char* s, Char ch) // Automatically provide non const, but looser type binding between s // and ch. Still requires nul termination, so doesn't really support more than // char*, const char*, wchar_t*, and const wchar_t*. // // StdFind is the obvious generalization that doesn't require a particular // terminal value, but the ability to pass a terminal pointer or iterator. template inline String StringFindChar(String s, Char ch) { String end = s + StringLength(s); String found = StdFind(s, end, ch); if (found == end) { found = NULL; } return found; } /*----------------------------------------------------------------------------- specialize StringFindChar for char to use strchr provided in msvcrt.dll or ntdll.dll. -----------------------------------------------------------------------------*/ // strchr is getting defined to be StrChrW, which does not work. #if !defined(strchr) // { { template <> inline const char* StringFindChar(const char* s, char ch) { s = strchr(s, ch); return s; } template <> inline char* StringFindChar(char* s, char ch) { s = strchr(s, ch); return s; } #endif // } } /*----------------------------------------------------------------------------- specialize StringFindChar for wchar_t to use wcschr provided in msvcrt.dll or ntdll.dll. -----------------------------------------------------------------------------*/ template <> inline const wchar_t* StringFindChar(const wchar_t* s, wchar_t ch) { s = wcschr(s, ch); return s; } template <> inline wchar_t* StringFindChar(wchar_t* s, wchar_t ch) { s = wcschr(s, ch); return s; } /*----------------------------------------------------------------------------- common code for StringReverseSpan and StringReverseComplementSpan -----------------------------------------------------------------------------*/ template INT PrivateStringReverseSpanCommon( const Char* begin, const Char* end, const Char* set, // nul terminated bool breakVal ) { const Char* t = end; while (t != begin) { if (breakVal == !!StringFindChar(set, *--t)) { ++t; // don't count the last checked one break; } } return static_cast(end - t); } /*----------------------------------------------------------------------------- Find the length of the run of characters in set from the end of [begin, end). "wcsrspn" variants of this can be seen at \vsee\lib\xfcstr\strexw.cpp and \\jayk1\g\temp\rspn.cpp -----------------------------------------------------------------------------*/ template inline INT StringReverseSpan( const Char* begin, const Char* end, const Char* set ) { // break when not found return ::PrivateStringReverseSpanCommon(begin, end, set, false); } /*----------------------------------------------------------------------------- Find the length of the run of characters not in set from the end of [begin, end). "wcsrcspn" variants of this can be seen at \vsee\lib\xfcstr\strexw.cpp and \\jayk1\g\temp\rspn.cpp -----------------------------------------------------------------------------*/ template inline INT StringReverseComplementSpan( const Char* begin, const Char* end, const Char* set ) { // break when found return ::PrivateStringReverseSpanCommon(begin, end, set, true); } template inline INT PrivateStringSpanCommon( const Char* begin, const Char* end, const Char* set, bool breakVal ) { const Char* t = begin; while ( t != end ) { if (breakVal == !!StringFindChar(set, *t++)) { --t; break; } } return static_cast(t - begin); } template inline INT StringSpan( const Char* begin, const Char* end, const Char* set ) { return ::PrivateStringSpanCommon( begin, end, set, false ); } template inline INT StringComplimentSpan( const Char* begin, const Char* end, const Char* set ) { return ::PrivateStringSpanCommon( begin, end, set, true ); }