From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/MdePkg/Library/BaseLib/SafeString.c | 3535 +++++++++++++++++++++++++ 1 file changed, 3535 insertions(+) create mode 100644 roms/edk2/MdePkg/Library/BaseLib/SafeString.c (limited to 'roms/edk2/MdePkg/Library/BaseLib/SafeString.c') diff --git a/roms/edk2/MdePkg/Library/BaseLib/SafeString.c b/roms/edk2/MdePkg/Library/BaseLib/SafeString.c new file mode 100644 index 000000000..3bb23ca1a --- /dev/null +++ b/roms/edk2/MdePkg/Library/BaseLib/SafeString.c @@ -0,0 +1,3535 @@ +/** @file + Safe String functions. + + Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "BaseLibInternals.h" + +#define RSIZE_MAX (PcdGet32 (PcdMaximumUnicodeStringLength)) + +#define ASCII_RSIZE_MAX (PcdGet32 (PcdMaximumAsciiStringLength)) + +#define SAFE_STRING_CONSTRAINT_CHECK(Expression, Status) \ + do { \ + if (!(Expression)) { \ + DEBUG ((DEBUG_VERBOSE, \ + "%a(%d) %a: SAFE_STRING_CONSTRAINT_CHECK(%a) failed. Return %r\n", \ + __FILE__, __LINE__, __FUNCTION__, #Expression, Status)); \ + return Status; \ + } \ + } while (FALSE) + +/** + Returns if 2 memory blocks are overlapped. + + @param Base1 Base address of 1st memory block. + @param Size1 Size of 1st memory block. + @param Base2 Base address of 2nd memory block. + @param Size2 Size of 2nd memory block. + + @retval TRUE 2 memory blocks are overlapped. + @retval FALSE 2 memory blocks are not overlapped. +**/ +BOOLEAN +InternalSafeStringIsOverlap ( + IN VOID *Base1, + IN UINTN Size1, + IN VOID *Base2, + IN UINTN Size2 + ) +{ + if ((((UINTN)Base1 >= (UINTN)Base2) && ((UINTN)Base1 < (UINTN)Base2 + Size2)) || + (((UINTN)Base2 >= (UINTN)Base1) && ((UINTN)Base2 < (UINTN)Base1 + Size1))) { + return TRUE; + } + return FALSE; +} + +/** + Returns if 2 Unicode strings are not overlapped. + + @param Str1 Start address of 1st Unicode string. + @param Size1 The number of char in 1st Unicode string, + including terminating null char. + @param Str2 Start address of 2nd Unicode string. + @param Size2 The number of char in 2nd Unicode string, + including terminating null char. + + @retval TRUE 2 Unicode strings are NOT overlapped. + @retval FALSE 2 Unicode strings are overlapped. +**/ +BOOLEAN +InternalSafeStringNoStrOverlap ( + IN CHAR16 *Str1, + IN UINTN Size1, + IN CHAR16 *Str2, + IN UINTN Size2 + ) +{ + return !InternalSafeStringIsOverlap (Str1, Size1 * sizeof(CHAR16), Str2, Size2 * sizeof(CHAR16)); +} + +/** + Returns if 2 Ascii strings are not overlapped. + + @param Str1 Start address of 1st Ascii string. + @param Size1 The number of char in 1st Ascii string, + including terminating null char. + @param Str2 Start address of 2nd Ascii string. + @param Size2 The number of char in 2nd Ascii string, + including terminating null char. + + @retval TRUE 2 Ascii strings are NOT overlapped. + @retval FALSE 2 Ascii strings are overlapped. +**/ +BOOLEAN +InternalSafeStringNoAsciiStrOverlap ( + IN CHAR8 *Str1, + IN UINTN Size1, + IN CHAR8 *Str2, + IN UINTN Size2 + ) +{ + return !InternalSafeStringIsOverlap (Str1, Size1, Str2, Size2); +} + +/** + Returns the length of a Null-terminated Unicode string. + + This function is similar as strlen_s defined in C11. + + If String is not aligned on a 16-bit boundary, then ASSERT(). + + @param String A pointer to a Null-terminated Unicode string. + @param MaxSize The maximum number of Destination Unicode + char, including terminating null char. + + @retval 0 If String is NULL. + @retval MaxSize If there is no null character in the first MaxSize characters of String. + @return The number of characters that percede the terminating null character. + +**/ +UINTN +EFIAPI +StrnLenS ( + IN CONST CHAR16 *String, + IN UINTN MaxSize + ) +{ + UINTN Length; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // If String is a null pointer or MaxSize is 0, then the StrnLenS function returns zero. + // + if ((String == NULL) || (MaxSize == 0)) { + return 0; + } + + // + // Otherwise, the StrnLenS function returns the number of characters that precede the + // terminating null character. If there is no null character in the first MaxSize characters of + // String then StrnLenS returns MaxSize. At most the first MaxSize characters of String shall + // be accessed by StrnLenS. + // + Length = 0; + while (String[Length] != 0) { + if (Length >= MaxSize - 1) { + return MaxSize; + } + Length++; + } + return Length; +} + +/** + Returns the size of a Null-terminated Unicode string in bytes, including the + Null terminator. + + This function returns the size of the Null-terminated Unicode string + specified by String in bytes, including the Null terminator. + + If String is not aligned on a 16-bit boundary, then ASSERT(). + + @param String A pointer to a Null-terminated Unicode string. + @param MaxSize The maximum number of Destination Unicode + char, including the Null terminator. + + @retval 0 If String is NULL. + @retval (sizeof (CHAR16) * (MaxSize + 1)) + If there is no Null terminator in the first MaxSize characters of + String. + @return The size of the Null-terminated Unicode string in bytes, including + the Null terminator. + +**/ +UINTN +EFIAPI +StrnSizeS ( + IN CONST CHAR16 *String, + IN UINTN MaxSize + ) +{ + // + // If String is a null pointer, then the StrnSizeS function returns zero. + // + if (String == NULL) { + return 0; + } + + // + // Otherwise, the StrnSizeS function returns the size of the Null-terminated + // Unicode string in bytes, including the Null terminator. If there is no + // Null terminator in the first MaxSize characters of String, then StrnSizeS + // returns (sizeof (CHAR16) * (MaxSize + 1)) to keep a consistent map with + // the StrnLenS function. + // + return (StrnLenS (String, MaxSize) + 1) * sizeof (*String); +} + +/** + Copies the string pointed to by Source (including the terminating null char) + to the array pointed to by Destination. + + This function is similar as strcpy_s defined in C11. + + If Destination is not aligned on a 16-bit boundary, then ASSERT(). + If Source is not aligned on a 16-bit boundary, then ASSERT(). + + If an error is returned, then the Destination is unmodified. + + @param Destination A pointer to a Null-terminated Unicode string. + @param DestMax The maximum number of Destination Unicode + char, including terminating null char. + @param Source A pointer to a Null-terminated Unicode string. + + @retval RETURN_SUCCESS String is copied. + @retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than StrLen(Source). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumUnicodeStringLength is not zero, + and DestMax is greater than + PcdMaximumUnicodeStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. +**/ +RETURN_STATUS +EFIAPI +StrCpyS ( + OUT CHAR16 *Destination, + IN UINTN DestMax, + IN CONST CHAR16 *Source + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Destination & BIT0) == 0); + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. DestMax shall be greater than StrnLenS(Source, DestMax). + // + SourceLen = StrnLenS (Source, DestMax); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 5. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The StrCpyS function copies the string pointed to by Source (including the terminating + // null character) into the array pointed to by Destination. + // + while (*Source != 0) { + *(Destination++) = *(Source++); + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Copies not more than Length successive char from the string pointed to by + Source to the array pointed to by Destination. If no null char is copied from + Source, then Destination[Length] is always set to null. + + This function is similar as strncpy_s defined in C11. + + If Length > 0 and Destination is not aligned on a 16-bit boundary, then ASSERT(). + If Length > 0 and Source is not aligned on a 16-bit boundary, then ASSERT(). + + If an error is returned, then the Destination is unmodified. + + @param Destination A pointer to a Null-terminated Unicode string. + @param DestMax The maximum number of Destination Unicode + char, including terminating null char. + @param Source A pointer to a Null-terminated Unicode string. + @param Length The maximum number of Unicode characters to copy. + + @retval RETURN_SUCCESS String is copied. + @retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than + MIN(StrLen(Source), Length). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumUnicodeStringLength is not zero, + and DestMax is greater than + PcdMaximumUnicodeStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. +**/ +RETURN_STATUS +EFIAPI +StrnCpyS ( + OUT CHAR16 *Destination, + IN UINTN DestMax, + IN CONST CHAR16 *Source, + IN UINTN Length + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Destination & BIT0) == 0); + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Neither DestMax nor Length shall be greater than RSIZE_MAX + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. If Length is not less than DestMax, then DestMax shall be greater than StrnLenS(Source, DestMax). + // + SourceLen = StrnLenS (Source, MIN (DestMax, Length)); + if (Length >= DestMax) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + } + + // + // 5. Copying shall not take place between objects that overlap. + // + if (SourceLen > Length) { + SourceLen = Length; + } + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The StrnCpyS function copies not more than Length successive characters (characters that + // follow a null character are not copied) from the array pointed to by Source to the array + // pointed to by Destination. If no null character was copied from Source, then Destination[Length] is set to a null + // character. + // + while ((SourceLen > 0) && (*Source != 0)) { + *(Destination++) = *(Source++); + SourceLen--; + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Appends a copy of the string pointed to by Source (including the terminating + null char) to the end of the string pointed to by Destination. + + This function is similar as strcat_s defined in C11. + + If Destination is not aligned on a 16-bit boundary, then ASSERT(). + If Source is not aligned on a 16-bit boundary, then ASSERT(). + + If an error is returned, then the Destination is unmodified. + + @param Destination A pointer to a Null-terminated Unicode string. + @param DestMax The maximum number of Destination Unicode + char, including terminating null char. + @param Source A pointer to a Null-terminated Unicode string. + + @retval RETURN_SUCCESS String is appended. + @retval RETURN_BAD_BUFFER_SIZE If DestMax is NOT greater than + StrLen(Destination). + @retval RETURN_BUFFER_TOO_SMALL If (DestMax - StrLen(Destination)) is NOT + greater than StrLen(Source). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumUnicodeStringLength is not zero, + and DestMax is greater than + PcdMaximumUnicodeStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. +**/ +RETURN_STATUS +EFIAPI +StrCatS ( + IN OUT CHAR16 *Destination, + IN UINTN DestMax, + IN CONST CHAR16 *Source + ) +{ + UINTN DestLen; + UINTN CopyLen; + UINTN SourceLen; + + ASSERT (((UINTN) Destination & BIT0) == 0); + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // Let CopyLen denote the value DestMax - StrnLenS(Destination, DestMax) upon entry to StrCatS. + // + DestLen = StrnLenS (Destination, DestMax); + CopyLen = DestMax - DestLen; + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. CopyLen shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((CopyLen != 0), RETURN_BAD_BUFFER_SIZE); + + // + // 5. CopyLen shall be greater than StrnLenS(Source, CopyLen). + // + SourceLen = StrnLenS (Source, CopyLen); + SAFE_STRING_CONSTRAINT_CHECK ((CopyLen > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 6. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The StrCatS function appends a copy of the string pointed to by Source (including the + // terminating null character) to the end of the string pointed to by Destination. The initial character + // from Source overwrites the null character at the end of Destination. + // + Destination = Destination + DestLen; + while (*Source != 0) { + *(Destination++) = *(Source++); + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Appends not more than Length successive char from the string pointed to by + Source to the end of the string pointed to by Destination. If no null char is + copied from Source, then Destination[StrLen(Destination) + Length] is always + set to null. + + This function is similar as strncat_s defined in C11. + + If Destination is not aligned on a 16-bit boundary, then ASSERT(). + If Source is not aligned on a 16-bit boundary, then ASSERT(). + + If an error is returned, then the Destination is unmodified. + + @param Destination A pointer to a Null-terminated Unicode string. + @param DestMax The maximum number of Destination Unicode + char, including terminating null char. + @param Source A pointer to a Null-terminated Unicode string. + @param Length The maximum number of Unicode characters to copy. + + @retval RETURN_SUCCESS String is appended. + @retval RETURN_BAD_BUFFER_SIZE If DestMax is NOT greater than + StrLen(Destination). + @retval RETURN_BUFFER_TOO_SMALL If (DestMax - StrLen(Destination)) is NOT + greater than MIN(StrLen(Source), Length). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumUnicodeStringLength is not zero, + and DestMax is greater than + PcdMaximumUnicodeStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. +**/ +RETURN_STATUS +EFIAPI +StrnCatS ( + IN OUT CHAR16 *Destination, + IN UINTN DestMax, + IN CONST CHAR16 *Source, + IN UINTN Length + ) +{ + UINTN DestLen; + UINTN CopyLen; + UINTN SourceLen; + + ASSERT (((UINTN) Destination & BIT0) == 0); + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // Let CopyLen denote the value DestMax - StrnLenS(Destination, DestMax) upon entry to StrnCatS. + // + DestLen = StrnLenS (Destination, DestMax); + CopyLen = DestMax - DestLen; + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Neither DestMax nor Length shall be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. CopyLen shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((CopyLen != 0), RETURN_BAD_BUFFER_SIZE); + + // + // 5. If Length is not less than CopyLen, then CopyLen shall be greater than StrnLenS(Source, CopyLen). + // + SourceLen = StrnLenS (Source, MIN (CopyLen, Length)); + if (Length >= CopyLen) { + SAFE_STRING_CONSTRAINT_CHECK ((CopyLen > SourceLen), RETURN_BUFFER_TOO_SMALL); + } + + // + // 6. Copying shall not take place between objects that overlap. + // + if (SourceLen > Length) { + SourceLen = Length; + } + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The StrnCatS function appends not more than Length successive characters (characters + // that follow a null character are not copied) from the array pointed to by Source to the end of + // the string pointed to by Destination. The initial character from Source overwrites the null character at + // the end of Destination. If no null character was copied from Source, then Destination[DestMax-CopyLen+Length] is set to + // a null character. + // + Destination = Destination + DestLen; + while ((SourceLen > 0) && (*Source != 0)) { + *(Destination++) = *(Source++); + SourceLen--; + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode decimal string to a value of type UINTN. + + This function outputs a value of type UINTN by interpreting the contents of + the Unicode string specified by String as a decimal number. The format of the + input Unicode string String is: + + [spaces] [decimal digits]. + + The valid decimal digit character is in the range [0-9]. The function will + ignore the pad space, which includes spaces or tab characters, before + [decimal digits]. The running zero in the beginning of [decimal digits] will + be ignored. Then, the function stops at the first character that is a not a + valid decimal character or a Null-terminator, whichever one comes first. + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + If String has no valid decimal digits in the above format, then 0 is stored + at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINTN, then + MAX_UINTN is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + decimal digits right after the optional pad spaces, the value of String is + stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumUnicodeStringLength is not + zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINTN. + +**/ +RETURN_STATUS +EFIAPI +StrDecimalToUintnS ( + IN CONST CHAR16 *String, + OUT CHAR16 **EndPointer, OPTIONAL + OUT UINTN *Data + ) +{ + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + *Data = 0; + + while (InternalIsDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINTN, then MAX_UINTN is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > ((MAX_UINTN - (*String - L'0')) / 10)) { + *Data = MAX_UINTN; + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = *Data * 10 + (*String - L'0'); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode decimal string to a value of type UINT64. + + This function outputs a value of type UINT64 by interpreting the contents of + the Unicode string specified by String as a decimal number. The format of the + input Unicode string String is: + + [spaces] [decimal digits]. + + The valid decimal digit character is in the range [0-9]. The function will + ignore the pad space, which includes spaces or tab characters, before + [decimal digits]. The running zero in the beginning of [decimal digits] will + be ignored. Then, the function stops at the first character that is a not a + valid decimal character or a Null-terminator, whichever one comes first. + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + If String has no valid decimal digits in the above format, then 0 is stored + at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINT64, then + MAX_UINT64 is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + decimal digits right after the optional pad spaces, the value of String is + stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumUnicodeStringLength is not + zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINT64. + +**/ +RETURN_STATUS +EFIAPI +StrDecimalToUint64S ( + IN CONST CHAR16 *String, + OUT CHAR16 **EndPointer, OPTIONAL + OUT UINT64 *Data + ) +{ + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + *Data = 0; + + while (InternalIsDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINT64, then MAX_UINT64 is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > DivU64x32 (MAX_UINT64 - (*String - L'0'), 10)) { + *Data = MAX_UINT64; + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = MultU64x32 (*Data, 10) + (*String - L'0'); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode hexadecimal string to a value of type + UINTN. + + This function outputs a value of type UINTN by interpreting the contents of + the Unicode string specified by String as a hexadecimal number. The format of + the input Unicode string String is: + + [spaces][zeros][x][hexadecimal digits]. + + The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F]. + The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix. + If "x" appears in the input string, it must be prefixed with at least one 0. + The function will ignore the pad space, which includes spaces or tab + characters, before [zeros], [x] or [hexadecimal digit]. The running zero + before [x] or [hexadecimal digit] will be ignored. Then, the decoding starts + after [x] or the first valid hexadecimal digit. Then, the function stops at + the first character that is a not a valid hexadecimal character or NULL, + whichever one comes first. + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + If String has no valid hexadecimal digits in the above format, then 0 is + stored at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINTN, then + MAX_UINTN is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + hexadecimal digits right after the optional pad spaces, the value of String + is stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumUnicodeStringLength is not + zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINTN. + +**/ +RETURN_STATUS +EFIAPI +StrHexToUintnS ( + IN CONST CHAR16 *String, + OUT CHAR16 **EndPointer, OPTIONAL + OUT UINTN *Data + ) +{ + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + if (CharToUpper (*String) == L'X') { + if (*(String - 1) != L'0') { + *Data = 0; + return RETURN_SUCCESS; + } + // + // Skip the 'X' + // + String++; + } + + *Data = 0; + + while (InternalIsHexaDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINTN, then MAX_UINTN is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > ((MAX_UINTN - InternalHexCharToUintn (*String)) >> 4)) { + *Data = MAX_UINTN; + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = (*Data << 4) + InternalHexCharToUintn (*String); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode hexadecimal string to a value of type + UINT64. + + This function outputs a value of type UINT64 by interpreting the contents of + the Unicode string specified by String as a hexadecimal number. The format of + the input Unicode string String is: + + [spaces][zeros][x][hexadecimal digits]. + + The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F]. + The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix. + If "x" appears in the input string, it must be prefixed with at least one 0. + The function will ignore the pad space, which includes spaces or tab + characters, before [zeros], [x] or [hexadecimal digit]. The running zero + before [x] or [hexadecimal digit] will be ignored. Then, the decoding starts + after [x] or the first valid hexadecimal digit. Then, the function stops at + the first character that is a not a valid hexadecimal character or NULL, + whichever one comes first. + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + If String has no valid hexadecimal digits in the above format, then 0 is + stored at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINT64, then + MAX_UINT64 is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + hexadecimal digits right after the optional pad spaces, the value of String + is stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumUnicodeStringLength is not + zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINT64. + +**/ +RETURN_STATUS +EFIAPI +StrHexToUint64S ( + IN CONST CHAR16 *String, + OUT CHAR16 **EndPointer, OPTIONAL + OUT UINT64 *Data + ) +{ + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + if (CharToUpper (*String) == L'X') { + if (*(String - 1) != L'0') { + *Data = 0; + return RETURN_SUCCESS; + } + // + // Skip the 'X' + // + String++; + } + + *Data = 0; + + while (InternalIsHexaDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINT64, then MAX_UINT64 is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > RShiftU64 (MAX_UINT64 - InternalHexCharToUintn (*String), 4)) { + *Data = MAX_UINT64; + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = LShiftU64 (*Data, 4) + InternalHexCharToUintn (*String); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode string to IPv6 address and prefix length. + + This function outputs a value of type IPv6_ADDRESS and may output a value + of type UINT8 by interpreting the contents of the Unicode string specified + by String. The format of the input Unicode string String is as follows: + + X:X:X:X:X:X:X:X[/P] + + X contains one to four hexadecimal digit characters in the range [0-9], [a-f] and + [A-F]. X is converted to a value of type UINT16, whose low byte is stored in low + memory address and high byte is stored in high memory address. P contains decimal + digit characters in the range [0-9]. The running zero in the beginning of P will + be ignored. /P is optional. + + When /P is not in the String, the function stops at the first character that is + not a valid hexadecimal digit character after eight X's are converted. + + When /P is in the String, the function stops at the first character that is not + a valid decimal digit character after P is converted. + + "::" can be used to compress one or more groups of X when X contains only 0. + The "::" can only appear once in the String. + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + If EndPointer is not NULL and Address is translated from String, a pointer + to the character that stopped the scan is stored at the location pointed to + by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Address Pointer to the converted IPv6 address. + @param PrefixLength Pointer to the converted IPv6 address prefix + length. MAX_UINT8 is returned when /P is + not in the String. + + @retval RETURN_SUCCESS Address is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + @retval RETURN_UNSUPPORTED If X contains more than four hexadecimal + digit characters. + If String contains "::" and number of X + is not less than 8. + If P starts with character that is not a + valid decimal digit character. + If the decimal number converted from P + exceeds 128. + +**/ +RETURN_STATUS +EFIAPI +StrToIpv6Address ( + IN CONST CHAR16 *String, + OUT CHAR16 **EndPointer, OPTIONAL + OUT IPv6_ADDRESS *Address, + OUT UINT8 *PrefixLength OPTIONAL + ) +{ + RETURN_STATUS Status; + UINTN AddressIndex; + UINTN Uintn; + IPv6_ADDRESS LocalAddress; + UINT8 LocalPrefixLength; + CONST CHAR16 *Pointer; + CHAR16 *End; + UINTN CompressStart; + BOOLEAN ExpectPrefix; + + LocalPrefixLength = MAX_UINT8; + CompressStart = ARRAY_SIZE (Address->Addr); + ExpectPrefix = FALSE; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER); + + for (Pointer = String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) { + if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) { + if (*Pointer != L':') { + // + // ":" or "/" should be followed by digit characters. + // + return RETURN_UNSUPPORTED; + } + + // + // Meet second ":" after previous ":" or "/" + // or meet first ":" in the beginning of String. + // + if (ExpectPrefix) { + // + // ":" shall not be after "/" + // + return RETURN_UNSUPPORTED; + } + + if (CompressStart != ARRAY_SIZE (Address->Addr) || AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // "::" can only appear once. + // "::" can only appear when address is not full length. + // + return RETURN_UNSUPPORTED; + } else { + // + // Remember the start of zero compressing. + // + CompressStart = AddressIndex; + Pointer++; + + if (CompressStart == 0) { + if (*Pointer != L':') { + // + // Single ":" shall not be in the beginning of String. + // + return RETURN_UNSUPPORTED; + } + Pointer++; + } + } + } + + if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) { + if (*Pointer == L'/') { + // + // Might be optional "/P" after "::". + // + if (CompressStart != AddressIndex) { + return RETURN_UNSUPPORTED; + } + } else { + break; + } + } else { + if (!ExpectPrefix) { + // + // Get X. + // + Status = StrHexToUintnS (Pointer, &End, &Uintn); + if (RETURN_ERROR (Status) || End - Pointer > 4) { + // + // Number of hexadecimal digit characters is no more than 4. + // + return RETURN_UNSUPPORTED; + } + Pointer = End; + // + // Uintn won't exceed MAX_UINT16 if number of hexadecimal digit characters is no more than 4. + // + ASSERT (AddressIndex + 1 < ARRAY_SIZE (Address->Addr)); + LocalAddress.Addr[AddressIndex] = (UINT8) ((UINT16) Uintn >> 8); + LocalAddress.Addr[AddressIndex + 1] = (UINT8) Uintn; + AddressIndex += 2; + } else { + // + // Get P, then exit the loop. + // + Status = StrDecimalToUintnS (Pointer, &End, &Uintn); + if (RETURN_ERROR (Status) || End == Pointer || Uintn > 128) { + // + // Prefix length should not exceed 128. + // + return RETURN_UNSUPPORTED; + } + LocalPrefixLength = (UINT8) Uintn; + Pointer = End; + break; + } + } + + // + // Skip ':' or "/" + // + if (*Pointer == L'/') { + ExpectPrefix = TRUE; + } else if (*Pointer == L':') { + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // Meet additional ":" after all 8 16-bit address + // + break; + } + } else { + // + // Meet other character that is not "/" or ":" after all 8 16-bit address + // + break; + } + Pointer++; + } + + if ((AddressIndex == ARRAY_SIZE (Address->Addr) && CompressStart != ARRAY_SIZE (Address->Addr)) || + (AddressIndex != ARRAY_SIZE (Address->Addr) && CompressStart == ARRAY_SIZE (Address->Addr)) + ) { + // + // Full length of address shall not have compressing zeros. + // Non-full length of address shall have compressing zeros. + // + return RETURN_UNSUPPORTED; + } + CopyMem (&Address->Addr[0], &LocalAddress.Addr[0], CompressStart); + ZeroMem (&Address->Addr[CompressStart], ARRAY_SIZE (Address->Addr) - AddressIndex); + if (AddressIndex > CompressStart) { + CopyMem ( + &Address->Addr[CompressStart + ARRAY_SIZE (Address->Addr) - AddressIndex], + &LocalAddress.Addr[CompressStart], + AddressIndex - CompressStart + ); + } + + if (PrefixLength != NULL) { + *PrefixLength = LocalPrefixLength; + } + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) Pointer; + } + + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode string to IPv4 address and prefix length. + + This function outputs a value of type IPv4_ADDRESS and may output a value + of type UINT8 by interpreting the contents of the Unicode string specified + by String. The format of the input Unicode string String is as follows: + + D.D.D.D[/P] + + D and P are decimal digit characters in the range [0-9]. The running zero in + the beginning of D and P will be ignored. /P is optional. + + When /P is not in the String, the function stops at the first character that is + not a valid decimal digit character after four D's are converted. + + When /P is in the String, the function stops at the first character that is not + a valid decimal digit character after P is converted. + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + If EndPointer is not NULL and Address is translated from String, a pointer + to the character that stopped the scan is stored at the location pointed to + by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Address Pointer to the converted IPv4 address. + @param PrefixLength Pointer to the converted IPv4 address prefix + length. MAX_UINT8 is returned when /P is + not in the String. + + @retval RETURN_SUCCESS Address is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + @retval RETURN_UNSUPPORTED If String is not in the correct format. + If any decimal number converted from D + exceeds 255. + If the decimal number converted from P + exceeds 32. + +**/ +RETURN_STATUS +EFIAPI +StrToIpv4Address ( + IN CONST CHAR16 *String, + OUT CHAR16 **EndPointer, OPTIONAL + OUT IPv4_ADDRESS *Address, + OUT UINT8 *PrefixLength OPTIONAL + ) +{ + RETURN_STATUS Status; + UINTN AddressIndex; + UINTN Uintn; + IPv4_ADDRESS LocalAddress; + UINT8 LocalPrefixLength; + CHAR16 *Pointer; + + LocalPrefixLength = MAX_UINT8; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER); + + for (Pointer = (CHAR16 *) String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) { + if (!InternalIsDecimalDigitCharacter (*Pointer)) { + // + // D or P contains invalid characters. + // + break; + } + + // + // Get D or P. + // + Status = StrDecimalToUintnS ((CONST CHAR16 *) Pointer, &Pointer, &Uintn); + if (RETURN_ERROR (Status)) { + return RETURN_UNSUPPORTED; + } + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // It's P. + // + if (Uintn > 32) { + return RETURN_UNSUPPORTED; + } + LocalPrefixLength = (UINT8) Uintn; + } else { + // + // It's D. + // + if (Uintn > MAX_UINT8) { + return RETURN_UNSUPPORTED; + } + LocalAddress.Addr[AddressIndex] = (UINT8) Uintn; + AddressIndex++; + } + + // + // Check the '.' or '/', depending on the AddressIndex. + // + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + if (*Pointer == L'/') { + // + // '/P' is in the String. + // Skip "/" and get P in next loop. + // + Pointer++; + } else { + // + // '/P' is not in the String. + // + break; + } + } else if (AddressIndex < ARRAY_SIZE (Address->Addr)) { + if (*Pointer == L'.') { + // + // D should be followed by '.' + // + Pointer++; + } else { + return RETURN_UNSUPPORTED; + } + } + } + + if (AddressIndex < ARRAY_SIZE (Address->Addr)) { + return RETURN_UNSUPPORTED; + } + + CopyMem (Address, &LocalAddress, sizeof (*Address)); + if (PrefixLength != NULL) { + *PrefixLength = LocalPrefixLength; + } + if (EndPointer != NULL) { + *EndPointer = Pointer; + } + + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode GUID string to a value of type + EFI_GUID. + + This function outputs a GUID value by interpreting the contents of + the Unicode string specified by String. The format of the input + Unicode string String consists of 36 characters, as follows: + + aabbccdd-eeff-gghh-iijj-kkllmmnnoopp + + The pairs aa - pp are two characters in the range [0-9], [a-f] and + [A-F], with each pair representing a single byte hexadecimal value. + + The mapping between String and the EFI_GUID structure is as follows: + aa Data1[24:31] + bb Data1[16:23] + cc Data1[8:15] + dd Data1[0:7] + ee Data2[8:15] + ff Data2[0:7] + gg Data3[8:15] + hh Data3[0:7] + ii Data4[0:7] + jj Data4[8:15] + kk Data4[16:23] + ll Data4[24:31] + mm Data4[32:39] + nn Data4[40:47] + oo Data4[48:55] + pp Data4[56:63] + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + @param String Pointer to a Null-terminated Unicode string. + @param Guid Pointer to the converted GUID. + + @retval RETURN_SUCCESS Guid is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + @retval RETURN_UNSUPPORTED If String is not as the above format. + +**/ +RETURN_STATUS +EFIAPI +StrToGuid ( + IN CONST CHAR16 *String, + OUT GUID *Guid + ) +{ + RETURN_STATUS Status; + GUID LocalGuid; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Guid != NULL), RETURN_INVALID_PARAMETER); + + // + // Get aabbccdd in big-endian. + // + Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data1), (UINT8 *) &LocalGuid.Data1, sizeof (LocalGuid.Data1)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data1)] != L'-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data1 = SwapBytes32 (LocalGuid.Data1); + String += 2 * sizeof (LocalGuid.Data1) + 1; + + // + // Get eeff in big-endian. + // + Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data2), (UINT8 *) &LocalGuid.Data2, sizeof (LocalGuid.Data2)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data2)] != L'-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data2 = SwapBytes16 (LocalGuid.Data2); + String += 2 * sizeof (LocalGuid.Data2) + 1; + + // + // Get gghh in big-endian. + // + Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data3), (UINT8 *) &LocalGuid.Data3, sizeof (LocalGuid.Data3)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data3)] != L'-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data3 = SwapBytes16 (LocalGuid.Data3); + String += 2 * sizeof (LocalGuid.Data3) + 1; + + // + // Get iijj. + // + Status = StrHexToBytes (String, 2 * 2, &LocalGuid.Data4[0], 2); + if (RETURN_ERROR (Status) || String[2 * 2] != L'-') { + return RETURN_UNSUPPORTED; + } + String += 2 * 2 + 1; + + // + // Get kkllmmnnoopp. + // + Status = StrHexToBytes (String, 2 * 6, &LocalGuid.Data4[2], 6); + if (RETURN_ERROR (Status)) { + return RETURN_UNSUPPORTED; + } + + CopyGuid (Guid, &LocalGuid); + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode hexadecimal string to a byte array. + + This function outputs a byte array by interpreting the contents of + the Unicode string specified by String in hexadecimal format. The format of + the input Unicode string String is: + + [XX]* + + X is a hexadecimal digit character in the range [0-9], [a-f] and [A-F]. + The function decodes every two hexadecimal digit characters as one byte. The + decoding stops after Length of characters and outputs Buffer containing + (Length / 2) bytes. + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + @param String Pointer to a Null-terminated Unicode string. + @param Length The number of Unicode characters to decode. + @param Buffer Pointer to the converted bytes array. + @param MaxBufferSize The maximum size of Buffer. + + @retval RETURN_SUCCESS Buffer is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If Length is not multiple of 2. + If PcdMaximumUnicodeStringLength is not zero, + and Length is greater than + PcdMaximumUnicodeStringLength. + @retval RETURN_UNSUPPORTED If Length of characters from String contain + a character that is not valid hexadecimal + digit characters, or a Null-terminator. + @retval RETURN_BUFFER_TOO_SMALL If MaxBufferSize is less than (Length / 2). +**/ +RETURN_STATUS +EFIAPI +StrHexToBytes ( + IN CONST CHAR16 *String, + IN UINTN Length, + OUT UINT8 *Buffer, + IN UINTN MaxBufferSize + ) +{ + UINTN Index; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Buffer shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Buffer != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Length shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. Length shall not be odd. + // + SAFE_STRING_CONSTRAINT_CHECK (((Length & BIT0) == 0), RETURN_INVALID_PARAMETER); + + // + // 4. MaxBufferSize shall equal to or greater than Length / 2. + // + SAFE_STRING_CONSTRAINT_CHECK ((MaxBufferSize >= Length / 2), RETURN_BUFFER_TOO_SMALL); + + // + // 5. String shall not contains invalid hexadecimal digits. + // + for (Index = 0; Index < Length; Index++) { + if (!InternalIsHexaDecimalDigitCharacter (String[Index])) { + break; + } + } + if (Index != Length) { + return RETURN_UNSUPPORTED; + } + + // + // Convert the hex string to bytes. + // + for(Index = 0; Index < Length; Index++) { + + // + // For even characters, write the upper nibble for each buffer byte, + // and for even characters, the lower nibble. + // + if ((Index & BIT0) == 0) { + Buffer[Index / 2] = (UINT8) InternalHexCharToUintn (String[Index]) << 4; + } else { + Buffer[Index / 2] |= (UINT8) InternalHexCharToUintn (String[Index]); + } + } + return RETURN_SUCCESS; +} + +/** + Returns the length of a Null-terminated Ascii string. + + This function is similar as strlen_s defined in C11. + + @param String A pointer to a Null-terminated Ascii string. + @param MaxSize The maximum number of Destination Ascii + char, including terminating null char. + + @retval 0 If String is NULL. + @retval MaxSize If there is no null character in the first MaxSize characters of String. + @return The number of characters that percede the terminating null character. + +**/ +UINTN +EFIAPI +AsciiStrnLenS ( + IN CONST CHAR8 *String, + IN UINTN MaxSize + ) +{ + UINTN Length; + + // + // If String is a null pointer or MaxSize is 0, then the AsciiStrnLenS function returns zero. + // + if ((String == NULL) || (MaxSize == 0)) { + return 0; + } + + // + // Otherwise, the AsciiStrnLenS function returns the number of characters that precede the + // terminating null character. If there is no null character in the first MaxSize characters of + // String then AsciiStrnLenS returns MaxSize. At most the first MaxSize characters of String shall + // be accessed by AsciiStrnLenS. + // + Length = 0; + while (String[Length] != 0) { + if (Length >= MaxSize - 1) { + return MaxSize; + } + Length++; + } + return Length; +} + +/** + Returns the size of a Null-terminated Ascii string in bytes, including the + Null terminator. + + This function returns the size of the Null-terminated Ascii string specified + by String in bytes, including the Null terminator. + + @param String A pointer to a Null-terminated Ascii string. + @param MaxSize The maximum number of Destination Ascii + char, including the Null terminator. + + @retval 0 If String is NULL. + @retval (sizeof (CHAR8) * (MaxSize + 1)) + If there is no Null terminator in the first MaxSize characters of + String. + @return The size of the Null-terminated Ascii string in bytes, including the + Null terminator. + +**/ +UINTN +EFIAPI +AsciiStrnSizeS ( + IN CONST CHAR8 *String, + IN UINTN MaxSize + ) +{ + // + // If String is a null pointer, then the AsciiStrnSizeS function returns + // zero. + // + if (String == NULL) { + return 0; + } + + // + // Otherwise, the AsciiStrnSizeS function returns the size of the + // Null-terminated Ascii string in bytes, including the Null terminator. If + // there is no Null terminator in the first MaxSize characters of String, + // then AsciiStrnSizeS returns (sizeof (CHAR8) * (MaxSize + 1)) to keep a + // consistent map with the AsciiStrnLenS function. + // + return (AsciiStrnLenS (String, MaxSize) + 1) * sizeof (*String); +} + +/** + Copies the string pointed to by Source (including the terminating null char) + to the array pointed to by Destination. + + This function is similar as strcpy_s defined in C11. + + If an error is returned, then the Destination is unmodified. + + @param Destination A pointer to a Null-terminated Ascii string. + @param DestMax The maximum number of Destination Ascii + char, including terminating null char. + @param Source A pointer to a Null-terminated Ascii string. + + @retval RETURN_SUCCESS String is copied. + @retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than StrLen(Source). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumAsciiStringLength is not zero, + and DestMax is greater than + PcdMaximumAsciiStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. +**/ +RETURN_STATUS +EFIAPI +AsciiStrCpyS ( + OUT CHAR8 *Destination, + IN UINTN DestMax, + IN CONST CHAR8 *Source + ) +{ + UINTN SourceLen; + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than ASCII_RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. DestMax shall be greater than AsciiStrnLenS(Source, DestMax). + // + SourceLen = AsciiStrnLenS (Source, DestMax); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 5. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoAsciiStrOverlap (Destination, DestMax, (CHAR8 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The AsciiStrCpyS function copies the string pointed to by Source (including the terminating + // null character) into the array pointed to by Destination. + // + while (*Source != 0) { + *(Destination++) = *(Source++); + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Copies not more than Length successive char from the string pointed to by + Source to the array pointed to by Destination. If no null char is copied from + Source, then Destination[Length] is always set to null. + + This function is similar as strncpy_s defined in C11. + + If an error is returned, then the Destination is unmodified. + + @param Destination A pointer to a Null-terminated Ascii string. + @param DestMax The maximum number of Destination Ascii + char, including terminating null char. + @param Source A pointer to a Null-terminated Ascii string. + @param Length The maximum number of Ascii characters to copy. + + @retval RETURN_SUCCESS String is copied. + @retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than + MIN(StrLen(Source), Length). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumAsciiStringLength is not zero, + and DestMax is greater than + PcdMaximumAsciiStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. +**/ +RETURN_STATUS +EFIAPI +AsciiStrnCpyS ( + OUT CHAR8 *Destination, + IN UINTN DestMax, + IN CONST CHAR8 *Source, + IN UINTN Length + ) +{ + UINTN SourceLen; + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Neither DestMax nor Length shall be greater than ASCII_RSIZE_MAX + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Length <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. If Length is not less than DestMax, then DestMax shall be greater than AsciiStrnLenS(Source, DestMax). + // + SourceLen = AsciiStrnLenS (Source, MIN (DestMax, Length)); + if (Length >= DestMax) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + } + + // + // 5. Copying shall not take place between objects that overlap. + // + if (SourceLen > Length) { + SourceLen = Length; + } + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoAsciiStrOverlap (Destination, DestMax, (CHAR8 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The AsciiStrnCpyS function copies not more than Length successive characters (characters that + // follow a null character are not copied) from the array pointed to by Source to the array + // pointed to by Destination. If no null character was copied from Source, then Destination[Length] is set to a null + // character. + // + while ((SourceLen > 0) && (*Source != 0)) { + *(Destination++) = *(Source++); + SourceLen--; + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Appends a copy of the string pointed to by Source (including the terminating + null char) to the end of the string pointed to by Destination. + + This function is similar as strcat_s defined in C11. + + If an error is returned, then the Destination is unmodified. + + @param Destination A pointer to a Null-terminated Ascii string. + @param DestMax The maximum number of Destination Ascii + char, including terminating null char. + @param Source A pointer to a Null-terminated Ascii string. + + @retval RETURN_SUCCESS String is appended. + @retval RETURN_BAD_BUFFER_SIZE If DestMax is NOT greater than + StrLen(Destination). + @retval RETURN_BUFFER_TOO_SMALL If (DestMax - StrLen(Destination)) is NOT + greater than StrLen(Source). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumAsciiStringLength is not zero, + and DestMax is greater than + PcdMaximumAsciiStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. +**/ +RETURN_STATUS +EFIAPI +AsciiStrCatS ( + IN OUT CHAR8 *Destination, + IN UINTN DestMax, + IN CONST CHAR8 *Source + ) +{ + UINTN DestLen; + UINTN CopyLen; + UINTN SourceLen; + + // + // Let CopyLen denote the value DestMax - AsciiStrnLenS(Destination, DestMax) upon entry to AsciiStrCatS. + // + DestLen = AsciiStrnLenS (Destination, DestMax); + CopyLen = DestMax - DestLen; + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than ASCII_RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. CopyLen shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((CopyLen != 0), RETURN_BAD_BUFFER_SIZE); + + // + // 5. CopyLen shall be greater than AsciiStrnLenS(Source, CopyLen). + // + SourceLen = AsciiStrnLenS (Source, CopyLen); + SAFE_STRING_CONSTRAINT_CHECK ((CopyLen > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 6. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoAsciiStrOverlap (Destination, DestMax, (CHAR8 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The AsciiStrCatS function appends a copy of the string pointed to by Source (including the + // terminating null character) to the end of the string pointed to by Destination. The initial character + // from Source overwrites the null character at the end of Destination. + // + Destination = Destination + DestLen; + while (*Source != 0) { + *(Destination++) = *(Source++); + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Appends not more than Length successive char from the string pointed to by + Source to the end of the string pointed to by Destination. If no null char is + copied from Source, then Destination[StrLen(Destination) + Length] is always + set to null. + + This function is similar as strncat_s defined in C11. + + If an error is returned, then the Destination is unmodified. + + @param Destination A pointer to a Null-terminated Ascii string. + @param DestMax The maximum number of Destination Ascii + char, including terminating null char. + @param Source A pointer to a Null-terminated Ascii string. + @param Length The maximum number of Ascii characters to copy. + + @retval RETURN_SUCCESS String is appended. + @retval RETURN_BAD_BUFFER_SIZE If DestMax is NOT greater than + StrLen(Destination). + @retval RETURN_BUFFER_TOO_SMALL If (DestMax - StrLen(Destination)) is NOT + greater than MIN(StrLen(Source), Length). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumAsciiStringLength is not zero, + and DestMax is greater than + PcdMaximumAsciiStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. +**/ +RETURN_STATUS +EFIAPI +AsciiStrnCatS ( + IN OUT CHAR8 *Destination, + IN UINTN DestMax, + IN CONST CHAR8 *Source, + IN UINTN Length + ) +{ + UINTN DestLen; + UINTN CopyLen; + UINTN SourceLen; + + // + // Let CopyLen denote the value DestMax - AsciiStrnLenS(Destination, DestMax) upon entry to AsciiStrnCatS. + // + DestLen = AsciiStrnLenS (Destination, DestMax); + CopyLen = DestMax - DestLen; + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Neither DestMax nor Length shall be greater than ASCII_RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Length <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. CopyLen shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((CopyLen != 0), RETURN_BAD_BUFFER_SIZE); + + // + // 5. If Length is not less than CopyLen, then CopyLen shall be greater than AsciiStrnLenS(Source, CopyLen). + // + SourceLen = AsciiStrnLenS (Source, MIN (CopyLen, Length)); + if (Length >= CopyLen) { + SAFE_STRING_CONSTRAINT_CHECK ((CopyLen > SourceLen), RETURN_BUFFER_TOO_SMALL); + } + + // + // 6. Copying shall not take place between objects that overlap. + // + if (SourceLen > Length) { + SourceLen = Length; + } + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoAsciiStrOverlap (Destination, DestMax, (CHAR8 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The AsciiStrnCatS function appends not more than Length successive characters (characters + // that follow a null character are not copied) from the array pointed to by Source to the end of + // the string pointed to by Destination. The initial character from Source overwrites the null character at + // the end of Destination. If no null character was copied from Source, then Destination[DestMax-CopyLen+Length] is set to + // a null character. + // + Destination = Destination + DestLen; + while ((SourceLen > 0) && (*Source != 0)) { + *(Destination++) = *(Source++); + SourceLen--; + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Ascii decimal string to a value of type UINTN. + + This function outputs a value of type UINTN by interpreting the contents of + the Ascii string specified by String as a decimal number. The format of the + input Ascii string String is: + + [spaces] [decimal digits]. + + The valid decimal digit character is in the range [0-9]. The function will + ignore the pad space, which includes spaces or tab characters, before + [decimal digits]. The running zero in the beginning of [decimal digits] will + be ignored. Then, the function stops at the first character that is a not a + valid decimal character or a Null-terminator, whichever one comes first. + + If String has no valid decimal digits in the above format, then 0 is stored + at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINTN, then + MAX_UINTN is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + decimal digits right after the optional pad spaces, the value of String is + stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Ascii string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumAsciiStringLength is not zero, + and String contains more than + PcdMaximumAsciiStringLength Ascii + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINTN. + +**/ +RETURN_STATUS +EFIAPI +AsciiStrDecimalToUintnS ( + IN CONST CHAR8 *String, + OUT CHAR8 **EndPointer, OPTIONAL + OUT UINTN *Data + ) +{ + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than ASCII_RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((AsciiStrnLenS (String, ASCII_RSIZE_MAX + 1) <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == ' ') || (*String == '\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == '0') { + String++; + } + + *Data = 0; + + while (InternalAsciiIsDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINTN, then MAX_UINTN is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > ((MAX_UINTN - (*String - '0')) / 10)) { + *Data = MAX_UINTN; + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = *Data * 10 + (*String - '0'); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Ascii decimal string to a value of type UINT64. + + This function outputs a value of type UINT64 by interpreting the contents of + the Ascii string specified by String as a decimal number. The format of the + input Ascii string String is: + + [spaces] [decimal digits]. + + The valid decimal digit character is in the range [0-9]. The function will + ignore the pad space, which includes spaces or tab characters, before + [decimal digits]. The running zero in the beginning of [decimal digits] will + be ignored. Then, the function stops at the first character that is a not a + valid decimal character or a Null-terminator, whichever one comes first. + + If String has no valid decimal digits in the above format, then 0 is stored + at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINT64, then + MAX_UINT64 is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + decimal digits right after the optional pad spaces, the value of String is + stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Ascii string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumAsciiStringLength is not zero, + and String contains more than + PcdMaximumAsciiStringLength Ascii + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINT64. + +**/ +RETURN_STATUS +EFIAPI +AsciiStrDecimalToUint64S ( + IN CONST CHAR8 *String, + OUT CHAR8 **EndPointer, OPTIONAL + OUT UINT64 *Data + ) +{ + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than ASCII_RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((AsciiStrnLenS (String, ASCII_RSIZE_MAX + 1) <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == ' ') || (*String == '\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == '0') { + String++; + } + + *Data = 0; + + while (InternalAsciiIsDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINT64, then MAX_UINT64 is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > DivU64x32 (MAX_UINT64 - (*String - '0'), 10)) { + *Data = MAX_UINT64; + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = MultU64x32 (*Data, 10) + (*String - '0'); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Ascii hexadecimal string to a value of type UINTN. + + This function outputs a value of type UINTN by interpreting the contents of + the Ascii string specified by String as a hexadecimal number. The format of + the input Ascii string String is: + + [spaces][zeros][x][hexadecimal digits]. + + The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F]. + The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix. If + "x" appears in the input string, it must be prefixed with at least one 0. The + function will ignore the pad space, which includes spaces or tab characters, + before [zeros], [x] or [hexadecimal digits]. The running zero before [x] or + [hexadecimal digits] will be ignored. Then, the decoding starts after [x] or + the first valid hexadecimal digit. Then, the function stops at the first + character that is a not a valid hexadecimal character or Null-terminator, + whichever on comes first. + + If String has no valid hexadecimal digits in the above format, then 0 is + stored at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINTN, then + MAX_UINTN is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + hexadecimal digits right after the optional pad spaces, the value of String + is stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Ascii string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumAsciiStringLength is not zero, + and String contains more than + PcdMaximumAsciiStringLength Ascii + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINTN. + +**/ +RETURN_STATUS +EFIAPI +AsciiStrHexToUintnS ( + IN CONST CHAR8 *String, + OUT CHAR8 **EndPointer, OPTIONAL + OUT UINTN *Data + ) +{ + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than ASCII_RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((AsciiStrnLenS (String, ASCII_RSIZE_MAX + 1) <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == ' ') || (*String == '\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == '0') { + String++; + } + + if (AsciiCharToUpper (*String) == 'X') { + if (*(String - 1) != '0') { + *Data = 0; + return RETURN_SUCCESS; + } + // + // Skip the 'X' + // + String++; + } + + *Data = 0; + + while (InternalAsciiIsHexaDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINTN, then MAX_UINTN is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > ((MAX_UINTN - InternalAsciiHexCharToUintn (*String)) >> 4)) { + *Data = MAX_UINTN; + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = (*Data << 4) + InternalAsciiHexCharToUintn (*String); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Ascii hexadecimal string to a value of type UINT64. + + This function outputs a value of type UINT64 by interpreting the contents of + the Ascii string specified by String as a hexadecimal number. The format of + the input Ascii string String is: + + [spaces][zeros][x][hexadecimal digits]. + + The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F]. + The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix. If + "x" appears in the input string, it must be prefixed with at least one 0. The + function will ignore the pad space, which includes spaces or tab characters, + before [zeros], [x] or [hexadecimal digits]. The running zero before [x] or + [hexadecimal digits] will be ignored. Then, the decoding starts after [x] or + the first valid hexadecimal digit. Then, the function stops at the first + character that is a not a valid hexadecimal character or Null-terminator, + whichever on comes first. + + If String has no valid hexadecimal digits in the above format, then 0 is + stored at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINT64, then + MAX_UINT64 is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + hexadecimal digits right after the optional pad spaces, the value of String + is stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Ascii string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumAsciiStringLength is not zero, + and String contains more than + PcdMaximumAsciiStringLength Ascii + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINT64. + +**/ +RETURN_STATUS +EFIAPI +AsciiStrHexToUint64S ( + IN CONST CHAR8 *String, + OUT CHAR8 **EndPointer, OPTIONAL + OUT UINT64 *Data + ) +{ + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than ASCII_RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((AsciiStrnLenS (String, ASCII_RSIZE_MAX + 1) <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == ' ') || (*String == '\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == '0') { + String++; + } + + if (AsciiCharToUpper (*String) == 'X') { + if (*(String - 1) != '0') { + *Data = 0; + return RETURN_SUCCESS; + } + // + // Skip the 'X' + // + String++; + } + + *Data = 0; + + while (InternalAsciiIsHexaDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINT64, then MAX_UINT64 is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > RShiftU64 (MAX_UINT64 - InternalAsciiHexCharToUintn (*String), 4)) { + *Data = MAX_UINT64; + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = LShiftU64 (*Data, 4) + InternalAsciiHexCharToUintn (*String); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode string to a Null-terminated + ASCII string. + + This function is similar to AsciiStrCpyS. + + This function converts the content of the Unicode string Source + to the ASCII string Destination by copying the lower 8 bits of + each Unicode character. The function terminates the ASCII string + Destination by appending a Null-terminator character at the end. + + The caller is responsible to make sure Destination points to a buffer with size + equal or greater than ((StrLen (Source) + 1) * sizeof (CHAR8)) in bytes. + + If any Unicode characters in Source contain non-zero value in + the upper 8 bits, then ASSERT(). + + If Source is not aligned on a 16-bit boundary, then ASSERT(). + + If an error is returned, then the Destination is unmodified. + + @param Source The pointer to a Null-terminated Unicode string. + @param Destination The pointer to a Null-terminated ASCII string. + @param DestMax The maximum number of Destination Ascii + char, including terminating null char. + + @retval RETURN_SUCCESS String is converted. + @retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than StrLen(Source). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumAsciiStringLength is not zero, + and DestMax is greater than + PcdMaximumAsciiStringLength. + If PcdMaximumUnicodeStringLength is not zero, + and DestMax is greater than + PcdMaximumUnicodeStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. + +**/ +RETURN_STATUS +EFIAPI +UnicodeStrToAsciiStrS ( + IN CONST CHAR16 *Source, + OUT CHAR8 *Destination, + IN UINTN DestMax + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than ASCII_RSIZE_MAX or RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. DestMax shall be greater than StrnLenS (Source, DestMax). + // + SourceLen = StrnLenS (Source, DestMax); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 5. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax, (VOID *)Source, (SourceLen + 1) * sizeof(CHAR16)), RETURN_ACCESS_DENIED); + + // + // convert string + // + while (*Source != '\0') { + // + // If any Unicode characters in Source contain + // non-zero value in the upper 8 bits, then ASSERT(). + // + ASSERT (*Source < 0x100); + *(Destination++) = (CHAR8) *(Source++); + } + *Destination = '\0'; + + return RETURN_SUCCESS; +} + +/** + Convert not more than Length successive characters from a Null-terminated + Unicode string to a Null-terminated Ascii string. If no null char is copied + from Source, then Destination[Length] is always set to null. + + This function converts not more than Length successive characters from the + Unicode string Source to the Ascii string Destination by copying the lower 8 + bits of each Unicode character. The function terminates the Ascii string + Destination by appending a Null-terminator character at the end. + + The caller is responsible to make sure Destination points to a buffer with + size not smaller than ((MIN(StrLen(Source), Length) + 1) * sizeof (CHAR8)) + in bytes. + + If any Unicode characters in Source contain non-zero value in the upper 8 + bits, then ASSERT(). + If Source is not aligned on a 16-bit boundary, then ASSERT(). + + If an error is returned, then Destination and DestinationLength are + unmodified. + + @param Source The pointer to a Null-terminated Unicode string. + @param Length The maximum number of Unicode characters to + convert. + @param Destination The pointer to a Null-terminated Ascii string. + @param DestMax The maximum number of Destination Ascii char, + including terminating null char. + @param DestinationLength The number of Unicode characters converted. + + @retval RETURN_SUCCESS String is converted. + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If DestinationLength is NULL. + If PcdMaximumAsciiStringLength is not zero, + and Length or DestMax is greater than + PcdMaximumAsciiStringLength. + If PcdMaximumUnicodeStringLength is not + zero, and Length or DestMax is greater than + PcdMaximumUnicodeStringLength. + If DestMax is 0. + @retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than + MIN(StrLen(Source), Length). + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. + +**/ +RETURN_STATUS +EFIAPI +UnicodeStrnToAsciiStrS ( + IN CONST CHAR16 *Source, + IN UINTN Length, + OUT CHAR8 *Destination, + IN UINTN DestMax, + OUT UINTN *DestinationLength + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // 1. None of Destination, Source or DestinationLength shall be a null + // pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((DestinationLength != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Neither Length nor DestMax shall be greater than ASCII_RSIZE_MAX or + // RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((Length <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. If Length is not less than DestMax, then DestMax shall be greater than + // StrnLenS(Source, DestMax). + // + SourceLen = StrnLenS (Source, DestMax); + if (Length >= DestMax) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + } + + // + // 5. Copying shall not take place between objects that overlap. + // + if (SourceLen > Length) { + SourceLen = Length; + } + SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax, (VOID *)Source, (SourceLen + 1) * sizeof(CHAR16)), RETURN_ACCESS_DENIED); + + *DestinationLength = 0; + + // + // Convert string + // + while ((*Source != 0) && (SourceLen > 0)) { + // + // If any Unicode characters in Source contain non-zero value in the upper + // 8 bits, then ASSERT(). + // + ASSERT (*Source < 0x100); + *(Destination++) = (CHAR8) *(Source++); + SourceLen--; + (*DestinationLength)++; + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Convert one Null-terminated ASCII string to a Null-terminated + Unicode string. + + This function is similar to StrCpyS. + + This function converts the contents of the ASCII string Source to the Unicode + string Destination. The function terminates the Unicode string Destination by + appending a Null-terminator character at the end. + + The caller is responsible to make sure Destination points to a buffer with size + equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes. + + If Destination is not aligned on a 16-bit boundary, then ASSERT(). + + If an error is returned, then the Destination is unmodified. + + @param Source The pointer to a Null-terminated ASCII string. + @param Destination The pointer to a Null-terminated Unicode string. + @param DestMax The maximum number of Destination Unicode + char, including terminating null char. + + @retval RETURN_SUCCESS String is converted. + @retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than StrLen(Source). + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If PcdMaximumUnicodeStringLength is not zero, + and DestMax is greater than + PcdMaximumUnicodeStringLength. + If PcdMaximumAsciiStringLength is not zero, + and DestMax is greater than + PcdMaximumAsciiStringLength. + If DestMax is 0. + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. + +**/ +RETURN_STATUS +EFIAPI +AsciiStrToUnicodeStrS ( + IN CONST CHAR8 *Source, + OUT CHAR16 *Destination, + IN UINTN DestMax + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Destination & BIT0) == 0); + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than RSIZE_MAX or ASCII_RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. DestMax shall be greater than AsciiStrnLenS(Source, DestMax). + // + SourceLen = AsciiStrnLenS (Source, DestMax); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 5. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax * sizeof(CHAR16), (VOID *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // Convert string + // + while (*Source != '\0') { + *(Destination++) = (CHAR16)(UINT8)*(Source++); + } + *Destination = '\0'; + + return RETURN_SUCCESS; +} + +/** + Convert not more than Length successive characters from a Null-terminated + Ascii string to a Null-terminated Unicode string. If no null char is copied + from Source, then Destination[Length] is always set to null. + + This function converts not more than Length successive characters from the + Ascii string Source to the Unicode string Destination. The function + terminates the Unicode string Destination by appending a Null-terminator + character at the end. + + The caller is responsible to make sure Destination points to a buffer with + size not smaller than + ((MIN(AsciiStrLen(Source), Length) + 1) * sizeof (CHAR8)) in bytes. + + If Destination is not aligned on a 16-bit boundary, then ASSERT(). + + If an error is returned, then Destination and DestinationLength are + unmodified. + + @param Source The pointer to a Null-terminated Ascii string. + @param Length The maximum number of Ascii characters to convert. + @param Destination The pointer to a Null-terminated Unicode string. + @param DestMax The maximum number of Destination Unicode char, + including terminating null char. + @param DestinationLength The number of Ascii characters converted. + + @retval RETURN_SUCCESS String is converted. + @retval RETURN_INVALID_PARAMETER If Destination is NULL. + If Source is NULL. + If DestinationLength is NULL. + If PcdMaximumUnicodeStringLength is not + zero, and Length or DestMax is greater than + PcdMaximumUnicodeStringLength. + If PcdMaximumAsciiStringLength is not zero, + and Length or DestMax is greater than + PcdMaximumAsciiStringLength. + If DestMax is 0. + @retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than + MIN(AsciiStrLen(Source), Length). + @retval RETURN_ACCESS_DENIED If Source and Destination overlap. + +**/ +RETURN_STATUS +EFIAPI +AsciiStrnToUnicodeStrS ( + IN CONST CHAR8 *Source, + IN UINTN Length, + OUT CHAR16 *Destination, + IN UINTN DestMax, + OUT UINTN *DestinationLength + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Destination & BIT0) == 0); + + // + // 1. None of Destination, Source or DestinationLength shall be a null + // pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((DestinationLength != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Neither Length nor DestMax shall be greater than ASCII_RSIZE_MAX or + // RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((Length <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. If Length is not less than DestMax, then DestMax shall be greater than + // AsciiStrnLenS(Source, DestMax). + // + SourceLen = AsciiStrnLenS (Source, DestMax); + if (Length >= DestMax) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + } + + // + // 5. Copying shall not take place between objects that overlap. + // + if (SourceLen > Length) { + SourceLen = Length; + } + SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax * sizeof(CHAR16), (VOID *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + *DestinationLength = 0; + + // + // Convert string + // + while ((*Source != 0) && (SourceLen > 0)) { + *(Destination++) = (CHAR16)(UINT8)*(Source++); + SourceLen--; + (*DestinationLength)++; + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated ASCII string to IPv6 address and prefix length. + + This function outputs a value of type IPv6_ADDRESS and may output a value + of type UINT8 by interpreting the contents of the ASCII string specified + by String. The format of the input ASCII string String is as follows: + + X:X:X:X:X:X:X:X[/P] + + X contains one to four hexadecimal digit characters in the range [0-9], [a-f] and + [A-F]. X is converted to a value of type UINT16, whose low byte is stored in low + memory address and high byte is stored in high memory address. P contains decimal + digit characters in the range [0-9]. The running zero in the beginning of P will + be ignored. /P is optional. + + When /P is not in the String, the function stops at the first character that is + not a valid hexadecimal digit character after eight X's are converted. + + When /P is in the String, the function stops at the first character that is not + a valid decimal digit character after P is converted. + + "::" can be used to compress one or more groups of X when X contains only 0. + The "::" can only appear once in the String. + + If EndPointer is not NULL and Address is translated from String, a pointer + to the character that stopped the scan is stored at the location pointed to + by EndPointer. + + @param String Pointer to a Null-terminated ASCII string. + @param EndPointer Pointer to character that stops scan. + @param Address Pointer to the converted IPv6 address. + @param PrefixLength Pointer to the converted IPv6 address prefix + length. MAX_UINT8 is returned when /P is + not in the String. + + @retval RETURN_SUCCESS Address is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + @retval RETURN_UNSUPPORTED If X contains more than four hexadecimal + digit characters. + If String contains "::" and number of X + is not less than 8. + If P starts with character that is not a + valid decimal digit character. + If the decimal number converted from P + exceeds 128. + +**/ +RETURN_STATUS +EFIAPI +AsciiStrToIpv6Address ( + IN CONST CHAR8 *String, + OUT CHAR8 **EndPointer, OPTIONAL + OUT IPv6_ADDRESS *Address, + OUT UINT8 *PrefixLength OPTIONAL + ) +{ + RETURN_STATUS Status; + UINTN AddressIndex; + UINTN Uintn; + IPv6_ADDRESS LocalAddress; + UINT8 LocalPrefixLength; + CONST CHAR8 *Pointer; + CHAR8 *End; + UINTN CompressStart; + BOOLEAN ExpectPrefix; + + LocalPrefixLength = MAX_UINT8; + CompressStart = ARRAY_SIZE (Address->Addr); + ExpectPrefix = FALSE; + + // + // None of String or Address shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER); + + for (Pointer = String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) { + if (!InternalAsciiIsHexaDecimalDigitCharacter (*Pointer)) { + if (*Pointer != ':') { + // + // ":" or "/" should be followed by digit characters. + // + return RETURN_UNSUPPORTED; + } + + // + // Meet second ":" after previous ":" or "/" + // or meet first ":" in the beginning of String. + // + if (ExpectPrefix) { + // + // ":" shall not be after "/" + // + return RETURN_UNSUPPORTED; + } + + if (CompressStart != ARRAY_SIZE (Address->Addr) || AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // "::" can only appear once. + // "::" can only appear when address is not full length. + // + return RETURN_UNSUPPORTED; + } else { + // + // Remember the start of zero compressing. + // + CompressStart = AddressIndex; + Pointer++; + + if (CompressStart == 0) { + if (*Pointer != ':') { + // + // Single ":" shall not be in the beginning of String. + // + return RETURN_UNSUPPORTED; + } + Pointer++; + } + } + } + + if (!InternalAsciiIsHexaDecimalDigitCharacter (*Pointer)) { + if (*Pointer == '/') { + // + // Might be optional "/P" after "::". + // + if (CompressStart != AddressIndex) { + return RETURN_UNSUPPORTED; + } + } else { + break; + } + } else { + if (!ExpectPrefix) { + // + // Get X. + // + Status = AsciiStrHexToUintnS (Pointer, &End, &Uintn); + if (RETURN_ERROR (Status) || End - Pointer > 4) { + // + // Number of hexadecimal digit characters is no more than 4. + // + return RETURN_UNSUPPORTED; + } + Pointer = End; + // + // Uintn won't exceed MAX_UINT16 if number of hexadecimal digit characters is no more than 4. + // + ASSERT (AddressIndex + 1 < ARRAY_SIZE (Address->Addr)); + LocalAddress.Addr[AddressIndex] = (UINT8) ((UINT16) Uintn >> 8); + LocalAddress.Addr[AddressIndex + 1] = (UINT8) Uintn; + AddressIndex += 2; + } else { + // + // Get P, then exit the loop. + // + Status = AsciiStrDecimalToUintnS (Pointer, &End, &Uintn); + if (RETURN_ERROR (Status) || End == Pointer || Uintn > 128) { + // + // Prefix length should not exceed 128. + // + return RETURN_UNSUPPORTED; + } + LocalPrefixLength = (UINT8) Uintn; + Pointer = End; + break; + } + } + + // + // Skip ':' or "/" + // + if (*Pointer == '/') { + ExpectPrefix = TRUE; + } else if (*Pointer == ':') { + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // Meet additional ":" after all 8 16-bit address + // + break; + } + } else { + // + // Meet other character that is not "/" or ":" after all 8 16-bit address + // + break; + } + Pointer++; + } + + if ((AddressIndex == ARRAY_SIZE (Address->Addr) && CompressStart != ARRAY_SIZE (Address->Addr)) || + (AddressIndex != ARRAY_SIZE (Address->Addr) && CompressStart == ARRAY_SIZE (Address->Addr)) + ) { + // + // Full length of address shall not have compressing zeros. + // Non-full length of address shall have compressing zeros. + // + return RETURN_UNSUPPORTED; + } + CopyMem (&Address->Addr[0], &LocalAddress.Addr[0], CompressStart); + ZeroMem (&Address->Addr[CompressStart], ARRAY_SIZE (Address->Addr) - AddressIndex); + if (AddressIndex > CompressStart) { + CopyMem ( + &Address->Addr[CompressStart + ARRAY_SIZE (Address->Addr) - AddressIndex], + &LocalAddress.Addr[CompressStart], + AddressIndex - CompressStart + ); + + } + + if (PrefixLength != NULL) { + *PrefixLength = LocalPrefixLength; + } + if (EndPointer != NULL) { + *EndPointer = (CHAR8 *) Pointer; + } + + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated ASCII string to IPv4 address and prefix length. + + This function outputs a value of type IPv4_ADDRESS and may output a value + of type UINT8 by interpreting the contents of the ASCII string specified + by String. The format of the input ASCII string String is as follows: + + D.D.D.D[/P] + + D and P are decimal digit characters in the range [0-9]. The running zero in + the beginning of D and P will be ignored. /P is optional. + + When /P is not in the String, the function stops at the first character that is + not a valid decimal digit character after four D's are converted. + + When /P is in the String, the function stops at the first character that is not + a valid decimal digit character after P is converted. + + If EndPointer is not NULL and Address is translated from String, a pointer + to the character that stopped the scan is stored at the location pointed to + by EndPointer. + + @param String Pointer to a Null-terminated ASCII string. + @param EndPointer Pointer to character that stops scan. + @param Address Pointer to the converted IPv4 address. + @param PrefixLength Pointer to the converted IPv4 address prefix + length. MAX_UINT8 is returned when /P is + not in the String. + + @retval RETURN_SUCCESS Address is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + @retval RETURN_UNSUPPORTED If String is not in the correct format. + If any decimal number converted from D + exceeds 255. + If the decimal number converted from P + exceeds 32. + +**/ +RETURN_STATUS +EFIAPI +AsciiStrToIpv4Address ( + IN CONST CHAR8 *String, + OUT CHAR8 **EndPointer, OPTIONAL + OUT IPv4_ADDRESS *Address, + OUT UINT8 *PrefixLength OPTIONAL + ) +{ + RETURN_STATUS Status; + UINTN AddressIndex; + UINTN Uintn; + IPv4_ADDRESS LocalAddress; + UINT8 LocalPrefixLength; + CHAR8 *Pointer; + + LocalPrefixLength = MAX_UINT8; + + // + // None of String or Address shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER); + + for (Pointer = (CHAR8 *) String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) { + if (!InternalAsciiIsDecimalDigitCharacter (*Pointer)) { + // + // D or P contains invalid characters. + // + break; + } + + // + // Get D or P. + // + Status = AsciiStrDecimalToUintnS ((CONST CHAR8 *) Pointer, &Pointer, &Uintn); + if (RETURN_ERROR (Status)) { + return RETURN_UNSUPPORTED; + } + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // It's P. + // + if (Uintn > 32) { + return RETURN_UNSUPPORTED; + } + LocalPrefixLength = (UINT8) Uintn; + } else { + // + // It's D. + // + if (Uintn > MAX_UINT8) { + return RETURN_UNSUPPORTED; + } + LocalAddress.Addr[AddressIndex] = (UINT8) Uintn; + AddressIndex++; + } + + // + // Check the '.' or '/', depending on the AddressIndex. + // + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + if (*Pointer == '/') { + // + // '/P' is in the String. + // Skip "/" and get P in next loop. + // + Pointer++; + } else { + // + // '/P' is not in the String. + // + break; + } + } else if (AddressIndex < ARRAY_SIZE (Address->Addr)) { + if (*Pointer == '.') { + // + // D should be followed by '.' + // + Pointer++; + } else { + return RETURN_UNSUPPORTED; + } + } + } + + if (AddressIndex < ARRAY_SIZE (Address->Addr)) { + return RETURN_UNSUPPORTED; + } + + CopyMem (Address, &LocalAddress, sizeof (*Address)); + if (PrefixLength != NULL) { + *PrefixLength = LocalPrefixLength; + } + if (EndPointer != NULL) { + *EndPointer = Pointer; + } + + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated ASCII GUID string to a value of type + EFI_GUID. + + This function outputs a GUID value by interpreting the contents of + the ASCII string specified by String. The format of the input + ASCII string String consists of 36 characters, as follows: + + aabbccdd-eeff-gghh-iijj-kkllmmnnoopp + + The pairs aa - pp are two characters in the range [0-9], [a-f] and + [A-F], with each pair representing a single byte hexadecimal value. + + The mapping between String and the EFI_GUID structure is as follows: + aa Data1[24:31] + bb Data1[16:23] + cc Data1[8:15] + dd Data1[0:7] + ee Data2[8:15] + ff Data2[0:7] + gg Data3[8:15] + hh Data3[0:7] + ii Data4[0:7] + jj Data4[8:15] + kk Data4[16:23] + ll Data4[24:31] + mm Data4[32:39] + nn Data4[40:47] + oo Data4[48:55] + pp Data4[56:63] + + @param String Pointer to a Null-terminated ASCII string. + @param Guid Pointer to the converted GUID. + + @retval RETURN_SUCCESS Guid is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + @retval RETURN_UNSUPPORTED If String is not as the above format. + +**/ +RETURN_STATUS +EFIAPI +AsciiStrToGuid ( + IN CONST CHAR8 *String, + OUT GUID *Guid + ) +{ + RETURN_STATUS Status; + GUID LocalGuid; + + // + // None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Guid != NULL), RETURN_INVALID_PARAMETER); + + // + // Get aabbccdd in big-endian. + // + Status = AsciiStrHexToBytes (String, 2 * sizeof (LocalGuid.Data1), (UINT8 *) &LocalGuid.Data1, sizeof (LocalGuid.Data1)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data1)] != '-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data1 = SwapBytes32 (LocalGuid.Data1); + String += 2 * sizeof (LocalGuid.Data1) + 1; + + // + // Get eeff in big-endian. + // + Status = AsciiStrHexToBytes (String, 2 * sizeof (LocalGuid.Data2), (UINT8 *) &LocalGuid.Data2, sizeof (LocalGuid.Data2)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data2)] != '-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data2 = SwapBytes16 (LocalGuid.Data2); + String += 2 * sizeof (LocalGuid.Data2) + 1; + + // + // Get gghh in big-endian. + // + Status = AsciiStrHexToBytes (String, 2 * sizeof (LocalGuid.Data3), (UINT8 *) &LocalGuid.Data3, sizeof (LocalGuid.Data3)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data3)] != '-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data3 = SwapBytes16 (LocalGuid.Data3); + String += 2 * sizeof (LocalGuid.Data3) + 1; + + // + // Get iijj. + // + Status = AsciiStrHexToBytes (String, 2 * 2, &LocalGuid.Data4[0], 2); + if (RETURN_ERROR (Status) || String[2 * 2] != '-') { + return RETURN_UNSUPPORTED; + } + String += 2 * 2 + 1; + + // + // Get kkllmmnnoopp. + // + Status = AsciiStrHexToBytes (String, 2 * 6, &LocalGuid.Data4[2], 6); + if (RETURN_ERROR (Status)) { + return RETURN_UNSUPPORTED; + } + + CopyGuid (Guid, &LocalGuid); + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated ASCII hexadecimal string to a byte array. + + This function outputs a byte array by interpreting the contents of + the ASCII string specified by String in hexadecimal format. The format of + the input ASCII string String is: + + [XX]* + + X is a hexadecimal digit character in the range [0-9], [a-f] and [A-F]. + The function decodes every two hexadecimal digit characters as one byte. The + decoding stops after Length of characters and outputs Buffer containing + (Length / 2) bytes. + + @param String Pointer to a Null-terminated ASCII string. + @param Length The number of ASCII characters to decode. + @param Buffer Pointer to the converted bytes array. + @param MaxBufferSize The maximum size of Buffer. + + @retval RETURN_SUCCESS Buffer is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If Length is not multiple of 2. + If PcdMaximumAsciiStringLength is not zero, + and Length is greater than + PcdMaximumAsciiStringLength. + @retval RETURN_UNSUPPORTED If Length of characters from String contain + a character that is not valid hexadecimal + digit characters, or a Null-terminator. + @retval RETURN_BUFFER_TOO_SMALL If MaxBufferSize is less than (Length / 2). +**/ +RETURN_STATUS +EFIAPI +AsciiStrHexToBytes ( + IN CONST CHAR8 *String, + IN UINTN Length, + OUT UINT8 *Buffer, + IN UINTN MaxBufferSize + ) +{ + UINTN Index; + + // + // 1. None of String or Buffer shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Buffer != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Length shall not be greater than ASCII_RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((Length <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. Length shall not be odd. + // + SAFE_STRING_CONSTRAINT_CHECK (((Length & BIT0) == 0), RETURN_INVALID_PARAMETER); + + // + // 4. MaxBufferSize shall equal to or greater than Length / 2. + // + SAFE_STRING_CONSTRAINT_CHECK ((MaxBufferSize >= Length / 2), RETURN_BUFFER_TOO_SMALL); + + // + // 5. String shall not contains invalid hexadecimal digits. + // + for (Index = 0; Index < Length; Index++) { + if (!InternalAsciiIsHexaDecimalDigitCharacter (String[Index])) { + break; + } + } + if (Index != Length) { + return RETURN_UNSUPPORTED; + } + + // + // Convert the hex string to bytes. + // + for(Index = 0; Index < Length; Index++) { + + // + // For even characters, write the upper nibble for each buffer byte, + // and for even characters, the lower nibble. + // + if ((Index & BIT0) == 0) { + Buffer[Index / 2] = (UINT8) InternalAsciiHexCharToUintn (String[Index]) << 4; + } else { + Buffer[Index / 2] |= (UINT8) InternalAsciiHexCharToUintn (String[Index]); + } + } + return RETURN_SUCCESS; +} + -- cgit