]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c
MdeModulePkg: Add BmpSupportLib class and instance
[mirror_edk2.git] / MdeModulePkg / Library / BaseBmpSupportLib / BmpSupportLib.c
diff --git a/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c b/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c
new file mode 100644 (file)
index 0000000..2c95e91
--- /dev/null
@@ -0,0 +1,583 @@
+/** @file\r
+\r
+  Provides services to convert a BMP graphics image to a GOP BLT buffer and\r
+  from a GOP BLT buffer to a BMP graphics image.\r
+\r
+  Caution: This module requires additional review when modified.\r
+  This module processes external input - BMP image.\r
+  This external input must be validated carefully to avoid security issue such\r
+  as buffer overflow, integer overflow.\r
+\r
+  TranslateBmpToGopBlt() receives untrusted input and performs basic validation.\r
+\r
+  Copyright (c) 2016-2017, Microsoft Corporation\r
+  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
+\r
+  All rights reserved.\r
+  Redistribution and use in source and binary forms, with or without\r
+  modification, are permitted provided that the following conditions are met:\r
+  1. Redistributions of source code must retain the above copyright notice,\r
+  this list of conditions and the following disclaimer.\r
+  2. Redistributions in binary form must reproduce the above copyright notice,\r
+  this list of conditions and the following disclaimer in the documentation\r
+  and/or other materials provided with the distribution.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\r
+  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
+  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\r
+  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/SafeIntLib.h>\r
+#include <IndustryStandard/Bmp.h>\r
+\r
+#include <Library/BmpSupportLib.h>\r
+\r
+//\r
+// BMP Image header for an uncompressed 24-bit per pixel BMP image.\r
+//\r
+const BMP_IMAGE_HEADER  mBmpImageHeaderTemplate = {\r
+  'B',    // CharB\r
+  'M',    // CharM\r
+  0,      // Size will be updated at runtime\r
+  {0, 0}, // Reserved\r
+  sizeof (BMP_IMAGE_HEADER), // ImageOffset\r
+  sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize\r
+  0,      // PixelWidth will be updated at runtime\r
+  0,      // PixelHeight will be updated at runtime\r
+  1,      // Planes\r
+  24,     // BitPerPixel\r
+  0,      // CompressionType\r
+  0,      // ImageSize will be updated at runtime\r
+  0,      // XPixelsPerMeter\r
+  0,      // YPixelsPerMeter\r
+  0,      // NumberOfColors\r
+  0       // ImportantColors\r
+};\r
+\r
+/**\r
+  Translate a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer\r
+  is passed in a GopBlt buffer will be allocated by this routine using\r
+  EFI_BOOT_SERVICES.AllocatePool(). If a GopBlt buffer is passed in it will be\r
+  used if it is big enough.\r
+\r
+  @param[in]       BmpImage      Pointer to BMP file.\r
+  @param[in]       BmpImageSize  Number of bytes in BmpImage.\r
+  @param[in, out]  GopBlt        Buffer containing GOP version of BmpImage.\r
+  @param[in, out]  GopBltSize    Size of GopBlt in bytes.\r
+  @param[out]      PixelHeight   Height of GopBlt/BmpImage in pixels.\r
+  @param[out]      PixelWidth    Width of GopBlt/BmpImage in pixels.\r
+\r
+  @retval  RETURN_SUCCESS            GopBlt and GopBltSize are returned.\r
+  @retval  RETURN_INVALID_PARAMETER  BmpImage is NULL.\r
+  @retval  RETURN_INVALID_PARAMETER  GopBlt is NULL.\r
+  @retval  RETURN_INVALID_PARAMETER  GopBltSize is NULL.\r
+  @retval  RETURN_INVALID_PARAMETER  PixelHeight is NULL.\r
+  @retval  RETURN_INVALID_PARAMETER  PixelWidth is NULL.\r
+  @retval  RETURN_UNSUPPORTED        BmpImage is not a valid *.BMP image.\r
+  @retval  RETURN_BUFFER_TOO_SMALL   The passed in GopBlt buffer is not big\r
+                                     enough.  The required size is returned in\r
+                                     GopBltSize.\r
+  @retval  RETURN_OUT_OF_RESOURCES   The GopBlt buffer could not be allocated.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+TranslateBmpToGopBlt (\r
+  IN     VOID                           *BmpImage,\r
+  IN     UINTN                          BmpImageSize,\r
+  IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL  **GopBlt,\r
+  IN OUT UINTN                          *GopBltSize,\r
+  OUT    UINTN                          *PixelHeight,\r
+  OUT    UINTN                          *PixelWidth\r
+  )\r
+{\r
+  UINT8                          *Image;\r
+  UINT8                          *ImageHeader;\r
+  BMP_IMAGE_HEADER               *BmpHeader;\r
+  BMP_COLOR_MAP                  *BmpColorMap;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *BltBuffer;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *Blt;\r
+  UINT32                         BltBufferSize;\r
+  UINTN                          Index;\r
+  UINTN                          Height;\r
+  UINTN                          Width;\r
+  UINTN                          ImageIndex;\r
+  UINT32                         DataSizePerLine;\r
+  BOOLEAN                        IsAllocated;\r
+  UINT32                         ColorMapNum;\r
+  RETURN_STATUS                  Status;\r
+  UINT32                         DataSize;\r
+  UINT32                         Temp;\r
+\r
+  if (BmpImage == NULL || GopBlt == NULL || GopBltSize == NULL) {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+  if (PixelHeight == NULL || PixelWidth == NULL) {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BmpImageSize < sizeof (BMP_IMAGE_HEADER)) {\r
+    DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpImageSize too small\n"));\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  BmpHeader = (BMP_IMAGE_HEADER *)BmpImage;\r
+\r
+  if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {\r
+    DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->Char fields incorrect\n"));\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Doesn't support compress.\r
+  //\r
+  if (BmpHeader->CompressionType != 0) {\r
+    DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: Compression Type unsupported.\n"));\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Only support BITMAPINFOHEADER format.\r
+  // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER\r
+  //\r
+  if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateBmpToGopBlt: BmpHeader->Headership is not as expected.  Headersize is 0x%x\n",\r
+      BmpHeader->HeaderSize\r
+      ));\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // The data size in each line must be 4 byte alignment.\r
+  //\r
+  Status = SafeUint32Mult (\r
+             BmpHeader->PixelWidth,\r
+             BmpHeader->BitPerPixel,\r
+             &DataSizePerLine\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateBmpToGopBlt: invalid BmpImage... PixelWidth:0x%x BitPerPixel:0x%x\n",\r
+      BmpHeader->PixelWidth,\r
+      BmpHeader->BitPerPixel\r
+      ));\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  Status = SafeUint32Add (DataSizePerLine, 31, &DataSizePerLine);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x\n",\r
+      DataSizePerLine\r
+      ));\r
+\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  DataSizePerLine = (DataSizePerLine >> 3) &(~0x3);\r
+  Status = SafeUint32Mult (\r
+             DataSizePerLine,\r
+             BmpHeader->PixelHeight,\r
+             &BltBufferSize\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x PixelHeight:0x%x\n",\r
+      DataSizePerLine, BmpHeader->PixelHeight\r
+      ));\r
+\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  Status = SafeUint32Mult (\r
+             BmpHeader->PixelHeight,\r
+             DataSizePerLine,\r
+             &DataSize\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateBmpToGopBlt: invalid BmpImage... PixelHeight:0x%x DataSizePerLine:0x%x\n",\r
+      BmpHeader->PixelHeight, DataSizePerLine\r
+      ));\r
+\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  if ((BmpHeader->Size != BmpImageSize) ||\r
+      (BmpHeader->Size < BmpHeader->ImageOffset) ||\r
+      (BmpHeader->Size - BmpHeader->ImageOffset != DataSize)) {\r
+\r
+    DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: invalid BmpImage... \n"));\r
+    DEBUG ((DEBUG_ERROR, "   BmpHeader->Size: 0x%x\n", BmpHeader->Size));\r
+    DEBUG ((DEBUG_ERROR, "   BmpHeader->ImageOffset: 0x%x\n", BmpHeader->ImageOffset));\r
+    DEBUG ((DEBUG_ERROR, "   BmpImageSize: 0x%lx\n", (UINTN)BmpImageSize));\r
+    DEBUG ((DEBUG_ERROR, "   DataSize: 0x%lx\n", (UINTN)DataSize));\r
+\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Calculate Color Map offset in the image.\r
+  //\r
+  Image = BmpImage;\r
+  BmpColorMap = (BMP_COLOR_MAP *)(Image + sizeof (BMP_IMAGE_HEADER));\r
+  if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {\r
+    switch (BmpHeader->BitPerPixel) {\r
+    case 1:\r
+      ColorMapNum = 2;\r
+      break;\r
+    case 4:\r
+      ColorMapNum = 16;\r
+      break;\r
+    case 8:\r
+      ColorMapNum = 256;\r
+      break;\r
+    default:\r
+      ColorMapNum = 0;\r
+      break;\r
+    }\r
+    //\r
+    // BMP file may has padding data between the bmp header section and the\r
+    // bmp data section.\r
+    //\r
+    if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Calculate graphics image data address in the image\r
+  //\r
+  Image = ((UINT8 *)BmpImage) + BmpHeader->ImageOffset;\r
+  ImageHeader = Image;\r
+\r
+  //\r
+  // Calculate the BltBuffer needed size.\r
+  //\r
+  Status = SafeUint32Mult (\r
+             BmpHeader->PixelWidth,\r
+             BmpHeader->PixelHeight,\r
+             &BltBufferSize\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth:0x%x PixelHeight:0x%x\n",\r
+      BltBufferSize\r
+      ));\r
+\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  Temp = BltBufferSize;\r
+  Status = SafeUint32Mult (\r
+             BltBufferSize,\r
+             sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),\r
+             &BltBufferSize\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateBmpToGopBlt: invalid BltBuffer needed size... BltBufferSize:0x%lx struct size:0x%x\n",\r
+      Temp, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
+      ));\r
+\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  IsAllocated = FALSE;\r
+  if (*GopBlt == NULL) {\r
+    //\r
+    // GopBlt is not allocated by caller.\r
+    //\r
+    DEBUG ((DEBUG_INFO, "Bmp Support: Allocating 0x%X bytes of memory\n", BltBufferSize));\r
+    *GopBltSize = (UINTN)BltBufferSize;\r
+    *GopBlt = AllocatePool (*GopBltSize);\r
+    IsAllocated = TRUE;\r
+    if (*GopBlt == NULL) {\r
+      return RETURN_OUT_OF_RESOURCES;\r
+    }\r
+  } else {\r
+    //\r
+    // GopBlt has been allocated by caller.\r
+    //\r
+    if (*GopBltSize < (UINTN)BltBufferSize) {\r
+      *GopBltSize = (UINTN)BltBufferSize;\r
+      return RETURN_BUFFER_TOO_SMALL;\r
+    }\r
+  }\r
+\r
+  *PixelWidth  = BmpHeader->PixelWidth;\r
+  *PixelHeight = BmpHeader->PixelHeight;\r
+  DEBUG ((DEBUG_INFO, "BmpHeader->ImageOffset 0x%X\n", BmpHeader->ImageOffset));\r
+  DEBUG ((DEBUG_INFO, "BmpHeader->PixelWidth 0x%X\n", BmpHeader->PixelWidth));\r
+  DEBUG ((DEBUG_INFO, "BmpHeader->PixelHeight 0x%X\n", BmpHeader->PixelHeight));\r
+  DEBUG ((DEBUG_INFO, "BmpHeader->BitPerPixel 0x%X\n", BmpHeader->BitPerPixel));\r
+  DEBUG ((DEBUG_INFO, "BmpHeader->ImageSize 0x%X\n", BmpHeader->ImageSize));\r
+  DEBUG ((DEBUG_INFO, "BmpHeader->HeaderSize 0x%X\n", BmpHeader->HeaderSize));\r
+  DEBUG ((DEBUG_INFO, "BmpHeader->Size 0x%X\n", BmpHeader->Size));\r
+\r
+  //\r
+  // Translate image from BMP to Blt buffer format\r
+  //\r
+  BltBuffer = *GopBlt;\r
+  for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {\r
+    Blt = &BltBuffer[ (BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];\r
+    for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {\r
+      switch (BmpHeader->BitPerPixel) {\r
+      case 1:\r
+        //\r
+        // Translate 1-bit (2 colors) BMP to 24-bit color\r
+        //\r
+        for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {\r
+          Blt->Red   = BmpColorMap[ ((*Image) >> (7 - Index)) & 0x1].Red;\r
+          Blt->Green = BmpColorMap[ ((*Image) >> (7 - Index)) & 0x1].Green;\r
+          Blt->Blue  = BmpColorMap[ ((*Image) >> (7 - Index)) & 0x1].Blue;\r
+          Blt++;\r
+          Width++;\r
+        }\r
+\r
+        Blt--;\r
+        Width--;\r
+        break;\r
+\r
+      case 4:\r
+        //\r
+        // Translate 4-bit (16 colors) BMP Palette to 24-bit color\r
+        //\r
+        Index = (*Image) >> 4;\r
+        Blt->Red   = BmpColorMap[Index].Red;\r
+        Blt->Green = BmpColorMap[Index].Green;\r
+        Blt->Blue  = BmpColorMap[Index].Blue;\r
+        if (Width < (BmpHeader->PixelWidth - 1)) {\r
+          Blt++;\r
+          Width++;\r
+          Index = (*Image) & 0x0f;\r
+          Blt->Red   = BmpColorMap[Index].Red;\r
+          Blt->Green = BmpColorMap[Index].Green;\r
+          Blt->Blue  = BmpColorMap[Index].Blue;\r
+        }\r
+        break;\r
+\r
+      case 8:\r
+        //\r
+        // Translate 8-bit (256 colors) BMP Palette to 24-bit color\r
+        //\r
+        Blt->Red   = BmpColorMap[*Image].Red;\r
+        Blt->Green = BmpColorMap[*Image].Green;\r
+        Blt->Blue  = BmpColorMap[*Image].Blue;\r
+        break;\r
+\r
+      case 24:\r
+        //\r
+        // It is 24-bit BMP.\r
+        //\r
+        Blt->Blue  = *Image++;\r
+        Blt->Green = *Image++;\r
+        Blt->Red   = *Image;\r
+        break;\r
+\r
+      case 32:\r
+        //\r
+        //Conver 32 bit to 24bit bmp - just ignore the final byte of each pixel\r
+        Blt->Blue  = *Image++;\r
+        Blt->Green = *Image++;\r
+        Blt->Red   = *Image++;\r
+        break;\r
+\r
+      default:\r
+        //\r
+        // Other bit format BMP is not supported.\r
+        //\r
+        if (IsAllocated) {\r
+          FreePool (*GopBlt);\r
+          *GopBlt = NULL;\r
+        }\r
+        DEBUG ((DEBUG_ERROR, "Bmp Bit format not supported.  0x%X\n", BmpHeader->BitPerPixel));\r
+        return RETURN_UNSUPPORTED;\r
+        break;\r
+      };\r
+\r
+    }\r
+\r
+    ImageIndex = (UINTN)(Image - ImageHeader);\r
+    if ((ImageIndex % 4) != 0) {\r
+      //\r
+      // Bmp Image starts each row on a 32-bit boundary!\r
+      //\r
+      Image = Image + (4 - (ImageIndex % 4));\r
+    }\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Translate a GOP blt buffer to an uncompressed 24-bit per pixel BMP graphics\r
+  image. If a NULL BmpImage is passed in a BmpImage buffer will be allocated by\r
+  this routine using EFI_BOOT_SERVICES.AllocatePool(). If a BmpImage buffer is\r
+  passed in it will be used if it is big enough.\r
+\r
+  @param [in]      GopBlt        Pointer to GOP blt buffer.\r
+  @param [in]      PixelHeight   Height of GopBlt/BmpImage in pixels.\r
+  @param [in]      PixelWidth    Width of GopBlt/BmpImage in pixels.\r
+  @param [in, out] BmpImage      Buffer containing BMP version of GopBlt.\r
+  @param [in, out] BmpImageSize  Size of BmpImage in bytes.\r
+\r
+  @retval RETURN_SUCCESS            BmpImage and BmpImageSize are returned.\r
+  @retval RETURN_INVALID_PARAMETER  GopBlt is NULL.\r
+  @retval RETURN_INVALID_PARAMETER  BmpImage is NULL.\r
+  @retval RETURN_INVALID_PARAMETER  BmpImageSize is NULL.\r
+  @retval RETURN_UNSUPPORTED        GopBlt cannot be converted to a *.BMP image.\r
+  @retval RETURN_BUFFER_TOO_SMALL   The passed in BmpImage buffer is not big\r
+                                    enough.  The required size is returned in\r
+                                    BmpImageSize.\r
+  @retval RETURN_OUT_OF_RESOURCES   The BmpImage buffer could not be allocated.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+TranslateGopBltToBmp (\r
+  IN     EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *GopBlt,\r
+  IN     UINT32                         PixelHeight,\r
+  IN     UINT32                         PixelWidth,\r
+  IN OUT VOID                           **BmpImage,\r
+  IN OUT UINT32                         *BmpImageSize\r
+  )\r
+{\r
+  RETURN_STATUS                  Status;\r
+  UINT32                         PaddingSize;\r
+  UINT32                         BmpSize;\r
+  BMP_IMAGE_HEADER               *BmpImageHeader;\r
+  UINT8                          *Image;\r
+  UINTN                          Col;\r
+  UINTN                          Row;\r
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL  *BltPixel;\r
+\r
+  if (GopBlt == NULL || BmpImage == NULL || BmpImageSize == NULL) {\r
+    return RETURN_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Allocate memory for BMP file.\r
+  //\r
+  PaddingSize = PixelWidth & 0x3;\r
+\r
+  //\r
+  // First check PixelWidth * 3 + PaddingSize doesn't overflow\r
+  //\r
+  Status = SafeUint32Mult (PixelWidth, 3, &BmpSize);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
+      PixelHeight,\r
+      PixelWidth\r
+      ));\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+  Status = SafeUint32Add (BmpSize, PaddingSize, &BmpSize);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
+      PixelHeight,\r
+      PixelWidth\r
+      ));\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow\r
+  //\r
+  Status = SafeUint32Mult (BmpSize, PixelHeight, &BmpSize);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
+      PixelHeight,\r
+      PixelWidth\r
+      ));\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+  Status = SafeUint32Add (BmpSize, sizeof (BMP_IMAGE_HEADER), &BmpSize);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      DEBUG_ERROR,\r
+      "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
+      PixelHeight,\r
+      PixelWidth\r
+      ));\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // The image should be stored in EfiBootServicesData, allowing the system to\r
+  // reclaim the memory\r
+  //\r
+  if (*BmpImage == NULL) {\r
+    *BmpImage = AllocateZeroPool (BmpSize);\r
+    if (*BmpImage == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    *BmpImageSize = BmpSize;\r
+  } else if (*BmpImageSize < BmpSize) {\r
+    *BmpImageSize = BmpSize;\r
+    return RETURN_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  BmpImageHeader = (BMP_IMAGE_HEADER *)*BmpImage;\r
+  CopyMem (BmpImageHeader, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));\r
+  BmpImageHeader->Size        = *BmpImageSize;\r
+  BmpImageHeader->ImageSize   = *BmpImageSize - sizeof (BMP_IMAGE_HEADER);\r
+  BmpImageHeader->PixelWidth  = PixelWidth;\r
+  BmpImageHeader->PixelHeight = PixelHeight;\r
+\r
+  //\r
+  // Convert BLT buffer to BMP file.\r
+  //\r
+  Image = (UINT8 *)BmpImageHeader + sizeof (BMP_IMAGE_HEADER);\r
+  for (Row = 0; Row < PixelHeight; Row++) {\r
+    BltPixel = &GopBlt[(PixelHeight - Row - 1) * PixelWidth];\r
+\r
+    for (Col = 0; Col < PixelWidth; Col++) {\r
+      *Image++ = BltPixel->Blue;\r
+      *Image++ = BltPixel->Green;\r
+      *Image++ = BltPixel->Red;\r
+      BltPixel++;\r
+    }\r
+\r
+    //\r
+    // Padding for 4 byte alignment.\r
+    //\r
+    Image += PaddingSize;\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r