mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1210 lines
24 KiB
1210 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spdrutil.c
|
|
|
|
Abstract:
|
|
|
|
This module contains general utility and helper functions used by ASR
|
|
in textmode Setup.
|
|
|
|
Authors:
|
|
|
|
Michael Peterson, Seagate Software (v-michpe) 13-May-1997
|
|
Guhan Suriyanarayanan (guhans) 21-Aug-1999
|
|
|
|
Environment:
|
|
|
|
Textmode Setup, Kernel-mode.
|
|
|
|
Revision History:
|
|
|
|
21-Aug-1999 guhans
|
|
Code clean-up and re-write.
|
|
|
|
13-May-1997 v-michpe
|
|
Initial implementation.
|
|
|
|
--*/
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
|
|
#define THIS_MODULE L"spdrutil.c"
|
|
#define THIS_MODULE_CODE L"U"
|
|
|
|
static const PCWSTR ASR_MOUNTED_DEVICES_KEY = L"\\registry\\machine\\SYSTEM\\MountedDevices";
|
|
static const PCWSTR ASR_HKLM_SYSTEM_KEY = L"\\registry\\machine\\SYSTEM";
|
|
|
|
#ifndef ULONGLONG_MAX
|
|
#define ULONGLONG_MAX (0xFFFFFFFFFFFFFFFF)
|
|
#endif
|
|
|
|
//
|
|
// Caller must free the string
|
|
//
|
|
PWSTR
|
|
SpAsrGetRegionName(IN PDISK_REGION pRegion)
|
|
{
|
|
SpNtNameFromRegion(
|
|
pRegion,
|
|
(PWSTR) TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
PartitionOrdinalCurrent
|
|
);
|
|
|
|
return SpDupStringW((PWSTR)TemporaryBuffer);
|
|
}
|
|
|
|
|
|
ULONG
|
|
SpAsrGetActualDiskSignature(IN ULONG DiskNumber)
|
|
{
|
|
PHARD_DISK pDisk = &HardDisks[DiskNumber];
|
|
ULONG Signature = 0;
|
|
|
|
if (PARTITION_STYLE_MBR == (PARTITION_STYLE) pDisk->DriveLayout.PartitionStyle) {
|
|
|
|
Signature = pDisk->DriveLayout.Mbr.Signature;
|
|
}
|
|
|
|
return Signature;
|
|
}
|
|
|
|
ULONGLONG
|
|
SpAsrConvertSectorsToMB(
|
|
IN ULONGLONG SectorCount,
|
|
IN ULONG BytesPerSector
|
|
)
|
|
{
|
|
ULONGLONG mb = 1024 * 1024;
|
|
|
|
if ((ULONGLONG) (SectorCount / mb) > (ULONGLONG) (ULONGLONG_MAX / BytesPerSector)) {
|
|
//
|
|
// This is strange. The sizeMB of the disk is too big to fit in 64-bits,
|
|
// yet the SectorCount does. This implies that this disk has more than
|
|
// 1 MB Per Sector. Since this is very improbable (disks commonly have 512
|
|
// BytesPerSector today), we bail out with an internal error.
|
|
//
|
|
DbgFatalMesg((_asrerr, "SpAsrConvertSectorsToMB. Disk has too many sectors\n"));
|
|
INTERNAL_ERROR((L"Disk has too many sectors\n")); // ok
|
|
}
|
|
|
|
return (ULONGLONG) ((SectorCount * BytesPerSector) / mb);
|
|
}
|
|
|
|
extern
|
|
VOID
|
|
SpDeleteStorageVolumes (
|
|
IN HANDLE SysPrepRegHandle,
|
|
IN DWORD ControlSetNumber
|
|
);
|
|
|
|
extern
|
|
NTSTATUS
|
|
SpGetCurrentControlSetNumber(
|
|
IN HANDLE SystemHiveRoot,
|
|
OUT PULONG Number
|
|
);
|
|
|
|
|
|
VOID
|
|
SpAsrDeleteMountedDevicesKey(VOID)
|
|
{
|
|
NTSTATUS status;
|
|
OBJECT_ATTRIBUTES objAttrib;
|
|
UNICODE_STRING unicodeString;
|
|
HANDLE keyHandle;
|
|
|
|
//
|
|
// Delete HKLM\SYSTEM\MountedDevices.
|
|
//
|
|
INIT_OBJA(&objAttrib, &unicodeString, ASR_MOUNTED_DEVICES_KEY);
|
|
|
|
objAttrib.RootDirectory = NULL;
|
|
|
|
status = ZwOpenKey(&keyHandle, KEY_ALL_ACCESS, &objAttrib);
|
|
if(NT_SUCCESS(status)) {
|
|
status = ZwDeleteKey(keyHandle);
|
|
DbgStatusMesg((_asrinfo,
|
|
"SpAsrDeleteMountedDevicesKey. DeleteKey [%ls] on the setup hive returned 0x%lx. \n",
|
|
ASR_MOUNTED_DEVICES_KEY,
|
|
status
|
|
));
|
|
|
|
ZwClose(keyHandle);
|
|
}
|
|
else {
|
|
DbgErrorMesg((_asrwarn,
|
|
"SpAsrDeleteMountedDevicesKey. No [%ls] on the setup hive.\n",
|
|
ASR_MOUNTED_DEVICES_KEY));
|
|
}
|
|
}
|
|
|
|
|
|
PVOID
|
|
SpAsrMemAlloc(
|
|
ULONG Size,
|
|
BOOLEAN IsErrorFatal
|
|
)
|
|
{
|
|
PVOID ptr = SpMemAlloc(Size);
|
|
|
|
if (ptr) {
|
|
RtlZeroMemory(ptr, Size);
|
|
}
|
|
else { // allocation failed
|
|
if (IsErrorFatal) {
|
|
DbgFatalMesg((_asrerr,
|
|
"SpAsrMemAlloc. Memory allocation failed, SpMemAlloc(%lu) returned NULL.\n",
|
|
Size
|
|
));
|
|
SpAsrRaiseFatalError(SP_SCRN_OUT_OF_MEMORY, L"Out of memory.");
|
|
}
|
|
else {
|
|
DbgErrorMesg((_asrerr,
|
|
"SpAsrMemAlloc. Memory allocation failed, SpMemAlloc(%lu) returned NULL. Continuing.\n",
|
|
Size
|
|
));
|
|
}
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrIsValidBootDrive(IN OUT PWSTR NtDir)
|
|
/*
|
|
Returns TRUE if NtDir starts with ?:\,
|
|
where ? is between C and Z or c and z,
|
|
and wcslen(NtDir) <= SpGetMaxNtDirLen().
|
|
|
|
|
|
Converts the drive letter to uppercase.
|
|
|
|
*/
|
|
{
|
|
if (!NtDir ||
|
|
wcslen(NtDir) > SpGetMaxNtDirLen()
|
|
) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
// convert drive-letter to upper-case
|
|
if (NtDir[0] >= L'c' && NtDir[0] <= L'z') {
|
|
NtDir[0] = NtDir[0] - L'a' + L'A';
|
|
}
|
|
|
|
// check drive letter
|
|
if (NtDir[0] < L'C' || NtDir[0] > L'Z') {
|
|
return FALSE;
|
|
}
|
|
|
|
// check " :\"
|
|
if (NtDir[1] == L':' && NtDir[2] == L'\\') {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrIsBootPartitionRecord(IN ULONG CriticalPartitionFlag)
|
|
{
|
|
return (BOOLEAN) (CriticalPartitionFlag & ASR_PTN_MASK_BOOT);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrIsSystemPartitionRecord(IN ULONG CriticalPartitionFlag)
|
|
{
|
|
return (BOOLEAN) (CriticalPartitionFlag & ASR_PTN_MASK_SYS);
|
|
}
|
|
|
|
|
|
|
|
// Fatal Error Routines
|
|
// -guhans! Lots of code-repitition here, there must be a more efficient way.
|
|
|
|
|
|
VOID
|
|
SpAsrRaiseFatalError(
|
|
IN ULONG ErrorCode,
|
|
IN PWSTR KdPrintStr
|
|
)
|
|
|
|
/*++
|
|
Routine:
|
|
Terminate setup
|
|
|
|
Returns:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
KdPrintEx((_asrerr, "SETUP: + %ws\n", KdPrintStr));
|
|
|
|
SpStartScreen(ErrorCode,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE);
|
|
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0);
|
|
SpInputDrain();
|
|
|
|
while(SpInputGetKeypress() != KEY_F3);
|
|
|
|
SpDone(0, FALSE, TRUE);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrRaiseFatalErrorWs(
|
|
IN ULONG ErrorCode,
|
|
IN PWSTR KdPrintStr,
|
|
IN PWSTR MessageStr
|
|
)
|
|
{
|
|
KdPrintEx((_asrerr, "SETUP: + %ws\n", KdPrintStr));
|
|
|
|
SpStartScreen(ErrorCode,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
MessageStr
|
|
);
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F3_EQUALS_EXIT, 0);
|
|
SpInputDrain();
|
|
|
|
while(SpInputGetKeypress() != KEY_F3);
|
|
|
|
SpDone(0, FALSE, TRUE);
|
|
}
|
|
|
|
VOID
|
|
SpAsrRaiseFatalErrorWsWs(
|
|
IN ULONG ErrorCode,
|
|
IN PWSTR KdPrintStr,
|
|
IN PWSTR MessageStr1,
|
|
IN PWSTR MessageStr2
|
|
)
|
|
{
|
|
KdPrintEx((_asrerr, "SETUP: + %ws\n", KdPrintStr));
|
|
|
|
SpStartScreen(ErrorCode,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
MessageStr1,
|
|
MessageStr2
|
|
);
|
|
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F3_EQUALS_EXIT, 0);
|
|
SpInputDrain();
|
|
|
|
while(SpInputGetKeypress() != KEY_F3);
|
|
|
|
SpDone(0, FALSE, TRUE);
|
|
}
|
|
|
|
VOID
|
|
SpAsrRaiseFatalErrorWsLu(
|
|
IN ULONG ErrorCode,
|
|
IN PWSTR KdPrintStr,
|
|
IN PWSTR MessageStr,
|
|
IN ULONG MessageVal
|
|
)
|
|
{
|
|
KdPrintEx((_asrerr, "SETUP: + %ws\n", KdPrintStr));
|
|
|
|
SpStartScreen(ErrorCode,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
MessageStr,
|
|
MessageVal
|
|
);
|
|
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F3_EQUALS_EXIT, 0);
|
|
SpInputDrain();
|
|
|
|
while(SpInputGetKeypress() != KEY_F3);
|
|
|
|
SpDone(0, FALSE, TRUE);
|
|
}
|
|
|
|
VOID
|
|
SpAsrRaiseFatalErrorLu(
|
|
IN ULONG ErrorCode,
|
|
IN PWSTR KdPrintStr,
|
|
IN ULONG MessageVal
|
|
)
|
|
{
|
|
KdPrintEx((_asrerr, "SETUP: + %ws\n", KdPrintStr));
|
|
|
|
SpStartScreen(ErrorCode,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
MessageVal
|
|
);
|
|
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F3_EQUALS_EXIT, 0);
|
|
SpInputDrain();
|
|
|
|
while(SpInputGetKeypress() != KEY_F3);
|
|
|
|
SpDone(0, FALSE, TRUE);
|
|
}
|
|
|
|
VOID
|
|
SpAsrRaiseFatalErrorLuLu(
|
|
IN ULONG ErrorCode,
|
|
IN PWSTR KdPrintStr,
|
|
IN ULONG MessageVal1,
|
|
IN ULONG MessageVal2
|
|
)
|
|
{
|
|
KdPrintEx((_asrerr, "SETUP: + %ws\n", KdPrintStr));
|
|
|
|
SpStartScreen(ErrorCode,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
MessageVal1,
|
|
MessageVal2
|
|
);
|
|
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F3_EQUALS_EXIT, 0);
|
|
SpInputDrain();
|
|
|
|
while(SpInputGetKeypress() != KEY_F3);
|
|
|
|
SpDone(0, FALSE, TRUE);
|
|
}
|
|
|
|
|
|
#define ASCI_O 79
|
|
#define ASCI_o 111
|
|
|
|
//
|
|
// SpAsrFileErrorRetryIgnoreAbort
|
|
// Display an error screen if the file that we are trying to
|
|
// copy already exists on target system. Allows user to
|
|
// O = Over-write existing file
|
|
// ESC = Skip this file (preserve existing file)
|
|
// F3 = Exit from Setup
|
|
//
|
|
// Returns TRUE if the user chose overwrite
|
|
// FALSE if the user chose skip
|
|
// Does not return if the user hit ESC
|
|
//
|
|
BOOL
|
|
SpAsrFileErrorDeleteSkipAbort(
|
|
IN ULONG ErrorCode,
|
|
IN PWSTR DestinationFile
|
|
)
|
|
{
|
|
ULONG optionKeys[] = {KEY_F3, ASCI_ESC};
|
|
ULONG mnemonicKeys[] = {MnemonicOverwrite, 0};
|
|
ULONG *keysPtr;
|
|
BOOL done = FALSE,
|
|
overwriteFile = FALSE;
|
|
|
|
while (!done) {
|
|
|
|
SpStartScreen(
|
|
ErrorCode,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
DestinationFile
|
|
);
|
|
|
|
keysPtr = optionKeys;
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_O_EQUALS_OVERWRITE,
|
|
SP_STAT_ESC_EQUALS_SKIP_FILE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
SpInputDrain();
|
|
|
|
switch(SpWaitValidKey(keysPtr,NULL,mnemonicKeys)) {
|
|
case (MnemonicOverwrite | KEY_MNEMONIC):
|
|
overwriteFile = TRUE;
|
|
done = TRUE;
|
|
break;
|
|
|
|
case ASCI_ESC:
|
|
overwriteFile = FALSE;
|
|
done = TRUE;
|
|
break;
|
|
|
|
case KEY_F3:
|
|
SpDone(0, FALSE, TRUE);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return overwriteFile;
|
|
}
|
|
|
|
|
|
//
|
|
// SpAsrFileErrorRetryIgnoreAbort
|
|
// Display an error screen if the file could not be copied
|
|
// over to the target system. Allows user to
|
|
// ENTER = Retry
|
|
// ESC = Skip this file and continue
|
|
// F3 = Exit from Setup
|
|
//
|
|
// Returns TRUE if the user chose skip
|
|
// FALSE if the user chose retry
|
|
// Does not return if the user hit ESC
|
|
//
|
|
BOOL
|
|
SpAsrFileErrorRetrySkipAbort(
|
|
IN ULONG ErrorCode,
|
|
IN PWSTR SourceFile,
|
|
IN PWSTR Label,
|
|
IN PWSTR Vendor,
|
|
IN BOOL AllowSkip
|
|
)
|
|
{
|
|
ULONG optionKeys[] = {KEY_F3, ASCI_CR, ASCI_ESC};
|
|
ULONG mnemonicKeys[] = {0};
|
|
ULONG *keysPtr;
|
|
BOOL done = FALSE,
|
|
skipFile = FALSE;
|
|
|
|
while (!done) {
|
|
|
|
SpStartScreen(
|
|
ErrorCode,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
SourceFile,
|
|
Label,
|
|
Vendor);
|
|
|
|
keysPtr = optionKeys;
|
|
|
|
if (AllowSkip) {
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_RETRY,
|
|
SP_STAT_ESC_EQUALS_SKIP_FILE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0);
|
|
}
|
|
else {
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_RETRY,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0);
|
|
}
|
|
|
|
SpInputDrain();
|
|
|
|
switch(SpWaitValidKey(keysPtr,NULL,mnemonicKeys)) {
|
|
case ASCI_CR:
|
|
skipFile = FALSE;
|
|
done = TRUE;
|
|
break;
|
|
|
|
case ASCI_ESC:
|
|
if (AllowSkip) {
|
|
skipFile = TRUE;
|
|
done = TRUE;
|
|
}
|
|
break;
|
|
|
|
case KEY_F3:
|
|
SpDone(0, FALSE, TRUE);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return skipFile;
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrRaiseInternalError(
|
|
IN PWSTR ModuleName,
|
|
IN PWSTR ModuleCode,
|
|
IN ULONG LineNumber,
|
|
IN PWSTR KdPrintStr)
|
|
{
|
|
PWSTR TmpMsgBuf = SpAsrMemAlloc(4096 * sizeof(WCHAR), TRUE);
|
|
swprintf(TmpMsgBuf, L"%ws%lu", ModuleCode, LineNumber);
|
|
|
|
DbgFatalMesg((_asrerr,
|
|
" Internal Error (%ws:%lu %ws) %ws\n",
|
|
ModuleName,
|
|
LineNumber,
|
|
TmpMsgBuf,
|
|
KdPrintStr
|
|
));
|
|
|
|
SpAsrRaiseFatalErrorWs(SP_TEXT_DR_INTERNAL_ERROR,
|
|
KdPrintStr,
|
|
TmpMsgBuf
|
|
);
|
|
//
|
|
// Never gets here
|
|
//
|
|
|
|
}
|
|
|
|
|
|
ULONGLONG
|
|
SpAsrStringToULongLong(
|
|
IN PWSTR String,
|
|
OUT PWCHAR *EndOfValue,
|
|
IN unsigned Radix
|
|
)
|
|
{
|
|
PWSTR p;
|
|
BOOLEAN Negative;
|
|
ULONGLONG Accum,v;
|
|
WCHAR HighestDigitAllowed,HighestLetterAllowed;
|
|
WCHAR c;
|
|
|
|
//
|
|
// Validate radix, 0 or 2-36.
|
|
//
|
|
if((Radix == 1) || (Radix > 36)) {
|
|
if(EndOfValue) {
|
|
*EndOfValue = String;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
p = String;
|
|
|
|
//
|
|
// Skip whitespace.
|
|
//
|
|
while(SpIsSpace(*p)) {
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// First char may be a plus or minus.
|
|
//
|
|
Negative = FALSE;
|
|
if(*p == L'-') {
|
|
Negative = TRUE;
|
|
p++;
|
|
} else {
|
|
if(*p == L'+') {
|
|
p++;
|
|
}
|
|
}
|
|
|
|
if(!Radix) {
|
|
if(*p == L'0') {
|
|
//
|
|
// Octal number
|
|
//
|
|
Radix = 8;
|
|
p++;
|
|
if((*p == L'x') || (*p == L'X')) {
|
|
//
|
|
// hex number
|
|
//
|
|
Radix = 16;
|
|
p++;
|
|
}
|
|
} else {
|
|
Radix = 10;
|
|
}
|
|
}
|
|
|
|
HighestDigitAllowed = (Radix < 10) ? L'0'+(WCHAR)(Radix-1) : L'9';
|
|
HighestLetterAllowed = (Radix > 10) ? L'A'+(WCHAR)(Radix-11) : 0;
|
|
|
|
Accum = 0;
|
|
|
|
while(1) {
|
|
|
|
c = *p;
|
|
|
|
if((c >= L'0') && (c <= HighestDigitAllowed)) {
|
|
v = c - L'0';
|
|
} else {
|
|
|
|
c = SpToUpper(c);
|
|
|
|
if((c >= L'A') && (c <= HighestLetterAllowed)) {
|
|
v = c - L'A' + 10;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Accum *= Radix;
|
|
Accum += v;
|
|
|
|
p++;
|
|
}
|
|
|
|
if(EndOfValue) {
|
|
*EndOfValue = p;
|
|
}
|
|
|
|
return(Negative ? (0-Accum) : Accum);
|
|
}
|
|
|
|
LONGLONG
|
|
SpAsrStringToLongLong(
|
|
IN PWSTR String,
|
|
OUT PWCHAR *EndOfValue,
|
|
IN unsigned Radix
|
|
)
|
|
{
|
|
PWSTR p;
|
|
BOOLEAN Negative;
|
|
LONGLONG Accum,v;
|
|
WCHAR HighestDigitAllowed,HighestLetterAllowed;
|
|
WCHAR c;
|
|
|
|
//
|
|
// Validate radix, 0 or 2-36.
|
|
//
|
|
if((Radix == 1) || (Radix > 36)) {
|
|
if(EndOfValue) {
|
|
*EndOfValue = String;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
p = String;
|
|
|
|
//
|
|
// Skip whitespace.
|
|
//
|
|
while(SpIsSpace(*p)) {
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// First char may be a plus or minus.
|
|
//
|
|
Negative = FALSE;
|
|
if(*p == L'-') {
|
|
Negative = TRUE;
|
|
p++;
|
|
} else {
|
|
if(*p == L'+') {
|
|
p++;
|
|
}
|
|
}
|
|
|
|
if(!Radix) {
|
|
if(*p == L'0') {
|
|
//
|
|
// Octal number
|
|
//
|
|
Radix = 8;
|
|
p++;
|
|
if((*p == L'x') || (*p == L'X')) {
|
|
//
|
|
// hex number
|
|
//
|
|
Radix = 16;
|
|
p++;
|
|
}
|
|
} else {
|
|
Radix = 10;
|
|
}
|
|
}
|
|
|
|
HighestDigitAllowed = (Radix < 10) ? L'0'+(WCHAR)(Radix-1) : L'9';
|
|
HighestLetterAllowed = (Radix > 10) ? L'A'+(WCHAR)(Radix-11) : 0;
|
|
|
|
Accum = 0;
|
|
|
|
while(1) {
|
|
|
|
c = *p;
|
|
|
|
if((c >= L'0') && (c <= HighestDigitAllowed)) {
|
|
v = c - L'0';
|
|
} else {
|
|
|
|
c = SpToUpper(c);
|
|
|
|
if((c >= L'A') && (c <= HighestLetterAllowed)) {
|
|
v = c - L'A' + 10;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Accum *= Radix;
|
|
Accum += v;
|
|
|
|
p++;
|
|
}
|
|
|
|
if(EndOfValue) {
|
|
*EndOfValue = p;
|
|
}
|
|
|
|
return(Negative ? (0-Accum) : Accum);
|
|
}
|
|
|
|
ULONG
|
|
SpAsrStringToULong(
|
|
IN PWSTR String,
|
|
OUT PWCHAR *EndOfValue,
|
|
IN unsigned Radix
|
|
)
|
|
{
|
|
PWSTR p;
|
|
BOOLEAN Negative;
|
|
ULONG Accum,v;
|
|
WCHAR HighestDigitAllowed,HighestLetterAllowed;
|
|
WCHAR c;
|
|
|
|
//
|
|
// Validate radix, 0 or 2-36.
|
|
//
|
|
if((Radix == 1) || (Radix > 36)) {
|
|
if(EndOfValue) {
|
|
*EndOfValue = String;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
p = String;
|
|
|
|
//
|
|
// Skip whitespace.
|
|
//
|
|
while(SpIsSpace(*p)) {
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// First char may be a plus or minus.
|
|
//
|
|
Negative = FALSE;
|
|
if(*p == L'-') {
|
|
Negative = TRUE;
|
|
p++;
|
|
} else {
|
|
if(*p == L'+') {
|
|
p++;
|
|
}
|
|
}
|
|
|
|
if(!Radix) {
|
|
if(*p == L'0') {
|
|
//
|
|
// Octal number
|
|
//
|
|
Radix = 8;
|
|
p++;
|
|
if((*p == L'x') || (*p == L'X')) {
|
|
//
|
|
// hex number
|
|
//
|
|
Radix = 16;
|
|
p++;
|
|
}
|
|
} else {
|
|
Radix = 10;
|
|
}
|
|
}
|
|
|
|
HighestDigitAllowed = (Radix < 10) ? L'0'+(WCHAR)(Radix-1) : L'9';
|
|
HighestLetterAllowed = (Radix > 10) ? L'A'+(WCHAR)(Radix-11) : 0;
|
|
|
|
Accum = 0;
|
|
|
|
while(1) {
|
|
|
|
c = *p;
|
|
|
|
if((c >= L'0') && (c <= HighestDigitAllowed)) {
|
|
v = c - L'0';
|
|
} else {
|
|
|
|
c = SpToUpper(c);
|
|
|
|
if((c >= L'A') && (c <= HighestLetterAllowed)) {
|
|
v = c - L'A' + 10;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Accum *= Radix;
|
|
Accum += v;
|
|
|
|
p++;
|
|
}
|
|
|
|
if(EndOfValue) {
|
|
*EndOfValue = p;
|
|
}
|
|
|
|
return(Negative ? (0-Accum) : Accum);
|
|
}
|
|
|
|
|
|
USHORT
|
|
SpAsrStringToUShort(
|
|
IN PWSTR String,
|
|
OUT PWCHAR *EndOfValue,
|
|
IN USHORT Radix
|
|
)
|
|
{
|
|
PWSTR p;
|
|
BOOLEAN Negative;
|
|
USHORT Accum,v;
|
|
WCHAR HighestDigitAllowed,HighestLetterAllowed;
|
|
WCHAR c;
|
|
|
|
//
|
|
// Validate radix, 0 or 2-36.
|
|
//
|
|
if((Radix == 1) || (Radix > 36)) {
|
|
if(EndOfValue) {
|
|
*EndOfValue = String;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
p = String;
|
|
|
|
//
|
|
// Skip whitespace.
|
|
//
|
|
while(SpIsSpace(*p)) {
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// First char may be a plus or minus.
|
|
//
|
|
Negative = FALSE;
|
|
if(*p == L'-') {
|
|
Negative = TRUE;
|
|
p++;
|
|
} else {
|
|
if(*p == L'+') {
|
|
p++;
|
|
}
|
|
}
|
|
|
|
if(!Radix) {
|
|
if(*p == L'0') {
|
|
//
|
|
// Octal number
|
|
//
|
|
Radix = 8;
|
|
p++;
|
|
if((*p == L'x') || (*p == L'X')) {
|
|
//
|
|
// hex number
|
|
//
|
|
Radix = 16;
|
|
p++;
|
|
}
|
|
} else {
|
|
Radix = 10;
|
|
}
|
|
}
|
|
|
|
HighestDigitAllowed = (Radix < 10) ? L'0'+(WCHAR)(Radix-1) : L'9';
|
|
HighestLetterAllowed = (Radix > 10) ? L'A'+(WCHAR)(Radix-11) : 0;
|
|
|
|
Accum = 0;
|
|
|
|
while(1) {
|
|
|
|
c = *p;
|
|
|
|
if((c >= L'0') && (c <= HighestDigitAllowed)) {
|
|
v = c - L'0';
|
|
} else {
|
|
|
|
c = SpToUpper(c);
|
|
|
|
if((c >= L'A') && (c <= HighestLetterAllowed)) {
|
|
v = c - L'A' + 10;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Accum *= Radix;
|
|
Accum += v;
|
|
|
|
p++;
|
|
}
|
|
|
|
if(EndOfValue) {
|
|
*EndOfValue = p;
|
|
}
|
|
|
|
return(Negative ? (0-Accum) : Accum);
|
|
}
|
|
|
|
|
|
int
|
|
SpAsrCharToInt(
|
|
IN PWSTR String,
|
|
OUT PWCHAR *EndOfValue,
|
|
IN USHORT Radix
|
|
)
|
|
{
|
|
PWSTR p;
|
|
BOOLEAN Negative;
|
|
USHORT Accum,v;
|
|
WCHAR HighestDigitAllowed,HighestLetterAllowed;
|
|
WCHAR c;
|
|
|
|
//
|
|
// Validate radix, 0 or 2-36.
|
|
//
|
|
if((Radix == 1) || (Radix > 36)) {
|
|
if(EndOfValue) {
|
|
*EndOfValue = String;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
p = String;
|
|
|
|
//
|
|
// Skip whitespace.
|
|
//
|
|
while(SpIsSpace(*p)) {
|
|
p++;
|
|
}
|
|
|
|
//
|
|
// First char may be a plus or minus.
|
|
//
|
|
Negative = FALSE;
|
|
if(*p == L'-') {
|
|
Negative = TRUE;
|
|
p++;
|
|
} else {
|
|
if(*p == L'+') {
|
|
p++;
|
|
}
|
|
}
|
|
|
|
if(!Radix) {
|
|
if(*p == L'0') {
|
|
//
|
|
// Octal number
|
|
//
|
|
Radix = 8;
|
|
p++;
|
|
if((*p == L'x') || (*p == L'X')) {
|
|
//
|
|
// hex number
|
|
//
|
|
Radix = 16;
|
|
p++;
|
|
}
|
|
} else {
|
|
Radix = 10;
|
|
}
|
|
}
|
|
|
|
HighestDigitAllowed = (Radix < 10) ? L'0'+(WCHAR)(Radix-1) : L'9';
|
|
HighestLetterAllowed = (Radix > 10) ? L'A'+(WCHAR)(Radix-11) : 0;
|
|
|
|
Accum = 0;
|
|
|
|
while(1) {
|
|
|
|
c = *p;
|
|
|
|
if((c >= L'0') && (c <= HighestDigitAllowed)) {
|
|
v = c - L'0';
|
|
} else {
|
|
|
|
c = SpToUpper(c);
|
|
|
|
if((c >= L'A') && (c <= HighestLetterAllowed)) {
|
|
v = c - L'A' + 10;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Accum *= Radix;
|
|
Accum += v;
|
|
|
|
p++;
|
|
}
|
|
|
|
if(EndOfValue) {
|
|
*EndOfValue = p;
|
|
}
|
|
|
|
return(Negative ? (0-Accum) : Accum);
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SpAsrHexStringToUChar (
|
|
IN PWSTR String,
|
|
OUT unsigned char * Number
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
This routine converts the hex representation of a number into an
|
|
unsigned char. The hex representation is assumed to be a full
|
|
two characters long.
|
|
|
|
Arguments:
|
|
|
|
String - Supplies the hex representation of the number.
|
|
|
|
Number - Returns the number converted from hex representation.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the end of the hex representation is returned if the
|
|
hex representation was successfully converted to an unsigned char.
|
|
Otherwise, zero is returned, indicating that an error occured.
|
|
|
|
--*/
|
|
{
|
|
WCHAR Result;
|
|
int Count;
|
|
|
|
Result = 0;
|
|
for (Count = 0; Count < 2; Count++, String++) {
|
|
if ((*String >= L'0') && (*String <= L'9')) {
|
|
Result = (Result << 4) + *String - L'0';
|
|
}
|
|
else if ((*String >= L'A') && (*String <= L'F')) {
|
|
Result = (Result << 4) + *String - L'A' + 10;
|
|
}
|
|
else if ((*String >= L'a') && (*String <= L'f')) {
|
|
Result = (Result << 4) + *String - L'a' + 10;
|
|
}
|
|
}
|
|
*Number = (unsigned char)Result;
|
|
|
|
return String;
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrGuidFromString(
|
|
IN OUT GUID* Guid,
|
|
IN PWSTR GuidString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets a GUID from a string
|
|
|
|
Arguments:
|
|
|
|
Guid - The GUID that holds string representation
|
|
Buffer - The string version of the guid, in the form
|
|
"%x-%x-%x-%x%x%x%x%x%x%x%x"
|
|
|
|
Return Value:
|
|
|
|
Returns the converted string version of the given GUID
|
|
|
|
--*/
|
|
{
|
|
PWSTR Buffer = GuidString;
|
|
int i = 0;
|
|
|
|
if (Guid) {
|
|
ZeroMemory(Guid, sizeof(GUID));
|
|
}
|
|
|
|
if (Guid && Buffer) {
|
|
|
|
Guid->Data1 = SpAsrStringToULong(Buffer, NULL, 16);
|
|
Buffer += 9;
|
|
|
|
Guid->Data2 = SpAsrStringToUShort(Buffer, NULL, 16);
|
|
Buffer += 5;
|
|
|
|
Guid->Data3 = SpAsrStringToUShort(Buffer, NULL, 16);
|
|
Buffer += 5;
|
|
|
|
Buffer = SpAsrHexStringToUChar(Buffer,&(Guid->Data4[0]));
|
|
Buffer = SpAsrHexStringToUChar(Buffer,&(Guid->Data4[1]));
|
|
++Buffer;
|
|
Buffer = SpAsrHexStringToUChar(Buffer,&(Guid->Data4[2]));
|
|
Buffer = SpAsrHexStringToUChar(Buffer,&(Guid->Data4[3]));
|
|
Buffer = SpAsrHexStringToUChar(Buffer,&(Guid->Data4[4]));
|
|
Buffer = SpAsrHexStringToUChar(Buffer,&(Guid->Data4[5]));
|
|
Buffer = SpAsrHexStringToUChar(Buffer,&(Guid->Data4[6]));
|
|
Buffer = SpAsrHexStringToUChar(Buffer,&(Guid->Data4[7]));
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrIsZeroGuid(
|
|
IN GUID * Guid
|
|
)
|
|
{
|
|
|
|
GUID ZeroGuid;
|
|
|
|
ZeroMemory(&ZeroGuid, sizeof(GUID));
|
|
|
|
if (!memcmp(&ZeroGuid, Guid, sizeof(GUID))) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|