text: /** @file
    Unicode and ASCII string primitives.
  
    Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
    SPDX-License-Identifier: BSD-2-Clause-Patent
  
  **/
  
  #include "BaseLibInternals.h"
  
  
  /**
    Returns the length of a Null-terminated Unicode string.
  
    This function returns the number of Unicode characters in the Null-terminated
    Unicode string specified by String.
  
    If String is NULL, then ASSERT().
    If String is not aligned on a 16-bit boundary, then ASSERT().
    If PcdMaximumUnicodeStringLength is not zero, and String contains more than
    PcdMaximumUnicodeStringLength Unicode characters, not including the
    Null-terminator, then ASSERT().
  
    @param  String  A pointer to a Null-terminated Unicode string.
  
    @return The length of String.
  
  **/
  UINTN
  EFIAPI
  StrLen (
    IN      CONST CHAR16              *String
    )
  {
    UINTN                             Length;
  
    ASSERT (String != NULL);
    ASSERT (((UINTN) String & BIT0) == 0);
  
    for (Length = 0; *String != L'\0'; String++, Length++) {
      //
      // If PcdMaximumUnicodeStringLength is not zero,
      // length should not more than PcdMaximumUnicodeStringLength
      //
      if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) {
        ASSERT (Length < PcdGet32 (PcdMaximumUnicodeStringLength));
      }
    }
    return Length;
  }
  
  /**
    Returns the size of a Null-terminated Unicode string in bytes, including the
    Null terminator.
  
    This function returns the size, in bytes, of the Null-terminated Unicode string
    specified by String.
  
    If String is NULL, then ASSERT().
    If String is not aligned on a 16-bit boundary, then ASSERT().
    If PcdMaximumUnicodeStringLength is not zero, and String contains more than
    PcdMaximumUnicodeStringLength Unicode characters, not including the
    Null-terminator, then ASSERT().
  
    @param  String  A pointer to a Null-terminated Unicode string.
  
    @return The size of String.
  
  **/
  UINTN
  EFIAPI
  StrSize (
    IN      CONST CHAR16              *String
    )
  {
    return (StrLen (String) + 1) * sizeof (*String);
  }
  
  /**
    Compares two Null-terminated Unicode strings, and returns the difference
    between the first mismatched Unicode characters.
  
    This function compares the Null-terminated Unicode string FirstString to the
    Null-terminated Unicode string SecondString. If FirstString is identical to
    SecondString, then 0 is returned. Otherwise, the value returned is the first
    mismatched Unicode character in SecondString subtracted from the first
    mismatched Unicode character in FirstString.
  
    If FirstString is NULL, then ASSERT().
    If FirstString is not aligned on a 16-bit boundary, then ASSERT().
    If SecondString is NULL, then ASSERT().
    If SecondString is not aligned on a 16-bit boundary, then ASSERT().
    If PcdMaximumUnicodeStringLength is not zero, and FirstString contains more
    than PcdMaximumUnicodeStringLength Unicode characters, not including the
    Null-terminator, then ASSERT().
    If PcdMaximumUnicodeStringLength is not zero, and SecondString contains more
    than PcdMaximumUnicodeStringLength Unicode characters, not including the
    Null-terminator, then ASSERT().
  
    @param  FirstString   A pointer to a Null-terminated Unicode string.
    @param  SecondString  A pointer to a Null-terminated Unicode string.
  
    @retval 0      FirstString is identical to SecondString.
    @return others FirstString is not identical to SecondString.
  
  **/
  INTN
  EFIAPI
  StrCmp (
    IN      CONST CHAR16              *FirstString,
    IN      CONST CHAR16              *SecondString
    )
  {
    //
    // ASSERT both strings are less long than PcdMaximumUnicodeStringLength
    //
    ASSERT (StrSize (FirstString) != 0);
    ASSERT (StrSize (SecondString) != 0);
  
    while ((*FirstString != L'\0') && (*FirstString == *SecondString)) {
      FirstString++;
      SecondString++;
    }
    return *FirstString - *SecondString;
  }
  
  /**
    Compares up to a specified length the contents of two Null-terminated Unicode strings,
    and returns the difference between the first mismatched Unicode characters.
  
    This function compares the Null-terminated Unicode string FirstString to the
    Null-terminated Unicode string SecondString. At most, Length Unicode
    characters will be compared. If Length is 0, then 0 is returned. If
    FirstString is identical to SecondString, then 0 is returned. Otherwise, the
    value returned is the first mismatched Unicode character in SecondString
    subtracted from the first mismatched Unicode character in FirstString.
  
    If Length > 0 and FirstString is NULL, then ASSERT().
    If Length > 0 and FirstString is not aligned on a 16-bit boundary, then ASSERT().
    If Length > 0 and SecondString is NULL, then ASSERT().
    If Length > 0 and SecondString is not aligned on a 16-bit boundary, then ASSERT().
    If PcdMaximumUnicodeStringLength is not zero, and Length is greater than
    PcdMaximumUnicodeStringLength, then ASSERT().
    If PcdMaximumUnicodeStringLength is not zero, and FirstString contains more than
    PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
    then ASSERT().
    If PcdMaximumUnicodeStringLength is not zero, and SecondString contains more than
    PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
    then ASSERT().
  
    @param  FirstString   A pointer to a Null-terminated Unicode string.
    @param  SecondString  A pointer to a Null-terminated Unicode string.
    @param  Length        The maximum number of Unicode characters to compare.
  
    @retval 0      FirstString is identical to SecondString.
    @return others FirstString is not identical to SecondString.
  
  **/
  INTN
  EFIAPI
  StrnCmp (
    IN      CONST CHAR16              *FirstString,
    IN      CONST CHAR16              *SecondString,
    IN      UINTN                     Length
    )
  {
    if (Length == 0) {
      return 0;
    }
  
    //
    // ASSERT both strings are less long than PcdMaximumUnicodeStringLength.
    // Length tests are performed inside StrLen().
    //
    ASSERT (StrSize (FirstString) != 0);
    ASSERT (StrSize (SecondString) != 0);
  
    if (PcdGet32 (PcdMaximumUnicodeStringLength) != 0) {
      ASSERT (Length <= PcdGet32 (PcdMaximumUnicodeStringLength));
    }
  
    while ((*FirstString != L'\0') &&
           (*SecondString != L'\0') &&
           (*FirstString == *SecondString) &&
           (Length > 1)) {
      FirstString++;
      SecondString++;
      Length--;
    }
  
    return *FirstString - *SecondString;
  }
  
  
  /**
    Returns the first occurrence of a Null-terminated Unicode sub-string
    in a Null-terminated Unicode string.
  
    This function scans the contents of the Null-terminated Unicode string
    specified by String and returns the first occurrence of SearchString.
    If SearchString is not found in String, then NULL is returned.  If
    the length of SearchString is zero, then String is
    returned.
  
    If String is NULL, then ASSERT().
    If String is not aligned on a 16-bit boundary, then ASSERT().
    If SearchString is NULL, then ASSERT().
    If SearchString is not aligned on a 16-bit boundary, then ASSERT().
  
    If PcdMaximumUnicodeStringLength is not zero, and SearchString
    or String contains more than PcdMaximumUnicodeStringLength Unicode
    characters, not including the Null-terminator, then ASSERT().
  
    @param  String          A pointer to a Null-terminated Unicode string.
    @param  SearchString    A pointer to a Null-terminated Unicode string to search for.
  
    @retval NULL            If the SearchString does not appear in String.
    @return others          If there is a match.
  
  **/
  CHAR16 *
  EFIAPI
  StrStr (
    IN      CONST CHAR16              *String,
    IN      CONST CHAR16              *SearchString
    )
  {
    CONST CHAR16 *FirstMatch;
    CONST CHAR16 *SearchStringTmp;
  
    //
    // ASSERT both strings are less long than PcdMaximumUnicodeStringLength.
    // Length tests are performed inside StrLen().
    //
    ASSERT (StrSize (String) != 0);
    ASSERT (StrSize (SearchString) != 0);
  
    if (*SearchString == L'\0') {
      return (CHAR16 *) String;
    }
  
    while (*String != L'\0') {
      SearchStringTmp = SearchString;
      FirstMatch = String;
  
      while ((*String == *SearchStringTmp)
              && (*String != L'\0')) {
        String++;
        SearchStringTmp++;
      }
  
      if (*SearchStringTmp == L'\0') {
        return (CHAR16 *) FirstMatch;
      }
  
      if (*String == L'\0') {
        return NULL;
      }
  
      String = FirstMatch + 1;
    }
  
    return NULL;
  }
  
  /**
    Check if a Unicode character is a decimal character.
  
    This internal function checks if a Unicode character is a
    decimal character. The valid decimal character is from
    L'0' to L'9'.
  
    @param  Char  The character to check against.
  
    @retval TRUE  If the Char is a decmial character.
    @retval FALSE If the Char is not a decmial character.
  
  **/
  BOOLEAN
  EFIAPI
  InternalIsDecimalDigitCharacter (
    IN      CHAR16                    Char
    )
  {
    return (BOOLEAN) (Char >= L'0' && Char <= L'9');
  }
  
  /**
    Convert a Unicode character to upper case only if
    it maps to a valid small-case ASCII character.
  
    This internal function only deal with Unicode character
    which maps to a valid small-case ASCII character, i.e.
    L'a' to L'z'. For other Unicode character, the input character
    is returned directly.
  
    @param  Char  The character to convert.
  
    @retval LowerCharacter   If the Char is with range L'a' to L'z'.
    @retval Unchanged        Otherwise.
  
  **/
  CHAR16
  EFIAPI
  CharToUpper (
    IN      CHAR16                    Char
    )
  {
    if (Char >= L'a' && Char <= L'z') {
      return (CHAR16) (Char - (L'a' - L'A'));
    }
  
    return Char;
  }
  
  /**
    Convert a Unicode character to numerical value.
  
    This internal function only deal with Unicode character
    which maps to a valid hexadecimal ASII character, i.e.
    L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
    Unicode character, the value returned does not make sense.
  
    @param  Char  The character to convert.
  
    @return The numerical value converted.
  
  **/
  UINTN
  EFIAPI
  InternalHexCharToUintn (
    IN      CHAR16                    Char
    )
  {
    if (InternalIsDecimalDigitCharacter (Char)) {
      return Char - L'0';
    }
  
    return (10 + CharToUpper (Char) - L'A');
  }
  
  /**
    Check if a Unicode character is a hexadecimal character.
  
    This internal function checks if a Unicode character is a
    decimal character.  The valid hexadecimal character is
    L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
  
  
    @param  Char  The character to check against.
  
    @retval TRUE  If the Char is a hexadecmial character.
    @retval FALSE If the Char is not a hexadecmial character.
  
  **/
  BOOLEAN
  EFIAPI
  InternalIsHexaDecimalDigitCharacter (
    IN      CHAR16                    Char
    )
  {
  
    return (BOOLEAN) (InternalIsDecimalDigitCharacter (Char) ||
      (Char >= L'A' && Char <= L'F') ||
      (Char >= L'a' && Char <= L'f'));
  }
  
  /**
    Convert a Null-terminated Unicode decimal string to a value of
    type UINTN.
  
    This function returns 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 NULL, then ASSERT().
    If String is not aligned in a 16-bit boundary, then ASSERT().
    If String has only pad spaces, then 0 is returned.
    If String has no pad spaces or valid decimal digits,
    then 0 is returned.
    If the number represented by String overflows according
    to the range defined by UINTN, then MAX_UINTN is returned.
  
    If PcdMaximumUnicodeStringLength is not zero, and String contains
    more than PcdMaximumUnicodeStringLength Unicode characters, not including
    the Null-terminator, then ASSERT().
  
    @param  String      A pointer to a Null-terminated Unicode string.
  
    @retval Value translated from String.
  
  **/
  UINTN
  EFIAPI
  StrDecimalToUintn (
    IN      CONST CHAR16              *String
    )
  {
    UINTN     Result;
  
    StrDecimalToUintnS (String, (CHAR16 **) NULL, &Result);
    return Result;
  }
  
  
  /**
    Convert a Null-terminated Unicode decimal string to a value of
    type UINT64.
  
    This function returns 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 NULL, then ASSERT().
    If String is not aligned in a 16-bit boundary, then ASSERT().
    If String has only pad spaces, then 0 is returned.
    If String has no pad spaces or valid decimal digits,
    then 0 is returned.
    If the number represented by String overflows according
    to the range defined by UINT64, then MAX_UINT64 is returned.
  
    If PcdMaximumUnicodeStringLength is not zero, and String contains
    more than PcdMaximumUnicodeStringLength Unicode characters, not including
    the Null-terminator, then ASSERT().
  
    @param  String          A pointer to a Null-terminated Unicode string.
  
    @retval Value translated from String.
  
  **/
  UINT64
  EFIAPI
  StrDecimalToUint64 (
    IN      CONST CHAR16              *String
    )
  {
    UINT64     Result;
  
    StrDecimalToUint64S (String, (CHAR16 **) NULL, &Result);
    return Result;
  }
  
  /**
    Convert a Null-terminated Unicode hexadecimal string to a value of type UINTN.
  
    This function returns 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 NULL, then ASSERT().
    If String is not aligned in a 16-bit boundary, then ASSERT().
    If String has only pad spaces, then zero is returned.
    If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
    then zero is returned.
    If the number represented by String overflows according to the range defined by
    UINTN, then MAX_UINTN is returned.
  
    If PcdMaximumUnicodeStringLength is not zero, and String contains more than
    PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
    then ASSERT().
  
    @param  String          A pointer to a Null-terminated Unicode string.
  
    @retval Value translated from String.
  
  **/
  UINTN
  EFIAPI
  StrHexToUintn (
    IN      CONST CHAR16              *String
    )
  {
    UINTN     Result;
  
    StrHexToUintnS (String, (CHAR16 **) NULL, &Result);
    return Result;
  }
  
  
  /**
    Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
  
    This function returns 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 NULL, then ASSERT().
    If String is not aligned in a 16-bit boundary, then ASSERT().
    If String has only pad spaces, then zero is returned.
    If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
    then zero is returned.
    If the number represented by String overflows according to the range defined by
    UINT64, then MAX_UINT64 is returned.
  
    If PcdMaximumUnicodeStringLength is not zero, and String contains more than
    PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
    then ASSERT().
  
    @param  String          A pointer to a Null-terminated Unicode string.
  
    @retval Value translated from String.
  
  **/
  UINT64
  EFIAPI
  StrHexToUint64 (
    IN      CONST CHAR16             *String
    )
  {
    UINT64    Result;
  
    StrHexToUint64S (String, (CHAR16 **) NULL, &Result);
    return Result;
  }
  
  /**
    Check if a ASCII character is a decimal character.
  
    This internal function checks if a Unicode character is a
    decimal character. The valid decimal character is from
    '0' to '9'.
  
    @param  Char  The character to check against.
  
    @retval TRUE  If the Char is a decmial character.
    @retval FALSE If the Char is not a decmial character.
  
  **/
  BOOLEAN
  EFIAPI
  InternalAsciiIsDecimalDigitCharacter (
    IN      CHAR8                     Char
    )
  {
    return (BOOLEAN) (Char >= '0' && Char <= '9');
  }
  
  /**
    Check if a ASCII character is a hexadecimal character.
  
    This internal function checks if a ASCII character is a
    decimal character.  The valid hexadecimal character is
    L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
  
  
    @param  Char  The character to check against.
  
    @retval TRUE  If the Char is a hexadecmial character.
    @retval FALSE If the Char is not a hexadecmial character.
  
  **/
  BOOLEAN
  EFIAPI
  InternalAsciiIsHexaDecimalDigitCharacter (
    IN      CHAR8                    Char
    )
  {
  
    return (BOOLEAN) (InternalAsciiIsDecimalDigitCharacter (Char) ||
      (Char >= 'A' && Char <= 'F') ||
      (Char >= 'a' && Char <= 'f'));
  }
  
  /**
    Copies up to a specified length one Null-terminated ASCII string to another
    Null-terminated ASCII string and returns the new ASCII string.
  
    This function copies the contents of the ASCII string Source to the ASCII
    string Destination, and returns Destination. At most, Length ASCII characters
    are copied from Source to Destination. If Length is 0, then Destination is
    returned unmodified. If Length is greater that the number of ASCII characters
    in Source, then Destination is padded with Null ASCII characters. If Source
    and Destination overlap, then the results are undefined.
    
    If Destination is NULL, then ASSERT().
    If Source is NULL, then ASSERT().
    If Source and Destination overlap, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero, and Length is greater than
    PcdMaximumAsciiStringLength, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero, and Source contains more than
    PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
    then ASSERT().
    
    @param  Destination A pointer to a Null-terminated ASCII string.
    @param  Source      A pointer to a Null-terminated ASCII string.
    @param  Length      The maximum number of ASCII characters to copy.
    @return Destination
  **/
  CHAR8 *
  EFIAPI
  AsciiStrnCpy (
    OUT     CHAR8                     *Destination,
    IN      CONST CHAR8               *Source,
    IN      UINTN                     Length
    )
  {
    CHAR8                             *ReturnValue;
  
    if (Length == 0) {
      return Destination;
    }
  
    //
    // Destination cannot be NULL
    //
    ASSERT (Destination != NULL);
  
    //
    // Destination and source cannot overlap
    //
    ASSERT ((UINTN)(Destination - Source) > AsciiStrLen (Source));
    ASSERT ((UINTN)(Source - Destination) >= Length);
  
    if (PcdGet32 (PcdMaximumAsciiStringLength) != 0) {
      ASSERT (Length <= PcdGet32 (PcdMaximumAsciiStringLength));
    }
  
    ReturnValue = Destination;
  
    while (*Source != 0 && Length > 0) {
      *(Destination++) = *(Source++);
      Length--;
    }
  
    ZeroMem (Destination, Length * sizeof (*Destination));
    return ReturnValue;
  }
  
  /**
    Returns the length of a Null-terminated ASCII string.
  
    This function returns the number of ASCII characters in the Null-terminated
    ASCII string specified by String.
  
    If Length > 0 and Destination is NULL, then ASSERT().
    If Length > 0 and Source is NULL, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero and String contains more than
    PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
    then ASSERT().
  
    @param  String  A pointer to a Null-terminated ASCII string.
  
    @return The length of String.
  
  **/
  UINTN
  EFIAPI
  AsciiStrLen (
    IN      CONST CHAR8               *String
    )
  {
    UINTN                             Length;
  
    ASSERT (String != NULL);
  
    for (Length = 0; *String != '\0'; String++, Length++) {
      //
      // If PcdMaximumUnicodeStringLength is not zero,
      // length should not more than PcdMaximumUnicodeStringLength
      //
      if (PcdGet32 (PcdMaximumAsciiStringLength) != 0) {
        ASSERT (Length < PcdGet32 (PcdMaximumAsciiStringLength));
      }
    }
    return Length;
  }
  
  /**
    Returns the size of a Null-terminated ASCII string in bytes, including the
    Null terminator.
  
    This function returns the size, in bytes, of the Null-terminated ASCII string
    specified by String.
  
    If String is NULL, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero and String contains more than
    PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
    then ASSERT().
  
    @param  String  A pointer to a Null-terminated ASCII string.
  
    @return The size of String.
  
  **/
  UINTN
  EFIAPI
  AsciiStrSize (
    IN      CONST CHAR8               *String
    )
  {
    return (AsciiStrLen (String) + 1) * sizeof (*String);
  }
  
  /**
    Compares two Null-terminated ASCII strings, and returns the difference
    between the first mismatched ASCII characters.
  
    This function compares the Null-terminated ASCII string FirstString to the
    Null-terminated ASCII string SecondString. If FirstString is identical to
    SecondString, then 0 is returned. Otherwise, the value returned is the first
    mismatched ASCII character in SecondString subtracted from the first
    mismatched ASCII character in FirstString.
  
    If FirstString is NULL, then ASSERT().
    If SecondString is NULL, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero and FirstString contains more than
    PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
    then ASSERT().
    If PcdMaximumAsciiStringLength is not zero and SecondString contains more
    than PcdMaximumAsciiStringLength ASCII characters, not including the
    Null-terminator, then ASSERT().
  
    @param  FirstString   A pointer to a Null-terminated ASCII string.
    @param  SecondString  A pointer to a Null-terminated ASCII string.
  
    @retval ==0      FirstString is identical to SecondString.
    @retval !=0      FirstString is not identical to SecondString.
  
  **/
  INTN
  EFIAPI
  AsciiStrCmp (
    IN      CONST CHAR8               *FirstString,
    IN      CONST CHAR8               *SecondString
    )
  {
    //
    // ASSERT both strings are less long than PcdMaximumAsciiStringLength
    //
    ASSERT (AsciiStrSize (FirstString));
    ASSERT (AsciiStrSize (SecondString));
  
    while ((*FirstString != '\0') && (*FirstString == *SecondString)) {
      FirstString++;
      SecondString++;
    }
  
    return *FirstString - *SecondString;
  }
  
  /**
    Converts a lowercase Ascii character to upper one.
  
    If Chr is lowercase Ascii character, then converts it to upper one.
  
    If Value >= 0xA0, then ASSERT().
    If (Value & 0x0F) >= 0x0A, then ASSERT().
  
    @param  Chr   one Ascii character
  
    @return The uppercase value of Ascii character
  
  **/
  CHAR8
  EFIAPI
  AsciiCharToUpper (
    IN      CHAR8                     Chr
    )
  {
    return (UINT8) ((Chr >= 'a' && Chr <= 'z') ? Chr - ('a' - 'A') : Chr);
  }
  
  /**
    Convert a ASCII character to numerical value.
  
    This internal function only deal with Unicode character
    which maps to a valid hexadecimal ASII character, i.e.
    '0' to '9', 'a' to 'f' or 'A' to 'F'. For other
    ASCII character, the value returned does not make sense.
  
    @param  Char  The character to convert.
  
    @return The numerical value converted.
  
  **/
  UINTN
  EFIAPI
  InternalAsciiHexCharToUintn (
    IN      CHAR8                    Char
    )
  {
    if (InternalIsDecimalDigitCharacter (Char)) {
      return Char - '0';
    }
  
    return (10 + AsciiCharToUpper (Char) - 'A');
  }
  
  
  /**
    Performs a case insensitive comparison of two Null-terminated ASCII strings,
    and returns the difference between the first mismatched ASCII characters.
  
    This function performs a case insensitive comparison of the Null-terminated
    ASCII string FirstString to the Null-terminated ASCII string SecondString. If
    FirstString is identical to SecondString, then 0 is returned. Otherwise, the
    value returned is the first mismatched lower case ASCII character in
    SecondString subtracted from the first mismatched lower case ASCII character
    in FirstString.
  
    If FirstString is NULL, then ASSERT().
    If SecondString is NULL, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero and FirstString contains more than
    PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
    then ASSERT().
    If PcdMaximumAsciiStringLength is not zero and SecondString contains more
    than PcdMaximumAsciiStringLength ASCII characters, not including the
    Null-terminator, then ASSERT().
  
    @param  FirstString   A pointer to a Null-terminated ASCII string.
    @param  SecondString  A pointer to a Null-terminated ASCII string.
  
    @retval ==0    FirstString is identical to SecondString using case insensitive
                   comparisons.
    @retval !=0    FirstString is not identical to SecondString using case
                   insensitive comparisons.
  
  **/
  INTN
  EFIAPI
  AsciiStriCmp (
    IN      CONST CHAR8               *FirstString,
    IN      CONST CHAR8               *SecondString
    )
  {
    CHAR8  UpperFirstString;
    CHAR8  UpperSecondString;
  
    //
    // ASSERT both strings are less long than PcdMaximumAsciiStringLength
    //
    ASSERT (AsciiStrSize (FirstString));
    ASSERT (AsciiStrSize (SecondString));
  
    UpperFirstString  = AsciiCharToUpper (*FirstString);
    UpperSecondString = AsciiCharToUpper (*SecondString);
    while ((*FirstString != '\0') && (*SecondString != '\0') && (UpperFirstString == UpperSecondString)) {
      FirstString++;
      SecondString++;
      UpperFirstString  = AsciiCharToUpper (*FirstString);
      UpperSecondString = AsciiCharToUpper (*SecondString);
    }
  
    return UpperFirstString - UpperSecondString;
  }
  
  /**
    Compares two Null-terminated ASCII strings with maximum lengths, and returns
    the difference between the first mismatched ASCII characters.
  
    This function compares the Null-terminated ASCII string FirstString to the
    Null-terminated ASCII  string SecondString. At most, Length ASCII characters
    will be compared. If Length is 0, then 0 is returned. If FirstString is
    identical to SecondString, then 0 is returned. Otherwise, the value returned
    is the first mismatched ASCII character in SecondString subtracted from the
    first mismatched ASCII character in FirstString.
  
    If Length > 0 and FirstString is NULL, then ASSERT().
    If Length > 0 and SecondString is NULL, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero, and Length is greater than
    PcdMaximumAsciiStringLength, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero, and FirstString contains more than
    PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
    then ASSERT().
    If PcdMaximumAsciiStringLength is not zero, and SecondString contains more than
    PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
    then ASSERT().
  
    @param  FirstString   A pointer to a Null-terminated ASCII string.
    @param  SecondString  A pointer to a Null-terminated ASCII string.
    @param  Length        The maximum number of ASCII characters for compare.
  
    @retval ==0       FirstString is identical to SecondString.
    @retval !=0       FirstString is not identical to SecondString.
  
  **/
  INTN
  EFIAPI
  AsciiStrnCmp (
    IN      CONST CHAR8               *FirstString,
    IN      CONST CHAR8               *SecondString,
    IN      UINTN                     Length
    )
  {
    if (Length == 0) {
      return 0;
    }
  
    //
    // ASSERT both strings are less long than PcdMaximumAsciiStringLength
    //
    ASSERT (AsciiStrSize (FirstString));
    ASSERT (AsciiStrSize (SecondString));
  
    if (PcdGet32 (PcdMaximumAsciiStringLength) != 0) {
      ASSERT (Length <= PcdGet32 (PcdMaximumAsciiStringLength));
    }
  
    while ((*FirstString != '\0') &&
           (*SecondString != '\0') &&
           (*FirstString == *SecondString) &&
           (Length > 1)) {
      FirstString++;
      SecondString++;
      Length--;
    }
    return *FirstString - *SecondString;
  }
  
  
  /**
    Returns the first occurrence of a Null-terminated ASCII sub-string
    in a Null-terminated ASCII string.
  
    This function scans the contents of the ASCII string specified by String
    and returns the first occurrence of SearchString. If SearchString is not
    found in String, then NULL is returned. If the length of SearchString is zero,
    then String is returned.
  
    If String is NULL, then ASSERT().
    If SearchString is NULL, then ASSERT().
  
    If PcdMaximumAsciiStringLength is not zero, and SearchString or
    String contains more than PcdMaximumAsciiStringLength Unicode characters
    not including the Null-terminator, then ASSERT().
  
    @param  String          A pointer to a Null-terminated ASCII string.
    @param  SearchString    A pointer to a Null-terminated ASCII string to search for.
  
    @retval NULL            If the SearchString does not appear in String.
    @retval others          If there is a match return the first occurrence of SearchingString.
                            If the length of SearchString is zero,return String.
  
  **/
  CHAR8 *
  EFIAPI
  AsciiStrStr (
    IN      CONST CHAR8               *String,
    IN      CONST CHAR8               *SearchString
    )
  {
    CONST CHAR8 *FirstMatch;
    CONST CHAR8 *SearchStringTmp;
  
    //
    // ASSERT both strings are less long than PcdMaximumAsciiStringLength
    //
    ASSERT (AsciiStrSize (String) != 0);
    ASSERT (AsciiStrSize (SearchString) != 0);
  
    if (*SearchString == '\0') {
      return (CHAR8 *) String;
    }
  
    while (*String != '\0') {
      SearchStringTmp = SearchString;
      FirstMatch = String;
  
      while ((*String == *SearchStringTmp)
              && (*String != '\0')) {
        String++;
        SearchStringTmp++;
      }
  
      if (*SearchStringTmp == '\0') {
        return (CHAR8 *) FirstMatch;
      }
  
      if (*String == '\0') {
        return NULL;
      }
  
      String = FirstMatch + 1;
    }
  
    return NULL;
  }
  
  /**
    Convert a Null-terminated ASCII decimal string to a value of type
    UINTN.
  
    This function returns a value of type UINTN by interpreting the contents
    of the ASCII string 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 the 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
    Null-terminator, whichever on comes first.
  
    If String has only pad spaces, then 0 is returned.
    If String has no pad spaces or valid decimal digits, then 0 is returned.
    If the number represented by String overflows according to the range defined by
    UINTN, then MAX_UINTN is returned.
    If String is NULL, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero, and String contains more than
    PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
    then ASSERT().
  
    @param  String          A pointer to a Null-terminated ASCII string.
  
    @retval Value translated from String.
  
  **/
  UINTN
  EFIAPI
  AsciiStrDecimalToUintn (
    IN      CONST CHAR8               *String
    )
  {
    UINTN     Result;
  
    AsciiStrDecimalToUintnS (String, (CHAR8 **) NULL, &Result);
    return Result;
  }
  
  
  /**
    Convert a Null-terminated ASCII decimal string to a value of type
    UINT64.
  
    This function returns a value of type UINT64 by interpreting the contents
    of the ASCII string 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 the 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
    Null-terminator, whichever on comes first.
  
    If String has only pad spaces, then 0 is returned.
    If String has no pad spaces or valid decimal digits, then 0 is returned.
    If the number represented by String overflows according to the range defined by
    UINT64, then MAX_UINT64 is returned.
    If String is NULL, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero, and String contains more than
    PcdMaximumAsciiStringLength ASCII characters not including the Null-terminator,
    then ASSERT().
  
    @param  String          A pointer to a Null-terminated ASCII string.
  
    @retval Value translated from String.
  
  **/
  UINT64
  EFIAPI
  AsciiStrDecimalToUint64 (
    IN      CONST CHAR8               *String
    )
  {
    UINT64     Result;
  
    AsciiStrDecimalToUint64S (String, (CHAR8 **) NULL, &Result);
    return Result;
  }
  
  /**
    Convert a Null-terminated ASCII hexadecimal string to a value of type UINTN.
  
    This function returns a value of type UINTN by interpreting the contents of
    the ASCII string 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 only pad spaces, then 0 is returned.
    If String has no leading pad spaces, leading zeros or valid hexadecimal digits, then
    0 is returned.
  
    If the number represented by String overflows according to the range defined by UINTN,
    then MAX_UINTN is returned.
    If String is NULL, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero,
    and String contains more than PcdMaximumAsciiStringLength ASCII characters not including
    the Null-terminator, then ASSERT().
  
    @param  String          A pointer to a Null-terminated ASCII string.
  
    @retval Value translated from String.
  
  **/
  UINTN
  EFIAPI
  AsciiStrHexToUintn (
    IN      CONST CHAR8               *String
    )
  {
    UINTN     Result;
  
    AsciiStrHexToUintnS (String, (CHAR8 **) NULL, &Result);
    return Result;
  }
  
  
  /**
    Convert a Null-terminated ASCII hexadecimal string to a value of type UINT64.
  
    This function returns a value of type UINT64 by interpreting the contents of
    the ASCII string 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 only pad spaces, then 0 is returned.
    If String has no leading pad spaces, leading zeros or valid hexadecimal digits, then
    0 is returned.
  
    If the number represented by String overflows according to the range defined by UINT64,
    then MAX_UINT64 is returned.
    If String is NULL, then ASSERT().
    If PcdMaximumAsciiStringLength is not zero,
    and String contains more than PcdMaximumAsciiStringLength ASCII characters not including
    the Null-terminator, then ASSERT().
  
    @param  String          A pointer to a Null-terminated ASCII string.
  
    @retval Value translated from String.
  
  **/
  UINT64
  EFIAPI
  AsciiStrHexToUint64 (
    IN      CONST CHAR8                *String
    )
  {
    UINT64    Result;
  
    AsciiStrHexToUint64S (String, (CHAR8 **) NULL, &Result);
    return Result;
  }
  
  
  STATIC CHAR8 EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                  "abcdefghijklmnopqrstuvwxyz"
                                  "0123456789+/";
  
  /**
    Convert binary data to a Base64 encoded ascii string based on RFC4648.
  
    Produce a Null-terminated Ascii string in the output buffer specified by Destination and DestinationSize.
    The Ascii string is produced by converting the data string specified by Source and SourceLength.
  
    @param Source            Input UINT8 data
    @param SourceLength      Number of UINT8 bytes of data
    @param Destination       Pointer to output string buffer
    @param DestinationSize   Size of ascii buffer. Set to 0 to get the size needed.
                             Caller is responsible for passing in buffer of DestinationSize
  
    @retval RETURN_SUCCESS             When ascii buffer is filled in.
    @retval RETURN_INVALID_PARAMETER   If Source is NULL or DestinationSize is NULL.
    @retval RETURN_INVALID_PARAMETER   If SourceLength or DestinationSize is bigger than (MAX_ADDRESS - (UINTN)Destination).
    @retval RETURN_BUFFER_TOO_SMALL    If SourceLength is 0 and DestinationSize is <1.
    @retval RETURN_BUFFER_TOO_SMALL    If Destination is NULL or DestinationSize is smaller than required buffersize.
  
  **/
  RETURN_STATUS
  EFIAPI
  Base64Encode (
    IN  CONST UINT8  *Source,
    IN        UINTN   SourceLength,
    OUT       CHAR8  *Destination   OPTIONAL,
    IN OUT    UINTN  *DestinationSize
    )
  {
  
    UINTN          RequiredSize;
    UINTN          Left;
  
    //
    // Check pointers, and SourceLength is valid
    //
    if ((Source == NULL) || (DestinationSize == NULL)) {
      return RETURN_INVALID_PARAMETER;
    }
  
    //
    // Allow for RFC 4648 test vector 1
    //
    if (SourceLength == 0) {
      if (*DestinationSize < 1) {
        *DestinationSize = 1;
        return RETURN_BUFFER_TOO_SMALL;
      }
      *DestinationSize = 1;
      *Destination = '\0';
      return RETURN_SUCCESS;
    }
  
    //
    // Check if SourceLength or  DestinationSize is valid
    //
    if ((SourceLength >= (MAX_ADDRESS - (UINTN)Source)) || (*DestinationSize >= (MAX_ADDRESS - (UINTN)Destination))){
      return RETURN_INVALID_PARAMETER;
    }
  
    //
    // 4 ascii per 3 bytes + NULL
    //
    RequiredSize = ((SourceLength + 2) / 3) * 4 + 1;
    if ((Destination == NULL) || *DestinationSize < RequiredSize) {
      *DestinationSize = RequiredSize;
      return RETURN_BUFFER_TOO_SMALL;
    }
  
    Left = SourceLength;
  
    //
    // Encode 24 bits (three bytes) into 4 ascii characters
    //
    while (Left >= 3) {
  
      *Destination++ = EncodingTable[( Source[0] & 0xfc) >> 2 ];
      *Destination++ = EncodingTable[((Source[0] & 0x03) << 4) + ((Source[1] & 0xf0) >> 4)];
      *Destination++ = EncodingTable[((Source[1] & 0x0f) << 2) + ((Source[2] & 0xc0) >> 6)];
      *Destination++ = EncodingTable[( Source[2] & 0x3f)];
      Left -= 3;
      Source += 3;
    }
  
    //
    // Handle the remainder, and add padding '=' characters as necessary.
    //
    switch (Left) {
      case 0:
  
        //
        // No bytes Left, done.
        //
        break;
      case 1:
  
        //
        // One more data byte, two pad characters
        //
        *Destination++ = EncodingTable[( Source[0] & 0xfc) >> 2];
        *Destination++ = EncodingTable[((Source[0] & 0x03) << 4)];
        *Destination++ = '=';
        *Destination++ = '=';
        break;
      case 2:
  
        //
        // Two more data bytes, and one pad character
        //
        *Destination++ = EncodingTable[( Source[0] & 0xfc) >> 2];
        *Destination++ = EncodingTable[((Source[0] & 0x03) << 4) + ((Source[1] & 0xf0) >> 4)];
        *Destination++ = EncodingTable[((Source[1] & 0x0f) << 2)];
        *Destination++ = '=';
        break;
      }
    //
    // Add terminating NULL
    //
    *Destination = '\0';
    return RETURN_SUCCESS;
  }
  
  /**
    Decode Base64 ASCII encoded data to 8-bit binary representation, based on
    RFC4648.
  
    Decoding occurs according to "Table 1: The Base 64 Alphabet" in RFC4648.
  
    Whitespace is ignored at all positions:
    - 0x09 ('\t') horizontal tab
    - 0x0A ('\n') new line
    - 0x0B ('\v') vertical tab
    - 0x0C ('\f') form feed
    - 0x0D ('\r') carriage return
    - 0x20 (' ')  space
  
    The minimum amount of required padding (with ASCII 0x3D, '=') is tolerated
    and enforced at the end of the Base64 ASCII encoded data, and only there.
  
    Other characters outside of the encoding alphabet cause the function to
    reject the Base64 ASCII encoded data.
  
    @param[in] Source               Array of CHAR8 elements containing the Base64
                                    ASCII encoding. May be NULL if SourceSize is
                                    zero.
  
    @param[in] SourceSize           Number of CHAR8 elements in Source.
  
    @param[out] Destination         Array of UINT8 elements receiving the decoded
                                    8-bit binary representation. Allocated by the
                                    caller. May be NULL if DestinationSize is
                                    zero on input. If NULL, decoding is
                                    performed, but the 8-bit binary
                                    representation is not stored. If non-NULL and
                                    the function returns an error, the contents
                                    of Destination are indeterminate.
  
    @param[in,out] DestinationSize  On input, the number of UINT8 elements that
                                    the caller allocated for Destination. On
                                    output, if the function returns
                                    RETURN_SUCCESS or RETURN_BUFFER_TOO_SMALL,
                                    the number of UINT8 elements that are
                                    required for decoding the Base64 ASCII
                                    representation. If the function returns a
                                    value different from both RETURN_SUCCESS and
                                    RETURN_BUFFER_TOO_SMALL, then DestinationSize
                                    is indeterminate on output.
  
    @retval RETURN_SUCCESS            SourceSize CHAR8 elements at Source have
                                      been decoded to on-output DestinationSize
                                      UINT8 elements at Destination. Note that
                                      RETURN_SUCCESS covers the case when
                                      DestinationSize is zero on input, and
                                      Source decodes to zero bytes (due to
                                      containing at most ignored whitespace).
  
    @retval RETURN_BUFFER_TOO_SMALL   The input value of DestinationSize is not
                                      large enough for decoding SourceSize CHAR8
                                      elements at Source. The required number of
                                      UINT8 elements has been stored to
                                      DestinationSize.
  
    @retval RETURN_INVALID_PARAMETER  DestinationSize is NULL.
  
    @retval RETURN_INVALID_PARAMETER  Source is NULL, but SourceSize is not zero.
  
    @retval RETURN_INVALID_PARAMETER  Destination is NULL, but DestinationSize is
                                      not zero on input.
  
    @retval RETURN_INVALID_PARAMETER  Source is non-NULL, and (Source +
                                      SourceSize) would wrap around MAX_ADDRESS.
  
    @retval RETURN_INVALID_PARAMETER  Destination is non-NULL, and (Destination +
                                      DestinationSize) would wrap around
                                      MAX_ADDRESS, as specified on input.
  
    @retval RETURN_INVALID_PARAMETER  None of Source and Destination are NULL,
                                      and CHAR8[SourceSize] at Source overlaps
                                      UINT8[DestinationSize] at Destination, as
                                      specified on input.
  
    @retval RETURN_INVALID_PARAMETER  Invalid CHAR8 element encountered in
                                      Source.
  **/
  RETURN_STATUS
  EFIAPI
  Base64Decode (
    IN     CONST CHAR8 *Source          OPTIONAL,
    IN     UINTN       SourceSize,
    OUT    UINT8       *Destination     OPTIONAL,
    IN OUT UINTN       *DestinationSize
    )
  {
    BOOLEAN PaddingMode;
    UINTN   SixBitGroupsConsumed;
    UINT32  Accumulator;
    UINTN   OriginalDestinationSize;
    UINTN   SourceIndex;
    CHAR8   SourceChar;
    UINT32  Base64Value;
    UINT8   DestinationOctet;
  
    if (DestinationSize == NULL) {
      return RETURN_INVALID_PARAMETER;
    }
  
    //
    // Check Source array validity.
    //
    if (Source == NULL) {
      if (SourceSize > 0) {
        //
        // At least one CHAR8 element at NULL Source.
        //
        return RETURN_INVALID_PARAMETER;
      }
    } else if (SourceSize > MAX_ADDRESS - (UINTN)Source) {
      //
      // Non-NULL Source, but it wraps around.
      //
      return RETURN_INVALID_PARAMETER;
    }
  
    //
    // Check Destination array validity.
    //
    if (Destination == NULL) {
      if (*DestinationSize > 0) {
        //
        // At least one UINT8 element at NULL Destination.
        //
        return RETURN_INVALID_PARAMETER;
      }
    } else if (*DestinationSize > MAX_ADDRESS - (UINTN)Destination) {
      //
      // Non-NULL Destination, but it wraps around.
      //
      return RETURN_INVALID_PARAMETER;
    }
  
    //
    // Check for overlap.
    //
    if (Source != NULL && Destination != NULL) {
      //
      // Both arrays have been provided, and we know from earlier that each array
      // is valid in itself.
      //
      if ((UINTN)Source + SourceSize <= (UINTN)Destination) {
        //
        // Source array precedes Destination array, OK.
        //
      } else if ((UINTN)Destination + *DestinationSize <= (UINTN)Source) {
        //
        // Destination array precedes Source array, OK.
        //
      } else {
        //
        // Overlap.
        //
        return RETURN_INVALID_PARAMETER;
      }
    }
  
    //
    // Decoding loop setup.
    //
    PaddingMode             = FALSE;
    SixBitGroupsConsumed    = 0;
    Accumulator             = 0;
    OriginalDestinationSize = *DestinationSize;
    *DestinationSize        = 0;
  
    //
    // Decoding loop.
    //
    for (SourceIndex = 0; SourceIndex < SourceSize; SourceIndex++) {
      SourceChar = Source[SourceIndex];
  
      //
      // Whitespace is ignored at all positions (regardless of padding mode).
      //
      if (SourceChar == '\t' || SourceChar == '\n' || SourceChar == '\v' ||
          SourceChar == '\f' || SourceChar == '\r' || SourceChar == ' ') {
        continue;
      }
  
      //
      // If we're in padding mode, accept another padding character, as long as
      // that padding character completes the quantum. This completes case (2)
      // from RFC4648, Chapter 4. "Base 64 Encoding":
      //
      // (2) The final quantum of encoding input is exactly 8 bits; here, the
      //     final unit of encoded output will be two characters followed by two
      //     "=" padding characters.
      //
      if (PaddingMode) {
        if (SourceChar == '=' && SixBitGroupsConsumed == 3) {
          SixBitGroupsConsumed = 0;
          continue;
        }
        return RETURN_INVALID_PARAMETER;
      }
  
      //
      // When not in padding mode, decode Base64Value based on RFC4648, "Table 1:
      // The Base 64 Alphabet".
      //
      if ('A' <= SourceChar && SourceChar <= 'Z') {
        Base64Value = SourceChar - 'A';
      } else if ('a' <= SourceChar && SourceChar <= 'z') {
        Base64Value = 26 + (SourceChar - 'a');
      } else if ('0' <= SourceChar && SourceChar <= '9') {
        Base64Value = 52 + (SourceChar - '0');
      } else if (SourceChar == '+') {
        Base64Value = 62;
      } else if (SourceChar == '/') {
        Base64Value = 63;
      } else if (SourceChar == '=') {
        //
        // Enter padding mode.
        //
        PaddingMode = TRUE;
  
        if (SixBitGroupsConsumed == 2) {
          //
          // If we have consumed two 6-bit groups from the current quantum before
          // encountering the first padding character, then this is case (2) from
          // RFC4648, Chapter 4. "Base 64 Encoding". Bump SixBitGroupsConsumed,
          // and we'll enforce another padding character.
          //
          SixBitGroupsConsumed = 3;
        } else if (SixBitGroupsConsumed == 3) {
          //
          // If we have consumed three 6-bit groups from the current quantum
          // before encountering the first padding character, then this is case
          // (3) from RFC4648, Chapter 4. "Base 64 Encoding". The quantum is now
          // complete.
          //
          SixBitGroupsConsumed = 0;
        } else {
          //
          // Padding characters are not allowed at the first two positions of a
          // quantum.
          //
          return RETURN_INVALID_PARAMETER;
        }
  
        //
        // Wherever in a quantum we enter padding mode, we enforce the padding
        // bits pending in the accumulator -- from the last 6-bit group just
        // preceding the padding character -- to be zero. Refer to RFC4648,
        // Chapter 3.5. "Canonical Encoding".
        //
        if (Accumulator != 0) {
          return RETURN_INVALID_PARAMETER;
        }
  
        //
        // Advance to the next source character.
        //
        continue;
      } else {
        //
        // Other characters outside of the encoding alphabet are rejected.
        //
        return RETURN_INVALID_PARAMETER;
      }
  
      //
      // Feed the bits of the current 6-bit group of the quantum to the
      // accumulator.
      //
      Accumulator = (Accumulator << 6) | Base64Value;
      SixBitGroupsConsumed++;
      switch (SixBitGroupsConsumed) {
      case 1:
        //
        // No octet to spill after consuming the first 6-bit group of the
        // quantum; advance to the next source character.
        //
        continue;
      case 2:
        //
        // 12 bits accumulated (6 pending + 6 new); prepare for spilling an
        // octet. 4 bits remain pending.
        //
        DestinationOctet = (UINT8)(Accumulator >> 4);
        Accumulator &= 0xF;
        break;
      case 3:
        //
        // 10 bits accumulated (4 pending + 6 new); prepare for spilling an
        // octet. 2 bits remain pending.
        //
        DestinationOctet = (UINT8)(Accumulator >> 2);
        Accumulator &= 0x3;
        break;
      default:
        ASSERT (SixBitGroupsConsumed == 4);
        //
        // 8 bits accumulated (2 pending + 6 new); prepare for spilling an octet.
        // The quantum is complete, 0 bits remain pending.
        //
        DestinationOctet = (UINT8)Accumulator;
        Accumulator = 0;
        SixBitGroupsConsumed = 0;
        break;
      }
  
      //
      // Store the decoded octet if there's room left. Increment
      // (*DestinationSize) unconditionally.
      //
      if (*DestinationSize < OriginalDestinationSize) {
        ASSERT (Destination != NULL);
        Destination[*DestinationSize] = DestinationOctet;
      }
      (*DestinationSize)++;
  
      //
      // Advance to the next source character.
      //
    }
  
    //
    // If Source terminates mid-quantum, then Source is invalid.
    //
    if (SixBitGroupsConsumed != 0) {
      return RETURN_INVALID_PARAMETER;
    }
  
    //
    // Done.
    //
    if (*DestinationSize <= OriginalDestinationSize) {
      return RETURN_SUCCESS;
    }
    return RETURN_BUFFER_TOO_SMALL;
  }
  
  /**
    Converts an 8-bit value to an 8-bit BCD value.
  
    Converts the 8-bit value specified by Value to BCD. The BCD value is
    returned.
  
    If Value >= 100, then ASSERT().
  
    @param  Value The 8-bit value to convert to BCD. Range 0..99.
  
    @return The BCD value.
  
  **/
  UINT8
  EFIAPI
  DecimalToBcd8 (
    IN      UINT8                     Value
    )
  {
    ASSERT (Value < 100);
    return (UINT8) (((Value / 10) << 4) | (Value % 10));
  }
  
  /**
    Converts an 8-bit BCD value to an 8-bit value.
  
    Converts the 8-bit BCD value specified by Value to an 8-bit value. The 8-bit
    value is returned.
  
    If Value >= 0xA0, then ASSERT().
    If (Value & 0x0F) >= 0x0A, then ASSERT().
  
    @param  Value The 8-bit BCD value to convert to an 8-bit value.
  
    @return The 8-bit value is returned.
  
  **/
  UINT8
  EFIAPI
  BcdToDecimal8 (
    IN      UINT8                     Value
    )
  {
    ASSERT (Value < 0xa0);
    ASSERT ((Value & 0xf) < 0xa);
    return (UINT8) ((Value >> 4) * 10 + (Value & 0xf));
  }