singrdk/base/boot/SingLdrPc/blstring.cpp

1487 lines
30 KiB
C++

//++
//
// Copyright (c) Microsoft Corporation
//
// Module Name:
//
// blstring.cpp
//
// Abstract:
//
// This module implements string functions for the boot loader environment.
//
//--
#include "bl.h"
#define ABS(X) (((X) < 0) ? (-(X)) : (X))
#define STRING_TOKEN_LONG 1
#define STRING_TOKEN_ULONG 2
#define STRING_TOKEN_ULONG_HEX 3
#define STRING_TOKEN_LONGLONG 4
#define STRING_TOKEN_ULONGLONG 5
#define STRING_TOKEN_ULONGLONG_HEX 6
#define STRING_TOKEN_PVOID 7
#define STRING_TOKEN_PCHAR 8
#define STRING_TOKEN_CHAR 9
CHAR
BlRtlConvertCharacterToUpperCase(
CHAR C
)
//++
//
// Routine Description:
//
// This function converts the specified character to upper case.
//
// Arguments:
//
// C - Supplies the character to convert.
//
// Return Value:
//
// Upper case character matching the specified character.
//
//--
{
if ((C >= 'a') && (C <= 'z')) {
return C + 'A' - 'a';
}
return C;
}
BOOLEAN
BlRtlParsePositiveDecimal(
PCSTR String,
PUINT32 Number,
PUINT32 CharactersConsumed
)
//++
//
// Routine Description:
//
// This function parses a positive decimal value.
//
// Arguments:
//
// String - Supplies a pointer to the string to parse.
//
// Number - Receives the number.
//
// CharactersConsumed - Receives the number of characters consumed.
//
//
// Return Value:
//
// TRUE, if parse was successful.
// FALSE, otherwise.
//
//--
{
UINT32 Digit;
UINT32 Index;
UINT32 Temp;
if ((String[0] < '0') || (String[0] > '9')) {
return FALSE;
}
Index = 0;
Temp = 0;
for (;;) {
if ((String[Index] < '0') || (String[Index] > '9')) {
*Number = Temp;
*CharactersConsumed = Index;
return TRUE;
}
Digit = String[Index] - '0';
if (((Temp * 10) + Digit) < Temp) {
return FALSE;
}
Temp = (Temp * 10) + Digit;
Index += 1;
}
}
BOOLEAN
BlRtlParseTypeSpecifier(
PCSTR String,
PINT32 Width,
PCHAR PadCharacter,
PUINT8 TokenType,
PUINT32 CharactersConsumed
)
//++
//
// Routine Description:
//
// This function parses a type specifier.
//
// Arguments:
//
// String - Supplies a pointer to the string to parse.
//
// Width - Receives the width.
//
// PadCharacter - Receives the pad character.
//
// TokenType - Receives the token type.
//
// CharactersConsumed - Receives the number of characters consumed.
//
//
// Return Value:
//
// TRUE, if parse was successful.
// FALSE, otherwise.
//
//--
{
UINT32 Advance;
BOOLEAN WidthPresent;
UINT32 Index;
BOOLEAN Minus;
UINT32 WidthPositiveValue;
BOOLEAN Zero;
SATISFY_OVERZEALOUS_COMPILER(WidthPositiveValue = 0);
//
// Check if type specifier character is present.
//
if (String[0] != '%') {
return FALSE;
}
Index = 1;
//
// Check for pad modifiers.
//
Minus = FALSE;
Zero = FALSE;
for (;;) {
if (String[Index] == '-') {
if (Minus != FALSE) {
return FALSE;
}
Minus = TRUE;
Index += 1;
} else if (String[Index] == '0') {
if (Zero != FALSE) {
return FALSE;
}
Zero = TRUE;
Index += 1;
} else {
break;
}
}
//
// - and 0 pad modifiers are mutually exclusive.
//
if ((Minus != FALSE) && (Zero != FALSE)) {
return FALSE;
}
//
// If there is a width value, then parse it.
//
WidthPresent = ((String[Index] >= '1') && (String[Index] <= '9'));
if (WidthPresent != FALSE) {
if (BlRtlParsePositiveDecimal(&String[Index],
&WidthPositiveValue,
&Advance) == FALSE) {
return FALSE;
}
Index += Advance;
}
//
// Pad modifiers require width value.
//
if (((Minus != FALSE) || (Zero != FALSE)) && (WidthPresent == FALSE)) {
return FALSE;
}
//
// Set pad character.
//
if (Zero != FALSE) {
*PadCharacter = '0';
} else {
*PadCharacter = ' ';
}
//
// Compute signed width value.
//
if (WidthPresent == FALSE) {
*Width = 0;
} else if (Minus == FALSE) {
*Width = (INT32) WidthPositiveValue;
} else {
*Width = -((INT32) WidthPositiveValue);
}
//
// Set type character.
//
if (BlRtlEqualStringN(&String[Index], "d", 1) != FALSE) {
*TokenType = STRING_TOKEN_LONG;
Index += 1;
} else if (BlRtlEqualStringN(&String[Index], "u", 1) != FALSE) {
*TokenType = STRING_TOKEN_ULONG;
Index += 1;
} else if (BlRtlEqualStringN(&String[Index], "x", 1) != FALSE) {
*TokenType = STRING_TOKEN_ULONG_HEX;
Index += 1;
} else if (BlRtlEqualStringN(&String[Index], "I64d", 4) != FALSE) {
*TokenType = STRING_TOKEN_LONGLONG;
Index += 4;
} else if (BlRtlEqualStringN(&String[Index], "I64u", 4) != FALSE) {
*TokenType = STRING_TOKEN_ULONGLONG;
Index += 4;
} else if (BlRtlEqualStringN(&String[Index], "I64x", 4) != FALSE) {
*TokenType = STRING_TOKEN_ULONGLONG_HEX;
Index += 4;
} else if (BlRtlEqualStringN(&String[Index], "p", 1) != FALSE) {
*TokenType = STRING_TOKEN_PVOID;
Index += 1;
} else if (BlRtlEqualStringN(&String[Index], "s", 1) != FALSE) {
*TokenType = STRING_TOKEN_PCHAR;
Index += 1;
} else if (BlRtlEqualStringN(&String[Index], "c", 1) != FALSE) {
*TokenType = STRING_TOKEN_CHAR;
Index += 1;
} else {
return FALSE;
}
//
// Set number of characters consumed.
//
*CharactersConsumed = Index;
return TRUE;
}
BOOLEAN
BlRtlFormatSignedDecimalLong(
PCHAR Output,
UINT32 OutputSize,
INT32 Value,
INT32 Width,
PUINT32 CharactersConsumed
)
//++
//
// Routine Description:
//
// This function formats a signed decimal long.
//
// Arguments:
//
// Output - Supplies a pointer to the output buffer.
//
// OutputSize - Supplies the size of the output buffer.
//
// Value - Supplies the value to format.
//
// Width - Supplies the width.
//
// CharactersConsumed - Receives the number of characters consumed.
//
//
// Return Value:
//
// TRUE, if format was successful.
// FALSE, otherwise.
//
//--
{
UINT32 Index;
UINT32 MinimumWidth;
BOOLEAN Minus;
UINT32 NumberWidth;
UINT32 PadWidth;
UINT32 Temp;
//
// Check if this is a negative value.
//
Minus = (BOOLEAN) (Value < 0);
//
// Compute the number of characters necessary.
//
Temp = ABS(Value);
NumberWidth = 0;
do {
NumberWidth += 1;
Temp = Temp / 10;
} while (Temp > 0);
if (Minus != FALSE) {
NumberWidth += 1;
}
PadWidth = 0;
MinimumWidth = ABS(Width);
if (MinimumWidth > NumberWidth) {
PadWidth = MinimumWidth - NumberWidth;
}
//
// Check if there is sufficient space in the output buffer.
//
if ((NumberWidth + PadWidth) > OutputSize) {
return FALSE;
}
Index = 0;
//
// If right alignment is specified, then insert any necessary pads before the number.
//
if (Width > 0) {
while (PadWidth > 0) {
Output[Index] = ' ';
Index += 1;
PadWidth -= 1;
}
}
//
// Insert absolute number starting with the least significant digit, going right to left.
//
Temp = ABS(Value);
Index += NumberWidth;
do {
Index -= 1;
Output[Index] = (CHAR) ('0' + (Temp % 10));
Temp = Temp / 10;
} while (Temp > 0);
//
// If the number is negative, then insert the negative sign.
//
if (Minus != FALSE) {
Index -= 1;
Output[Index] = '-';
}
//
// If left alignment was specified, then insert any necessary pads after the number.
//
Index += NumberWidth;
while (PadWidth > 0) {
Output[Index] = ' ';
Index += 1;
PadWidth -= 1;
}
//
// Set number of characters consumed in the buffer.
//
*CharactersConsumed = Index;
return TRUE;
}
BOOLEAN
BlRtlFormatUnsignedLong(
PCHAR Output,
UINT32 OutputSize,
UINT32 Value,
UINT8 PadCharacter,
INT32 Width,
UINT32 Base,
PUINT32 CharactersConsumed
)
//++
//
// Routine Description:
//
// This function formats an unsigned long.
//
// Arguments:
//
// Output - Supplies a pointer to the output buffer.
//
// OutputSize - Supplies the size of the output buffer.
//
// Value - Supplies the value to format.
//
// PadCharacter - Supplies the pad character.
//
// Width - Supplies the width.
//
// Base - Supplies the base.
//
// CharactersConsumed - Receives the number of characters consumed.
//
//
// Return Value:
//
// TRUE, if format was successful.
// FALSE, otherwise.
//
//--
{
UINT32 Index;
UINT32 MinimumWidth;
UINT32 NumberWidth;
UINT32 PadWidth;
UINT32 Temp;
if (Base == 0) {
return FALSE;
}
//
// Compute the number of characters necessary.
//
Temp = Value;
NumberWidth = 0;
do {
NumberWidth += 1;
Temp = Temp / Base;
} while (Temp > 0);
PadWidth = 0;
MinimumWidth = ABS(Width);
if (MinimumWidth > NumberWidth) {
PadWidth = MinimumWidth - NumberWidth;
}
//
// Check if there is sufficient space in the output buffer.
//
if ((NumberWidth + PadWidth) > OutputSize) {
return FALSE;
}
Index = 0;
//
// If right alignment is specified, then insert any necessary pads before the number.
//
if (Width > 0) {
while (PadWidth > 0) {
Output[Index] = PadCharacter;
Index += 1;
PadWidth -= 1;
}
}
//
// Insert absolute number starting with the least significant digit, going right to left.
//
Temp = Value;
Index += NumberWidth;
do {
Index -= 1;
switch (Base) {
case 10: {
Output[Index] = (CHAR) ('0' + (Temp % Base));
break;
}
case 16: {
if ((Temp % Base) < 10) {
Output[Index] = (CHAR) ('0' + (Temp % Base));
} else {
Output[Index] = (CHAR) ('A' + (Temp % Base) - 10);
}
break;
}
default: {
return FALSE;
}
}
Temp = Temp / Base;
} while (Temp > 0);
//
// If left alignment was specified, then insert any necessary pads after the number.
//
Index += NumberWidth;
while (PadWidth > 0) {
Output[Index] = PadCharacter;
Index += 1;
PadWidth -= 1;
}
//
// Set number of characters consumed in the buffer.
//
*CharactersConsumed = Index;
return TRUE;
}
BOOLEAN
BlRtlFormatUnsignedLongLong(
PCHAR Output,
UINT32 OutputSize,
UINT64 Value,
UINT8 PadCharacter,
INT32 Width,
UINT32 Base,
PUINT32 CharactersConsumed
)
//++
//
// Routine Description:
//
// This function formats an unsigned long long.
//
// Arguments:
//
// Output - Supplies a pointer to the output buffer.
//
// OutputSize - Supplies the size of the output buffer.
//
// Value - Supplies the value to format.
//
// PadCharacter - Supplies the pad character.
//
// Width - Supplies the width.
//
// Base - Supplies the base.
//
// CharactersConsumed - Receives the number of characters consumed.
//
//
// Return Value:
//
// TRUE, if format was successful.
// FALSE, otherwise.
//
//--
{
UINT32 Index;
UINT32 MinimumWidth;
UINT32 NumberWidth;
UINT32 PadWidth;
UINT64 Temp;
if (Base == 0) {
return FALSE;
}
//
// Compute the number of characters necessary.
//
Temp = Value;
NumberWidth = 0;
do {
NumberWidth += 1;
Temp = Temp / Base;
} while (Temp > 0);
PadWidth = 0;
MinimumWidth = ABS(Width);
if (MinimumWidth > NumberWidth) {
PadWidth = MinimumWidth - NumberWidth;
}
//
// Check if there is sufficient space in the output buffer.
//
if ((NumberWidth + PadWidth) > OutputSize) {
return FALSE;
}
Index = 0;
//
// If right alignment is specified, then insert any necessary pads before the number.
//
if (Width > 0) {
while (PadWidth > 0) {
Output[Index] = PadCharacter;
Index += 1;
PadWidth -= 1;
}
}
//
// Insert absolute number starting with the least significant digit, going right to left.
//
Temp = Value;
Index += NumberWidth;
do {
Index -= 1;
switch (Base) {
case 10: {
Output[Index] = (CHAR) ('0' + (Temp % Base));
break;
}
case 16: {
if ((Temp % Base) < 10) {
Output[Index] = (CHAR) ('0' + (Temp % Base));
} else {
Output[Index] = (CHAR) ('A' + (Temp % Base) - 10);
}
break;
}
default: {
return FALSE;
}
}
Temp = Temp / Base;
} while (Temp > 0);
//
// If left alignment was specified, then insert any necessary pads after the number.
//
Index += NumberWidth;
while (PadWidth > 0) {
Output[Index] = PadCharacter;
Index += 1;
PadWidth -= 1;
}
//
// Set number of characters consumed in the buffer.
//
*CharactersConsumed = Index;
return TRUE;
}
UINT32
BlRtlStringLength(
PCSTR String
)
//++
//
// Routine Description:
//
// This function returns the length of the specified string.
//
// Arguments:
//
// String - Supplies a pointer to the string.
//
// Return Value:
//
// Length of the string.
//
//--
{
UINT32 Index;
Index = 0;
while (String[Index] != 0) {
Index += 1;
}
return Index;
}
UINT32
BlRtlStringLengthW(
PCWSTR String
)
//++
//
// Routine Description:
//
// This function returns the length of the specified wide string.
//
// Arguments:
//
// String - Supplies a pointer to the string.
//
// Return Value:
//
// Length of the string.
//
//--
{
UINT32 Index;
Index = 0;
while (String[Index] != 0) {
Index += 1;
}
return Index;
}
BOOLEAN
BlRtlFormatStringToken(
PCHAR Output,
UINT32 OutputSize,
PCSTR String,
INT32 Width,
PUINT32 CharactersConsumed
)
//++
//
// Routine Description:
//
// This function formats a string token.
//
// Arguments:
//
// Output - Supplies a pointer to the output buffer.
//
// OutputSize - Supplies the size of the output buffer.
//
// String - Supplies the string token.
//
// Width - Supplies the width.
//
// CharactersConsumed - Receives the number of characters consumed.
//
//
// Return Value:
//
// TRUE, if format was successful.
// FALSE, otherwise.
//
//--
{
UINT32 Index;
UINT32 MinimumWidth;
UINT32 PadWidth;
UINT32 StringIndex;
UINT32 StringLength;
//
// Compute string length, minimum width, and pad width.
//
StringLength = BlRtlStringLength(String);
MinimumWidth = ABS(Width);
PadWidth = 0;
if (MinimumWidth > StringLength) {
PadWidth = MinimumWidth - StringLength;
}
//
// Check if there is sufficient space in the output buffer.
//
if ((StringLength + PadWidth) > OutputSize) {
return FALSE;
}
Index = 0;
//
// If right alignment is specified, then insert any necessary pads before the string.
//
if (Width > 0) {
while (PadWidth > 0) {
Output[Index] = ' ';
Index += 1;
PadWidth -= 1;
}
}
//
// Copy the string.
//
for (StringIndex = 0; StringIndex < StringLength; StringIndex += 1) {
Output[Index] = String[StringIndex];
Index += 1;
}
//
// If left alignment was specified, then insert any necessary pads after the string.
//
while (PadWidth > 0) {
Output[Index] = ' ';
Index += 1;
PadWidth -= 1;
}
//
// Set number of characters consumed in the buffer.
//
*CharactersConsumed = Index;
return TRUE;
}
BOOLEAN
BlRtlFormatChar(
PCHAR Output,
UINT32 OutputSize,
CHAR Value,
PUINT32 CharactersConsumed
)
//++
//
// Routine Description:
//
// This function formats a character.
//
// Arguments:
//
// Output - Supplies a pointer to the output buffer.
//
// OutputSize - Supplies the size of the output buffer.
//
// Value - Supplies the value to format.
//
// CharactersConsumed - Receives the number of characters consumed.
//
//
// Return Value:
//
// TRUE, if format was successful.
// FALSE, otherwise.
//
//--
{
//
// Check if there is sufficient space in the output buffer.
//
if (1 > OutputSize) {
return FALSE;
}
Output[0] = Value;
//
// Set number of characters consumed in the buffer.
//
*CharactersConsumed = 1;
return TRUE;
}
BOOLEAN
BlRtlFormatString(
PCHAR Output,
UINT32 OutputSize,
PCSTR Format,
va_list ArgumentList
)
//++
//
// Routine Description:
//
// This function formats a string.
//
// Arguments:
//
// Output - Supplies a pointer to the output buffer.
//
// OutputSize - Supplies the size of the output buffer.
//
// Format - Supplies the format string.
//
// ArgumentList - Supplies the input parameters.
//
// Return Value:
//
// TRUE, if format was successful.
// FALSE, otherwise.
//
//--
{
UINT32 CharactersConsumed;
UINT32 InputIndex;
UINT32 OutputIndex;
CHAR PadCharacter;
UINT8 TokenType;
INT32 Width;
InputIndex = 0;
OutputIndex = 0;
for (;;) {
if (OutputIndex == OutputSize) {
return FALSE;
}
if (Format[InputIndex] == 0) {
Output[OutputIndex] = 0;
return TRUE;
}
if (Format[InputIndex] == '\\') {
switch (Format[InputIndex + 1]) {
case '\\': {
Output[OutputIndex] = '\\';
OutputIndex += 1;
break;
}
case 'r': {
Output[OutputIndex] = '\r';
OutputIndex += 1;
break;
}
case 'n': {
Output[OutputIndex] = '\r';
OutputIndex += 1;
break;
}
default: {
return FALSE;
}
}
InputIndex += 2;
continue;
}
if (BlRtlParseTypeSpecifier(&Format[InputIndex],
&Width,
&PadCharacter,
&TokenType,
&CharactersConsumed) != FALSE) {
InputIndex += CharactersConsumed;
switch (TokenType) {
case STRING_TOKEN_LONG: {
if (BlRtlFormatSignedDecimalLong(&Output[OutputIndex],
OutputSize - OutputIndex,
va_arg(ArgumentList, INT32),
Width,
&CharactersConsumed) == FALSE) {
return FALSE;
}
OutputIndex += CharactersConsumed;
break;
}
case STRING_TOKEN_ULONG: {
if (BlRtlFormatUnsignedLong(&Output[OutputIndex],
OutputSize - OutputIndex,
va_arg(ArgumentList, UINT32),
PadCharacter,
Width,
10,
&CharactersConsumed) == FALSE) {
return FALSE;
}
OutputIndex += CharactersConsumed;
break;
}
case STRING_TOKEN_ULONG_HEX: {
if (BlRtlFormatUnsignedLong(&Output[OutputIndex],
OutputSize - OutputIndex,
va_arg(ArgumentList, UINT32),
PadCharacter,
Width,
16,
&CharactersConsumed) == FALSE) {
return FALSE;
}
OutputIndex += CharactersConsumed;
break;
}
case STRING_TOKEN_ULONGLONG: {
if (BlRtlFormatUnsignedLongLong(&Output[OutputIndex],
OutputSize - OutputIndex,
va_arg(ArgumentList, UINT64),
PadCharacter,
Width,
10,
&CharactersConsumed) == FALSE) {
return FALSE;
}
OutputIndex += CharactersConsumed;
break;
}
case STRING_TOKEN_ULONGLONG_HEX: {
if (BlRtlFormatUnsignedLongLong(&Output[OutputIndex],
OutputSize - OutputIndex,
va_arg(ArgumentList, UINT64),
PadCharacter,
Width,
16,
&CharactersConsumed) == FALSE) {
return FALSE;
}
OutputIndex += CharactersConsumed;
break;
}
case STRING_TOKEN_PVOID: {
#if defined(BOOT_X86)
if (BlRtlFormatUnsignedLong(&Output[OutputIndex],
OutputSize - OutputIndex,
va_arg(ArgumentList, UINT32),
'0',
8,
16,
&CharactersConsumed) == FALSE) {
return FALSE;
}
#elif defined(BOOT_X64)
if (BlRtlFormatUnsignedLongLong(&Output[OutputIndex],
OutputSize - OutputIndex,
va_arg(ArgumentList, UINT64),
'0',
16,
16,
&CharactersConsumed) == FALSE) {
return FALSE;
}
#endif
OutputIndex += CharactersConsumed;
break;
}
case STRING_TOKEN_PCHAR: {
if (BlRtlFormatStringToken(&Output[OutputIndex],
OutputSize - OutputIndex,
va_arg(ArgumentList, PCHAR),
Width,
&CharactersConsumed) == FALSE) {
return FALSE;
}
OutputIndex += CharactersConsumed;
break;
}
case STRING_TOKEN_CHAR: {
if (BlRtlFormatChar(&Output[OutputIndex],
OutputSize - OutputIndex,
va_arg(ArgumentList, CHAR),
&CharactersConsumed) == FALSE) {
return FALSE;
}
OutputIndex += CharactersConsumed;
break;
}
}
continue;
}
Output[OutputIndex] = Format[InputIndex];
InputIndex += 1;
OutputIndex += 1;
}
}
BOOLEAN
BlRtlPrintf(
PCSTR Format,
...
)
//++
//
// Routine Description:
//
// This function implements C-style printf for the boot loader environment.
//
// Arguments:
//
// Format - Supplies the format string.
//
// ... - Supplies the input parameters.
//
// Return Value:
//
// TRUE, if operation was successful.
// FALSE, otherwise.
//
//--
{
va_list ArgumentList;
CHAR Buffer[4096];
va_start(ArgumentList, Format);
if (BlRtlFormatString(Buffer, sizeof(Buffer), Format, ArgumentList) == FALSE) {
return FALSE;
}
BlVideoPrintString(Buffer);
BlKdPrintString(Buffer);
return TRUE;
}
BOOLEAN
BlRtlEqualStringN(
PCSTR String1,
PCSTR String2,
UINT32 Count
)
//++
//
// Routine Description:
//
// This function compares two strings.
//
// Arguments:
//
// String1 - Supplies a pointer to the first string.
//
// String2 - Supplies a pointer to the second string.
//
// Count - Number of characters to compare.
//
// Return Value:
//
// TRUE, if strings are equal.
// FALSE, otherwise.
//
//--
{
while (Count > 0) {
if ((*String1 == 0) || (*String2 == 0)) {
return FALSE;
}
if (*String1 != *String2) {
return FALSE;
}
String1 += 1;
String2 += 1;
Count -= 1;
}
return TRUE;
}
BOOLEAN
BlRtlEqualStringI(
PCSTR String1,
PCSTR String2
)
//++
//
// Routine Description:
//
// This function compares two strings ignoring case differences.
//
// Arguments:
//
// String1 - Supplies a pointer to the first string.
//
// String2 - Supplies a pointer to the second string.
//
// Return Value:
//
// TRUE, if strings are equal.
// FALSE, otherwise.
//
//--
{
for (;;) {
if (BlRtlConvertCharacterToUpperCase(*String1) != BlRtlConvertCharacterToUpperCase(*String2)) {
return FALSE;
}
if (*String1 == 0) {
return TRUE;
}
String1 += 1;
String2 += 1;
}
}
PCSTR
BlRtlFindSubstring(
PCSTR String,
PCSTR Substring
)
//++
//
// Routine Description:
//
// This function searches for a substring.
//
// Arguments:
//
// String - Supplies a pointer to the string to search in.
//
// Substring - Supplies a pointer to the substring to search for.
//
// Return Value:
//
// A pointer to the first instance of the substring, if search was successful.
// NULL, otherwise.
//
//--
{
UINT32 SubstringLength;
SubstringLength = BlRtlStringLength(Substring);
while (*String != 0) {
if (BlRtlEqualStringN(String, Substring, SubstringLength) != FALSE) {
return String;
}
String += 1;
}
return NULL;
}