MdePkg/BasePrintLib: Add safe print functions [A|U]ValueToStringS
[mirror_edk2.git] / MdePkg / Library / BasePrintLib / PrintLibInternal.c
index 155fe6a..9b15a07 100644 (file)
@@ -291,6 +291,210 @@ BasePrintLibConvertValueToString (
   return ((Buffer - OriginalBuffer) / Increment);\r
 }\r
 \r
+/**\r
+  Internal function that converts a decimal value to a Null-terminated string.\r
+\r
+  Converts the decimal number specified by Value to a Null-terminated string\r
+  specified by Buffer containing at most Width characters. If Width is 0 then a\r
+  width of MAXIMUM_VALUE_CHARACTERS is assumed. If the conversion contains more\r
+  than Width characters, then only the first Width characters are placed in\r
+  Buffer. Additional conversion parameters are specified in Flags.\r
+  The Flags bit LEFT_JUSTIFY is always ignored.\r
+  All conversions are left justified in Buffer.\r
+  If Width is 0, PREFIX_ZERO is ignored in Flags.\r
+  If COMMA_TYPE is set in Flags, then PREFIX_ZERO is ignored in Flags, and\r
+  commas are inserted every 3rd digit starting from the right.\r
+  If Value is < 0, then the fist character in Buffer is a '-'.\r
+  If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored,\r
+  then Buffer is padded with '0' characters so the combination of the optional\r
+  '-' sign character, '0' characters, digit characters for Value, and the\r
+  Null-terminator add up to Width characters.\r
+\r
+  If an error would be returned, the function will ASSERT().\r
+\r
+  @param  Buffer      The pointer to the output buffer for the produced\r
+                      Null-terminated string.\r
+  @param  BufferSize  The size of Buffer in bytes, including the\r
+                      Null-terminator.\r
+  @param  Flags       The bitmask of flags that specify left justification,\r
+                      zero pad, and commas.\r
+  @param  Value       The 64-bit signed value to convert to a string.\r
+  @param  Width       The maximum number of characters to place in Buffer,\r
+                      not including the Null-terminator.\r
+  @param  Increment   The character increment in Buffer.\r
+\r
+  @retval RETURN_SUCCESS           The decimal value is converted.\r
+  @retval RETURN_BUFFER_TOO_SMALL  If BufferSize cannot hold the converted\r
+                                   value.\r
+  @retval RETURN_INVALID_PARAMETER If Buffer is NULL.\r
+                                   If Increment is 1 and\r
+                                   PcdMaximumAsciiStringLength is not zero,\r
+                                   BufferSize is greater than\r
+                                   PcdMaximumAsciiStringLength.\r
+                                   If Increment is not 1 and\r
+                                   PcdMaximumUnicodeStringLength is not zero,\r
+                                   BufferSize is greater than\r
+                                   (PcdMaximumUnicodeStringLength *\r
+                                   sizeof (CHAR16) + 1).\r
+                                   If unsupported bits are set in Flags.\r
+                                   If both COMMA_TYPE and RADIX_HEX are set in\r
+                                   Flags.\r
+                                   If Width >= MAXIMUM_VALUE_CHARACTERS.\r
+\r
+**/\r
+RETURN_STATUS\r
+BasePrintLibConvertValueToStringS (\r
+  IN OUT CHAR8   *Buffer,\r
+  IN UINTN       BufferSize,\r
+  IN UINTN       Flags,\r
+  IN INT64       Value,\r
+  IN UINTN       Width,\r
+  IN UINTN       Increment\r
+  )\r
+{\r
+  CHAR8  *EndBuffer;\r
+  CHAR8  ValueBuffer[MAXIMUM_VALUE_CHARACTERS];\r
+  CHAR8  *ValueBufferPtr;\r
+  UINTN  Count;\r
+  UINTN  Digits;\r
+  UINTN  Index;\r
+  UINTN  Radix;\r
+\r
+  //\r
+  // 1. Buffer shall not be a null pointer.\r
+  //\r
+  SAFE_PRINT_CONSTRAINT_CHECK ((Buffer != NULL), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // 2. BufferSize shall not be greater than (RSIZE_MAX * sizeof (CHAR16)) for\r
+  //    Unicode output string or shall not be greater than ASCII_RSIZE_MAX for\r
+  //    Ascii output string.\r
+  //\r
+  if (Increment == 1) {\r
+    //\r
+    // Ascii output string\r
+    //\r
+    if (ASCII_RSIZE_MAX != 0) {\r
+      SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);\r
+    }\r
+  } else {\r
+    //\r
+    // Unicode output string\r
+    //\r
+    if (RSIZE_MAX != 0) {\r
+      SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize <= RSIZE_MAX * sizeof (CHAR16) + 1), RETURN_INVALID_PARAMETER);\r
+    }\r
+  }\r
+\r
+  //\r
+  // 3. Flags shall be set properly.\r
+  //\r
+  SAFE_PRINT_CONSTRAINT_CHECK (((Flags & ~(LEFT_JUSTIFY | COMMA_TYPE | PREFIX_ZERO | RADIX_HEX)) == 0), RETURN_INVALID_PARAMETER);\r
+  SAFE_PRINT_CONSTRAINT_CHECK ((((Flags & COMMA_TYPE) == 0) || ((Flags & RADIX_HEX) == 0)), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // 4. Width shall be smaller than MAXIMUM_VALUE_CHARACTERS.\r
+  //\r
+  SAFE_PRINT_CONSTRAINT_CHECK ((Width < MAXIMUM_VALUE_CHARACTERS), RETURN_INVALID_PARAMETER);\r
+\r
+  //\r
+  // Width is 0 or COMMA_TYPE is set, PREFIX_ZERO is ignored.\r
+  //\r
+  if (Width == 0 || (Flags & COMMA_TYPE) != 0) {\r
+    Flags &= ~((UINTN) PREFIX_ZERO);\r
+  }\r
+  //\r
+  // If Width is 0 then a width of MAXIMUM_VALUE_CHARACTERS is assumed.\r
+  //\r
+  if (Width == 0) {\r
+    Width = MAXIMUM_VALUE_CHARACTERS - 1;\r
+  }\r
+\r
+  //\r
+  // Count the characters of the output string.\r
+  //\r
+  Count = 0;\r
+  Radix = ((Flags & RADIX_HEX) == 0)? 10 : 16;\r
+\r
+  if ((Flags & PREFIX_ZERO) != 0) {\r
+    Count = Width;\r
+  } else {\r
+    if ((Value < 0) && ((Flags & RADIX_HEX) == 0)) {\r
+      Count++;  // minus sign\r
+      ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, -Value, Radix);\r
+    } else {\r
+      ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);\r
+    }\r
+    Digits = ValueBufferPtr - ValueBuffer;\r
+    Count += Digits;\r
+\r
+    if ((Flags & COMMA_TYPE) != 0) {\r
+      Count += (Digits - 1) / 3;  // commas\r
+    }\r
+  }\r
+\r
+  Width = MIN (Count, Width);\r
+\r
+  //\r
+  // 5. BufferSize shall be large enough to hold the converted string.\r
+  //\r
+  SAFE_PRINT_CONSTRAINT_CHECK ((BufferSize >= (Width + 1) * Increment), RETURN_BUFFER_TOO_SMALL);\r
+\r
+  //\r
+  // Set the tag for the end of the input Buffer.\r
+  //\r
+  EndBuffer = Buffer + Width * Increment;\r
+\r
+  //\r
+  // Convert decimal negative\r
+  //\r
+  if ((Value < 0) && ((Flags & RADIX_HEX) == 0)) {\r
+    Value = -Value;\r
+    Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, '-', Increment);\r
+    Width--;\r
+  }\r
+\r
+  //\r
+  // Count the length of the value string.\r
+  //\r
+  ValueBufferPtr = BasePrintLibValueToString (ValueBuffer, Value, Radix);\r
+  Count = ValueBufferPtr - ValueBuffer;\r
+\r
+  //\r
+  // Append Zero\r
+  //\r
+  if ((Flags & PREFIX_ZERO) != 0) {\r
+    Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, Width - Count, '0', Increment);\r
+  }\r
+\r
+  //\r
+  // Print Comma type for every 3 characters\r
+  //\r
+  Digits = Count % 3;\r
+  if (Digits != 0) {\r
+    Digits = 3 - Digits;\r
+  }\r
+  for (Index = 0; Index < Count; Index++) {\r
+    Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, *ValueBufferPtr--, Increment);\r
+    if ((Flags & COMMA_TYPE) != 0) {\r
+      Digits++;\r
+      if (Digits == 3) {\r
+        Digits = 0;\r
+        if ((Index + 1) < Count) {\r
+          Buffer = BasePrintLibFillBuffer (Buffer, EndBuffer, 1, ',', Increment);\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Print Null-terminator\r
+  //\r
+  BasePrintLibFillBuffer (Buffer, EndBuffer + Increment, 1, 0, Increment);\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
 /**\r
   Worker function that produces a Null-terminated string in an output buffer \r
   based on a Null-terminated format string and a VA_LIST argument list.\r