/*++ Copyright (c) 1992-2000 Microsoft Corporation Module Name: wstring.cxx --*/ #include #define _NTAPI_ULIB_ #define _ULIB_MEMBER_ #include "ulib.hxx" #include "wstring.hxx" #if !defined( _EFICHECK_ ) #include #include #endif BOOLEAN WSTRING::_UseAnsiConversions = FALSE; BOOLEAN WSTRING::_UseConsoleConversions = FALSE; #if defined FE_SB BOOLEAN WSTRING::_UseAnsiConversionsPrev = FALSE; BOOLEAN WSTRING::_UseConsoleConversionsPrev = FALSE; #endif // Helper functions for OEM/Unicode conversion. Note that these // are abstracted to private functions to make it easier to set // them up for various environments. // INLINE BOOLEAN WSTRING::ConvertOemToUnicodeN( PWSTR UnicodeString, ULONG MaxBytesInUnicodeString, PULONG BytesInUnicodeString, PCHAR OemString, ULONG BytesInOemString ) { UINT32 i; // BUGBUG this is a big hack. if( MaxBytesInUnicodeString == 0 ) { *BytesInUnicodeString = 2*BytesInOemString; return TRUE; } if( MaxBytesInUnicodeString < 2*BytesInOemString ) { *BytesInUnicodeString = 2*BytesInOemString; return FALSE; } memset(UnicodeString,0,MaxBytesInUnicodeString); for (i=0; i_l); Length = min(Length, InitialString->_l - Position); if (!NewBuf(Length)) { return FALSE; } memcpy(_s, InitialString->_s + Position, (UINT) Length*sizeof(WCHAR)); return TRUE; } BOOLEAN WSTRING::Initialize( IN PCWSTR InitialString, IN CHNUM StringLength ) /*++ Routine Description: This routine initializes the current string by copying the contents of the given string. Arguments: InitialString - Supplies the initial string. Return Value: FALSE - Failure. TRUE - Success. --*/ { if (StringLength == TO_END) { StringLength = wcslen(InitialString); } if (!NewBuf(StringLength)) { return FALSE; } memcpy(_s, InitialString, (UINT) StringLength*sizeof(WCHAR)); return TRUE; } BOOLEAN WSTRING::Initialize( IN PCSTR InitialString, IN CHNUM StringLength ) /*++ Routine Description: This routine initializes the current string by copying the contents of the given string. Arguments: InitialString - Supplies the initial string. Return Value: FALSE - Failure. TRUE - Success. --*/ { CHNUM length=0; BOOLEAN status; if (StringLength == TO_END) { StringLength = strlen(InitialString); } if (!StringLength) { return Resize(0); } // We want to avoid making two calls to RtlOemToUnicodeN so // try to guess an adequate size for the buffer. if (!NewBuf(StringLength)) { return FALSE; } status = ConvertOemToUnicodeN(_s, _l*sizeof(WCHAR), &length, (PSTR) InitialString, StringLength); length /= sizeof(WCHAR); if (status) { return Resize(length); } // We didn't manage to make in one try so ask exactly how much // we need and then make the call. status = ConvertOemToUnicodeN(NULL, 0, &length, (PSTR) InitialString, StringLength); length /= sizeof(WCHAR); if (!status || !NewBuf(length)) { return FALSE; } status = ConvertOemToUnicodeN(_s, _l*sizeof(WCHAR), &length, (PSTR) InitialString, StringLength); if (!status) { return FALSE; } DebugAssert(length == _l*sizeof(WCHAR)); return TRUE; } BOOLEAN WSTRING::Initialize( IN LONG Number ) /*++ Routine Description: This routine initializes the current string by copying the contents of the given string. Arguments: Number - Supplies the number to initialize the string to. Return Value: FALSE - Failure. TRUE - Success. --*/ { WCHAR tmp[64]; SPrint(tmp, 64, TEXT("%d"), Number); return Initialize(tmp); } NONVIRTUAL PWSTRING WSTRING::QueryString( IN CHNUM Position, IN CHNUM Length ) CONST /*++ Routine Description: This routine returns a copy of this string from the specified coordinates. Arguments: Position - Supplies the initialize position of the string. Length - Supplies the length of the string. Return Value: A pointer to a string or NULL. --*/ { PWSTRING p; if (!(p = NEW DSTRING) || !p->Initialize(this, Position, Length)) { DELETE(p); } return p; } BOOLEAN WSTRING::QueryNumber( OUT PLONG Number, IN CHNUM Position, IN CHNUM Length ) CONST /*++ Routine Description: This routine queries a number from the string. Arguments: Number - Returns the number parsed out of the string. Position - Supplies the position of the number. Length - Supplies the length of the number. Return Value: FALSE - Failure. TRUE - Success. --*/ { FSTRING String; PSTR p; CHNUM spn; if (Position >= _l) { return FALSE; } Length = min(Length, _l - Position); // // Note that 123+123 will be a number! // String.Initialize((PWSTR) L"1234567890+-"); spn = Strspn(&String, Position); if ((spn == INVALID_CHNUM || spn >= Position + Length) && (p = QuerySTR(Position, Length))) { *Number = atol(p); DELETE(p); return TRUE; } return FALSE; } VOID WSTRING::DeleteChAt( IN CHNUM Position, IN CHNUM Length ) /*++ Routine Description: This routine removes the character at the given position. Arguments: Position - Supplies the position of the character to remove. Length - Supplies the number of characters to remove. Return Value: FALSE - Failure. TRUE - Success. --*/ { DebugAssert(Position <= _l); Length = min(Length, _l - Position); memmove(_s + Position, _s + Position + Length, (UINT) (_l - Position - Length)*sizeof(WCHAR)); Resize(_l - Length); } NONVIRTUAL BOOLEAN WSTRING::InsertString( IN CHNUM AtPosition, IN PCWSTRING String, IN CHNUM FromPosition, IN CHNUM FromLength ) /*++ Routine Description: This routine inserts the given string at the given position in this string. Arguments: AtPosition - Supplies the position at which to insert the string. String - Supplies the string to insert. Return Value: FALSE - Failure. TRUE - Success. --*/ { CHNUM old_length; DebugAssert(AtPosition <= _l); DebugAssert(FromPosition <= String->_l); FromLength = min(FromLength, String->_l - FromPosition); old_length = _l; if (!Resize(_l + FromLength)) { return FALSE; } memmove(_s + AtPosition + FromLength, _s + AtPosition, (UINT) (old_length - AtPosition)*sizeof(WCHAR)); memcpy(_s + AtPosition, String->_s + FromPosition, (UINT) FromLength*sizeof(WCHAR)); return TRUE; } NONVIRTUAL BOOLEAN WSTRING::Replace( IN CHNUM AtPosition, IN CHNUM AtLength, IN PCWSTRING String, IN CHNUM FromPosition, IN CHNUM FromLength ) /*++ Routine Description: This routine replaces the contents of this string from 'Position' to 'Length' with the contents of 'String2' from 'Position2' to 'Length2'. Arguments: AtPosition - Supplies the position to replace at. AtLength - Supplies the length to replace at. String - Supplies the string to replace with. FromPosition - Supplies the position to replace from in String2. FromLength - Supplies the position to replace from in String2. Return Value: FALSE - Failure. TRUE - Success. --*/ { CHNUM old_length; DebugAssert(AtPosition <= _l); DebugAssert(FromPosition <= String->_l); AtLength = min(AtLength, _l - AtPosition); FromLength = min(FromLength, String->_l - FromPosition); // Make sure up front that we have the room but don't disturb // the string. if (FromLength > AtLength) { old_length = _l; if (!Resize(_l + FromLength - AtLength)) { return FALSE; } Resize(old_length); } DeleteChAt(AtPosition, AtLength); if (!InsertString(AtPosition, String, FromPosition, FromLength)) { DebugAbort("This absolutely can never happen\n"); return FALSE; } return TRUE; } NONVIRTUAL BOOLEAN WSTRING::ReplaceWithChars( IN CHNUM AtPosition, IN CHNUM AtLength, IN WCHAR Character, IN CHNUM FromLength ) /*++ Routine Description: This routine replaces the contents of this string from AtPosition of AtLength with the string formed by Character of FromLength. Arguments: AtPosition - Supplies the position to replace at. AtLength - Supplies the length to replace at. Character - Supplies the character to replace with. FromLength - Supplies the total number of new characters to replace the old one with. Return Value: FALSE - Failure. TRUE - Success. --*/ { CHNUM old_length; PWCHAR currptr, endptr; DebugAssert(AtPosition <= _l); AtLength = min(AtLength, _l - AtPosition); // Make sure up front that we have the room but don't disturb // the string. if (FromLength > AtLength) { old_length = _l; if (!Resize(_l + FromLength - AtLength)) { return FALSE; } Resize(old_length); } DeleteChAt(AtPosition, AtLength); old_length = _l; if (!Resize(_l + FromLength)) { DebugPrint("This should not fail\n"); return FALSE; } memmove(_s + AtPosition + FromLength, _s + AtPosition, (UINT) (old_length - AtPosition)*sizeof(WCHAR)); for (currptr = _s + AtPosition, endptr = currptr + FromLength; currptr < endptr; currptr++) { *currptr = Character; } return TRUE; } PWSTR WSTRING::QueryWSTR( IN CHNUM Position, IN CHNUM Length, OUT PWSTR Buffer, IN CHNUM BufferLength, IN BOOLEAN ForceNull ) CONST /*++ Routine Description: This routine makes a copy of this string into the provided buffer. If this string is not provided then a buffer is allocated on the heap. Arguments: Position - Supplies the position within this string. Length - Supplies the length of this string to take. Buffer - Supplies the buffer to copy to. BufferLength - Supplies the number of characters in the buffer. ForceNull - Specifies whether or not to force the final character of the buffer to be NULL in the case when there isn't enough room for the whole string including the NULL. Return Value: A pointer to a NULL terminated string. --*/ { DebugAssert(Position <= _l); Length = min(Length, _l - Position); if (!Buffer) { BufferLength = Length + 1; if (!(Buffer = (PWCHAR) MALLOC(BufferLength*sizeof(WCHAR)))) { return NULL; } } if (BufferLength > Length) { memcpy(Buffer, _s + Position, (UINT) Length*sizeof(WCHAR)); Buffer[Length] = 0; } else { memcpy(Buffer, _s + Position, (UINT) BufferLength*sizeof(WCHAR)); if (ForceNull) { Buffer[BufferLength - 1] = 0; } } return Buffer; } PSTR WSTRING::QuerySTR( IN CHNUM Position, IN CHNUM Length, OUT PSTR Buffer, IN CHNUM BufferLength, IN BOOLEAN ForceNull ) CONST /*++ Routine Description: This routine computes a multi-byte version of the current unicode string. If the buffer is not supplied then it will be allocated by this routine. Arguments: Position - Supplies the position within this string. Length - Supplies the length of this string to take. Buffer - Supplies the buffer to convert into. BufferLength - Supplies the number of characters in this buffer. ForceNull - Specifies whether or not to force a NULL even when the buffer is too small for the string. Return Value: A pointer to a NULL terminated multi byte string. --*/ { ULONG ansi_length; DebugAssert(Position <= _l); Length = min(Length, _l - Position); // First special case the empty result. if (!Length) { if (!Buffer) { if (!(Buffer = (PSTR) MALLOC(1))) { return NULL; } } else if (!BufferLength) { return NULL; } Buffer[0] = 0; return Buffer; } // Next case is that the buffer is not provided and thus // we have to figure out what size it should be. if (!Buffer) { // We want to avoid too many calls to RtlUnicodeToOemN // so we'll estimate a correct size for the buffer and // hope that that works. BufferLength = 2*Length + 1; if (!(Buffer = (PSTR) MALLOC(BufferLength))) { return NULL; } if (ConvertUnicodeToOemN(Buffer, BufferLength - 1, &ansi_length, _s + Position, Length*sizeof(WCHAR))) { Buffer[ansi_length] = 0; return Buffer; } // We failed to estimate the necessary size of the buffer. // So ask the correct size and try again. FREE(Buffer); if (!ConvertUnicodeToOemN(NULL, 0, &ansi_length, _s + Position, Length*sizeof(WCHAR))) { return NULL; } BufferLength = ansi_length + 1; if (!(Buffer = (PSTR) MALLOC(BufferLength))) { return NULL; } } if (!ConvertUnicodeToOemN(Buffer, BufferLength, &ansi_length, _s + Position, Length*sizeof(WCHAR))) { return NULL; } if (BufferLength > ansi_length) { Buffer[ansi_length] = 0; } else { if (ForceNull) { Buffer[BufferLength - 1] = 0; } } return Buffer; } BOOLEAN WSTRING::Strcat( IN PCWSTRING String ) /*++ Routine Description: This routine concatenates the given string onto this one. Arguments: String - Supplies the string to concatenate to this one. Return Value: FALSE - Failure. TRUE - Success. --*/ { CHNUM old_length; old_length = _l; if (!Resize(_l + String->_l)) { return FALSE; } memcpy(_s + old_length, String->_s, (UINT) String->_l*sizeof(WCHAR)); return TRUE; } NONVIRTUAL PWSTRING WSTRING::Strupr( IN CHNUM StartPosition, IN CHNUM Length ) /*++ Routine Description: This routine upcases a portion of this string. Arguments: StartPosition - Supplies the start position of the substring to upcase. Length - Supplies the length of the substring to upscase. Return Value: A pointer to this string. --*/ { WCHAR c; DebugAssert(StartPosition <= _l); Length = min(Length, _l - StartPosition); c = _s[StartPosition + Length]; _s[StartPosition + Length] = 0; // BUGBUG don't have an upcase function in EFI. // _wcsupr(_s + StartPosition); _s[StartPosition + Length] = c; return this; } NONVIRTUAL PWSTRING WSTRING::Strlwr( IN CHNUM StartPosition, IN CHNUM Length ) /*++ Routine Description: This routine lowercases a portion of this string. Arguments: StartPosition - Supplies the start position of the substring to lowercase. Length - Supplies the length of the substring to lowercase. Return Value: A pointer to this string. --*/ { WCHAR c; DebugAssert(StartPosition <= _l); Length = min(Length, _l - StartPosition); c = _s[StartPosition + Length]; _s[StartPosition + Length] = 0; // BUGBUG we don't have a lowercase function in EFI // _wcslwr(_s + StartPosition); _s[StartPosition + Length] = c; return this; } NONVIRTUAL LONG WSTRING::Strcmp( IN PCWSTRING String, IN CHNUM LeftPosition, IN CHNUM LeftLength, IN CHNUM RightPosition, IN CHNUM RightLength ) CONST /*++ Routine Description: This routine compares two substrings. Arguments: String - Supplies the string to compare this one to. LeftPosition - Supplies the postion for the left substring. LeftLength - Supplies the length of the left substring. LeftPosition - Supplies the postion for the left substring. LeftLength - Supplies the length of the left substring. Return Value: <0 - Left substring is less than right substring. 0 - Left and Right substrings are equal >0 - Left substring is greater than right substring. --*/ { WCHAR c, d; LONG r; DebugAssert(LeftPosition <= _l); DebugAssert(RightPosition <= String->_l); LeftLength = min(LeftLength, _l - LeftPosition); RightLength = min(RightLength, String->_l - RightPosition); c = _s[LeftPosition + LeftLength]; d = String->_s[RightPosition + RightLength]; _s[LeftPosition + LeftLength] = 0; String->_s[RightPosition + RightLength] = 0; r = wcscmp(_s + LeftPosition, String->_s + RightPosition); _s[LeftPosition + LeftLength] = c; String->_s[RightPosition + RightLength] = d; return r; } NONVIRTUAL LONG WSTRING::Stricmp( IN PCWSTRING String, IN CHNUM LeftPosition, IN CHNUM LeftLength, IN CHNUM RightPosition, IN CHNUM RightLength ) CONST /*++ Routine Description: This routine compares two substrings insensitive of case. Arguments: String - Supplies the string to compare this one to. LeftPosition - Supplies the postion for the left substring. LeftLength - Supplies the length of the left substring. LeftPosition - Supplies the postion for the left substring. LeftLength - Supplies the length of the left substring. Return Value: <0 - Left substring is less than right substring. 0 - Left and Right substrings are equal >0 - Left substring is greater than right substring. --*/ { WCHAR c, d; LONG r; DebugAssert(LeftPosition <= _l); DebugAssert(RightPosition <= String->_l); LeftLength = min(LeftLength, _l - LeftPosition); RightLength = min(RightLength, String->_l - RightPosition); c = _s[LeftPosition + LeftLength]; d = String->_s[RightPosition + RightLength]; _s[LeftPosition + LeftLength] = 0; String->_s[RightPosition + RightLength] = 0; #if !defined _AUTOCHECK_ && !defined _EFICHECK_ // This works around a bug in the libc version of wcsicoll, where // it doesn't specify STRINGSORT to CompareString(). To reproduce the // bug, try sorting 1 and -1. (-1 should sort before 1.) // r = CompareString(GetUserDefaultLCID(), NORM_IGNORECASE | SORT_STRINGSORT, _s + LeftPosition, -1, String->_s + RightPosition, -1 ); if (r >= 1) { // // return codes 1, 2, and 3 map to -1, 0, and 1. // _s[LeftPosition + LeftLength] = c; String->_s[RightPosition + RightLength] = d; return r - 2; } // If 'r' is 0, this indicates failure and we'll fall through and // call wcsicoll. // #endif // _AUTOCHECK_ r = _wcsicmp(_s + LeftPosition, String->_s + RightPosition); _s[LeftPosition + LeftLength] = c; String->_s[RightPosition + RightLength] = d; return r; } PWSTR WSTRING::SkipWhite( IN PWSTR p ) { #ifdef FE_SB while (*p) { if (iswspace(*p)) p++; else if ( *p == 0x3000 ) { *p++ = TEXT(' '); } else break; } #else while (iswspace(*p)) { p++; } #endif return p; } /**************************************************************************/ /* Compare two strings, ignoring white space, case is significant, return */ /* 0 if identical, <>0 otherwise. Leading and trailing white space is */ /* ignored, internal white space is treated as single characters. */ /**************************************************************************/ INT WSTRING::Strcmps ( IN PWSTR p1, IN PWSTR p2 ) { WCHAR *q; p1 = WSTRING::SkipWhite(p1); /* skip any leading white space */ p2 = WSTRING::SkipWhite(p2); while (TRUE) { if (*p1 == *p2) { if (*p1++ == 0) /* quit if at the end */ return (0); else p2++; #ifdef FE_SB if (CheckSpace(p1)) #else if (iswspace(*p1)) /* compress multiple spaces */ #endif { q = WSTRING::SkipWhite(p1); p1 = (*q == 0) ? q : q - 1; } #ifdef FE_SB if (CheckSpace(p2)) #else if (iswspace(*p2)) #endif { q = WSTRING::SkipWhite(p2); p2 = (*q == 0) ? q : q - 1; } } else return *p1-*p2; } } /**************************************************************************/ /* Compare two strings, ignoring white space, case is not significant, */ /* return 0 if identical, <>0 otherwise. Leading and trailing white */ /* space is ignored, internal white space is treated as single characters.*/ /**************************************************************************/ INT WSTRING::Strcmpis ( IN PWSTR p1, IN PWSTR p2 ) { WCHAR *q; #ifdef FE_SB WCHAR c1,c2; #endif p1 = WSTRING::SkipWhite(p1); /* skip any leading white space */ p2 = WSTRING::SkipWhite(p2); while (TRUE) { if (towupper(*p1) == towupper(*p2)) { if (*p1++ == 0) /* quit if at the end */ return (0); else p2++; #ifdef FE_SB if (CheckSpace(p1)) #else if (iswspace(*p1)) /* compress multiple spaces */ #endif { q = SkipWhite(p1); p1 = (*q == 0) ? q : q - 1; } #ifdef FE_SB if (CheckSpace(p2)) #else if (iswspace(*p2)) #endif { q = WSTRING::SkipWhite(p2); p2 = (*q == 0) ? q : q - 1; } } else return *p1-*p2; } } #ifdef FE_SB /**************************************************************************/ /* Routine: CheckSpace */ /* Arguments: an arbitrary string */ /* Function: Determine whether there is a space in the string. */ /* Side effects: none */ /**************************************************************************/ INT WSTRING::CheckSpace( IN PWSTR s ) { if (iswspace(*s) || *s == 0x3000 ) return (TRUE); else return (FALSE); } #endif #define DUMMY_ULIB_EXPORT DEFINE_EXPORTED_CONSTRUCTOR( FSTRING, WSTRING, DUMMY_ULIB_EXPORT ); BOOLEAN FSTRING::Resize( IN CHNUM NewStringLength ) /*++ Routine Description: This routine implements the WSTRING Resize routine by using the buffer supplied at initialization time. Arguments: NewStringLength - Supplies the new length of the string. Return Value: FALSE - Failure. TRUE - Success. --*/ { return NewBuf(NewStringLength); } BOOLEAN FSTRING::NewBuf( IN CHNUM NewStringLength ) /*++ Routine Description: This routine implements the WSTRING NewBuf routine by using the buffer supplied at initialization time. Arguments: NewStringLength - Supplies the new length of the string. Return Value: FALSE - Failure. TRUE - Success. --*/ { if (NewStringLength >= _buffer_length) { return FALSE; } PutString((PWSTR) GetWSTR(), NewStringLength); return TRUE; } INLINE VOID DSTRING::Construct( ) /*++ Routine Description: This routine initializes the string to a valid initial state. Arguments: None. Return Value: None. --*/ { _buf = NULL; _length = 0; } DEFINE_EXPORTED_CONSTRUCTOR( DSTRING, WSTRING, DUMMY_ULIB_EXPORT ); DSTRING::~DSTRING( ) /*++ Routine Description: Destructor for DSTRING. Arguments: None. Return Value: None. --*/ { FREE(_buf); } BOOLEAN DSTRING::Resize( IN CHNUM NewStringLength ) /*++ Routine Description: This routine resizes this string to the specified new size. Arguments: NewStringLength - Supplies the new length of the string. Return Value: FALSE - Failure. TRUE - Success. --*/ { PWSTR new_buf; if (NewStringLength >= _length) { if (_buf) { #if !defined( _EFICHECK_ ) if (!(new_buf = (PWSTR) REALLOC(_buf, (NewStringLength + 1)*sizeof(WCHAR)))) { return FALSE; } #else new_buf = (PWSTR) ReallocatePool( _buf, _length * sizeof(WCHAR), (NewStringLength + 1)*sizeof(WCHAR) ); if ( new_buf == NULL ) { return FALSE; } #endif } else { if (!(new_buf = (PWSTR) MALLOC((NewStringLength + 1)*sizeof(WCHAR)))) { return FALSE; } } _buf = new_buf; _length = NewStringLength + 1; } PutString(_buf, NewStringLength); return TRUE; } BOOLEAN DSTRING::NewBuf( IN CHNUM NewStringLength ) /*++ Routine Description: This routine resizes this string to the specified new size. Arguments: NewStringLength - Supplies the new length of the string. Return Value: FALSE - Failure. TRUE - Success. --*/ { PWSTR new_buf; if (NewStringLength >= _length) { if (!(new_buf = (PWSTR) MALLOC((NewStringLength + 1)*sizeof(WCHAR)))) { return FALSE; } if (_buf) { FREE(_buf); } _buf = new_buf; _length = NewStringLength + 1; } PutString(_buf, NewStringLength); return TRUE; } #if defined FE_SB VOID WSTRING::ResetConversions( ) { _UseAnsiConversions = _UseAnsiConversionsPrev; _UseConsoleConversions = _UseConsoleConversionsPrev; } #endif VOID WSTRING::SetAnsiConversions( ) /*++ Routine Description: This routine declares that all conversions from multi byte to unicode will take place using the ANSI code page. Note that this is a STATIC method. Therefore this switch affects *all* WSTRINGs. Arguments: None. Return Value: None. --*/ { #if defined FE_SB _UseAnsiConversionsPrev = _UseAnsiConversions; _UseConsoleConversionsPrev = _UseConsoleConversions; #endif _UseAnsiConversions = TRUE; _UseConsoleConversions = FALSE; } VOID WSTRING::SetOemConversions( ) /*++ Routine Description: This routine declares that all conversions from multi byte to unicode will take place using the OEM code page. Note that this is a STATIC method. Therefore this switch affects *all* WSTRINGs. This is the default if neither this nor the above function is called. Arguments: None. Return Value: None. --*/ { #if defined FE_SB _UseAnsiConversionsPrev = _UseAnsiConversions; _UseConsoleConversionsPrev = _UseConsoleConversions; #endif _UseAnsiConversions = FALSE; _UseConsoleConversions = FALSE; } VOID WSTRING::SetConsoleConversions( ) /*++ Routine Description: This routine declares that all conversions from multi byte to unicode will take place using the current console code page. Note that this is a STATIC method. Therefore this switch affects *all* WSTRINGs. Arguments: None. Return Value: None. --*/ { #if defined FE_SB _UseAnsiConversionsPrev = _UseAnsiConversions; _UseConsoleConversionsPrev = _UseConsoleConversions; #endif _UseAnsiConversions = FALSE; _UseConsoleConversions = TRUE; } #if defined FE_SB CHNUM WSTRING::QueryByteCount( ) CONST /*++ Routine Description: This routine returns the number of ANSI bytes the UNICODE string consists of. Arguments: None. Return Value: Number of ANSI bytes the UNICODE string is made from, or INVALID_CHNUM on error. --*/ { ULONG ansi_length; ULONG BufferLen = _l * sizeof(WCHAR) + 1; PSTR Buffer; BOOLEAN success; if ( !_l ) { return( (CHNUM)0 ); } if (NULL == (Buffer = (PSTR)MALLOC( BufferLen ))) { return( INVALID_CHNUM ); } success = ConvertUnicodeToOemN( Buffer, BufferLen - 1, &ansi_length, _s, BufferLen - 1 ); FREE( Buffer ); if (!success) { return INVALID_CHNUM; } return ansi_length; } #endif