Coverage Report

Created: 2026-02-03 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}