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