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