]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Library / BaseBmpSupportLib / BmpSupportLib.c
CommitLineData
4123d6da
KM
1/** @file\r
2\r
3 Provides services to convert a BMP graphics image to a GOP BLT buffer and\r
4 from a GOP BLT buffer to a BMP graphics image.\r
5\r
6 Caution: This module requires additional review when modified.\r
7 This module processes external input - BMP image.\r
8 This external input must be validated carefully to avoid security issue such\r
9 as buffer overflow, integer overflow.\r
10\r
11 TranslateBmpToGopBlt() receives untrusted input and performs basic validation.\r
12\r
13 Copyright (c) 2016-2017, Microsoft Corporation\r
14 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
15\r
16 All rights reserved.\r
9d510e61 17 SPDX-License-Identifier: BSD-2-Clause-Patent\r
4123d6da
KM
18\r
19**/\r
20\r
21#include <PiDxe.h>\r
22#include <Library/DebugLib.h>\r
23#include <Library/BaseMemoryLib.h>\r
24#include <Library/MemoryAllocationLib.h>\r
25#include <Library/SafeIntLib.h>\r
26#include <IndustryStandard/Bmp.h>\r
27\r
28#include <Library/BmpSupportLib.h>\r
29\r
30//\r
31// BMP Image header for an uncompressed 24-bit per pixel BMP image.\r
32//\r
33const BMP_IMAGE_HEADER mBmpImageHeaderTemplate = {\r
34 'B', // CharB\r
35 'M', // CharM\r
36 0, // Size will be updated at runtime\r
37 {0, 0}, // Reserved\r
38 sizeof (BMP_IMAGE_HEADER), // ImageOffset\r
39 sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize\r
40 0, // PixelWidth will be updated at runtime\r
41 0, // PixelHeight will be updated at runtime\r
42 1, // Planes\r
43 24, // BitPerPixel\r
44 0, // CompressionType\r
45 0, // ImageSize will be updated at runtime\r
46 0, // XPixelsPerMeter\r
47 0, // YPixelsPerMeter\r
48 0, // NumberOfColors\r
49 0 // ImportantColors\r
50};\r
51\r
52/**\r
53 Translate a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer\r
54 is passed in a GopBlt buffer will be allocated by this routine using\r
55 EFI_BOOT_SERVICES.AllocatePool(). If a GopBlt buffer is passed in it will be\r
56 used if it is big enough.\r
57\r
58 @param[in] BmpImage Pointer to BMP file.\r
59 @param[in] BmpImageSize Number of bytes in BmpImage.\r
60 @param[in, out] GopBlt Buffer containing GOP version of BmpImage.\r
61 @param[in, out] GopBltSize Size of GopBlt in bytes.\r
62 @param[out] PixelHeight Height of GopBlt/BmpImage in pixels.\r
63 @param[out] PixelWidth Width of GopBlt/BmpImage in pixels.\r
64\r
65 @retval RETURN_SUCCESS GopBlt and GopBltSize are returned.\r
66 @retval RETURN_INVALID_PARAMETER BmpImage is NULL.\r
67 @retval RETURN_INVALID_PARAMETER GopBlt is NULL.\r
68 @retval RETURN_INVALID_PARAMETER GopBltSize is NULL.\r
69 @retval RETURN_INVALID_PARAMETER PixelHeight is NULL.\r
70 @retval RETURN_INVALID_PARAMETER PixelWidth is NULL.\r
71 @retval RETURN_UNSUPPORTED BmpImage is not a valid *.BMP image.\r
72 @retval RETURN_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big\r
73 enough. The required size is returned in\r
74 GopBltSize.\r
75 @retval RETURN_OUT_OF_RESOURCES The GopBlt buffer could not be allocated.\r
76\r
77**/\r
78RETURN_STATUS\r
79EFIAPI\r
80TranslateBmpToGopBlt (\r
81 IN VOID *BmpImage,\r
82 IN UINTN BmpImageSize,\r
83 IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt,\r
84 IN OUT UINTN *GopBltSize,\r
85 OUT UINTN *PixelHeight,\r
86 OUT UINTN *PixelWidth\r
87 )\r
88{\r
89 UINT8 *Image;\r
90 UINT8 *ImageHeader;\r
91 BMP_IMAGE_HEADER *BmpHeader;\r
92 BMP_COLOR_MAP *BmpColorMap;\r
93 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;\r
94 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;\r
95 UINT32 BltBufferSize;\r
96 UINTN Index;\r
97 UINTN Height;\r
98 UINTN Width;\r
99 UINTN ImageIndex;\r
100 UINT32 DataSizePerLine;\r
101 BOOLEAN IsAllocated;\r
102 UINT32 ColorMapNum;\r
103 RETURN_STATUS Status;\r
104 UINT32 DataSize;\r
105 UINT32 Temp;\r
106\r
107 if (BmpImage == NULL || GopBlt == NULL || GopBltSize == NULL) {\r
108 return RETURN_INVALID_PARAMETER;\r
109 }\r
110 if (PixelHeight == NULL || PixelWidth == NULL) {\r
111 return RETURN_INVALID_PARAMETER;\r
112 }\r
113\r
114 if (BmpImageSize < sizeof (BMP_IMAGE_HEADER)) {\r
115 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpImageSize too small\n"));\r
116 return RETURN_UNSUPPORTED;\r
117 }\r
118\r
119 BmpHeader = (BMP_IMAGE_HEADER *)BmpImage;\r
120\r
121 if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {\r
122 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->Char fields incorrect\n"));\r
123 return RETURN_UNSUPPORTED;\r
124 }\r
125\r
126 //\r
127 // Doesn't support compress.\r
128 //\r
129 if (BmpHeader->CompressionType != 0) {\r
130 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: Compression Type unsupported.\n"));\r
131 return RETURN_UNSUPPORTED;\r
132 }\r
133\r
51fe5b51
RN
134 if ((BmpHeader->PixelHeight == 0) || (BmpHeader->PixelWidth == 0)) {\r
135 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->PixelHeight or BmpHeader->PixelWidth is 0.\n"));\r
136 return RETURN_UNSUPPORTED;\r
137 }\r
138\r
4123d6da
KM
139 //\r
140 // Only support BITMAPINFOHEADER format.\r
141 // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER\r
142 //\r
143 if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize)) {\r
144 DEBUG ((\r
145 DEBUG_ERROR,\r
146 "TranslateBmpToGopBlt: BmpHeader->Headership is not as expected. Headersize is 0x%x\n",\r
147 BmpHeader->HeaderSize\r
148 ));\r
149 return RETURN_UNSUPPORTED;\r
150 }\r
151\r
152 //\r
153 // The data size in each line must be 4 byte alignment.\r
154 //\r
155 Status = SafeUint32Mult (\r
156 BmpHeader->PixelWidth,\r
157 BmpHeader->BitPerPixel,\r
158 &DataSizePerLine\r
159 );\r
160 if (EFI_ERROR (Status)) {\r
161 DEBUG ((\r
162 DEBUG_ERROR,\r
163 "TranslateBmpToGopBlt: invalid BmpImage... PixelWidth:0x%x BitPerPixel:0x%x\n",\r
164 BmpHeader->PixelWidth,\r
165 BmpHeader->BitPerPixel\r
166 ));\r
167 return RETURN_UNSUPPORTED;\r
168 }\r
169\r
170 Status = SafeUint32Add (DataSizePerLine, 31, &DataSizePerLine);\r
171 if (EFI_ERROR (Status)) {\r
172 DEBUG ((\r
173 DEBUG_ERROR,\r
174 "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x\n",\r
175 DataSizePerLine\r
176 ));\r
177\r
178 return RETURN_UNSUPPORTED;\r
179 }\r
180\r
181 DataSizePerLine = (DataSizePerLine >> 3) &(~0x3);\r
182 Status = SafeUint32Mult (\r
183 DataSizePerLine,\r
184 BmpHeader->PixelHeight,\r
185 &BltBufferSize\r
186 );\r
187\r
188 if (EFI_ERROR (Status)) {\r
189 DEBUG ((\r
190 DEBUG_ERROR,\r
191 "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x PixelHeight:0x%x\n",\r
192 DataSizePerLine, BmpHeader->PixelHeight\r
193 ));\r
194\r
195 return RETURN_UNSUPPORTED;\r
196 }\r
197\r
198 Status = SafeUint32Mult (\r
199 BmpHeader->PixelHeight,\r
200 DataSizePerLine,\r
201 &DataSize\r
202 );\r
203\r
204 if (EFI_ERROR (Status)) {\r
205 DEBUG ((\r
206 DEBUG_ERROR,\r
207 "TranslateBmpToGopBlt: invalid BmpImage... PixelHeight:0x%x DataSizePerLine:0x%x\n",\r
208 BmpHeader->PixelHeight, DataSizePerLine\r
209 ));\r
210\r
211 return RETURN_UNSUPPORTED;\r
212 }\r
213\r
214 if ((BmpHeader->Size != BmpImageSize) ||\r
215 (BmpHeader->Size < BmpHeader->ImageOffset) ||\r
216 (BmpHeader->Size - BmpHeader->ImageOffset != DataSize)) {\r
217\r
218 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: invalid BmpImage... \n"));\r
219 DEBUG ((DEBUG_ERROR, " BmpHeader->Size: 0x%x\n", BmpHeader->Size));\r
220 DEBUG ((DEBUG_ERROR, " BmpHeader->ImageOffset: 0x%x\n", BmpHeader->ImageOffset));\r
221 DEBUG ((DEBUG_ERROR, " BmpImageSize: 0x%lx\n", (UINTN)BmpImageSize));\r
222 DEBUG ((DEBUG_ERROR, " DataSize: 0x%lx\n", (UINTN)DataSize));\r
223\r
224 return RETURN_UNSUPPORTED;\r
225 }\r
226\r
227 //\r
228 // Calculate Color Map offset in the image.\r
229 //\r
230 Image = BmpImage;\r
231 BmpColorMap = (BMP_COLOR_MAP *)(Image + sizeof (BMP_IMAGE_HEADER));\r
232 if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {\r
233 return RETURN_UNSUPPORTED;\r
234 }\r
235\r
236 if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {\r
237 switch (BmpHeader->BitPerPixel) {\r
238 case 1:\r
239 ColorMapNum = 2;\r
240 break;\r
241 case 4:\r
242 ColorMapNum = 16;\r
243 break;\r
244 case 8:\r
245 ColorMapNum = 256;\r
246 break;\r
247 default:\r
248 ColorMapNum = 0;\r
249 break;\r
250 }\r
251 //\r
252 // BMP file may has padding data between the bmp header section and the\r
253 // bmp data section.\r
254 //\r
255 if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {\r
256 return RETURN_UNSUPPORTED;\r
257 }\r
258 }\r
259\r
260 //\r
261 // Calculate graphics image data address in the image\r
262 //\r
263 Image = ((UINT8 *)BmpImage) + BmpHeader->ImageOffset;\r
264 ImageHeader = Image;\r
265\r
266 //\r
267 // Calculate the BltBuffer needed size.\r
268 //\r
269 Status = SafeUint32Mult (\r
270 BmpHeader->PixelWidth,\r
271 BmpHeader->PixelHeight,\r
272 &BltBufferSize\r
273 );\r
274\r
275 if (EFI_ERROR (Status)) {\r
276 DEBUG ((\r
277 DEBUG_ERROR,\r
278 "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth:0x%x PixelHeight:0x%x\n",\r
2a9e1b97 279 BmpHeader->PixelWidth, BmpHeader->PixelHeight\r
4123d6da
KM
280 ));\r
281\r
282 return RETURN_UNSUPPORTED;\r
283 }\r
284\r
285 Temp = BltBufferSize;\r
286 Status = SafeUint32Mult (\r
287 BltBufferSize,\r
288 sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),\r
289 &BltBufferSize\r
290 );\r
291\r
292 if (EFI_ERROR (Status)) {\r
293 DEBUG ((\r
294 DEBUG_ERROR,\r
2a9e1b97 295 "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth x PixelHeight:0x%x struct size:0x%x\n",\r
4123d6da
KM
296 Temp, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
297 ));\r
298\r
299 return RETURN_UNSUPPORTED;\r
300 }\r
301\r
302 IsAllocated = FALSE;\r
303 if (*GopBlt == NULL) {\r
304 //\r
305 // GopBlt is not allocated by caller.\r
306 //\r
307 DEBUG ((DEBUG_INFO, "Bmp Support: Allocating 0x%X bytes of memory\n", BltBufferSize));\r
308 *GopBltSize = (UINTN)BltBufferSize;\r
309 *GopBlt = AllocatePool (*GopBltSize);\r
310 IsAllocated = TRUE;\r
311 if (*GopBlt == NULL) {\r
312 return RETURN_OUT_OF_RESOURCES;\r
313 }\r
314 } else {\r
315 //\r
316 // GopBlt has been allocated by caller.\r
317 //\r
318 if (*GopBltSize < (UINTN)BltBufferSize) {\r
319 *GopBltSize = (UINTN)BltBufferSize;\r
320 return RETURN_BUFFER_TOO_SMALL;\r
321 }\r
322 }\r
323\r
324 *PixelWidth = BmpHeader->PixelWidth;\r
325 *PixelHeight = BmpHeader->PixelHeight;\r
326 DEBUG ((DEBUG_INFO, "BmpHeader->ImageOffset 0x%X\n", BmpHeader->ImageOffset));\r
327 DEBUG ((DEBUG_INFO, "BmpHeader->PixelWidth 0x%X\n", BmpHeader->PixelWidth));\r
328 DEBUG ((DEBUG_INFO, "BmpHeader->PixelHeight 0x%X\n", BmpHeader->PixelHeight));\r
329 DEBUG ((DEBUG_INFO, "BmpHeader->BitPerPixel 0x%X\n", BmpHeader->BitPerPixel));\r
330 DEBUG ((DEBUG_INFO, "BmpHeader->ImageSize 0x%X\n", BmpHeader->ImageSize));\r
331 DEBUG ((DEBUG_INFO, "BmpHeader->HeaderSize 0x%X\n", BmpHeader->HeaderSize));\r
332 DEBUG ((DEBUG_INFO, "BmpHeader->Size 0x%X\n", BmpHeader->Size));\r
333\r
334 //\r
335 // Translate image from BMP to Blt buffer format\r
336 //\r
337 BltBuffer = *GopBlt;\r
338 for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {\r
339 Blt = &BltBuffer[ (BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];\r
340 for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {\r
341 switch (BmpHeader->BitPerPixel) {\r
342 case 1:\r
343 //\r
344 // Translate 1-bit (2 colors) BMP to 24-bit color\r
345 //\r
346 for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {\r
347 Blt->Red = BmpColorMap[ ((*Image) >> (7 - Index)) & 0x1].Red;\r
348 Blt->Green = BmpColorMap[ ((*Image) >> (7 - Index)) & 0x1].Green;\r
349 Blt->Blue = BmpColorMap[ ((*Image) >> (7 - Index)) & 0x1].Blue;\r
350 Blt++;\r
351 Width++;\r
352 }\r
353\r
354 Blt--;\r
355 Width--;\r
356 break;\r
357\r
358 case 4:\r
359 //\r
360 // Translate 4-bit (16 colors) BMP Palette to 24-bit color\r
361 //\r
362 Index = (*Image) >> 4;\r
363 Blt->Red = BmpColorMap[Index].Red;\r
364 Blt->Green = BmpColorMap[Index].Green;\r
365 Blt->Blue = BmpColorMap[Index].Blue;\r
366 if (Width < (BmpHeader->PixelWidth - 1)) {\r
367 Blt++;\r
368 Width++;\r
369 Index = (*Image) & 0x0f;\r
370 Blt->Red = BmpColorMap[Index].Red;\r
371 Blt->Green = BmpColorMap[Index].Green;\r
372 Blt->Blue = BmpColorMap[Index].Blue;\r
373 }\r
374 break;\r
375\r
376 case 8:\r
377 //\r
378 // Translate 8-bit (256 colors) BMP Palette to 24-bit color\r
379 //\r
380 Blt->Red = BmpColorMap[*Image].Red;\r
381 Blt->Green = BmpColorMap[*Image].Green;\r
382 Blt->Blue = BmpColorMap[*Image].Blue;\r
383 break;\r
384\r
385 case 24:\r
386 //\r
387 // It is 24-bit BMP.\r
388 //\r
389 Blt->Blue = *Image++;\r
390 Blt->Green = *Image++;\r
391 Blt->Red = *Image;\r
392 break;\r
393\r
394 case 32:\r
395 //\r
396 //Conver 32 bit to 24bit bmp - just ignore the final byte of each pixel\r
397 Blt->Blue = *Image++;\r
398 Blt->Green = *Image++;\r
399 Blt->Red = *Image++;\r
400 break;\r
401\r
402 default:\r
403 //\r
404 // Other bit format BMP is not supported.\r
405 //\r
406 if (IsAllocated) {\r
407 FreePool (*GopBlt);\r
408 *GopBlt = NULL;\r
409 }\r
410 DEBUG ((DEBUG_ERROR, "Bmp Bit format not supported. 0x%X\n", BmpHeader->BitPerPixel));\r
411 return RETURN_UNSUPPORTED;\r
412 break;\r
413 };\r
414\r
415 }\r
416\r
99576ee3 417 ImageIndex = (UINTN)Image - (UINTN)ImageHeader;\r
4123d6da
KM
418 if ((ImageIndex % 4) != 0) {\r
419 //\r
420 // Bmp Image starts each row on a 32-bit boundary!\r
421 //\r
422 Image = Image + (4 - (ImageIndex % 4));\r
423 }\r
424 }\r
425\r
426 return RETURN_SUCCESS;\r
427}\r
428\r
429/**\r
430 Translate a GOP blt buffer to an uncompressed 24-bit per pixel BMP graphics\r
431 image. If a NULL BmpImage is passed in a BmpImage buffer will be allocated by\r
432 this routine using EFI_BOOT_SERVICES.AllocatePool(). If a BmpImage buffer is\r
433 passed in it will be used if it is big enough.\r
434\r
435 @param [in] GopBlt Pointer to GOP blt buffer.\r
436 @param [in] PixelHeight Height of GopBlt/BmpImage in pixels.\r
437 @param [in] PixelWidth Width of GopBlt/BmpImage in pixels.\r
438 @param [in, out] BmpImage Buffer containing BMP version of GopBlt.\r
439 @param [in, out] BmpImageSize Size of BmpImage in bytes.\r
440\r
441 @retval RETURN_SUCCESS BmpImage and BmpImageSize are returned.\r
442 @retval RETURN_INVALID_PARAMETER GopBlt is NULL.\r
443 @retval RETURN_INVALID_PARAMETER BmpImage is NULL.\r
444 @retval RETURN_INVALID_PARAMETER BmpImageSize is NULL.\r
445 @retval RETURN_UNSUPPORTED GopBlt cannot be converted to a *.BMP image.\r
446 @retval RETURN_BUFFER_TOO_SMALL The passed in BmpImage buffer is not big\r
447 enough. The required size is returned in\r
448 BmpImageSize.\r
449 @retval RETURN_OUT_OF_RESOURCES The BmpImage buffer could not be allocated.\r
450\r
451**/\r
452RETURN_STATUS\r
453EFIAPI\r
454TranslateGopBltToBmp (\r
455 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt,\r
456 IN UINT32 PixelHeight,\r
457 IN UINT32 PixelWidth,\r
458 IN OUT VOID **BmpImage,\r
459 IN OUT UINT32 *BmpImageSize\r
460 )\r
461{\r
462 RETURN_STATUS Status;\r
463 UINT32 PaddingSize;\r
464 UINT32 BmpSize;\r
465 BMP_IMAGE_HEADER *BmpImageHeader;\r
466 UINT8 *Image;\r
467 UINTN Col;\r
468 UINTN Row;\r
469 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;\r
470\r
471 if (GopBlt == NULL || BmpImage == NULL || BmpImageSize == NULL) {\r
472 return RETURN_INVALID_PARAMETER;\r
473 }\r
474\r
51fe5b51
RN
475 if ((PixelHeight == 0) || (PixelWidth == 0)) {\r
476 return RETURN_UNSUPPORTED;\r
477 }\r
478\r
4123d6da
KM
479 //\r
480 // Allocate memory for BMP file.\r
481 //\r
482 PaddingSize = PixelWidth & 0x3;\r
483\r
484 //\r
485 // First check PixelWidth * 3 + PaddingSize doesn't overflow\r
486 //\r
487 Status = SafeUint32Mult (PixelWidth, 3, &BmpSize);\r
488 if (EFI_ERROR (Status)) {\r
489 DEBUG ((\r
490 DEBUG_ERROR,\r
491 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
492 PixelHeight,\r
493 PixelWidth\r
494 ));\r
495 return RETURN_UNSUPPORTED;\r
496 }\r
497 Status = SafeUint32Add (BmpSize, PaddingSize, &BmpSize);\r
498 if (EFI_ERROR (Status)) {\r
499 DEBUG ((\r
500 DEBUG_ERROR,\r
501 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
502 PixelHeight,\r
503 PixelWidth\r
504 ));\r
505 return RETURN_UNSUPPORTED;\r
506 }\r
507\r
508 //\r
509 // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow\r
510 //\r
511 Status = SafeUint32Mult (BmpSize, PixelHeight, &BmpSize);\r
512 if (EFI_ERROR (Status)) {\r
513 DEBUG ((\r
514 DEBUG_ERROR,\r
515 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
516 PixelHeight,\r
517 PixelWidth\r
518 ));\r
519 return RETURN_UNSUPPORTED;\r
520 }\r
521 Status = SafeUint32Add (BmpSize, sizeof (BMP_IMAGE_HEADER), &BmpSize);\r
522 if (EFI_ERROR (Status)) {\r
523 DEBUG ((\r
524 DEBUG_ERROR,\r
525 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
526 PixelHeight,\r
527 PixelWidth\r
528 ));\r
529 return RETURN_UNSUPPORTED;\r
530 }\r
531\r
532 //\r
533 // The image should be stored in EfiBootServicesData, allowing the system to\r
534 // reclaim the memory\r
535 //\r
536 if (*BmpImage == NULL) {\r
537 *BmpImage = AllocateZeroPool (BmpSize);\r
538 if (*BmpImage == NULL) {\r
539 return EFI_OUT_OF_RESOURCES;\r
540 }\r
541 *BmpImageSize = BmpSize;\r
542 } else if (*BmpImageSize < BmpSize) {\r
543 *BmpImageSize = BmpSize;\r
544 return RETURN_BUFFER_TOO_SMALL;\r
545 }\r
546\r
547 BmpImageHeader = (BMP_IMAGE_HEADER *)*BmpImage;\r
548 CopyMem (BmpImageHeader, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));\r
549 BmpImageHeader->Size = *BmpImageSize;\r
550 BmpImageHeader->ImageSize = *BmpImageSize - sizeof (BMP_IMAGE_HEADER);\r
551 BmpImageHeader->PixelWidth = PixelWidth;\r
552 BmpImageHeader->PixelHeight = PixelHeight;\r
553\r
554 //\r
555 // Convert BLT buffer to BMP file.\r
556 //\r
557 Image = (UINT8 *)BmpImageHeader + sizeof (BMP_IMAGE_HEADER);\r
558 for (Row = 0; Row < PixelHeight; Row++) {\r
559 BltPixel = &GopBlt[(PixelHeight - Row - 1) * PixelWidth];\r
560\r
561 for (Col = 0; Col < PixelWidth; Col++) {\r
562 *Image++ = BltPixel->Blue;\r
563 *Image++ = BltPixel->Green;\r
564 *Image++ = BltPixel->Red;\r
565 BltPixel++;\r
566 }\r
567\r
568 //\r
569 // Padding for 4 byte alignment.\r
570 //\r
571 Image += PaddingSize;\r
572 }\r
573\r
574 return RETURN_SUCCESS;\r
575}\r