diff options
Diffstat (limited to 'MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c')
| -rw-r--r-- | MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c | 1170 |
1 files changed, 585 insertions, 585 deletions
diff --git a/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c b/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c index c5e885d7a6..18df11f008 100644 --- a/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c +++ b/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c @@ -1,585 +1,585 @@ -/** @file
-
- Provides services to convert a BMP graphics image to a GOP BLT buffer and
- from a GOP BLT buffer to a BMP graphics image.
-
- Caution: This module requires additional review when modified.
- This module processes external input - BMP image.
- This external input must be validated carefully to avoid security issue such
- as buffer overflow, integer overflow.
-
- TranslateBmpToGopBlt() receives untrusted input and performs basic validation.
-
- Copyright (c) 2016-2017, Microsoft Corporation
- Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
-
- All rights reserved.
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/SafeIntLib.h>
-#include <IndustryStandard/Bmp.h>
-
-#include <Library/BmpSupportLib.h>
-
-//
-// BMP Image header for an uncompressed 24-bit per pixel BMP image.
-//
-const BMP_IMAGE_HEADER mBmpImageHeaderTemplate = {
- 'B', // CharB
- 'M', // CharM
- 0, // Size will be updated at runtime
- { 0, 0 }, // Reserved
- sizeof (BMP_IMAGE_HEADER), // ImageOffset
- sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize
- 0, // PixelWidth will be updated at runtime
- 0, // PixelHeight will be updated at runtime
- 1, // Planes
- 24, // BitPerPixel
- 0, // CompressionType
- 0, // ImageSize will be updated at runtime
- 0, // XPixelsPerMeter
- 0, // YPixelsPerMeter
- 0, // NumberOfColors
- 0 // ImportantColors
-};
-
-/**
- Translate a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
- is passed in a GopBlt buffer will be allocated by this routine using
- EFI_BOOT_SERVICES.AllocatePool(). If a GopBlt buffer is passed in it will be
- used if it is big enough.
-
- @param[in] BmpImage Pointer to BMP file.
- @param[in] BmpImageSize Number of bytes in BmpImage.
- @param[in, out] GopBlt Buffer containing GOP version of BmpImage.
- @param[in, out] GopBltSize Size of GopBlt in bytes.
- @param[out] PixelHeight Height of GopBlt/BmpImage in pixels.
- @param[out] PixelWidth Width of GopBlt/BmpImage in pixels.
-
- @retval RETURN_SUCCESS GopBlt and GopBltSize are returned.
- @retval RETURN_INVALID_PARAMETER BmpImage is NULL.
- @retval RETURN_INVALID_PARAMETER GopBlt is NULL.
- @retval RETURN_INVALID_PARAMETER GopBltSize is NULL.
- @retval RETURN_INVALID_PARAMETER PixelHeight is NULL.
- @retval RETURN_INVALID_PARAMETER PixelWidth is NULL.
- @retval RETURN_UNSUPPORTED BmpImage is not a valid *.BMP image.
- @retval RETURN_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big
- enough. The required size is returned in
- GopBltSize.
- @retval RETURN_OUT_OF_RESOURCES The GopBlt buffer could not be allocated.
-
-**/
-RETURN_STATUS
-EFIAPI
-TranslateBmpToGopBlt (
- IN VOID *BmpImage,
- IN UINTN BmpImageSize,
- IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt,
- IN OUT UINTN *GopBltSize,
- OUT UINTN *PixelHeight,
- OUT UINTN *PixelWidth
- )
-{
- UINT8 *Image;
- UINT8 *ImageHeader;
- BMP_IMAGE_HEADER *BmpHeader;
- BMP_COLOR_MAP *BmpColorMap;
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
- UINT32 BltBufferSize;
- UINTN Index;
- UINTN Height;
- UINTN Width;
- UINTN ImageIndex;
- UINT32 DataSizePerLine;
- BOOLEAN IsAllocated;
- UINT32 ColorMapNum;
- RETURN_STATUS Status;
- UINT32 DataSize;
- UINT32 Temp;
-
- if ((BmpImage == NULL) || (GopBlt == NULL) || (GopBltSize == NULL)) {
- return RETURN_INVALID_PARAMETER;
- }
-
- if ((PixelHeight == NULL) || (PixelWidth == NULL)) {
- return RETURN_INVALID_PARAMETER;
- }
-
- if (BmpImageSize < sizeof (BMP_IMAGE_HEADER)) {
- DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpImageSize too small\n"));
- return RETURN_UNSUPPORTED;
- }
-
- BmpHeader = (BMP_IMAGE_HEADER *)BmpImage;
-
- if ((BmpHeader->CharB != 'B') || (BmpHeader->CharM != 'M')) {
- DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->Char fields incorrect\n"));
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Doesn't support compress.
- //
- if (BmpHeader->CompressionType != 0) {
- DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: Compression Type unsupported.\n"));
- return RETURN_UNSUPPORTED;
- }
-
- if ((BmpHeader->PixelHeight == 0) || (BmpHeader->PixelWidth == 0)) {
- DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->PixelHeight or BmpHeader->PixelWidth is 0.\n"));
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Only support BITMAPINFOHEADER format.
- // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
- //
- if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateBmpToGopBlt: BmpHeader->Headership is not as expected. Headersize is 0x%x\n",
- BmpHeader->HeaderSize
- ));
- return RETURN_UNSUPPORTED;
- }
-
- //
- // The data size in each line must be 4 byte alignment.
- //
- Status = SafeUint32Mult (
- BmpHeader->PixelWidth,
- BmpHeader->BitPerPixel,
- &DataSizePerLine
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateBmpToGopBlt: invalid BmpImage... PixelWidth:0x%x BitPerPixel:0x%x\n",
- BmpHeader->PixelWidth,
- BmpHeader->BitPerPixel
- ));
- return RETURN_UNSUPPORTED;
- }
-
- Status = SafeUint32Add (DataSizePerLine, 31, &DataSizePerLine);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x\n",
- DataSizePerLine
- ));
-
- return RETURN_UNSUPPORTED;
- }
-
- DataSizePerLine = (DataSizePerLine >> 3) &(~0x3);
- Status = SafeUint32Mult (
- DataSizePerLine,
- BmpHeader->PixelHeight,
- &BltBufferSize
- );
-
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x PixelHeight:0x%x\n",
- DataSizePerLine,
- BmpHeader->PixelHeight
- ));
-
- return RETURN_UNSUPPORTED;
- }
-
- Status = SafeUint32Mult (
- BmpHeader->PixelHeight,
- DataSizePerLine,
- &DataSize
- );
-
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateBmpToGopBlt: invalid BmpImage... PixelHeight:0x%x DataSizePerLine:0x%x\n",
- BmpHeader->PixelHeight,
- DataSizePerLine
- ));
-
- return RETURN_UNSUPPORTED;
- }
-
- if ((BmpHeader->Size != BmpImageSize) ||
- (BmpHeader->Size < BmpHeader->ImageOffset) ||
- (BmpHeader->Size - BmpHeader->ImageOffset != DataSize))
- {
- DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: invalid BmpImage... \n"));
- DEBUG ((DEBUG_ERROR, " BmpHeader->Size: 0x%x\n", BmpHeader->Size));
- DEBUG ((DEBUG_ERROR, " BmpHeader->ImageOffset: 0x%x\n", BmpHeader->ImageOffset));
- DEBUG ((DEBUG_ERROR, " BmpImageSize: 0x%lx\n", (UINTN)BmpImageSize));
- DEBUG ((DEBUG_ERROR, " DataSize: 0x%lx\n", (UINTN)DataSize));
-
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Calculate Color Map offset in the image.
- //
- Image = BmpImage;
- BmpColorMap = (BMP_COLOR_MAP *)(Image + sizeof (BMP_IMAGE_HEADER));
- if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
- return RETURN_UNSUPPORTED;
- }
-
- if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
- switch (BmpHeader->BitPerPixel) {
- case 1:
- ColorMapNum = 2;
- break;
- case 4:
- ColorMapNum = 16;
- break;
- case 8:
- ColorMapNum = 256;
- break;
- default:
- ColorMapNum = 0;
- break;
- }
-
- //
- // BMP file may has padding data between the bmp header section and the
- // bmp data section.
- //
- if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
- return RETURN_UNSUPPORTED;
- }
- }
-
- //
- // Calculate graphics image data address in the image
- //
- Image = ((UINT8 *)BmpImage) + BmpHeader->ImageOffset;
- ImageHeader = Image;
-
- //
- // Calculate the BltBuffer needed size.
- //
- Status = SafeUint32Mult (
- BmpHeader->PixelWidth,
- BmpHeader->PixelHeight,
- &BltBufferSize
- );
-
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth:0x%x PixelHeight:0x%x\n",
- BmpHeader->PixelWidth,
- BmpHeader->PixelHeight
- ));
-
- return RETURN_UNSUPPORTED;
- }
-
- Temp = BltBufferSize;
- Status = SafeUint32Mult (
- BltBufferSize,
- sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),
- &BltBufferSize
- );
-
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth x PixelHeight:0x%x struct size:0x%x\n",
- Temp,
- sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
- ));
-
- return RETURN_UNSUPPORTED;
- }
-
- IsAllocated = FALSE;
- if (*GopBlt == NULL) {
- //
- // GopBlt is not allocated by caller.
- //
- DEBUG ((DEBUG_INFO, "Bmp Support: Allocating 0x%X bytes of memory\n", BltBufferSize));
- *GopBltSize = (UINTN)BltBufferSize;
- *GopBlt = AllocatePool (*GopBltSize);
- IsAllocated = TRUE;
- if (*GopBlt == NULL) {
- return RETURN_OUT_OF_RESOURCES;
- }
- } else {
- //
- // GopBlt has been allocated by caller.
- //
- if (*GopBltSize < (UINTN)BltBufferSize) {
- *GopBltSize = (UINTN)BltBufferSize;
- return RETURN_BUFFER_TOO_SMALL;
- }
- }
-
- *PixelWidth = BmpHeader->PixelWidth;
- *PixelHeight = BmpHeader->PixelHeight;
- DEBUG ((DEBUG_INFO, "BmpHeader->ImageOffset 0x%X\n", BmpHeader->ImageOffset));
- DEBUG ((DEBUG_INFO, "BmpHeader->PixelWidth 0x%X\n", BmpHeader->PixelWidth));
- DEBUG ((DEBUG_INFO, "BmpHeader->PixelHeight 0x%X\n", BmpHeader->PixelHeight));
- DEBUG ((DEBUG_INFO, "BmpHeader->BitPerPixel 0x%X\n", BmpHeader->BitPerPixel));
- DEBUG ((DEBUG_INFO, "BmpHeader->ImageSize 0x%X\n", BmpHeader->ImageSize));
- DEBUG ((DEBUG_INFO, "BmpHeader->HeaderSize 0x%X\n", BmpHeader->HeaderSize));
- DEBUG ((DEBUG_INFO, "BmpHeader->Size 0x%X\n", BmpHeader->Size));
-
- //
- // Translate image from BMP to Blt buffer format
- //
- BltBuffer = *GopBlt;
- for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
- Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
- for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
- switch (BmpHeader->BitPerPixel) {
- case 1:
- //
- // Translate 1-bit (2 colors) BMP to 24-bit color
- //
- for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
- Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
- Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
- Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
- Blt++;
- Width++;
- }
-
- Blt--;
- Width--;
- break;
-
- case 4:
- //
- // Translate 4-bit (16 colors) BMP Palette to 24-bit color
- //
- Index = (*Image) >> 4;
- Blt->Red = BmpColorMap[Index].Red;
- Blt->Green = BmpColorMap[Index].Green;
- Blt->Blue = BmpColorMap[Index].Blue;
- if (Width < (BmpHeader->PixelWidth - 1)) {
- Blt++;
- Width++;
- Index = (*Image) & 0x0f;
- Blt->Red = BmpColorMap[Index].Red;
- Blt->Green = BmpColorMap[Index].Green;
- Blt->Blue = BmpColorMap[Index].Blue;
- }
-
- break;
-
- case 8:
- //
- // Translate 8-bit (256 colors) BMP Palette to 24-bit color
- //
- Blt->Red = BmpColorMap[*Image].Red;
- Blt->Green = BmpColorMap[*Image].Green;
- Blt->Blue = BmpColorMap[*Image].Blue;
- break;
-
- case 24:
- //
- // It is 24-bit BMP.
- //
- Blt->Blue = *Image++;
- Blt->Green = *Image++;
- Blt->Red = *Image;
- break;
-
- case 32:
- //
- // Conver 32 bit to 24bit bmp - just ignore the final byte of each pixel
- Blt->Blue = *Image++;
- Blt->Green = *Image++;
- Blt->Red = *Image++;
- break;
-
- default:
- //
- // Other bit format BMP is not supported.
- //
- if (IsAllocated) {
- FreePool (*GopBlt);
- *GopBlt = NULL;
- }
-
- DEBUG ((DEBUG_ERROR, "Bmp Bit format not supported. 0x%X\n", BmpHeader->BitPerPixel));
- return RETURN_UNSUPPORTED;
- break;
- }
- }
-
- ImageIndex = (UINTN)Image - (UINTN)ImageHeader;
- if ((ImageIndex % 4) != 0) {
- //
- // Bmp Image starts each row on a 32-bit boundary!
- //
- Image = Image + (4 - (ImageIndex % 4));
- }
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Translate a GOP blt buffer to an uncompressed 24-bit per pixel BMP graphics
- image. If a NULL BmpImage is passed in a BmpImage buffer will be allocated by
- this routine using EFI_BOOT_SERVICES.AllocatePool(). If a BmpImage buffer is
- passed in it will be used if it is big enough.
-
- @param [in] GopBlt Pointer to GOP blt buffer.
- @param [in] PixelHeight Height of GopBlt/BmpImage in pixels.
- @param [in] PixelWidth Width of GopBlt/BmpImage in pixels.
- @param [in, out] BmpImage Buffer containing BMP version of GopBlt.
- @param [in, out] BmpImageSize Size of BmpImage in bytes.
-
- @retval RETURN_SUCCESS BmpImage and BmpImageSize are returned.
- @retval RETURN_INVALID_PARAMETER GopBlt is NULL.
- @retval RETURN_INVALID_PARAMETER BmpImage is NULL.
- @retval RETURN_INVALID_PARAMETER BmpImageSize is NULL.
- @retval RETURN_UNSUPPORTED GopBlt cannot be converted to a *.BMP image.
- @retval RETURN_BUFFER_TOO_SMALL The passed in BmpImage buffer is not big
- enough. The required size is returned in
- BmpImageSize.
- @retval RETURN_OUT_OF_RESOURCES The BmpImage buffer could not be allocated.
-
-**/
-RETURN_STATUS
-EFIAPI
-TranslateGopBltToBmp (
- IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt,
- IN UINT32 PixelHeight,
- IN UINT32 PixelWidth,
- IN OUT VOID **BmpImage,
- IN OUT UINT32 *BmpImageSize
- )
-{
- RETURN_STATUS Status;
- UINT32 PaddingSize;
- UINT32 BmpSize;
- BMP_IMAGE_HEADER *BmpImageHeader;
- UINT8 *Image;
- UINTN Col;
- UINTN Row;
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;
-
- if ((GopBlt == NULL) || (BmpImage == NULL) || (BmpImageSize == NULL)) {
- return RETURN_INVALID_PARAMETER;
- }
-
- if ((PixelHeight == 0) || (PixelWidth == 0)) {
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Allocate memory for BMP file.
- //
- PaddingSize = PixelWidth & 0x3;
-
- //
- // First check PixelWidth * 3 + PaddingSize doesn't overflow
- //
- Status = SafeUint32Mult (PixelWidth, 3, &BmpSize);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
- PixelHeight,
- PixelWidth
- ));
- return RETURN_UNSUPPORTED;
- }
-
- Status = SafeUint32Add (BmpSize, PaddingSize, &BmpSize);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
- PixelHeight,
- PixelWidth
- ));
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow
- //
- Status = SafeUint32Mult (BmpSize, PixelHeight, &BmpSize);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
- PixelHeight,
- PixelWidth
- ));
- return RETURN_UNSUPPORTED;
- }
-
- Status = SafeUint32Add (BmpSize, sizeof (BMP_IMAGE_HEADER), &BmpSize);
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_ERROR,
- "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",
- PixelHeight,
- PixelWidth
- ));
- return RETURN_UNSUPPORTED;
- }
-
- //
- // The image should be stored in EfiBootServicesData, allowing the system to
- // reclaim the memory
- //
- if (*BmpImage == NULL) {
- *BmpImage = AllocateZeroPool (BmpSize);
- if (*BmpImage == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- *BmpImageSize = BmpSize;
- } else if (*BmpImageSize < BmpSize) {
- *BmpImageSize = BmpSize;
- return RETURN_BUFFER_TOO_SMALL;
- }
-
- BmpImageHeader = (BMP_IMAGE_HEADER *)*BmpImage;
- CopyMem (BmpImageHeader, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));
- BmpImageHeader->Size = *BmpImageSize;
- BmpImageHeader->ImageSize = *BmpImageSize - sizeof (BMP_IMAGE_HEADER);
- BmpImageHeader->PixelWidth = PixelWidth;
- BmpImageHeader->PixelHeight = PixelHeight;
-
- //
- // Convert BLT buffer to BMP file.
- //
- Image = (UINT8 *)BmpImageHeader + sizeof (BMP_IMAGE_HEADER);
- for (Row = 0; Row < PixelHeight; Row++) {
- BltPixel = &GopBlt[(PixelHeight - Row - 1) * PixelWidth];
-
- for (Col = 0; Col < PixelWidth; Col++) {
- *Image++ = BltPixel->Blue;
- *Image++ = BltPixel->Green;
- *Image++ = BltPixel->Red;
- BltPixel++;
- }
-
- //
- // Padding for 4 byte alignment.
- //
- Image += PaddingSize;
- }
-
- return RETURN_SUCCESS;
-}
+/** @file + + Provides services to convert a BMP graphics image to a GOP BLT buffer and + from a GOP BLT buffer to a BMP graphics image. + + Caution: This module requires additional review when modified. + This module processes external input - BMP image. + This external input must be validated carefully to avoid security issue such + as buffer overflow, integer overflow. + + TranslateBmpToGopBlt() receives untrusted input and performs basic validation. + + Copyright (c) 2016-2017, Microsoft Corporation + Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> + + All rights reserved. + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/SafeIntLib.h> +#include <IndustryStandard/Bmp.h> + +#include <Library/BmpSupportLib.h> + +// +// BMP Image header for an uncompressed 24-bit per pixel BMP image. +// +const BMP_IMAGE_HEADER mBmpImageHeaderTemplate = { + 'B', // CharB + 'M', // CharM + 0, // Size will be updated at runtime + { 0, 0 }, // Reserved + sizeof (BMP_IMAGE_HEADER), // ImageOffset + sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize + 0, // PixelWidth will be updated at runtime + 0, // PixelHeight will be updated at runtime + 1, // Planes + 24, // BitPerPixel + 0, // CompressionType + 0, // ImageSize will be updated at runtime + 0, // XPixelsPerMeter + 0, // YPixelsPerMeter + 0, // NumberOfColors + 0 // ImportantColors +}; + +/** + Translate a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer + is passed in a GopBlt buffer will be allocated by this routine using + EFI_BOOT_SERVICES.AllocatePool(). If a GopBlt buffer is passed in it will be + used if it is big enough. + + @param[in] BmpImage Pointer to BMP file. + @param[in] BmpImageSize Number of bytes in BmpImage. + @param[in, out] GopBlt Buffer containing GOP version of BmpImage. + @param[in, out] GopBltSize Size of GopBlt in bytes. + @param[out] PixelHeight Height of GopBlt/BmpImage in pixels. + @param[out] PixelWidth Width of GopBlt/BmpImage in pixels. + + @retval RETURN_SUCCESS GopBlt and GopBltSize are returned. + @retval RETURN_INVALID_PARAMETER BmpImage is NULL. + @retval RETURN_INVALID_PARAMETER GopBlt is NULL. + @retval RETURN_INVALID_PARAMETER GopBltSize is NULL. + @retval RETURN_INVALID_PARAMETER PixelHeight is NULL. + @retval RETURN_INVALID_PARAMETER PixelWidth is NULL. + @retval RETURN_UNSUPPORTED BmpImage is not a valid *.BMP image. + @retval RETURN_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big + enough. The required size is returned in + GopBltSize. + @retval RETURN_OUT_OF_RESOURCES The GopBlt buffer could not be allocated. + +**/ +RETURN_STATUS +EFIAPI +TranslateBmpToGopBlt ( + IN VOID *BmpImage, + IN UINTN BmpImageSize, + IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt, + IN OUT UINTN *GopBltSize, + OUT UINTN *PixelHeight, + OUT UINTN *PixelWidth + ) +{ + UINT8 *Image; + UINT8 *ImageHeader; + BMP_IMAGE_HEADER *BmpHeader; + BMP_COLOR_MAP *BmpColorMap; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + UINT32 BltBufferSize; + UINTN Index; + UINTN Height; + UINTN Width; + UINTN ImageIndex; + UINT32 DataSizePerLine; + BOOLEAN IsAllocated; + UINT32 ColorMapNum; + RETURN_STATUS Status; + UINT32 DataSize; + UINT32 Temp; + + if ((BmpImage == NULL) || (GopBlt == NULL) || (GopBltSize == NULL)) { + return RETURN_INVALID_PARAMETER; + } + + if ((PixelHeight == NULL) || (PixelWidth == NULL)) { + return RETURN_INVALID_PARAMETER; + } + + if (BmpImageSize < sizeof (BMP_IMAGE_HEADER)) { + DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpImageSize too small\n")); + return RETURN_UNSUPPORTED; + } + + BmpHeader = (BMP_IMAGE_HEADER *)BmpImage; + + if ((BmpHeader->CharB != 'B') || (BmpHeader->CharM != 'M')) { + DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->Char fields incorrect\n")); + return RETURN_UNSUPPORTED; + } + + // + // Doesn't support compress. + // + if (BmpHeader->CompressionType != 0) { + DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: Compression Type unsupported.\n")); + return RETURN_UNSUPPORTED; + } + + if ((BmpHeader->PixelHeight == 0) || (BmpHeader->PixelWidth == 0)) { + DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->PixelHeight or BmpHeader->PixelWidth is 0.\n")); + return RETURN_UNSUPPORTED; + } + + // + // Only support BITMAPINFOHEADER format. + // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER + // + if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize)) { + DEBUG (( + DEBUG_ERROR, + "TranslateBmpToGopBlt: BmpHeader->Headership is not as expected. Headersize is 0x%x\n", + BmpHeader->HeaderSize + )); + return RETURN_UNSUPPORTED; + } + + // + // The data size in each line must be 4 byte alignment. + // + Status = SafeUint32Mult ( + BmpHeader->PixelWidth, + BmpHeader->BitPerPixel, + &DataSizePerLine + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateBmpToGopBlt: invalid BmpImage... PixelWidth:0x%x BitPerPixel:0x%x\n", + BmpHeader->PixelWidth, + BmpHeader->BitPerPixel + )); + return RETURN_UNSUPPORTED; + } + + Status = SafeUint32Add (DataSizePerLine, 31, &DataSizePerLine); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x\n", + DataSizePerLine + )); + + return RETURN_UNSUPPORTED; + } + + DataSizePerLine = (DataSizePerLine >> 3) &(~0x3); + Status = SafeUint32Mult ( + DataSizePerLine, + BmpHeader->PixelHeight, + &BltBufferSize + ); + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x PixelHeight:0x%x\n", + DataSizePerLine, + BmpHeader->PixelHeight + )); + + return RETURN_UNSUPPORTED; + } + + Status = SafeUint32Mult ( + BmpHeader->PixelHeight, + DataSizePerLine, + &DataSize + ); + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateBmpToGopBlt: invalid BmpImage... PixelHeight:0x%x DataSizePerLine:0x%x\n", + BmpHeader->PixelHeight, + DataSizePerLine + )); + + return RETURN_UNSUPPORTED; + } + + if ((BmpHeader->Size != BmpImageSize) || + (BmpHeader->Size < BmpHeader->ImageOffset) || + (BmpHeader->Size - BmpHeader->ImageOffset != DataSize)) + { + DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: invalid BmpImage... \n")); + DEBUG ((DEBUG_ERROR, " BmpHeader->Size: 0x%x\n", BmpHeader->Size)); + DEBUG ((DEBUG_ERROR, " BmpHeader->ImageOffset: 0x%x\n", BmpHeader->ImageOffset)); + DEBUG ((DEBUG_ERROR, " BmpImageSize: 0x%lx\n", (UINTN)BmpImageSize)); + DEBUG ((DEBUG_ERROR, " DataSize: 0x%lx\n", (UINTN)DataSize)); + + return RETURN_UNSUPPORTED; + } + + // + // Calculate Color Map offset in the image. + // + Image = BmpImage; + BmpColorMap = (BMP_COLOR_MAP *)(Image + sizeof (BMP_IMAGE_HEADER)); + if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) { + return RETURN_UNSUPPORTED; + } + + if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) { + switch (BmpHeader->BitPerPixel) { + case 1: + ColorMapNum = 2; + break; + case 4: + ColorMapNum = 16; + break; + case 8: + ColorMapNum = 256; + break; + default: + ColorMapNum = 0; + break; + } + + // + // BMP file may has padding data between the bmp header section and the + // bmp data section. + // + if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) { + return RETURN_UNSUPPORTED; + } + } + + // + // Calculate graphics image data address in the image + // + Image = ((UINT8 *)BmpImage) + BmpHeader->ImageOffset; + ImageHeader = Image; + + // + // Calculate the BltBuffer needed size. + // + Status = SafeUint32Mult ( + BmpHeader->PixelWidth, + BmpHeader->PixelHeight, + &BltBufferSize + ); + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth:0x%x PixelHeight:0x%x\n", + BmpHeader->PixelWidth, + BmpHeader->PixelHeight + )); + + return RETURN_UNSUPPORTED; + } + + Temp = BltBufferSize; + Status = SafeUint32Mult ( + BltBufferSize, + sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), + &BltBufferSize + ); + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth x PixelHeight:0x%x struct size:0x%x\n", + Temp, + sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + )); + + return RETURN_UNSUPPORTED; + } + + IsAllocated = FALSE; + if (*GopBlt == NULL) { + // + // GopBlt is not allocated by caller. + // + DEBUG ((DEBUG_INFO, "Bmp Support: Allocating 0x%X bytes of memory\n", BltBufferSize)); + *GopBltSize = (UINTN)BltBufferSize; + *GopBlt = AllocatePool (*GopBltSize); + IsAllocated = TRUE; + if (*GopBlt == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + } else { + // + // GopBlt has been allocated by caller. + // + if (*GopBltSize < (UINTN)BltBufferSize) { + *GopBltSize = (UINTN)BltBufferSize; + return RETURN_BUFFER_TOO_SMALL; + } + } + + *PixelWidth = BmpHeader->PixelWidth; + *PixelHeight = BmpHeader->PixelHeight; + DEBUG ((DEBUG_INFO, "BmpHeader->ImageOffset 0x%X\n", BmpHeader->ImageOffset)); + DEBUG ((DEBUG_INFO, "BmpHeader->PixelWidth 0x%X\n", BmpHeader->PixelWidth)); + DEBUG ((DEBUG_INFO, "BmpHeader->PixelHeight 0x%X\n", BmpHeader->PixelHeight)); + DEBUG ((DEBUG_INFO, "BmpHeader->BitPerPixel 0x%X\n", BmpHeader->BitPerPixel)); + DEBUG ((DEBUG_INFO, "BmpHeader->ImageSize 0x%X\n", BmpHeader->ImageSize)); + DEBUG ((DEBUG_INFO, "BmpHeader->HeaderSize 0x%X\n", BmpHeader->HeaderSize)); + DEBUG ((DEBUG_INFO, "BmpHeader->Size 0x%X\n", BmpHeader->Size)); + + // + // Translate image from BMP to Blt buffer format + // + BltBuffer = *GopBlt; + for (Height = 0; Height < BmpHeader->PixelHeight; Height++) { + Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth]; + for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) { + switch (BmpHeader->BitPerPixel) { + case 1: + // + // Translate 1-bit (2 colors) BMP to 24-bit color + // + for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) { + Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red; + Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green; + Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue; + Blt++; + Width++; + } + + Blt--; + Width--; + break; + + case 4: + // + // Translate 4-bit (16 colors) BMP Palette to 24-bit color + // + Index = (*Image) >> 4; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + if (Width < (BmpHeader->PixelWidth - 1)) { + Blt++; + Width++; + Index = (*Image) & 0x0f; + Blt->Red = BmpColorMap[Index].Red; + Blt->Green = BmpColorMap[Index].Green; + Blt->Blue = BmpColorMap[Index].Blue; + } + + break; + + case 8: + // + // Translate 8-bit (256 colors) BMP Palette to 24-bit color + // + Blt->Red = BmpColorMap[*Image].Red; + Blt->Green = BmpColorMap[*Image].Green; + Blt->Blue = BmpColorMap[*Image].Blue; + break; + + case 24: + // + // It is 24-bit BMP. + // + Blt->Blue = *Image++; + Blt->Green = *Image++; + Blt->Red = *Image; + break; + + case 32: + // + // Conver 32 bit to 24bit bmp - just ignore the final byte of each pixel + Blt->Blue = *Image++; + Blt->Green = *Image++; + Blt->Red = *Image++; + break; + + default: + // + // Other bit format BMP is not supported. + // + if (IsAllocated) { + FreePool (*GopBlt); + *GopBlt = NULL; + } + + DEBUG ((DEBUG_ERROR, "Bmp Bit format not supported. 0x%X\n", BmpHeader->BitPerPixel)); + return RETURN_UNSUPPORTED; + break; + } + } + + ImageIndex = (UINTN)Image - (UINTN)ImageHeader; + if ((ImageIndex % 4) != 0) { + // + // Bmp Image starts each row on a 32-bit boundary! + // + Image = Image + (4 - (ImageIndex % 4)); + } + } + + return RETURN_SUCCESS; +} + +/** + Translate a GOP blt buffer to an uncompressed 24-bit per pixel BMP graphics + image. If a NULL BmpImage is passed in a BmpImage buffer will be allocated by + this routine using EFI_BOOT_SERVICES.AllocatePool(). If a BmpImage buffer is + passed in it will be used if it is big enough. + + @param [in] GopBlt Pointer to GOP blt buffer. + @param [in] PixelHeight Height of GopBlt/BmpImage in pixels. + @param [in] PixelWidth Width of GopBlt/BmpImage in pixels. + @param [in, out] BmpImage Buffer containing BMP version of GopBlt. + @param [in, out] BmpImageSize Size of BmpImage in bytes. + + @retval RETURN_SUCCESS BmpImage and BmpImageSize are returned. + @retval RETURN_INVALID_PARAMETER GopBlt is NULL. + @retval RETURN_INVALID_PARAMETER BmpImage is NULL. + @retval RETURN_INVALID_PARAMETER BmpImageSize is NULL. + @retval RETURN_UNSUPPORTED GopBlt cannot be converted to a *.BMP image. + @retval RETURN_BUFFER_TOO_SMALL The passed in BmpImage buffer is not big + enough. The required size is returned in + BmpImageSize. + @retval RETURN_OUT_OF_RESOURCES The BmpImage buffer could not be allocated. + +**/ +RETURN_STATUS +EFIAPI +TranslateGopBltToBmp ( + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt, + IN UINT32 PixelHeight, + IN UINT32 PixelWidth, + IN OUT VOID **BmpImage, + IN OUT UINT32 *BmpImageSize + ) +{ + RETURN_STATUS Status; + UINT32 PaddingSize; + UINT32 BmpSize; + BMP_IMAGE_HEADER *BmpImageHeader; + UINT8 *Image; + UINTN Col; + UINTN Row; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel; + + if ((GopBlt == NULL) || (BmpImage == NULL) || (BmpImageSize == NULL)) { + return RETURN_INVALID_PARAMETER; + } + + if ((PixelHeight == 0) || (PixelWidth == 0)) { + return RETURN_UNSUPPORTED; + } + + // + // Allocate memory for BMP file. + // + PaddingSize = PixelWidth & 0x3; + + // + // First check PixelWidth * 3 + PaddingSize doesn't overflow + // + Status = SafeUint32Mult (PixelWidth, 3, &BmpSize); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n", + PixelHeight, + PixelWidth + )); + return RETURN_UNSUPPORTED; + } + + Status = SafeUint32Add (BmpSize, PaddingSize, &BmpSize); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n", + PixelHeight, + PixelWidth + )); + return RETURN_UNSUPPORTED; + } + + // + // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow + // + Status = SafeUint32Mult (BmpSize, PixelHeight, &BmpSize); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n", + PixelHeight, + PixelWidth + )); + return RETURN_UNSUPPORTED; + } + + Status = SafeUint32Add (BmpSize, sizeof (BMP_IMAGE_HEADER), &BmpSize); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n", + PixelHeight, + PixelWidth + )); + return RETURN_UNSUPPORTED; + } + + // + // The image should be stored in EfiBootServicesData, allowing the system to + // reclaim the memory + // + if (*BmpImage == NULL) { + *BmpImage = AllocateZeroPool (BmpSize); + if (*BmpImage == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *BmpImageSize = BmpSize; + } else if (*BmpImageSize < BmpSize) { + *BmpImageSize = BmpSize; + return RETURN_BUFFER_TOO_SMALL; + } + + BmpImageHeader = (BMP_IMAGE_HEADER *)*BmpImage; + CopyMem (BmpImageHeader, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER)); + BmpImageHeader->Size = *BmpImageSize; + BmpImageHeader->ImageSize = *BmpImageSize - sizeof (BMP_IMAGE_HEADER); + BmpImageHeader->PixelWidth = PixelWidth; + BmpImageHeader->PixelHeight = PixelHeight; + + // + // Convert BLT buffer to BMP file. + // + Image = (UINT8 *)BmpImageHeader + sizeof (BMP_IMAGE_HEADER); + for (Row = 0; Row < PixelHeight; Row++) { + BltPixel = &GopBlt[(PixelHeight - Row - 1) * PixelWidth]; + + for (Col = 0; Col < PixelWidth; Col++) { + *Image++ = BltPixel->Blue; + *Image++ = BltPixel->Green; + *Image++ = BltPixel->Red; + BltPixel++; + } + + // + // Padding for 4 byte alignment. + // + Image += PaddingSize; + } + + return RETURN_SUCCESS; +} |
