1487 lines
30 KiB
C++
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;
|
||
|
}
|
||
|
|