MdeModulePkg/BmpSupportLib: Check PixelHeight/PixelWidth against 0
[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
51fe5b51
RN
151 if ((BmpHeader->PixelHeight == 0) || (BmpHeader->PixelWidth == 0)) {\r
152 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: BmpHeader->PixelHeight or BmpHeader->PixelWidth is 0.\n"));\r
153 return RETURN_UNSUPPORTED;\r
154 }\r
155\r
4123d6da
KM
156 //\r
157 // Only support BITMAPINFOHEADER format.\r
158 // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER\r
159 //\r
160 if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF (BMP_IMAGE_HEADER, HeaderSize)) {\r
161 DEBUG ((\r
162 DEBUG_ERROR,\r
163 "TranslateBmpToGopBlt: BmpHeader->Headership is not as expected. Headersize is 0x%x\n",\r
164 BmpHeader->HeaderSize\r
165 ));\r
166 return RETURN_UNSUPPORTED;\r
167 }\r
168\r
169 //\r
170 // The data size in each line must be 4 byte alignment.\r
171 //\r
172 Status = SafeUint32Mult (\r
173 BmpHeader->PixelWidth,\r
174 BmpHeader->BitPerPixel,\r
175 &DataSizePerLine\r
176 );\r
177 if (EFI_ERROR (Status)) {\r
178 DEBUG ((\r
179 DEBUG_ERROR,\r
180 "TranslateBmpToGopBlt: invalid BmpImage... PixelWidth:0x%x BitPerPixel:0x%x\n",\r
181 BmpHeader->PixelWidth,\r
182 BmpHeader->BitPerPixel\r
183 ));\r
184 return RETURN_UNSUPPORTED;\r
185 }\r
186\r
187 Status = SafeUint32Add (DataSizePerLine, 31, &DataSizePerLine);\r
188 if (EFI_ERROR (Status)) {\r
189 DEBUG ((\r
190 DEBUG_ERROR,\r
191 "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x\n",\r
192 DataSizePerLine\r
193 ));\r
194\r
195 return RETURN_UNSUPPORTED;\r
196 }\r
197\r
198 DataSizePerLine = (DataSizePerLine >> 3) &(~0x3);\r
199 Status = SafeUint32Mult (\r
200 DataSizePerLine,\r
201 BmpHeader->PixelHeight,\r
202 &BltBufferSize\r
203 );\r
204\r
205 if (EFI_ERROR (Status)) {\r
206 DEBUG ((\r
207 DEBUG_ERROR,\r
208 "TranslateBmpToGopBlt: invalid BmpImage... DataSizePerLine:0x%x PixelHeight:0x%x\n",\r
209 DataSizePerLine, BmpHeader->PixelHeight\r
210 ));\r
211\r
212 return RETURN_UNSUPPORTED;\r
213 }\r
214\r
215 Status = SafeUint32Mult (\r
216 BmpHeader->PixelHeight,\r
217 DataSizePerLine,\r
218 &DataSize\r
219 );\r
220\r
221 if (EFI_ERROR (Status)) {\r
222 DEBUG ((\r
223 DEBUG_ERROR,\r
224 "TranslateBmpToGopBlt: invalid BmpImage... PixelHeight:0x%x DataSizePerLine:0x%x\n",\r
225 BmpHeader->PixelHeight, DataSizePerLine\r
226 ));\r
227\r
228 return RETURN_UNSUPPORTED;\r
229 }\r
230\r
231 if ((BmpHeader->Size != BmpImageSize) ||\r
232 (BmpHeader->Size < BmpHeader->ImageOffset) ||\r
233 (BmpHeader->Size - BmpHeader->ImageOffset != DataSize)) {\r
234\r
235 DEBUG ((DEBUG_ERROR, "TranslateBmpToGopBlt: invalid BmpImage... \n"));\r
236 DEBUG ((DEBUG_ERROR, " BmpHeader->Size: 0x%x\n", BmpHeader->Size));\r
237 DEBUG ((DEBUG_ERROR, " BmpHeader->ImageOffset: 0x%x\n", BmpHeader->ImageOffset));\r
238 DEBUG ((DEBUG_ERROR, " BmpImageSize: 0x%lx\n", (UINTN)BmpImageSize));\r
239 DEBUG ((DEBUG_ERROR, " DataSize: 0x%lx\n", (UINTN)DataSize));\r
240\r
241 return RETURN_UNSUPPORTED;\r
242 }\r
243\r
244 //\r
245 // Calculate Color Map offset in the image.\r
246 //\r
247 Image = BmpImage;\r
248 BmpColorMap = (BMP_COLOR_MAP *)(Image + sizeof (BMP_IMAGE_HEADER));\r
249 if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {\r
250 return RETURN_UNSUPPORTED;\r
251 }\r
252\r
253 if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {\r
254 switch (BmpHeader->BitPerPixel) {\r
255 case 1:\r
256 ColorMapNum = 2;\r
257 break;\r
258 case 4:\r
259 ColorMapNum = 16;\r
260 break;\r
261 case 8:\r
262 ColorMapNum = 256;\r
263 break;\r
264 default:\r
265 ColorMapNum = 0;\r
266 break;\r
267 }\r
268 //\r
269 // BMP file may has padding data between the bmp header section and the\r
270 // bmp data section.\r
271 //\r
272 if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {\r
273 return RETURN_UNSUPPORTED;\r
274 }\r
275 }\r
276\r
277 //\r
278 // Calculate graphics image data address in the image\r
279 //\r
280 Image = ((UINT8 *)BmpImage) + BmpHeader->ImageOffset;\r
281 ImageHeader = Image;\r
282\r
283 //\r
284 // Calculate the BltBuffer needed size.\r
285 //\r
286 Status = SafeUint32Mult (\r
287 BmpHeader->PixelWidth,\r
288 BmpHeader->PixelHeight,\r
289 &BltBufferSize\r
290 );\r
291\r
292 if (EFI_ERROR (Status)) {\r
293 DEBUG ((\r
294 DEBUG_ERROR,\r
295 "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth:0x%x PixelHeight:0x%x\n",\r
2a9e1b97 296 BmpHeader->PixelWidth, BmpHeader->PixelHeight\r
4123d6da
KM
297 ));\r
298\r
299 return RETURN_UNSUPPORTED;\r
300 }\r
301\r
302 Temp = BltBufferSize;\r
303 Status = SafeUint32Mult (\r
304 BltBufferSize,\r
305 sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL),\r
306 &BltBufferSize\r
307 );\r
308\r
309 if (EFI_ERROR (Status)) {\r
310 DEBUG ((\r
311 DEBUG_ERROR,\r
2a9e1b97 312 "TranslateBmpToGopBlt: invalid BltBuffer needed size... PixelWidth x PixelHeight:0x%x struct size:0x%x\n",\r
4123d6da
KM
313 Temp, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)\r
314 ));\r
315\r
316 return RETURN_UNSUPPORTED;\r
317 }\r
318\r
319 IsAllocated = FALSE;\r
320 if (*GopBlt == NULL) {\r
321 //\r
322 // GopBlt is not allocated by caller.\r
323 //\r
324 DEBUG ((DEBUG_INFO, "Bmp Support: Allocating 0x%X bytes of memory\n", BltBufferSize));\r
325 *GopBltSize = (UINTN)BltBufferSize;\r
326 *GopBlt = AllocatePool (*GopBltSize);\r
327 IsAllocated = TRUE;\r
328 if (*GopBlt == NULL) {\r
329 return RETURN_OUT_OF_RESOURCES;\r
330 }\r
331 } else {\r
332 //\r
333 // GopBlt has been allocated by caller.\r
334 //\r
335 if (*GopBltSize < (UINTN)BltBufferSize) {\r
336 *GopBltSize = (UINTN)BltBufferSize;\r
337 return RETURN_BUFFER_TOO_SMALL;\r
338 }\r
339 }\r
340\r
341 *PixelWidth = BmpHeader->PixelWidth;\r
342 *PixelHeight = BmpHeader->PixelHeight;\r
343 DEBUG ((DEBUG_INFO, "BmpHeader->ImageOffset 0x%X\n", BmpHeader->ImageOffset));\r
344 DEBUG ((DEBUG_INFO, "BmpHeader->PixelWidth 0x%X\n", BmpHeader->PixelWidth));\r
345 DEBUG ((DEBUG_INFO, "BmpHeader->PixelHeight 0x%X\n", BmpHeader->PixelHeight));\r
346 DEBUG ((DEBUG_INFO, "BmpHeader->BitPerPixel 0x%X\n", BmpHeader->BitPerPixel));\r
347 DEBUG ((DEBUG_INFO, "BmpHeader->ImageSize 0x%X\n", BmpHeader->ImageSize));\r
348 DEBUG ((DEBUG_INFO, "BmpHeader->HeaderSize 0x%X\n", BmpHeader->HeaderSize));\r
349 DEBUG ((DEBUG_INFO, "BmpHeader->Size 0x%X\n", BmpHeader->Size));\r
350\r
351 //\r
352 // Translate image from BMP to Blt buffer format\r
353 //\r
354 BltBuffer = *GopBlt;\r
355 for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {\r
356 Blt = &BltBuffer[ (BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];\r
357 for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {\r
358 switch (BmpHeader->BitPerPixel) {\r
359 case 1:\r
360 //\r
361 // Translate 1-bit (2 colors) BMP to 24-bit color\r
362 //\r
363 for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {\r
364 Blt->Red = BmpColorMap[ ((*Image) >> (7 - Index)) & 0x1].Red;\r
365 Blt->Green = BmpColorMap[ ((*Image) >> (7 - Index)) & 0x1].Green;\r
366 Blt->Blue = BmpColorMap[ ((*Image) >> (7 - Index)) & 0x1].Blue;\r
367 Blt++;\r
368 Width++;\r
369 }\r
370\r
371 Blt--;\r
372 Width--;\r
373 break;\r
374\r
375 case 4:\r
376 //\r
377 // Translate 4-bit (16 colors) BMP Palette to 24-bit color\r
378 //\r
379 Index = (*Image) >> 4;\r
380 Blt->Red = BmpColorMap[Index].Red;\r
381 Blt->Green = BmpColorMap[Index].Green;\r
382 Blt->Blue = BmpColorMap[Index].Blue;\r
383 if (Width < (BmpHeader->PixelWidth - 1)) {\r
384 Blt++;\r
385 Width++;\r
386 Index = (*Image) & 0x0f;\r
387 Blt->Red = BmpColorMap[Index].Red;\r
388 Blt->Green = BmpColorMap[Index].Green;\r
389 Blt->Blue = BmpColorMap[Index].Blue;\r
390 }\r
391 break;\r
392\r
393 case 8:\r
394 //\r
395 // Translate 8-bit (256 colors) BMP Palette to 24-bit color\r
396 //\r
397 Blt->Red = BmpColorMap[*Image].Red;\r
398 Blt->Green = BmpColorMap[*Image].Green;\r
399 Blt->Blue = BmpColorMap[*Image].Blue;\r
400 break;\r
401\r
402 case 24:\r
403 //\r
404 // It is 24-bit BMP.\r
405 //\r
406 Blt->Blue = *Image++;\r
407 Blt->Green = *Image++;\r
408 Blt->Red = *Image;\r
409 break;\r
410\r
411 case 32:\r
412 //\r
413 //Conver 32 bit to 24bit bmp - just ignore the final byte of each pixel\r
414 Blt->Blue = *Image++;\r
415 Blt->Green = *Image++;\r
416 Blt->Red = *Image++;\r
417 break;\r
418\r
419 default:\r
420 //\r
421 // Other bit format BMP is not supported.\r
422 //\r
423 if (IsAllocated) {\r
424 FreePool (*GopBlt);\r
425 *GopBlt = NULL;\r
426 }\r
427 DEBUG ((DEBUG_ERROR, "Bmp Bit format not supported. 0x%X\n", BmpHeader->BitPerPixel));\r
428 return RETURN_UNSUPPORTED;\r
429 break;\r
430 };\r
431\r
432 }\r
433\r
99576ee3 434 ImageIndex = (UINTN)Image - (UINTN)ImageHeader;\r
4123d6da
KM
435 if ((ImageIndex % 4) != 0) {\r
436 //\r
437 // Bmp Image starts each row on a 32-bit boundary!\r
438 //\r
439 Image = Image + (4 - (ImageIndex % 4));\r
440 }\r
441 }\r
442\r
443 return RETURN_SUCCESS;\r
444}\r
445\r
446/**\r
447 Translate a GOP blt buffer to an uncompressed 24-bit per pixel BMP graphics\r
448 image. If a NULL BmpImage is passed in a BmpImage buffer will be allocated by\r
449 this routine using EFI_BOOT_SERVICES.AllocatePool(). If a BmpImage buffer is\r
450 passed in it will be used if it is big enough.\r
451\r
452 @param [in] GopBlt Pointer to GOP blt buffer.\r
453 @param [in] PixelHeight Height of GopBlt/BmpImage in pixels.\r
454 @param [in] PixelWidth Width of GopBlt/BmpImage in pixels.\r
455 @param [in, out] BmpImage Buffer containing BMP version of GopBlt.\r
456 @param [in, out] BmpImageSize Size of BmpImage in bytes.\r
457\r
458 @retval RETURN_SUCCESS BmpImage and BmpImageSize are returned.\r
459 @retval RETURN_INVALID_PARAMETER GopBlt is NULL.\r
460 @retval RETURN_INVALID_PARAMETER BmpImage is NULL.\r
461 @retval RETURN_INVALID_PARAMETER BmpImageSize is NULL.\r
462 @retval RETURN_UNSUPPORTED GopBlt cannot be converted to a *.BMP image.\r
463 @retval RETURN_BUFFER_TOO_SMALL The passed in BmpImage buffer is not big\r
464 enough. The required size is returned in\r
465 BmpImageSize.\r
466 @retval RETURN_OUT_OF_RESOURCES The BmpImage buffer could not be allocated.\r
467\r
468**/\r
469RETURN_STATUS\r
470EFIAPI\r
471TranslateGopBltToBmp (\r
472 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt,\r
473 IN UINT32 PixelHeight,\r
474 IN UINT32 PixelWidth,\r
475 IN OUT VOID **BmpImage,\r
476 IN OUT UINT32 *BmpImageSize\r
477 )\r
478{\r
479 RETURN_STATUS Status;\r
480 UINT32 PaddingSize;\r
481 UINT32 BmpSize;\r
482 BMP_IMAGE_HEADER *BmpImageHeader;\r
483 UINT8 *Image;\r
484 UINTN Col;\r
485 UINTN Row;\r
486 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;\r
487\r
488 if (GopBlt == NULL || BmpImage == NULL || BmpImageSize == NULL) {\r
489 return RETURN_INVALID_PARAMETER;\r
490 }\r
491\r
51fe5b51
RN
492 if ((PixelHeight == 0) || (PixelWidth == 0)) {\r
493 return RETURN_UNSUPPORTED;\r
494 }\r
495\r
4123d6da
KM
496 //\r
497 // Allocate memory for BMP file.\r
498 //\r
499 PaddingSize = PixelWidth & 0x3;\r
500\r
501 //\r
502 // First check PixelWidth * 3 + PaddingSize doesn't overflow\r
503 //\r
504 Status = SafeUint32Mult (PixelWidth, 3, &BmpSize);\r
505 if (EFI_ERROR (Status)) {\r
506 DEBUG ((\r
507 DEBUG_ERROR,\r
508 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
509 PixelHeight,\r
510 PixelWidth\r
511 ));\r
512 return RETURN_UNSUPPORTED;\r
513 }\r
514 Status = SafeUint32Add (BmpSize, PaddingSize, &BmpSize);\r
515 if (EFI_ERROR (Status)) {\r
516 DEBUG ((\r
517 DEBUG_ERROR,\r
518 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
519 PixelHeight,\r
520 PixelWidth\r
521 ));\r
522 return RETURN_UNSUPPORTED;\r
523 }\r
524\r
525 //\r
526 // Second check (mLogoWidth * 3 + PaddingSize) * mLogoHeight + sizeof (BMP_IMAGE_HEADER) doesn't overflow\r
527 //\r
528 Status = SafeUint32Mult (BmpSize, PixelHeight, &BmpSize);\r
529 if (EFI_ERROR (Status)) {\r
530 DEBUG ((\r
531 DEBUG_ERROR,\r
532 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
533 PixelHeight,\r
534 PixelWidth\r
535 ));\r
536 return RETURN_UNSUPPORTED;\r
537 }\r
538 Status = SafeUint32Add (BmpSize, sizeof (BMP_IMAGE_HEADER), &BmpSize);\r
539 if (EFI_ERROR (Status)) {\r
540 DEBUG ((\r
541 DEBUG_ERROR,\r
542 "TranslateGopBltToBmp: GopBlt is too large. PixelHeight:0x%x PixelWidth:0x%x\n",\r
543 PixelHeight,\r
544 PixelWidth\r
545 ));\r
546 return RETURN_UNSUPPORTED;\r
547 }\r
548\r
549 //\r
550 // The image should be stored in EfiBootServicesData, allowing the system to\r
551 // reclaim the memory\r
552 //\r
553 if (*BmpImage == NULL) {\r
554 *BmpImage = AllocateZeroPool (BmpSize);\r
555 if (*BmpImage == NULL) {\r
556 return EFI_OUT_OF_RESOURCES;\r
557 }\r
558 *BmpImageSize = BmpSize;\r
559 } else if (*BmpImageSize < BmpSize) {\r
560 *BmpImageSize = BmpSize;\r
561 return RETURN_BUFFER_TOO_SMALL;\r
562 }\r
563\r
564 BmpImageHeader = (BMP_IMAGE_HEADER *)*BmpImage;\r
565 CopyMem (BmpImageHeader, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));\r
566 BmpImageHeader->Size = *BmpImageSize;\r
567 BmpImageHeader->ImageSize = *BmpImageSize - sizeof (BMP_IMAGE_HEADER);\r
568 BmpImageHeader->PixelWidth = PixelWidth;\r
569 BmpImageHeader->PixelHeight = PixelHeight;\r
570\r
571 //\r
572 // Convert BLT buffer to BMP file.\r
573 //\r
574 Image = (UINT8 *)BmpImageHeader + sizeof (BMP_IMAGE_HEADER);\r
575 for (Row = 0; Row < PixelHeight; Row++) {\r
576 BltPixel = &GopBlt[(PixelHeight - Row - 1) * PixelWidth];\r
577\r
578 for (Col = 0; Col < PixelWidth; Col++) {\r
579 *Image++ = BltPixel->Blue;\r
580 *Image++ = BltPixel->Green;\r
581 *Image++ = BltPixel->Red;\r
582 BltPixel++;\r
583 }\r
584\r
585 //\r
586 // Padding for 4 byte alignment.\r
587 //\r
588 Image += PaddingSize;\r
589 }\r
590\r
591 return RETURN_SUCCESS;\r
592}\r