]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdePkg/Library/BaseLib/SafeString.c
MdePkg/BaseLib: Add StrToGuid/StrHexToBytes/StrToIpv[4/6]Address
[mirror_edk2.git] / MdePkg / Library / BaseLib / SafeString.c
index 5edc6ef06211483ca6b1981197a7431b210353fb..cf6f3e9eb90a3acfb079d5807306e3d0ef44c8ef 100644 (file)
@@ -128,9 +128,9 @@ StrnLenS (
   ASSERT (((UINTN) String & BIT0) == 0);\r
 \r
   //\r
-  // If String is a null pointer, then the StrnLenS function returns zero.\r
+  // If String is a null pointer or MaxSize is 0, then the StrnLenS function returns zero.\r
   //\r
-  if (String == NULL) {\r
+  if ((String == NULL) || (MaxSize == 0)) {\r
     return 0;\r
   }\r
 \r
@@ -1073,6 +1073,619 @@ StrHexToUint64S (
   return RETURN_SUCCESS;\r
 }\r
 \r
+/**\r
+  Convert a Null-terminated Unicode string to IPv6 address and prefix length.\r
+\r
+  This function outputs a value of type IPv6_ADDRESS and may output a value\r
+  of type UINT8 by interpreting the contents of the Unicode string specified\r
+  by String. The format of the input Unicode string String is as follows:\r
+\r
+                  X:X:X:X:X:X:X:X[/P]\r
+\r
+  X contains one to four hexadecimal digit characters in the range [0-9], [a-f] and\r
+  [A-F]. X is converted to a value of type UINT16, whose low byte is stored in low\r
+  memory address and high byte is stored in high memory address. P contains decimal\r
+  digit characters in the range [0-9]. The running zero in the beginning of P will\r
+  be ignored. /P is optional.\r
+\r
+  When /P is not in the String, the function stops at the first character that is\r
+  not a valid hexadecimal digit character after eight X's are converted.\r
+\r
+  When /P is in the String, the function stops at the first character that is not\r
+  a valid decimal digit character after P is converted.\r
+\r
+  "::" can be used to compress one or more groups of X when X contains only 0.\r
+  The "::" can only appear once in the String.\r
+\r
+  If String is NULL, then ASSERT().\r
+\r
+  If Address is NULL, then ASSERT().\r
+\r
+  If String is not aligned in a 16-bit boundary, then ASSERT().\r
+\r
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than\r
+  PcdMaximumUnicodeStringLength Unicode characters, not including the\r
+  Null-terminator, then ASSERT().\r
+\r
+  If EndPointer is not NULL and Address is translated from String, a pointer\r
+  to the character that stopped the scan is stored at the location pointed to\r
+  by EndPointer.\r
+\r
+  @param  String                   Pointer to a Null-terminated Unicode string.\r
+  @param  EndPointer               Pointer to character that stops scan.\r
+  @param  Address                  Pointer to the converted IPv6 address.\r
+  @param  PrefixLength             Pointer to the converted IPv6 address prefix\r
+                                   length. MAX_UINT8 is returned when /P is\r
+                                   not in the String.\r
+\r
+  @retval RETURN_SUCCESS           Address is translated from String.\r
+  @retval RETURN_INVALID_PARAMETER If String is NULL.\r
+                                   If Data is NULL.\r
+  @retval RETURN_UNSUPPORTED       If X contains more than four hexadecimal\r
+                                    digit characters.\r
+                                   If String contains "::" and number of X\r
+                                    is not less than 8.\r
+                                   If P starts with character that is not a\r
+                                    valid decimal digit character.\r
+                                   If the decimal number converted from P\r
+                                    exceeds 128.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+StrToIpv6Address (\r
+  IN  CONST CHAR16       *String,\r
+  OUT CHAR16             **EndPointer, OPTIONAL\r
+  OUT IPv6_ADDRESS       *Address,\r
+  OUT UINT8              *PrefixLength OPTIONAL\r
+  )\r
+{\r
+  RETURN_STATUS          Status;\r
+  UINTN                  AddressIndex;\r
+  UINTN                  Uintn;\r
+  IPv6_ADDRESS           LocalAddress;\r
+  UINT8                  LocalPrefixLength;\r
+  CONST CHAR16           *Pointer;\r
+  CHAR16                 *End;\r
+  UINTN                  CompressStart;\r
+  BOOLEAN                ExpectPrefix;\r
+\r
+  LocalPrefixLength = MAX_UINT8;\r
+  CompressStart     = ARRAY_SIZE (Address->Addr);\r
+  ExpectPrefix      = FALSE;\r
+\r
+  ASSERT (((UINTN) String & BIT0) == 0);\r
+\r
+  //\r
+  // 1. None of String or Guid shall be a null pointer.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);\r
+  SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER);\r
+\r
+  for (Pointer = String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) {\r
+    if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) {\r
+      if (*Pointer != L':') {\r
+        //\r
+        // ":" or "/" should be followed by digit characters.\r
+        //\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      //\r
+      // Meet second ":" after previous ":" or "/"\r
+      // or meet first ":" in the beginning of String.\r
+      //\r
+      if (ExpectPrefix) {\r
+        //\r
+        // ":" shall not be after "/"\r
+        //\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      if (CompressStart != ARRAY_SIZE (Address->Addr) || AddressIndex == ARRAY_SIZE (Address->Addr)) {\r
+        //\r
+        // "::" can only appear once.\r
+        // "::" can only appear when address is not full length.\r
+        //\r
+        return RETURN_UNSUPPORTED;\r
+      } else {\r
+        //\r
+        // Remember the start of zero compressing.\r
+        //\r
+        CompressStart = AddressIndex;\r
+        Pointer++;\r
+\r
+        if (CompressStart == 0) {\r
+          if (*Pointer != L':') {\r
+            //\r
+            // Single ":" shall not be in the beginning of String.\r
+            //\r
+            return RETURN_UNSUPPORTED;\r
+          }\r
+          Pointer++;\r
+        }\r
+      }\r
+    }\r
+\r
+    if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) {\r
+      if (*Pointer == L'/') {\r
+        //\r
+        // Might be optional "/P" after "::".\r
+        //\r
+        if (CompressStart != AddressIndex) {\r
+          return RETURN_UNSUPPORTED;\r
+        }\r
+      } else {\r
+        break;\r
+      }\r
+    } else {\r
+      if (!ExpectPrefix) {\r
+        //\r
+        // Get X.\r
+        //\r
+        Status = StrHexToUintnS (Pointer, &End, &Uintn);\r
+        if (RETURN_ERROR (Status) || End - Pointer > 4) {\r
+          //\r
+          // Number of hexadecimal digit characters is no more than 4.\r
+          //\r
+          return RETURN_UNSUPPORTED;\r
+        }\r
+        Pointer = End;\r
+        //\r
+        // Uintn won't exceed MAX_UINT16 if number of hexadecimal digit characters is no more than 4.\r
+        //\r
+        LocalAddress.Addr[AddressIndex] = (UINT8) ((UINT16) Uintn >> 8);\r
+        LocalAddress.Addr[AddressIndex + 1] = (UINT8) Uintn;\r
+        AddressIndex += 2;\r
+      } else {\r
+        //\r
+        // Get P, then exit the loop.\r
+        //\r
+        Status = StrDecimalToUintnS (Pointer, &End, &Uintn);\r
+        if (RETURN_ERROR (Status) || End == Pointer || Uintn > 128) {\r
+          //\r
+          // Prefix length should not exceed 128.\r
+          //\r
+          return RETURN_UNSUPPORTED;\r
+        }\r
+        LocalPrefixLength = (UINT8) Uintn;\r
+        Pointer = End;\r
+        break;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Skip ':' or "/"\r
+    //\r
+    if (*Pointer == L'/') {\r
+      ExpectPrefix = TRUE;\r
+    } else if (*Pointer == L':') {\r
+      if (AddressIndex == ARRAY_SIZE (Address->Addr)) {\r
+        //\r
+        // Meet additional ":" after all 8 16-bit address\r
+        //\r
+        break;\r
+      }\r
+    } else {\r
+      //\r
+      // Meet other character that is not "/" or ":" after all 8 16-bit address\r
+      //\r
+      break;\r
+    }\r
+    Pointer++;\r
+  }\r
+\r
+  if ((AddressIndex == ARRAY_SIZE (Address->Addr) && CompressStart != ARRAY_SIZE (Address->Addr)) ||\r
+    (AddressIndex != ARRAY_SIZE (Address->Addr) && CompressStart == ARRAY_SIZE (Address->Addr))\r
+      ) {\r
+    //\r
+    // Full length of address shall not have compressing zeros.\r
+    // Non-full length of address shall have compressing zeros.\r
+    //\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+  CopyMem (&Address->Addr[0], &LocalAddress.Addr[0], CompressStart);\r
+  ZeroMem (&Address->Addr[CompressStart], ARRAY_SIZE (Address->Addr) - AddressIndex);\r
+  CopyMem (\r
+    &Address->Addr[CompressStart + ARRAY_SIZE (Address->Addr) - AddressIndex],\r
+    &LocalAddress.Addr[CompressStart],\r
+    AddressIndex - CompressStart\r
+    );\r
+\r
+  if (PrefixLength != NULL) {\r
+    *PrefixLength = LocalPrefixLength;\r
+  }\r
+  if (EndPointer != NULL) {\r
+    *EndPointer = (CHAR16 *) Pointer;\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Convert a Null-terminated Unicode string to IPv4 address and prefix length.\r
+\r
+  This function outputs a value of type IPv4_ADDRESS and may output a value\r
+  of type UINT8 by interpreting the contents of the Unicode string specified\r
+  by String. The format of the input Unicode string String is as follows:\r
+\r
+                  D.D.D.D[/P]\r
+\r
+  D and P are decimal digit characters in the range [0-9]. The running zero in\r
+  the beginning of D and P will be ignored. /P is optional.\r
+\r
+  When /P is not in the String, the function stops at the first character that is\r
+  not a valid decimal digit character after four D's are converted.\r
+\r
+  When /P is in the String, the function stops at the first character that is not\r
+  a valid decimal digit character after P is converted.\r
+\r
+  If String is NULL, then ASSERT().\r
+\r
+  If Address is NULL, then ASSERT().\r
+\r
+  If String is not aligned in a 16-bit boundary, then ASSERT().\r
+\r
+  If PcdMaximumUnicodeStringLength is not zero, and String contains more than\r
+  PcdMaximumUnicodeStringLength Unicode characters, not including the\r
+  Null-terminator, then ASSERT().\r
+\r
+  If EndPointer is not NULL and Address is translated from String, a pointer\r
+  to the character that stopped the scan is stored at the location pointed to\r
+  by EndPointer.\r
+\r
+  @param  String                   Pointer to a Null-terminated Unicode string.\r
+  @param  EndPointer               Pointer to character that stops scan.\r
+  @param  Address                  Pointer to the converted IPv4 address.\r
+  @param  PrefixLength             Pointer to the converted IPv4 address prefix\r
+                                   length. MAX_UINT8 is returned when /P is\r
+                                   not in the String.\r
+\r
+  @retval RETURN_SUCCESS           Address is translated from String.\r
+  @retval RETURN_INVALID_PARAMETER If String is NULL.\r
+                                   If Data is NULL.\r
+  @retval RETURN_UNSUPPORTED       If String is not in the correct format.\r
+                                   If any decimal number converted from D\r
+                                    exceeds 255.\r
+                                   If the decimal number converted from P\r
+                                    exceeds 32.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+StrToIpv4Address (\r
+  IN  CONST CHAR16       *String,\r
+  OUT CHAR16             **EndPointer, OPTIONAL\r
+  OUT IPv4_ADDRESS       *Address,\r
+  OUT UINT8              *PrefixLength OPTIONAL\r
+  )\r
+{\r
+  RETURN_STATUS          Status;\r
+  UINTN                  AddressIndex;\r
+  UINTN                  Uintn;\r
+  IPv4_ADDRESS           LocalAddress;\r
+  UINT8                  LocalPrefixLength;\r
+  CHAR16                 *Pointer;\r
+\r
+  LocalPrefixLength = MAX_UINT8;\r
+\r
+  ASSERT (((UINTN) String & BIT0) == 0);\r
+\r
+  //\r
+  // 1. None of String or Guid shall be a null pointer.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);\r
+  SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER);\r
+\r
+  for (Pointer = (CHAR16 *) String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) {\r
+    if (!InternalIsDecimalDigitCharacter (*Pointer)) {\r
+      //\r
+      // D or P contains invalid characters.\r
+      //\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Get D or P.\r
+    //\r
+    Status = StrDecimalToUintnS ((CONST CHAR16 *) Pointer, &Pointer, &Uintn);\r
+    if (RETURN_ERROR (Status)) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+    if (AddressIndex == ARRAY_SIZE (Address->Addr)) {\r
+      //\r
+      // It's P.\r
+      //\r
+      if (Uintn > 32) {\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+      LocalPrefixLength = (UINT8) Uintn;\r
+    } else {\r
+      //\r
+      // It's D.\r
+      //\r
+      if (Uintn > MAX_UINT8) {\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+      LocalAddress.Addr[AddressIndex] = (UINT8) Uintn;\r
+      AddressIndex++;\r
+    }\r
+\r
+    //\r
+    // Check the '.' or '/', depending on the AddressIndex.\r
+    //\r
+    if (AddressIndex == ARRAY_SIZE (Address->Addr)) {\r
+      if (*Pointer == L'/') {\r
+        //\r
+        // '/P' is in the String.\r
+        // Skip "/" and get P in next loop.\r
+        //\r
+        Pointer++;\r
+      } else {\r
+        //\r
+        // '/P' is not in the String.\r
+        //\r
+        break;\r
+      }\r
+    } else if (AddressIndex < ARRAY_SIZE (Address->Addr)) {\r
+      if (*Pointer == L'.') {\r
+        //\r
+        // D should be followed by '.'\r
+        //\r
+        Pointer++;\r
+      } else {\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (AddressIndex < ARRAY_SIZE (Address->Addr)) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  CopyMem (Address, &LocalAddress, sizeof (*Address));\r
+  if (PrefixLength != NULL) {\r
+    *PrefixLength = LocalPrefixLength;\r
+  }\r
+  if (EndPointer != NULL) {\r
+    *EndPointer = Pointer;\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Convert a Null-terminated Unicode GUID string to a value of type\r
+  EFI_GUID.\r
+\r
+  This function outputs a GUID value by interpreting the contents of\r
+  the Unicode string specified by String. The format of the input\r
+  Unicode string String consists of 36 characters, as follows:\r
+\r
+                  aabbccdd-eeff-gghh-iijj-kkllmmnnoopp\r
+\r
+  The pairs aa - pp are two characters in the range [0-9], [a-f] and\r
+  [A-F], with each pair representing a single byte hexadecimal value.\r
+\r
+  The mapping between String and the EFI_GUID structure is as follows:\r
+                  aa          Data1[24:31]\r
+                  bb          Data1[16:23]\r
+                  cc          Data1[8:15]\r
+                  dd          Data1[0:7]\r
+                  ee          Data2[8:15]\r
+                  ff          Data2[0:7]\r
+                  gg          Data3[8:15]\r
+                  hh          Data3[0:7]\r
+                  ii          Data4[0:7]\r
+                  jj          Data4[8:15]\r
+                  kk          Data4[16:23]\r
+                  ll          Data4[24:31]\r
+                  mm          Data4[32:39]\r
+                  nn          Data4[40:47]\r
+                  oo          Data4[48:55]\r
+                  pp          Data4[56:63]\r
+\r
+  If String is NULL, then ASSERT().\r
+  If Guid is NULL, then ASSERT().\r
+  If String is not aligned in a 16-bit boundary, then ASSERT().\r
+\r
+  @param  String                   Pointer to a Null-terminated Unicode string.\r
+  @param  Guid                     Pointer to the converted GUID.\r
+\r
+  @retval RETURN_SUCCESS           Guid is translated from String.\r
+  @retval RETURN_INVALID_PARAMETER If String is NULL.\r
+                                   If Data is NULL.\r
+  @retval RETURN_UNSUPPORTED       If String is not as the above format.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+StrToGuid (\r
+  IN  CONST CHAR16       *String,\r
+  OUT GUID               *Guid\r
+  )\r
+{\r
+  RETURN_STATUS          Status;\r
+  GUID                   LocalGuid;\r
+\r
+  ASSERT (((UINTN) String & BIT0) == 0);\r
+\r
+  //\r
+  // 1. None of String or Guid shall be a null pointer.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);\r
+  SAFE_STRING_CONSTRAINT_CHECK ((Guid != NULL), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // Get aabbccdd in big-endian.\r
+  //\r
+  Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data1), (UINT8 *) &LocalGuid.Data1, sizeof (LocalGuid.Data1));\r
+  if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data1)] != L'-') {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Convert big-endian to little-endian.\r
+  //\r
+  LocalGuid.Data1 = SwapBytes32 (LocalGuid.Data1);\r
+  String += 2 * sizeof (LocalGuid.Data1) + 1;\r
+\r
+  //\r
+  // Get eeff in big-endian.\r
+  //\r
+  Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data2), (UINT8 *) &LocalGuid.Data2, sizeof (LocalGuid.Data2));\r
+  if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data2)] != L'-') {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Convert big-endian to little-endian.\r
+  //\r
+  LocalGuid.Data2 = SwapBytes16 (LocalGuid.Data2);\r
+  String += 2 * sizeof (LocalGuid.Data2) + 1;\r
+\r
+  //\r
+  // Get gghh in big-endian.\r
+  //\r
+  Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data3), (UINT8 *) &LocalGuid.Data3, sizeof (LocalGuid.Data3));\r
+  if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data3)] != L'-') {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Convert big-endian to little-endian.\r
+  //\r
+  LocalGuid.Data3 = SwapBytes16 (LocalGuid.Data3);\r
+  String += 2 * sizeof (LocalGuid.Data3) + 1;\r
+\r
+  //\r
+  // Get iijj.\r
+  //\r
+  Status = StrHexToBytes (String, 2 * 2, &LocalGuid.Data4[0], 2);\r
+  if (RETURN_ERROR (Status) || String[2 * 2] != L'-') {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+  String += 2 * 2 + 1;\r
+\r
+  //\r
+  // Get kkllmmnnoopp.\r
+  //\r
+  Status = StrHexToBytes (String, 2 * 6, &LocalGuid.Data4[2], 6);\r
+  if (RETURN_ERROR (Status)) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  CopyGuid (Guid, &LocalGuid);\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Convert a Null-terminated Unicode hexadecimal string to a byte array.\r
+\r
+  This function outputs a byte array by interpreting the contents of\r
+  the Unicode string specified by String in hexadecimal format. The format of\r
+  the input Unicode string String is:\r
+\r
+                  [XX]*\r
+\r
+  X is a hexadecimal digit character in the range [0-9], [a-f] and [A-F].\r
+  The function decodes every two hexadecimal digit characters as one byte. The\r
+  decoding stops after Length of characters and outputs Buffer containing\r
+  (Length / 2) bytes.\r
+\r
+  If String is not aligned in a 16-bit boundary, then ASSERT().\r
+\r
+  If String is NULL, then ASSERT().\r
+\r
+  If Buffer is NULL, then ASSERT().\r
+\r
+  If Length is not multiple of 2, then ASSERT().\r
+\r
+  If PcdMaximumUnicodeStringLength is not zero and Length is greater than\r
+  PcdMaximumUnicodeStringLength, then ASSERT().\r
+\r
+  If MaxBufferSize is less than (Length / 2), then ASSERT().\r
+\r
+  @param  String                   Pointer to a Null-terminated Unicode string.\r
+  @param  Length                   The number of Unicode characters to decode.\r
+  @param  Buffer                   Pointer to the converted bytes array.\r
+  @param  MaxBufferSize            The maximum size of Buffer.\r
+\r
+  @retval RETURN_SUCCESS           Buffer is translated from String.\r
+  @retval RETURN_INVALID_PARAMETER If String is NULL.\r
+                                   If Data is NULL.\r
+                                   If Length is not multiple of 2.\r
+                                   If PcdMaximumUnicodeStringLength is not zero,\r
+                                    and Length is greater than\r
+                                    PcdMaximumUnicodeStringLength.\r
+  @retval RETURN_UNSUPPORTED       If Length of characters from String contain\r
+                                    a character that is not valid hexadecimal\r
+                                    digit characters, or a Null-terminator.\r
+  @retval RETURN_BUFFER_TOO_SMALL  If MaxBufferSize is less than (Length / 2).\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+StrHexToBytes (\r
+  IN  CONST CHAR16       *String,\r
+  IN  UINTN              Length,\r
+  OUT UINT8              *Buffer,\r
+  IN  UINTN              MaxBufferSize\r
+  )\r
+{\r
+  UINTN                  Index;\r
+\r
+  ASSERT (((UINTN) String & BIT0) == 0);\r
+\r
+  //\r
+  // 1. None of String or Buffer shall be a null pointer.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);\r
+  SAFE_STRING_CONSTRAINT_CHECK ((Buffer != NULL), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // 2. Length shall not be greater than RSIZE_MAX.\r
+  //\r
+  if (RSIZE_MAX != 0) {\r
+    SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+  }\r
+\r
+  //\r
+  // 3. Length shall not be odd.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK (((Length & BIT0) == 0), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // 4. MaxBufferSize shall equal to or greater than Length / 2.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK ((MaxBufferSize >= Length / 2), RETURN_BUFFER_TOO_SMALL);\r
+\r
+  //\r
+  // 5. String shall not contains invalid hexadecimal digits.\r
+  //\r
+  for (Index = 0; Index < Length; Index++) {\r
+    if (!InternalIsHexaDecimalDigitCharacter (String[Index])) {\r
+      break;\r
+    }\r
+  }\r
+  if (Index != Length) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Convert the hex string to bytes.\r
+  //\r
+  for(Index = 0; Index < Length; Index++) {\r
+\r
+    //\r
+    // For even characters, write the upper nibble for each buffer byte,\r
+    // and for even characters, the lower nibble.\r
+    //\r
+    if ((Index & BIT0) == 0) {\r
+      Buffer[Index / 2]  = (UINT8) InternalHexCharToUintn (String[Index]) << 4;\r
+    } else {\r
+      Buffer[Index / 2] |= (UINT8) InternalHexCharToUintn (String[Index]);\r
+    }\r
+  }\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
 /**\r
   Returns the length of a Null-terminated Ascii string.\r
 \r
@@ -1097,9 +1710,9 @@ AsciiStrnLenS (
   UINTN                             Length;\r
 \r
   //\r
-  // If String is a null pointer, then the AsciiStrnLenS function returns zero.\r
+  // If String is a null pointer or MaxSize is 0, then the AsciiStrnLenS function returns zero.\r
   //\r
-  if (String == NULL) {\r
+  if ((String == NULL) || (MaxSize == 0)) {\r
     return 0;\r
   }\r
 \r
@@ -2108,6 +2721,128 @@ UnicodeStrToAsciiStrS (
   return RETURN_SUCCESS;\r
 }\r
 \r
+/**\r
+  Convert not more than Length successive characters from a Null-terminated\r
+  Unicode string to a Null-terminated Ascii string. If no null char is copied\r
+  from Source, then Destination[Length] is always set to null.\r
+\r
+  This function converts not more than Length successive characters from the\r
+  Unicode string Source to the Ascii string Destination by copying the lower 8\r
+  bits of each Unicode character. The function terminates the Ascii string\r
+  Destination by appending a Null-terminator character at the end.\r
+\r
+  The caller is responsible to make sure Destination points to a buffer with\r
+  size not smaller than ((MIN(StrLen(Source), Length) + 1) * sizeof (CHAR8))\r
+  in bytes.\r
+\r
+  If any Unicode characters in Source contain non-zero value in the upper 8\r
+  bits, then ASSERT().\r
+  If Source is not aligned on a 16-bit boundary, then ASSERT().\r
+  If an error would be returned, then the function will also ASSERT().\r
+\r
+  If an error is returned, then Destination and DestinationLength are\r
+  unmodified.\r
+\r
+  @param  Source             The pointer to a Null-terminated Unicode string.\r
+  @param  Length             The maximum number of Unicode characters to\r
+                             convert.\r
+  @param  Destination        The pointer to a Null-terminated Ascii string.\r
+  @param  DestMax            The maximum number of Destination Ascii char,\r
+                             including terminating null char.\r
+  @param  DestinationLength  The number of Unicode characters converted.\r
+\r
+  @retval RETURN_SUCCESS            String is converted.\r
+  @retval RETURN_INVALID_PARAMETER  If Destination is NULL.\r
+                                    If Source is NULL.\r
+                                    If DestinationLength is NULL.\r
+                                    If PcdMaximumAsciiStringLength is not zero,\r
+                                    and Length or DestMax is greater than\r
+                                    PcdMaximumAsciiStringLength.\r
+                                    If PcdMaximumUnicodeStringLength is not\r
+                                    zero, and Length or DestMax is greater than\r
+                                    PcdMaximumUnicodeStringLength.\r
+                                    If DestMax is 0.\r
+  @retval RETURN_BUFFER_TOO_SMALL   If DestMax is NOT greater than\r
+                                    MIN(StrLen(Source), Length).\r
+  @retval RETURN_ACCESS_DENIED      If Source and Destination overlap.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+UnicodeStrnToAsciiStrS (\r
+  IN      CONST CHAR16              *Source,\r
+  IN      UINTN                     Length,\r
+  OUT     CHAR8                     *Destination,\r
+  IN      UINTN                     DestMax,\r
+  OUT     UINTN                     *DestinationLength\r
+  )\r
+{\r
+  UINTN            SourceLen;\r
+\r
+  ASSERT (((UINTN) Source & BIT0) == 0);\r
+\r
+  //\r
+  // 1. None of Destination, Source or DestinationLength shall be a null\r
+  // pointer.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);\r
+  SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);\r
+  SAFE_STRING_CONSTRAINT_CHECK ((DestinationLength != NULL), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // 2. Neither Length nor DestMax shall be greater than ASCII_RSIZE_MAX or\r
+  // RSIZE_MAX.\r
+  //\r
+  if (ASCII_RSIZE_MAX != 0) {\r
+    SAFE_STRING_CONSTRAINT_CHECK ((Length <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+    SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+  }\r
+  if (RSIZE_MAX != 0) {\r
+    SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+    SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+  }\r
+\r
+  //\r
+  // 3. DestMax shall not equal zero.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // 4. If Length is not less than DestMax, then DestMax shall be greater than\r
+  // StrnLenS(Source, DestMax).\r
+  //\r
+  SourceLen = StrnLenS (Source, DestMax);\r
+  if (Length >= DestMax) {\r
+    SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);\r
+  }\r
+\r
+  //\r
+  // 5. Copying shall not take place between objects that overlap.\r
+  //\r
+  if (SourceLen > Length) {\r
+    SourceLen = Length;\r
+  }\r
+  SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax, (VOID *)Source, (SourceLen + 1) * sizeof(CHAR16)), RETURN_ACCESS_DENIED);\r
+\r
+  *DestinationLength = 0;\r
+\r
+  //\r
+  // Convert string\r
+  //\r
+  while ((*Source != 0) && (SourceLen > 0)) {\r
+    //\r
+    // If any Unicode characters in Source contain non-zero value in the upper\r
+    // 8 bits, then ASSERT().\r
+    //\r
+    ASSERT (*Source < 0x100);\r
+    *(Destination++) = (CHAR8) *(Source++);\r
+    SourceLen--;\r
+    (*DestinationLength)++;\r
+  }\r
+  *Destination = 0;\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
 \r
 /**\r
   Convert one Null-terminated ASCII string to a Null-terminated\r
@@ -2200,3 +2935,118 @@ AsciiStrToUnicodeStrS (
 \r
   return RETURN_SUCCESS;\r
 }\r
+\r
+/**\r
+  Convert not more than Length successive characters from a Null-terminated\r
+  Ascii string to a Null-terminated Unicode string. If no null char is copied\r
+  from Source, then Destination[Length] is always set to null.\r
+\r
+  This function converts not more than Length successive characters from the\r
+  Ascii string Source to the Unicode string Destination. The function\r
+  terminates the Unicode string Destination by appending a Null-terminator\r
+  character at the end.\r
+\r
+  The caller is responsible to make sure Destination points to a buffer with\r
+  size not smaller than\r
+  ((MIN(AsciiStrLen(Source), Length) + 1) * sizeof (CHAR8)) in bytes.\r
+\r
+  If Destination is not aligned on a 16-bit boundary, then ASSERT().\r
+  If an error would be returned, then the function will also ASSERT().\r
+\r
+  If an error is returned, then Destination and DestinationLength are\r
+  unmodified.\r
+\r
+  @param  Source             The pointer to a Null-terminated Ascii string.\r
+  @param  Length             The maximum number of Ascii characters to convert.\r
+  @param  Destination        The pointer to a Null-terminated Unicode string.\r
+  @param  DestMax            The maximum number of Destination Unicode char,\r
+                             including terminating null char.\r
+  @param  DestinationLength  The number of Ascii characters converted.\r
+\r
+  @retval RETURN_SUCCESS            String is converted.\r
+  @retval RETURN_INVALID_PARAMETER  If Destination is NULL.\r
+                                    If Source is NULL.\r
+                                    If DestinationLength is NULL.\r
+                                    If PcdMaximumUnicodeStringLength is not\r
+                                    zero, and Length or DestMax is greater than\r
+                                    PcdMaximumUnicodeStringLength.\r
+                                    If PcdMaximumAsciiStringLength is not zero,\r
+                                    and Length or DestMax is greater than\r
+                                    PcdMaximumAsciiStringLength.\r
+                                    If DestMax is 0.\r
+  @retval RETURN_BUFFER_TOO_SMALL   If DestMax is NOT greater than\r
+                                    MIN(AsciiStrLen(Source), Length).\r
+  @retval RETURN_ACCESS_DENIED      If Source and Destination overlap.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+AsciiStrnToUnicodeStrS (\r
+  IN      CONST CHAR8               *Source,\r
+  IN      UINTN                     Length,\r
+  OUT     CHAR16                    *Destination,\r
+  IN      UINTN                     DestMax,\r
+  OUT     UINTN                     *DestinationLength\r
+  )\r
+{\r
+  UINTN            SourceLen;\r
+\r
+  ASSERT (((UINTN) Destination & BIT0) == 0);\r
+\r
+  //\r
+  // 1. None of Destination, Source or DestinationLength shall be a null\r
+  // pointer.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);\r
+  SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);\r
+  SAFE_STRING_CONSTRAINT_CHECK ((DestinationLength != NULL), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // 2. Neither Length nor DestMax shall be greater than ASCII_RSIZE_MAX or\r
+  // RSIZE_MAX.\r
+  //\r
+  if (RSIZE_MAX != 0) {\r
+    SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+    SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+  }\r
+  if (ASCII_RSIZE_MAX != 0) {\r
+    SAFE_STRING_CONSTRAINT_CHECK ((Length <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+    SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+  }\r
+\r
+  //\r
+  // 3. DestMax shall not equal zero.\r
+  //\r
+  SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // 4. If Length is not less than DestMax, then DestMax shall be greater than\r
+  // AsciiStrnLenS(Source, DestMax).\r
+  //\r
+  SourceLen = AsciiStrnLenS (Source, DestMax);\r
+  if (Length >= DestMax) {\r
+    SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);\r
+  }\r
+\r
+  //\r
+  // 5. Copying shall not take place between objects that overlap.\r
+  //\r
+  if (SourceLen > Length) {\r
+    SourceLen = Length;\r
+  }\r
+  SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax * sizeof(CHAR16), (VOID *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);\r
+\r
+  *DestinationLength = 0;\r
+\r
+  //\r
+  // Convert string\r
+  //\r
+  while ((*Source != 0) && (SourceLen > 0)) {\r
+    *(Destination++) = (CHAR16)*(Source++);\r
+    SourceLen--;\r
+    (*DestinationLength)++;\r
+  }\r
+  *Destination = 0;\r
+\r
+  return RETURN_SUCCESS;\r
+}\r