mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-23 16:17:40 +01:00
6b33696c93
Signed-off-by: SergeySlice <sergey.slice@gmail.com>
576 lines
18 KiB
C
576 lines
18 KiB
C
/** @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;
|
|
}
|