727 lines
14 KiB
C
727 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
String.c
|
||
|
||
Abstract:
|
||
|
||
This module contains support for loading resource strings.
|
||
|
||
Author:
|
||
|
||
David J. Gilman (davegi) 11-Sep-1992
|
||
Gregg R. Acheson (GreggA) 28-Feb-1994
|
||
|
||
Environment:
|
||
|
||
User Mode
|
||
|
||
--*/
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
|
||
#include "wintools.h"
|
||
|
||
#include <search.h>
|
||
#include <string.h>
|
||
|
||
INT
|
||
StricmpW(
|
||
IN LPCWSTR String1,
|
||
IN LPCWSTR String2
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
StricmpW performs a case insesitive string compare returning a result that
|
||
is acceptable for WM_COMPAREITEM messages.
|
||
|
||
Arguments:
|
||
|
||
String1 - Supplies the first string to compare.
|
||
String2 - Supplies the second string to compare.
|
||
|
||
Return Value:
|
||
|
||
INT - Returns:
|
||
-1 String1 precedes String2 in the sorted order.
|
||
0 String1 and String2 are equivalent in the sorted order.
|
||
1 String1 follows String2 in the sorted order.
|
||
|
||
--*/
|
||
|
||
{
|
||
INT Compare;
|
||
|
||
Compare = _wcsicmp( String1, String2 );
|
||
|
||
if( Compare < 0 ) {
|
||
return -1;
|
||
} else if( Compare > 0 ) {
|
||
return 1;
|
||
} else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
LPCSTR
|
||
GetStringA(
|
||
IN UINT StringId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
GetStringA returns a pointer to the ANSI string corresponding to
|
||
the supplied resource id.
|
||
|
||
Arguments:
|
||
|
||
StringId - Supplies a string resource id.
|
||
|
||
Return Value:
|
||
|
||
LPCWSTR - Returns a pointer to a static buffer that contains
|
||
the ANSI string.
|
||
|
||
--*/
|
||
|
||
{
|
||
int Length;
|
||
|
||
static
|
||
CHAR Buffer[ MAX_CHARS ];
|
||
|
||
//
|
||
// Load the requested string making sure that it succesfully loaded
|
||
// and fit in the buffer.
|
||
//
|
||
|
||
Length = LoadStringA(
|
||
NULL,
|
||
StringId,
|
||
Buffer,
|
||
sizeof( Buffer )
|
||
);
|
||
DbgAssert( Length != 0 );
|
||
DbgAssert( Length < sizeof( Buffer ));
|
||
if(( Length == 0 ) || ( Length >= NumberOfCharacters( Buffer ))) {
|
||
return NULL;
|
||
}
|
||
|
||
return Buffer;
|
||
}
|
||
|
||
LPCWSTR
|
||
GetStringW(
|
||
IN UINT StringId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
GetStringW returns a pointer to the Unicode string corresponding to
|
||
the supplied resource id.
|
||
|
||
Arguments:
|
||
|
||
StringId - Supplies a string resource id.
|
||
|
||
Return Value:
|
||
|
||
LPCWSTR - Returns a pointer to a static buffer that contains
|
||
the Unicode string.
|
||
|
||
--*/
|
||
|
||
{
|
||
int Length;
|
||
|
||
static
|
||
WCHAR Buffer[ MAX_CHARS ];
|
||
|
||
//
|
||
// Load the requested string making sure that it succesfully loaded
|
||
// and fit in the buffer.
|
||
//
|
||
|
||
Length = LoadStringW(
|
||
NULL,
|
||
StringId,
|
||
Buffer,
|
||
sizeof( Buffer )
|
||
);
|
||
DbgAssert( Length != 0 );
|
||
DbgAssert( Length < sizeof( Buffer ));
|
||
if(( Length == 0 ) || ( Length >= NumberOfCharacters( Buffer ))) {
|
||
return NULL;
|
||
}
|
||
|
||
return Buffer;
|
||
}
|
||
|
||
LPWSTR
|
||
FormatLargeIntegerW(
|
||
IN PLARGE_INTEGER Value,
|
||
IN BOOL Signed
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts a large integer to a string inserting thousands separators
|
||
as appropriate.
|
||
|
||
Arguments:
|
||
|
||
LargeInteger - Supplies the number to be formatted.
|
||
Signed - Supplies a flag which if TRUE indicates that the supplied
|
||
value is a signed number.
|
||
|
||
Return Value:
|
||
|
||
LPWSTR - Returns a pointer to the formatted string.
|
||
|
||
--*/
|
||
|
||
{
|
||
static
|
||
CHAR pIntegerChars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
|
||
|
||
static
|
||
WCHAR Buffer[ MAX_PATH ];
|
||
|
||
WCHAR SThousand[ MAX_PATH ];
|
||
DWORD SThousandChars;
|
||
int Index;
|
||
DWORD Count;
|
||
WCHAR wString[ MAX_PATH ];
|
||
CHAR aString[ MAX_PATH ];
|
||
LONG OutputLength = 95;
|
||
|
||
CHAR Result[ 100 ], *s;
|
||
ULONG Shift, Digit;
|
||
LONG Length;
|
||
LARGE_INTEGER TempValue=*Value;
|
||
|
||
|
||
//
|
||
// Convert the Large Integer to a UNICODE string
|
||
//
|
||
|
||
Shift = 0;
|
||
s = &Result[ 99 ];
|
||
*s = '\0';
|
||
|
||
do {
|
||
|
||
TempValue = RtlExtendedLargeIntegerDivide(TempValue,10L,&Digit);
|
||
*--s = pIntegerChars[ Digit ];
|
||
|
||
} while (TempValue.HighPart != 0 || TempValue.LowPart != 0);
|
||
|
||
|
||
Length = &Result[ 99 ] - s;
|
||
|
||
if (OutputLength < 0) {
|
||
|
||
OutputLength = -OutputLength;
|
||
while ((LONG)Length < OutputLength) {
|
||
|
||
*--s = '0';
|
||
Length++;
|
||
|
||
}
|
||
}
|
||
|
||
if ((LONG)Length > OutputLength) {
|
||
|
||
return NULL;
|
||
|
||
} else {
|
||
|
||
RtlMoveMemory( aString, s, Length );
|
||
|
||
if ((LONG)Length < OutputLength) {
|
||
|
||
aString[ Length ] = '\0';
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// Convert to UNICODE
|
||
//
|
||
|
||
Length = wsprintf( wString, L"%S", aString );
|
||
|
||
//
|
||
// Get the thousand separator for this locale.
|
||
//
|
||
|
||
SThousandChars = GetLocaleInfoW(
|
||
LOCALE_USER_DEFAULT,
|
||
LOCALE_STHOUSAND,
|
||
SThousand,
|
||
NumberOfCharacters( SThousand )
|
||
);
|
||
|
||
DbgAssert( SThousandChars != 0 );
|
||
if( SThousandChars == 0 ) {
|
||
return NULL;
|
||
}
|
||
|
||
DbgAssert( Length < NumberOfCharacters( Buffer ));
|
||
|
||
Index = NumberOfCharacters( Buffer ) - 1;
|
||
Count = 0;
|
||
|
||
//
|
||
// Copy the NUL character.
|
||
//
|
||
|
||
Buffer[ Index-- ] = wString[ Length-- ];
|
||
|
||
//
|
||
// Copy the string in reverse order, inserting the thousands separator
|
||
// every three characters.
|
||
//
|
||
|
||
while( Length >= 0L ) {
|
||
|
||
Buffer[ Index-- ] = wString[ Length-- ];
|
||
|
||
Count++;
|
||
|
||
//
|
||
// Protect against leading separators by making sure that the last
|
||
// digit wasn't just copied.
|
||
//
|
||
|
||
if(( Count == 3 ) && ( Length >= 0L )) {
|
||
|
||
//
|
||
// Adjust the index by the length of the thousands separator less 2
|
||
// - one for the NUL and one because the index was already backed
|
||
// up by one above.
|
||
//
|
||
|
||
Index -= SThousandChars - 2;
|
||
|
||
wcsncpy( &Buffer[ Index ], SThousand, SThousandChars - 1 );
|
||
Index--;
|
||
Count = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Move the string to the beginning of the buffer (use MoveMemory to
|
||
// handle overlaps).
|
||
//
|
||
|
||
MoveMemory(
|
||
Buffer,
|
||
&Buffer[ Index + 1 ],
|
||
( wcslen( &Buffer[ Index + 1 ]) + 1) * sizeof( WCHAR )
|
||
);
|
||
|
||
return Buffer;
|
||
}
|
||
|
||
LPWSTR
|
||
FormatBigIntegerW(
|
||
IN DWORD BigInteger,
|
||
IN BOOL Signed
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts an integer to a string inserting thousands separators
|
||
as appropriate.
|
||
|
||
Arguments:
|
||
|
||
BigInteger - Supplies the number to be formatted.
|
||
Signed - Supplies a flag which if TRUE indicates that the supplied
|
||
value is a signed number.
|
||
|
||
Return Value:
|
||
|
||
LPWSTR - Returns a pointer to the formatted string.
|
||
|
||
--*/
|
||
|
||
{
|
||
WCHAR Buffer1[ MAX_PATH ];
|
||
WCHAR SThousand[ MAX_PATH ];
|
||
DWORD SThousandChars;
|
||
int Index1;
|
||
int Index;
|
||
DWORD Count;
|
||
|
||
static
|
||
WCHAR Buffer[ MAX_PATH ];
|
||
|
||
//
|
||
// Get the thousand separator for this locale.
|
||
//
|
||
|
||
SThousandChars = GetLocaleInfoW(
|
||
LOCALE_USER_DEFAULT,
|
||
LOCALE_STHOUSAND,
|
||
SThousand,
|
||
NumberOfCharacters( SThousand )
|
||
);
|
||
DbgAssert( SThousandChars != 0 );
|
||
if( SThousandChars == 0 ) {
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// Convert the number to a string.
|
||
//
|
||
|
||
Index1 = wsprintf( Buffer1, ( Signed ) ? L"%d" : L"%u", BigInteger );
|
||
DbgAssert( Index1 < NumberOfCharacters( Buffer ));
|
||
|
||
Index = NumberOfCharacters( Buffer ) - 1;
|
||
Count = 0;
|
||
|
||
//
|
||
// Copy the NUL character.
|
||
//
|
||
|
||
Buffer[ Index-- ] = Buffer1[ Index1-- ];
|
||
|
||
//
|
||
// Copy the string in reverse order, inserting the thousands separator
|
||
// every three characters.
|
||
//
|
||
|
||
while( Index1 >= 0 ) {
|
||
|
||
Buffer[ Index-- ] = Buffer1[ Index1-- ];
|
||
|
||
Count++;
|
||
|
||
//
|
||
// Protect against leading separators by making sure that the last
|
||
// digit wasn't just copied.
|
||
//
|
||
|
||
if(( Count == 3 ) && ( Index1 >= 0 )) {
|
||
|
||
//
|
||
// Adjust the index by the length of the thousands separator less 2
|
||
// - one for the NUL and one because the index was already backed
|
||
// up by one above.
|
||
//
|
||
|
||
Index -= SThousandChars - 2;
|
||
wcsncpy( &Buffer[ Index ], SThousand, SThousandChars - 1 );
|
||
Index--;
|
||
Count = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Move the string to the beginning of the buffer (use MoveMemory to
|
||
// handle overlaps).
|
||
//
|
||
|
||
MoveMemory(
|
||
Buffer,
|
||
&Buffer[ Index + 1 ],
|
||
( wcslen( &Buffer[ Index + 1 ]) + 1) * sizeof( WCHAR )
|
||
);
|
||
|
||
return Buffer;
|
||
}
|
||
|
||
DWORD
|
||
WFormatMessageA(
|
||
IN LPSTR Buffer,
|
||
IN DWORD BufferSize,
|
||
IN UINT FormatId,
|
||
IN ...
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Format a printf style string and place it the supplied ANSI buffer.
|
||
|
||
Arguments:
|
||
|
||
Buffer - Supplies a pointer to a buffer where the formatted string
|
||
will be stored.
|
||
BufferSize - Supplies the number of bytes in the supplied buffer.
|
||
FormatId - Supplies a resource id for a printf style format string.
|
||
... - Supplies zero or more values based on the format
|
||
descpritors supplied in Format.
|
||
|
||
Return Value:
|
||
|
||
DWORD _ Returns the number of bytes stored in the supplied buffer.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Count;
|
||
va_list Args;
|
||
|
||
DbgPointerAssert( Buffer );
|
||
|
||
//
|
||
// Retrieve the values and format the string.
|
||
//
|
||
|
||
va_start( Args, FormatId );
|
||
|
||
Count = FormatMessageA(
|
||
FORMAT_MESSAGE_FROM_HMODULE,
|
||
NULL,
|
||
FormatId,
|
||
0,
|
||
Buffer,
|
||
BufferSize,
|
||
&Args
|
||
);
|
||
DbgAssert( Count != 0 );
|
||
|
||
va_end( Args );
|
||
|
||
return Count;
|
||
}
|
||
|
||
DWORD
|
||
WFormatMessageW(
|
||
IN LPWSTR Buffer,
|
||
IN DWORD BufferSize,
|
||
IN UINT FormatId,
|
||
IN ...
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Format a printf style string and place it the supplied Unicode buffer.
|
||
|
||
Arguments:
|
||
|
||
Buffer - Supplies a pointer to a buffer where the formatted string
|
||
will be stored.
|
||
BufferSize - Supplies the number of bytes in the supplied buffer.
|
||
FormatId - Supplies a resource id for a printf style format string.
|
||
... - Supplies zero or more values based on the format
|
||
descpritors supplied in Format.
|
||
|
||
Return Value:
|
||
|
||
DWORD _ Returns the number of bytes stored in the supplied buffer.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Count;
|
||
va_list Args;
|
||
|
||
DbgPointerAssert( Buffer );
|
||
|
||
//
|
||
// Retrieve the values and format the string.
|
||
//
|
||
|
||
va_start( Args, FormatId );
|
||
|
||
Count = FormatMessageW(
|
||
FORMAT_MESSAGE_FROM_HMODULE,
|
||
NULL,
|
||
FormatId,
|
||
0,
|
||
Buffer,
|
||
BufferSize,
|
||
&Args
|
||
);
|
||
DbgAssert( Count != 0 );
|
||
|
||
va_end( Args );
|
||
|
||
return Count;
|
||
}
|
||
|
||
int
|
||
_CRTAPI1
|
||
CompareTableEntries(
|
||
IN const void* TableEntry1,
|
||
IN const void* TableEntry2
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compare the key portion of two STRING_TABLE_ENTRY objects in order to
|
||
determine if a match was found. This routine is used as a callback function
|
||
for the CRT lfind() function.
|
||
|
||
Arguments:
|
||
|
||
TableEntry1 - Supplies a pointer to the first STRING_TABLE_ENTRY object
|
||
whose Key is use in the comparison.
|
||
TableEntry1 - Supplies a pointer to the second STRING_TABLE_ENTRY object
|
||
whose Key is use in the comparison.
|
||
|
||
Return Value:
|
||
|
||
int - Returns:
|
||
|
||
< 0 TableEntry1 less than TableEntry2
|
||
= 0 TableEntry1 identical to TableEntry2
|
||
> 0 TableEntry1 greater than TableEntry2
|
||
|
||
--*/
|
||
|
||
{
|
||
return( ((( LPSTRING_TABLE_ENTRY ) TableEntry1 )->Key.LowPart
|
||
^ (( LPSTRING_TABLE_ENTRY ) TableEntry2 )->Key.LowPart )
|
||
| ((( LPSTRING_TABLE_ENTRY ) TableEntry1 )->Key.HighPart
|
||
^ (( LPSTRING_TABLE_ENTRY ) TableEntry2 )->Key.HighPart ));
|
||
}
|
||
|
||
LPSTRING_TABLE_ENTRY
|
||
SearchStringTable(
|
||
IN LPSTRING_TABLE_ENTRY StringTable,
|
||
IN DWORD Count,
|
||
IN int Class,
|
||
IN DWORD Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
SearchStringTable searches the supplied table of STRING_TABLE_ENTRY objects
|
||
looking for a match based on the supplied Class and Value.
|
||
|
||
Arguments:
|
||
|
||
StringTable - Supplies a table of STRING_TABLE_ENTRY objects that should
|
||
be searched.
|
||
Count - Supplies the number of entries in the StringTable.
|
||
Class - Supplies the class to be looked up.
|
||
Value - Supplies the value within the class to be looked up.
|
||
|
||
Return Value:
|
||
|
||
LPSTRING_TABLE_ENTRY - Returns a pointer to the STRING_TABLE_ENTRY if found,
|
||
NULL otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
STRING_TABLE_ENTRY TableEntry;
|
||
LPSTRING_TABLE_ENTRY Id;
|
||
|
||
DbgPointerAssert( StringTable );
|
||
|
||
//
|
||
// Assume that entry will not be found.
|
||
//
|
||
|
||
Id = NULL;
|
||
|
||
//
|
||
// Set up the search criteria.
|
||
//
|
||
|
||
TableEntry.Key.LowPart = Value;
|
||
TableEntry.Key.HighPart = Class;
|
||
|
||
//
|
||
// Do the search.
|
||
//
|
||
|
||
Id = _lfind(
|
||
&TableEntry,
|
||
StringTable,
|
||
&Count,
|
||
sizeof( STRING_TABLE_ENTRY ),
|
||
CompareTableEntries
|
||
);
|
||
|
||
//
|
||
// Return a pointer to the found entry.
|
||
//
|
||
|
||
return Id;
|
||
}
|
||
|
||
UINT
|
||
GetStringId(
|
||
IN LPSTRING_TABLE_ENTRY StringTable,
|
||
IN DWORD Count,
|
||
IN int Class,
|
||
IN DWORD Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
GetStringId returns the string resource id for the requested
|
||
STRING_TABLE_ENTRY object.
|
||
|
||
Arguments:
|
||
|
||
StringTable - Supplies a table of STRING_TABLE_ENTRY objects that should
|
||
be searched.
|
||
Count - Supplies the number of entries in the StringTable.
|
||
Class - Supplies the class to be looked up.
|
||
Value - Supplies the value within the class to be looked up.
|
||
|
||
Return Value:
|
||
|
||
UINT - Returns the string resource id for the entry that matches
|
||
the supplied Class and value.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPSTRING_TABLE_ENTRY Id;
|
||
|
||
DbgPointerAssert( StringTable );
|
||
|
||
Id = SearchStringTable(
|
||
StringTable,
|
||
Count,
|
||
Class,
|
||
Value
|
||
);
|
||
|
||
if (Id) {
|
||
|
||
return( Id->Id);
|
||
|
||
}
|
||
|
||
else
|
||
|
||
return 0;
|
||
|
||
}
|