]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/Image.c
MdeModulePkg/HiiDatabase: Fix potential integer overflow (CVE-2018-12181)
[mirror_edk2.git] / MdeModulePkg / Universal / HiiDatabaseDxe / Image.c
1 /** @file
2 Implementation for EFI_HII_IMAGE_PROTOCOL.
3
4
5 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16
17 #include "HiiDatabase.h"
18
19 #define MAX_UINT24 0xFFFFFF
20
21 /**
22 Get the imageid of last image block: EFI_HII_IIBT_END_BLOCK when input
23 ImageId is zero, otherwise return the address of the
24 corresponding image block with identifier specified by ImageId.
25
26 This is a internal function.
27
28 @param ImageBlocks Points to the beginning of a series of image blocks stored in order.
29 @param ImageId If input ImageId is 0, output the image id of the EFI_HII_IIBT_END_BLOCK;
30 else use this id to find its corresponding image block address.
31
32 @return The image block address when input ImageId is not zero; otherwise return NULL.
33
34 **/
35 EFI_HII_IMAGE_BLOCK *
36 GetImageIdOrAddress (
37 IN EFI_HII_IMAGE_BLOCK *ImageBlocks,
38 IN OUT EFI_IMAGE_ID *ImageId
39 )
40 {
41 EFI_IMAGE_ID ImageIdCurrent;
42 EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
43 UINTN Length;
44
45 ASSERT (ImageBlocks != NULL && ImageId != NULL);
46 CurrentImageBlock = ImageBlocks;
47 ImageIdCurrent = 1;
48
49 while (CurrentImageBlock->BlockType != EFI_HII_IIBT_END) {
50 if (*ImageId != 0) {
51 if (*ImageId == ImageIdCurrent) {
52 //
53 // If the found image block is a duplicate block, update the ImageId to
54 // find the previous defined image block.
55 //
56 if (CurrentImageBlock->BlockType == EFI_HII_IIBT_DUPLICATE) {
57 *ImageId = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_DUPLICATE_BLOCK *) CurrentImageBlock)->ImageId);
58 ASSERT (*ImageId != ImageIdCurrent);
59 ASSERT (*ImageId != 0);
60 CurrentImageBlock = ImageBlocks;
61 ImageIdCurrent = 1;
62 continue;
63 }
64
65 return CurrentImageBlock;
66 }
67 if (*ImageId < ImageIdCurrent) {
68 //
69 // Can not find the specified image block in this image.
70 //
71 return NULL;
72 }
73 }
74 switch (CurrentImageBlock->BlockType) {
75 case EFI_HII_IIBT_EXT1:
76 Length = ((EFI_HII_IIBT_EXT1_BLOCK *) CurrentImageBlock)->Length;
77 break;
78 case EFI_HII_IIBT_EXT2:
79 Length = ReadUnaligned16 (&((EFI_HII_IIBT_EXT2_BLOCK *) CurrentImageBlock)->Length);
80 break;
81 case EFI_HII_IIBT_EXT4:
82 Length = ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_EXT4_BLOCK *) CurrentImageBlock)->Length);
83 break;
84
85 case EFI_HII_IIBT_IMAGE_1BIT:
86 case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
87 Length = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
88 BITMAP_LEN_1_BIT (
89 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
90 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
91 );
92 ImageIdCurrent++;
93 break;
94
95 case EFI_HII_IIBT_IMAGE_4BIT:
96 case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
97 Length = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
98 BITMAP_LEN_4_BIT (
99 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
100 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
101 );
102 ImageIdCurrent++;
103 break;
104
105 case EFI_HII_IIBT_IMAGE_8BIT:
106 case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
107 Length = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
108 BITMAP_LEN_8_BIT (
109 (UINT32) ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
110 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
111 );
112 ImageIdCurrent++;
113 break;
114
115 case EFI_HII_IIBT_IMAGE_24BIT:
116 case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
117 Length = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
118 BITMAP_LEN_24_BIT (
119 (UINT32) ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
120 ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
121 );
122 ImageIdCurrent++;
123 break;
124
125 case EFI_HII_IIBT_DUPLICATE:
126 Length = sizeof (EFI_HII_IIBT_DUPLICATE_BLOCK);
127 ImageIdCurrent++;
128 break;
129
130 case EFI_HII_IIBT_IMAGE_JPEG:
131 Length = OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size);
132 ImageIdCurrent++;
133 break;
134
135 case EFI_HII_IIBT_IMAGE_PNG:
136 Length = OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size);
137 ImageIdCurrent++;
138 break;
139
140 case EFI_HII_IIBT_SKIP1:
141 Length = sizeof (EFI_HII_IIBT_SKIP1_BLOCK);
142 ImageIdCurrent += ((EFI_HII_IIBT_SKIP1_BLOCK *) CurrentImageBlock)->SkipCount;
143 break;
144
145 case EFI_HII_IIBT_SKIP2:
146 Length = sizeof (EFI_HII_IIBT_SKIP2_BLOCK);
147 ImageIdCurrent += ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_SKIP2_BLOCK *) CurrentImageBlock)->SkipCount);
148 break;
149
150 default:
151 //
152 // Unknown image blocks can not be skipped, processing halts.
153 //
154 ASSERT (FALSE);
155 Length = 0;
156 break;
157 }
158
159 CurrentImageBlock = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) CurrentImageBlock + Length);
160
161 }
162
163 //
164 // When ImageId is zero, return the imageid of last image block: EFI_HII_IIBT_END_BLOCK.
165 //
166 if (*ImageId == 0) {
167 *ImageId = ImageIdCurrent;
168 return CurrentImageBlock;
169 }
170
171 return NULL;
172 }
173
174
175
176 /**
177 Convert pixels from EFI_GRAPHICS_OUTPUT_BLT_PIXEL to EFI_HII_RGB_PIXEL style.
178
179 This is a internal function.
180
181
182 @param BitMapOut Pixels in EFI_HII_RGB_PIXEL format.
183 @param BitMapIn Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
184 @param PixelNum The number of pixels to be converted.
185
186
187 **/
188 VOID
189 CopyGopToRgbPixel (
190 OUT EFI_HII_RGB_PIXEL *BitMapOut,
191 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapIn,
192 IN UINTN PixelNum
193 )
194 {
195 UINTN Index;
196
197 ASSERT (BitMapOut != NULL && BitMapIn != NULL);
198
199 for (Index = 0; Index < PixelNum; Index++) {
200 CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
201 }
202 }
203
204
205 /**
206 Convert pixels from EFI_HII_RGB_PIXEL to EFI_GRAPHICS_OUTPUT_BLT_PIXEL style.
207
208 This is a internal function.
209
210
211 @param BitMapOut Pixels in EFI_GRAPHICS_OUTPUT_BLT_PIXEL format.
212 @param BitMapIn Pixels in EFI_HII_RGB_PIXEL format.
213 @param PixelNum The number of pixels to be converted.
214
215
216 **/
217 VOID
218 CopyRgbToGopPixel (
219 OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapOut,
220 IN EFI_HII_RGB_PIXEL *BitMapIn,
221 IN UINTN PixelNum
222 )
223 {
224 UINTN Index;
225
226 ASSERT (BitMapOut != NULL && BitMapIn != NULL);
227
228 for (Index = 0; Index < PixelNum; Index++) {
229 CopyMem (BitMapOut + Index, BitMapIn + Index, sizeof (EFI_HII_RGB_PIXEL));
230 }
231 }
232
233
234 /**
235 Output pixels in "1 bit per pixel" format to an image.
236
237 This is a internal function.
238
239
240 @param Image Points to the image which will store the pixels.
241 @param Data Stores the value of output pixels, 0 or 1.
242 @param PaletteInfo PaletteInfo which stores the color of the output
243 pixels. First entry corresponds to color 0 and
244 second one to color 1.
245
246
247 **/
248 VOID
249 Output1bitPixel (
250 IN OUT EFI_IMAGE_INPUT *Image,
251 IN UINT8 *Data,
252 IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
253 )
254 {
255 UINT16 Xpos;
256 UINT16 Ypos;
257 UINTN OffsetY;
258 UINT8 Index;
259 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
260 EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[2];
261 EFI_HII_IMAGE_PALETTE_INFO *Palette;
262 UINTN PaletteSize;
263 UINT8 Byte;
264
265 ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
266
267 BitMapPtr = Image->Bitmap;
268
269 //
270 // First entry corresponds to color 0 and second entry corresponds to color 1.
271 //
272 PaletteSize = 0;
273 CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
274 PaletteSize += sizeof (UINT16);
275 Palette = AllocateZeroPool (PaletteSize);
276 ASSERT (Palette != NULL);
277 if (Palette == NULL) {
278 return;
279 }
280 CopyMem (Palette, PaletteInfo, PaletteSize);
281
282 ZeroMem (PaletteValue, sizeof (PaletteValue));
283 CopyRgbToGopPixel (&PaletteValue[0], &Palette->PaletteValue[0], 1);
284 CopyRgbToGopPixel (&PaletteValue[1], &Palette->PaletteValue[1], 1);
285 FreePool (Palette);
286
287 //
288 // Convert the pixel from one bit to corresponding color.
289 //
290 for (Ypos = 0; Ypos < Image->Height; Ypos++) {
291 OffsetY = BITMAP_LEN_1_BIT (Image->Width, Ypos);
292 //
293 // All bits in these bytes are meaningful
294 //
295 for (Xpos = 0; Xpos < Image->Width / 8; Xpos++) {
296 Byte = *(Data + OffsetY + Xpos);
297 for (Index = 0; Index < 8; Index++) {
298 if ((Byte & (1 << Index)) != 0) {
299 BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[1];
300 } else {
301 BitMapPtr[Ypos * Image->Width + Xpos * 8 + (8 - Index - 1)] = PaletteValue[0];
302 }
303 }
304 }
305
306 if (Image->Width % 8 != 0) {
307 //
308 // Padding bits in this byte should be ignored.
309 //
310 Byte = *(Data + OffsetY + Xpos);
311 for (Index = 0; Index < Image->Width % 8; Index++) {
312 if ((Byte & (1 << (8 - Index - 1))) != 0) {
313 BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[1];
314 } else {
315 BitMapPtr[Ypos * Image->Width + Xpos * 8 + Index] = PaletteValue[0];
316 }
317 }
318 }
319 }
320 }
321
322
323 /**
324 Output pixels in "4 bit per pixel" format to an image.
325
326 This is a internal function.
327
328
329 @param Image Points to the image which will store the pixels.
330 @param Data Stores the value of output pixels, 0 ~ 15.
331 @param[in] PaletteInfo PaletteInfo which stores the color of the output
332 pixels. Each entry corresponds to a color within
333 [0, 15].
334
335
336 **/
337 VOID
338 Output4bitPixel (
339 IN OUT EFI_IMAGE_INPUT *Image,
340 IN UINT8 *Data,
341 IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
342 )
343 {
344 UINT16 Xpos;
345 UINT16 Ypos;
346 UINTN OffsetY;
347 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
348 EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[16];
349 EFI_HII_IMAGE_PALETTE_INFO *Palette;
350 UINTN PaletteSize;
351 UINT16 PaletteNum;
352 UINT8 Byte;
353
354 ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
355
356 BitMapPtr = Image->Bitmap;
357
358 //
359 // The bitmap should allocate each color index starting from 0.
360 //
361 PaletteSize = 0;
362 CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
363 PaletteSize += sizeof (UINT16);
364 Palette = AllocateZeroPool (PaletteSize);
365 ASSERT (Palette != NULL);
366 if (Palette == NULL) {
367 return;
368 }
369 CopyMem (Palette, PaletteInfo, PaletteSize);
370 PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
371
372 ZeroMem (PaletteValue, sizeof (PaletteValue));
373 CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, PaletteNum);
374 FreePool (Palette);
375
376 //
377 // Convert the pixel from 4 bit to corresponding color.
378 //
379 for (Ypos = 0; Ypos < Image->Height; Ypos++) {
380 OffsetY = BITMAP_LEN_4_BIT (Image->Width, Ypos);
381 //
382 // All bits in these bytes are meaningful
383 //
384 for (Xpos = 0; Xpos < Image->Width / 2; Xpos++) {
385 Byte = *(Data + OffsetY + Xpos);
386 BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4];
387 BitMapPtr[Ypos * Image->Width + Xpos * 2 + 1] = PaletteValue[Byte & 0x0F];
388 }
389
390 if (Image->Width % 2 != 0) {
391 //
392 // Padding bits in this byte should be ignored.
393 //
394 Byte = *(Data + OffsetY + Xpos);
395 BitMapPtr[Ypos * Image->Width + Xpos * 2] = PaletteValue[Byte >> 4];
396 }
397 }
398 }
399
400
401 /**
402 Output pixels in "8 bit per pixel" format to an image.
403
404 This is a internal function.
405
406
407 @param Image Points to the image which will store the pixels.
408 @param Data Stores the value of output pixels, 0 ~ 255.
409 @param[in] PaletteInfo PaletteInfo which stores the color of the output
410 pixels. Each entry corresponds to a color within
411 [0, 255].
412
413
414 **/
415 VOID
416 Output8bitPixel (
417 IN OUT EFI_IMAGE_INPUT *Image,
418 IN UINT8 *Data,
419 IN EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo
420 )
421 {
422 UINT16 Xpos;
423 UINT16 Ypos;
424 UINTN OffsetY;
425 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
426 EFI_GRAPHICS_OUTPUT_BLT_PIXEL PaletteValue[256];
427 EFI_HII_IMAGE_PALETTE_INFO *Palette;
428 UINTN PaletteSize;
429 UINT16 PaletteNum;
430 UINT8 Byte;
431
432 ASSERT (Image != NULL && Data != NULL && PaletteInfo != NULL);
433
434 BitMapPtr = Image->Bitmap;
435
436 //
437 // The bitmap should allocate each color index starting from 0.
438 //
439 PaletteSize = 0;
440 CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
441 PaletteSize += sizeof (UINT16);
442 Palette = AllocateZeroPool (PaletteSize);
443 ASSERT (Palette != NULL);
444 if (Palette == NULL) {
445 return;
446 }
447 CopyMem (Palette, PaletteInfo, PaletteSize);
448 PaletteNum = (UINT16)(Palette->PaletteSize / sizeof (EFI_HII_RGB_PIXEL));
449 ZeroMem (PaletteValue, sizeof (PaletteValue));
450 CopyRgbToGopPixel (PaletteValue, Palette->PaletteValue, PaletteNum);
451 FreePool (Palette);
452
453 //
454 // Convert the pixel from 8 bits to corresponding color.
455 //
456 for (Ypos = 0; Ypos < Image->Height; Ypos++) {
457 OffsetY = BITMAP_LEN_8_BIT ((UINT32) Image->Width, Ypos);
458 //
459 // All bits are meaningful since the bitmap is 8 bits per pixel.
460 //
461 for (Xpos = 0; Xpos < Image->Width; Xpos++) {
462 Byte = *(Data + OffsetY + Xpos);
463 BitMapPtr[OffsetY + Xpos] = PaletteValue[Byte];
464 }
465 }
466
467 }
468
469
470 /**
471 Output pixels in "24 bit per pixel" format to an image.
472
473 This is a internal function.
474
475
476 @param Image Points to the image which will store the pixels.
477 @param Data Stores the color of output pixels, allowing 16.8
478 millions colors.
479
480
481 **/
482 VOID
483 Output24bitPixel (
484 IN OUT EFI_IMAGE_INPUT *Image,
485 IN EFI_HII_RGB_PIXEL *Data
486 )
487 {
488 UINT16 Ypos;
489 UINTN OffsetY;
490 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BitMapPtr;
491
492 ASSERT (Image != NULL && Data != NULL);
493
494 BitMapPtr = Image->Bitmap;
495
496 for (Ypos = 0; Ypos < Image->Height; Ypos++) {
497 OffsetY = BITMAP_LEN_8_BIT ((UINT32) Image->Width, Ypos);
498 CopyRgbToGopPixel (&BitMapPtr[OffsetY], &Data[OffsetY], Image->Width);
499 }
500
501 }
502
503
504 /**
505 Convert the image from EFI_IMAGE_INPUT to EFI_IMAGE_OUTPUT format.
506
507 This is a internal function.
508
509
510 @param BltBuffer Buffer points to bitmap data of incoming image.
511 @param BltX Specifies the offset from the left and top edge of
512 the output image of the first pixel in the image.
513 @param BltY Specifies the offset from the left and top edge of
514 the output image of the first pixel in the image.
515 @param Width Width of the incoming image, in pixels.
516 @param Height Height of the incoming image, in pixels.
517 @param Transparent If TRUE, all "off" pixels in the image will be
518 drawn using the pixel value from blt and all other
519 pixels will be copied.
520 @param Blt Buffer points to bitmap data of output image.
521
522 @retval EFI_SUCCESS The image was successfully converted.
523 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
524
525 **/
526 EFI_STATUS
527 ImageToBlt (
528 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
529 IN UINTN BltX,
530 IN UINTN BltY,
531 IN UINTN Width,
532 IN UINTN Height,
533 IN BOOLEAN Transparent,
534 IN OUT EFI_IMAGE_OUTPUT **Blt
535 )
536 {
537 EFI_IMAGE_OUTPUT *ImageOut;
538 UINTN Xpos;
539 UINTN Ypos;
540 UINTN OffsetY1; // src buffer
541 UINTN OffsetY2; // dest buffer
542 EFI_GRAPHICS_OUTPUT_BLT_PIXEL SrcPixel;
543 EFI_GRAPHICS_OUTPUT_BLT_PIXEL ZeroPixel;
544
545 if (BltBuffer == NULL || Blt == NULL || *Blt == NULL) {
546 return EFI_INVALID_PARAMETER;
547 }
548
549 ImageOut = *Blt;
550
551 if (Width + BltX > ImageOut->Width) {
552 return EFI_INVALID_PARAMETER;
553 }
554 if (Height + BltY > ImageOut->Height) {
555 return EFI_INVALID_PARAMETER;
556 }
557
558 ZeroMem (&ZeroPixel, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
559
560 for (Ypos = 0; Ypos < Height; Ypos++) {
561 OffsetY1 = Width * Ypos;
562 OffsetY2 = ImageOut->Width * (BltY + Ypos);
563 for (Xpos = 0; Xpos < Width; Xpos++) {
564 SrcPixel = BltBuffer[OffsetY1 + Xpos];
565 if (Transparent) {
566 if (CompareMem (&SrcPixel, &ZeroPixel, 3) != 0) {
567 ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel;
568 }
569 } else {
570 ImageOut->Image.Bitmap[OffsetY2 + BltX + Xpos] = SrcPixel;
571 }
572 }
573 }
574
575 return EFI_SUCCESS;
576 }
577
578 /**
579 Return the HII package list identified by PackageList HII handle.
580
581 @param Database Pointer to HII database list header.
582 @param PackageList HII handle of the package list to locate.
583
584 @retval The HII package list instance.
585 **/
586 HII_DATABASE_PACKAGE_LIST_INSTANCE *
587 LocatePackageList (
588 IN LIST_ENTRY *Database,
589 IN EFI_HII_HANDLE PackageList
590 )
591 {
592 LIST_ENTRY *Link;
593 HII_DATABASE_RECORD *Record;
594
595 //
596 // Get the specified package list and image package.
597 //
598 for (Link = GetFirstNode (Database);
599 !IsNull (Database, Link);
600 Link = GetNextNode (Database, Link)
601 ) {
602 Record = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
603 if (Record->Handle == PackageList) {
604 return Record->PackageList;
605 }
606 }
607 return NULL;
608 }
609
610 /**
611 This function adds the image Image to the group of images owned by PackageList, and returns
612 a new image identifier (ImageId).
613
614 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
615 @param PackageList Handle of the package list where this image will
616 be added.
617 @param ImageId On return, contains the new image id, which is
618 unique within PackageList.
619 @param Image Points to the image.
620
621 @retval EFI_SUCCESS The new image was added successfully.
622 @retval EFI_NOT_FOUND The specified PackageList could not be found in
623 database.
624 @retval EFI_OUT_OF_RESOURCES Could not add the image due to lack of resources.
625 @retval EFI_INVALID_PARAMETER Image is NULL or ImageId is NULL.
626
627 **/
628 EFI_STATUS
629 EFIAPI
630 HiiNewImage (
631 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
632 IN EFI_HII_HANDLE PackageList,
633 OUT EFI_IMAGE_ID *ImageId,
634 IN CONST EFI_IMAGE_INPUT *Image
635 )
636 {
637 HII_DATABASE_PRIVATE_DATA *Private;
638 HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
639 HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
640 EFI_HII_IMAGE_BLOCK *ImageBlocks;
641 UINT32 NewBlockSize;
642
643 if (This == NULL || ImageId == NULL || Image == NULL || Image->Bitmap == NULL) {
644 return EFI_INVALID_PARAMETER;
645 }
646
647 Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
648 PackageListNode = LocatePackageList (&Private->DatabaseList, PackageList);
649 if (PackageListNode == NULL) {
650 return EFI_NOT_FOUND;
651 }
652
653 EfiAcquireLock (&mHiiDatabaseLock);
654
655 //
656 // Calcuate the size of new image.
657 // Make sure the size doesn't overflow UINT32.
658 // Note: 24Bit BMP occpuies 3 bytes per pixel.
659 //
660 NewBlockSize = (UINT32)Image->Width * Image->Height;
661 if (NewBlockSize > (MAX_UINT32 - (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))) / 3) {
662 return EFI_OUT_OF_RESOURCES;
663 }
664 NewBlockSize = NewBlockSize * 3 + (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL));
665
666 //
667 // Get the image package in the package list,
668 // or create a new image package if image package does not exist.
669 //
670 if (PackageListNode->ImagePkg != NULL) {
671 ImagePackage = PackageListNode->ImagePkg;
672
673 //
674 // Output the image id of the incoming image being inserted, which is the
675 // image id of the EFI_HII_IIBT_END block of old image package.
676 //
677 *ImageId = 0;
678 GetImageIdOrAddress (ImagePackage->ImageBlock, ImageId);
679
680 //
681 // Update the package's image block by appending the new block to the end.
682 //
683
684 //
685 // Make sure the final package length doesn't overflow.
686 // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24.
687 //
688 if (NewBlockSize > MAX_UINT24 - ImagePackage->ImagePkgHdr.Header.Length) {
689 return EFI_OUT_OF_RESOURCES;
690 }
691 //
692 // Because ImagePackage->ImageBlockSize < ImagePackage->ImagePkgHdr.Header.Length,
693 // So (ImagePackage->ImageBlockSize + NewBlockSize) <= MAX_UINT24
694 //
695 ImageBlocks = AllocatePool (ImagePackage->ImageBlockSize + NewBlockSize);
696 if (ImageBlocks == NULL) {
697 EfiReleaseLock (&mHiiDatabaseLock);
698 return EFI_OUT_OF_RESOURCES;
699 }
700 //
701 // Copy the original content.
702 //
703 CopyMem (
704 ImageBlocks,
705 ImagePackage->ImageBlock,
706 ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK)
707 );
708 FreePool (ImagePackage->ImageBlock);
709 ImagePackage->ImageBlock = ImageBlocks;
710
711 //
712 // Point to the very last block.
713 //
714 ImageBlocks = (EFI_HII_IMAGE_BLOCK *) (
715 (UINT8 *) ImageBlocks + ImagePackage->ImageBlockSize - sizeof (EFI_HII_IIBT_END_BLOCK)
716 );
717 //
718 // Update the length record.
719 //
720 ImagePackage->ImageBlockSize += NewBlockSize;
721 ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize;
722 PackageListNode->PackageListHdr.PackageLength += NewBlockSize;
723
724 } else {
725 //
726 // Make sure the final package length doesn't overflow.
727 // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24.
728 //
729 if (NewBlockSize > MAX_UINT24 - (sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + sizeof (EFI_HII_IIBT_END_BLOCK))) {
730 return EFI_OUT_OF_RESOURCES;
731 }
732 //
733 // The specified package list does not contain image package.
734 // Create one to add this image block.
735 //
736 ImagePackage = (HII_IMAGE_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IMAGE_PACKAGE_INSTANCE));
737 if (ImagePackage == NULL) {
738 EfiReleaseLock (&mHiiDatabaseLock);
739 return EFI_OUT_OF_RESOURCES;
740 }
741 //
742 // Output the image id of the incoming image being inserted, which is the
743 // first image block so that id is initially to one.
744 //
745 *ImageId = 1;
746 //
747 // Fill in image package header.
748 //
749 ImagePackage->ImagePkgHdr.Header.Length = sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK);
750 ImagePackage->ImagePkgHdr.Header.Type = EFI_HII_PACKAGE_IMAGES;
751 ImagePackage->ImagePkgHdr.ImageInfoOffset = sizeof (EFI_HII_IMAGE_PACKAGE_HDR);
752 ImagePackage->ImagePkgHdr.PaletteInfoOffset = 0;
753
754 //
755 // Fill in palette info.
756 //
757 ImagePackage->PaletteBlock = NULL;
758 ImagePackage->PaletteInfoSize = 0;
759
760 //
761 // Fill in image blocks.
762 //
763 ImagePackage->ImageBlockSize = NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK);
764 ImagePackage->ImageBlock = AllocateZeroPool (NewBlockSize + sizeof (EFI_HII_IIBT_END_BLOCK));
765 if (ImagePackage->ImageBlock == NULL) {
766 FreePool (ImagePackage);
767 EfiReleaseLock (&mHiiDatabaseLock);
768 return EFI_OUT_OF_RESOURCES;
769 }
770 ImageBlocks = ImagePackage->ImageBlock;
771
772 //
773 // Insert this image package.
774 //
775 PackageListNode->ImagePkg = ImagePackage;
776 PackageListNode->PackageListHdr.PackageLength += ImagePackage->ImagePkgHdr.Header.Length;
777 }
778
779 //
780 // Append the new block here
781 //
782 if (Image->Flags == EFI_IMAGE_TRANSPARENT) {
783 ImageBlocks->BlockType = EFI_HII_IIBT_IMAGE_24BIT_TRANS;
784 } else {
785 ImageBlocks->BlockType = EFI_HII_IIBT_IMAGE_24BIT;
786 }
787 WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Width, Image->Width);
788 WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Height, Image->Height);
789 CopyGopToRgbPixel (((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) ImageBlocks)->Bitmap.Bitmap, Image->Bitmap, (UINT32) Image->Width * Image->Height);
790
791 //
792 // Append the block end
793 //
794 ImageBlocks = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) ImageBlocks + NewBlockSize);
795 ImageBlocks->BlockType = EFI_HII_IIBT_END;
796
797 //
798 // Check whether need to get the contents of HiiDataBase.
799 // Only after ReadyToBoot to do the export.
800 //
801 if (gExportAfterReadyToBoot) {
802 HiiGetDatabaseInfo(&Private->HiiDatabase);
803 }
804
805 EfiReleaseLock (&mHiiDatabaseLock);
806
807 return EFI_SUCCESS;
808 }
809
810
811 /**
812 This function retrieves the image specified by ImageId which is associated with
813 the specified PackageList and copies it into the buffer specified by Image.
814
815 @param Database A pointer to the database list header.
816 @param PackageList Handle of the package list where this image will
817 be searched.
818 @param ImageId The image's id,, which is unique within
819 PackageList.
820 @param Image Points to the image.
821 @param BitmapOnly TRUE to only return the bitmap type image.
822 FALSE to locate image decoder instance to decode image.
823
824 @retval EFI_SUCCESS The new image was returned successfully.
825 @retval EFI_NOT_FOUND The image specified by ImageId is not in the
826 database. The specified PackageList is not in the database.
827 @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
828 hold the image.
829 @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
830 @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not
831 enough memory.
832 **/
833 EFI_STATUS
834 IGetImage (
835 IN LIST_ENTRY *Database,
836 IN EFI_HII_HANDLE PackageList,
837 IN EFI_IMAGE_ID ImageId,
838 OUT EFI_IMAGE_INPUT *Image,
839 IN BOOLEAN BitmapOnly
840 )
841 {
842 EFI_STATUS Status;
843 HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
844 HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
845 EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
846 EFI_HII_IIBT_IMAGE_1BIT_BLOCK Iibt1bit;
847 UINT16 Width;
848 UINT16 Height;
849 UINTN ImageLength;
850 UINT8 *PaletteInfo;
851 UINT8 PaletteIndex;
852 UINT16 PaletteSize;
853 EFI_HII_IMAGE_DECODER_PROTOCOL *Decoder;
854 EFI_IMAGE_OUTPUT *ImageOut;
855
856 if (Image == NULL || ImageId == 0) {
857 return EFI_INVALID_PARAMETER;
858 }
859
860 PackageListNode = LocatePackageList (Database, PackageList);
861 if (PackageListNode == NULL) {
862 return EFI_NOT_FOUND;
863 }
864 ImagePackage = PackageListNode->ImagePkg;
865 if (ImagePackage == NULL) {
866 return EFI_NOT_FOUND;
867 }
868
869 //
870 // Find the image block specified by ImageId
871 //
872 CurrentImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &ImageId);
873 if (CurrentImageBlock == NULL) {
874 return EFI_NOT_FOUND;
875 }
876
877 Image->Flags = 0;
878 switch (CurrentImageBlock->BlockType) {
879 case EFI_HII_IIBT_IMAGE_JPEG:
880 case EFI_HII_IIBT_IMAGE_PNG:
881 if (BitmapOnly) {
882 return EFI_UNSUPPORTED;
883 }
884
885 ImageOut = NULL;
886 Decoder = LocateHiiImageDecoder (CurrentImageBlock->BlockType);
887 if (Decoder == NULL) {
888 return EFI_UNSUPPORTED;
889 }
890 //
891 // Use the common block code since the definition of two structures is the same.
892 //
893 ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data));
894 ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data) ==
895 sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Data));
896 ASSERT (OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Size) == OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Size));
897 ASSERT (sizeof (((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size) ==
898 sizeof (((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size));
899 Status = Decoder->DecodeImage (
900 Decoder,
901 ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Data,
902 ((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size,
903 &ImageOut,
904 FALSE
905 );
906
907 //
908 // Spec requires to use the first capable image decoder instance.
909 // The first image decoder instance may fail to decode the image.
910 //
911 if (!EFI_ERROR (Status)) {
912 Image->Bitmap = ImageOut->Image.Bitmap;
913 Image->Height = ImageOut->Height;
914 Image->Width = ImageOut->Width;
915 FreePool (ImageOut);
916 }
917 return Status;
918
919 case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
920 case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
921 case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
922 Image->Flags = EFI_IMAGE_TRANSPARENT;
923 //
924 // fall through
925 //
926 case EFI_HII_IIBT_IMAGE_1BIT:
927 case EFI_HII_IIBT_IMAGE_4BIT:
928 case EFI_HII_IIBT_IMAGE_8BIT:
929 //
930 // Use the common block code since the definition of these structures is the same.
931 //
932 CopyMem (&Iibt1bit, CurrentImageBlock, sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK));
933 ImageLength = (UINTN) Iibt1bit.Bitmap.Width * Iibt1bit.Bitmap.Height;
934 if (ImageLength > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
935 return EFI_OUT_OF_RESOURCES;
936 }
937 ImageLength *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
938 Image->Bitmap = AllocateZeroPool (ImageLength);
939 if (Image->Bitmap == NULL) {
940 return EFI_OUT_OF_RESOURCES;
941 }
942
943 Image->Width = Iibt1bit.Bitmap.Width;
944 Image->Height = Iibt1bit.Bitmap.Height;
945
946 PaletteInfo = ImagePackage->PaletteBlock + sizeof (EFI_HII_IMAGE_PALETTE_INFO_HEADER);
947 for (PaletteIndex = 1; PaletteIndex < Iibt1bit.PaletteIndex; PaletteIndex++) {
948 CopyMem (&PaletteSize, PaletteInfo, sizeof (UINT16));
949 PaletteInfo += PaletteSize + sizeof (UINT16);
950 }
951 ASSERT (PaletteIndex == Iibt1bit.PaletteIndex);
952
953 //
954 // Output bitmap data
955 //
956 if (CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_1BIT ||
957 CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_1BIT_TRANS) {
958 Output1bitPixel (
959 Image,
960 ((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data,
961 (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
962 );
963 } else if (CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_4BIT ||
964 CurrentImageBlock->BlockType == EFI_HII_IIBT_IMAGE_4BIT_TRANS) {
965 Output4bitPixel (
966 Image,
967 ((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data,
968 (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
969 );
970 } else {
971 Output8bitPixel (
972 Image,
973 ((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Data,
974 (EFI_HII_IMAGE_PALETTE_INFO *) PaletteInfo
975 );
976 }
977
978 return EFI_SUCCESS;
979
980 case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
981 Image->Flags = EFI_IMAGE_TRANSPARENT;
982 //
983 // fall through
984 //
985 case EFI_HII_IIBT_IMAGE_24BIT:
986 Width = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width);
987 Height = ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height);
988 ImageLength = (UINTN)Width * Height;
989 if (ImageLength > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
990 return EFI_OUT_OF_RESOURCES;
991 }
992 ImageLength *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
993 Image->Bitmap = AllocateZeroPool (ImageLength);
994 if (Image->Bitmap == NULL) {
995 return EFI_OUT_OF_RESOURCES;
996 }
997
998 Image->Width = Width;
999 Image->Height = Height;
1000
1001 //
1002 // Output the bitmap data directly.
1003 //
1004 Output24bitPixel (
1005 Image,
1006 ((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Bitmap
1007 );
1008 return EFI_SUCCESS;
1009
1010 default:
1011 return EFI_NOT_FOUND;
1012 }
1013 }
1014
1015 /**
1016 This function retrieves the image specified by ImageId which is associated with
1017 the specified PackageList and copies it into the buffer specified by Image.
1018
1019 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
1020 @param PackageList Handle of the package list where this image will
1021 be searched.
1022 @param ImageId The image's id,, which is unique within
1023 PackageList.
1024 @param Image Points to the image.
1025
1026 @retval EFI_SUCCESS The new image was returned successfully.
1027 @retval EFI_NOT_FOUND The image specified by ImageId is not in the
1028 database. The specified PackageList is not in the database.
1029 @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to
1030 hold the image.
1031 @retval EFI_INVALID_PARAMETER The Image or ImageSize was NULL.
1032 @retval EFI_OUT_OF_RESOURCES The bitmap could not be retrieved because there was not
1033 enough memory.
1034
1035 **/
1036 EFI_STATUS
1037 EFIAPI
1038 HiiGetImage (
1039 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
1040 IN EFI_HII_HANDLE PackageList,
1041 IN EFI_IMAGE_ID ImageId,
1042 OUT EFI_IMAGE_INPUT *Image
1043 )
1044 {
1045 HII_DATABASE_PRIVATE_DATA *Private;
1046 Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1047 return IGetImage (&Private->DatabaseList, PackageList, ImageId, Image, TRUE);
1048 }
1049
1050
1051 /**
1052 This function updates the image specified by ImageId in the specified PackageListHandle to
1053 the image specified by Image.
1054
1055 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
1056 @param PackageList The package list containing the images.
1057 @param ImageId The image's id,, which is unique within
1058 PackageList.
1059 @param Image Points to the image.
1060
1061 @retval EFI_SUCCESS The new image was updated successfully.
1062 @retval EFI_NOT_FOUND The image specified by ImageId is not in the
1063 database. The specified PackageList is not in the database.
1064 @retval EFI_INVALID_PARAMETER The Image was NULL.
1065
1066 **/
1067 EFI_STATUS
1068 EFIAPI
1069 HiiSetImage (
1070 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
1071 IN EFI_HII_HANDLE PackageList,
1072 IN EFI_IMAGE_ID ImageId,
1073 IN CONST EFI_IMAGE_INPUT *Image
1074 )
1075 {
1076 HII_DATABASE_PRIVATE_DATA *Private;
1077 HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageListNode;
1078 HII_IMAGE_PACKAGE_INSTANCE *ImagePackage;
1079 EFI_HII_IMAGE_BLOCK *CurrentImageBlock;
1080 EFI_HII_IMAGE_BLOCK *ImageBlocks;
1081 EFI_HII_IMAGE_BLOCK *NewImageBlock;
1082 UINT32 NewBlockSize;
1083 UINT32 OldBlockSize;
1084 UINT32 Part1Size;
1085 UINT32 Part2Size;
1086
1087 if (This == NULL || Image == NULL || ImageId == 0 || Image->Bitmap == NULL) {
1088 return EFI_INVALID_PARAMETER;
1089 }
1090
1091 Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1092 PackageListNode = LocatePackageList (&Private->DatabaseList, PackageList);
1093 if (PackageListNode == NULL) {
1094 return EFI_NOT_FOUND;
1095 }
1096 ImagePackage = PackageListNode->ImagePkg;
1097 if (ImagePackage == NULL) {
1098 return EFI_NOT_FOUND;
1099 }
1100
1101 //
1102 // Find the image block specified by ImageId
1103 //
1104 CurrentImageBlock = GetImageIdOrAddress (ImagePackage->ImageBlock, &ImageId);
1105 if (CurrentImageBlock == NULL) {
1106 return EFI_NOT_FOUND;
1107 }
1108
1109 EfiAcquireLock (&mHiiDatabaseLock);
1110
1111 //
1112 // Get the size of original image block. Use some common block code here
1113 // since the definition of some structures is the same.
1114 //
1115 switch (CurrentImageBlock->BlockType) {
1116 case EFI_HII_IIBT_IMAGE_JPEG:
1117 OldBlockSize = OFFSET_OF (EFI_HII_IIBT_JPEG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_JPEG_BLOCK *) CurrentImageBlock)->Size);
1118 break;
1119 case EFI_HII_IIBT_IMAGE_PNG:
1120 OldBlockSize = OFFSET_OF (EFI_HII_IIBT_PNG_BLOCK, Data) + ReadUnaligned32 ((VOID *) &((EFI_HII_IIBT_PNG_BLOCK *) CurrentImageBlock)->Size);
1121 break;
1122 case EFI_HII_IIBT_IMAGE_1BIT:
1123 case EFI_HII_IIBT_IMAGE_1BIT_TRANS:
1124 OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_1BIT_BLOCK) - sizeof (UINT8) +
1125 BITMAP_LEN_1_BIT (
1126 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
1127 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_1BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
1128 );
1129 break;
1130 case EFI_HII_IIBT_IMAGE_4BIT:
1131 case EFI_HII_IIBT_IMAGE_4BIT_TRANS:
1132 OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_4BIT_BLOCK) - sizeof (UINT8) +
1133 BITMAP_LEN_4_BIT (
1134 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
1135 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_4BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
1136 );
1137 break;
1138 case EFI_HII_IIBT_IMAGE_8BIT:
1139 case EFI_HII_IIBT_IMAGE_8BIT_TRANS:
1140 OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_8BIT_BLOCK) - sizeof (UINT8) +
1141 BITMAP_LEN_8_BIT (
1142 (UINT32) ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
1143 ReadUnaligned16 (&((EFI_HII_IIBT_IMAGE_8BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
1144 );
1145 break;
1146 case EFI_HII_IIBT_IMAGE_24BIT:
1147 case EFI_HII_IIBT_IMAGE_24BIT_TRANS:
1148 OldBlockSize = sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL) +
1149 BITMAP_LEN_24_BIT (
1150 (UINT32) ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Width),
1151 ReadUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) CurrentImageBlock)->Bitmap.Height)
1152 );
1153 break;
1154 default:
1155 EfiReleaseLock (&mHiiDatabaseLock);
1156 return EFI_NOT_FOUND;
1157 }
1158
1159 //
1160 // Create the new image block according to input image.
1161 //
1162
1163 //
1164 // Make sure the final package length doesn't overflow.
1165 // Length of the package header is represented using 24 bits. So MAX length is MAX_UINT24.
1166 // 24Bit BMP occpuies 3 bytes per pixel.
1167 //
1168 NewBlockSize = (UINT32)Image->Width * Image->Height;
1169 if (NewBlockSize > (MAX_UINT32 - (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL))) / 3) {
1170 return EFI_OUT_OF_RESOURCES;
1171 }
1172 NewBlockSize = NewBlockSize * 3 + (sizeof (EFI_HII_IIBT_IMAGE_24BIT_BLOCK) - sizeof (EFI_HII_RGB_PIXEL));
1173 if ((NewBlockSize > OldBlockSize) &&
1174 (NewBlockSize - OldBlockSize > MAX_UINT24 - ImagePackage->ImagePkgHdr.Header.Length)
1175 ) {
1176 return EFI_OUT_OF_RESOURCES;
1177 }
1178
1179 //
1180 // Adjust the image package to remove the original block firstly then add the new block.
1181 //
1182 ImageBlocks = AllocateZeroPool (ImagePackage->ImageBlockSize + NewBlockSize - OldBlockSize);
1183 if (ImageBlocks == NULL) {
1184 EfiReleaseLock (&mHiiDatabaseLock);
1185 return EFI_OUT_OF_RESOURCES;
1186 }
1187
1188 Part1Size = (UINT32) ((UINTN) CurrentImageBlock - (UINTN) ImagePackage->ImageBlock);
1189 Part2Size = ImagePackage->ImageBlockSize - Part1Size - OldBlockSize;
1190 CopyMem (ImageBlocks, ImagePackage->ImageBlock, Part1Size);
1191
1192 //
1193 // Set the new image block
1194 //
1195 NewImageBlock = (EFI_HII_IMAGE_BLOCK *) ((UINT8 *) ImageBlocks + Part1Size);
1196 if ((Image->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
1197 NewImageBlock->BlockType= EFI_HII_IIBT_IMAGE_24BIT_TRANS;
1198 } else {
1199 NewImageBlock->BlockType = EFI_HII_IIBT_IMAGE_24BIT;
1200 }
1201 WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Width, Image->Width);
1202 WriteUnaligned16 ((VOID *) &((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Height, Image->Height);
1203 CopyGopToRgbPixel (((EFI_HII_IIBT_IMAGE_24BIT_BLOCK *) NewImageBlock)->Bitmap.Bitmap,
1204 Image->Bitmap, (UINT32) Image->Width * Image->Height);
1205
1206 CopyMem ((UINT8 *) NewImageBlock + NewBlockSize, (UINT8 *) CurrentImageBlock + OldBlockSize, Part2Size);
1207
1208 FreePool (ImagePackage->ImageBlock);
1209 ImagePackage->ImageBlock = ImageBlocks;
1210 ImagePackage->ImageBlockSize += NewBlockSize - OldBlockSize;
1211 ImagePackage->ImagePkgHdr.Header.Length += NewBlockSize - OldBlockSize;
1212 PackageListNode->PackageListHdr.PackageLength += NewBlockSize - OldBlockSize;
1213
1214 //
1215 // Check whether need to get the contents of HiiDataBase.
1216 // Only after ReadyToBoot to do the export.
1217 //
1218 if (gExportAfterReadyToBoot) {
1219 HiiGetDatabaseInfo(&Private->HiiDatabase);
1220 }
1221
1222 EfiReleaseLock (&mHiiDatabaseLock);
1223 return EFI_SUCCESS;
1224
1225 }
1226
1227
1228 /**
1229 This function renders an image to a bitmap or the screen using the specified
1230 color and options. It draws the image on an existing bitmap, allocates a new
1231 bitmap or uses the screen. The images can be clipped.
1232
1233 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
1234 @param Flags Describes how the image is to be drawn.
1235 @param Image Points to the image to be displayed.
1236 @param Blt If this points to a non-NULL on entry, this points
1237 to the image, which is Width pixels wide and
1238 Height pixels high. The image will be drawn onto
1239 this image and EFI_HII_DRAW_FLAG_CLIP is implied.
1240 If this points to a NULL on entry, then a buffer
1241 will be allocated to hold the generated image and
1242 the pointer updated on exit. It is the caller's
1243 responsibility to free this buffer.
1244 @param BltX Specifies the offset from the left and top edge of
1245 the output image of the first pixel in the image.
1246 @param BltY Specifies the offset from the left and top edge of
1247 the output image of the first pixel in the image.
1248
1249 @retval EFI_SUCCESS The image was successfully drawn.
1250 @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
1251 @retval EFI_INVALID_PARAMETER The Image or Blt was NULL.
1252 @retval EFI_INVALID_PARAMETER Any combination of Flags is invalid.
1253
1254 **/
1255 EFI_STATUS
1256 EFIAPI
1257 HiiDrawImage (
1258 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
1259 IN EFI_HII_DRAW_FLAGS Flags,
1260 IN CONST EFI_IMAGE_INPUT *Image,
1261 IN OUT EFI_IMAGE_OUTPUT **Blt,
1262 IN UINTN BltX,
1263 IN UINTN BltY
1264 )
1265 {
1266 EFI_STATUS Status;
1267 HII_DATABASE_PRIVATE_DATA *Private;
1268 BOOLEAN Transparent;
1269 EFI_IMAGE_OUTPUT *ImageOut;
1270 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
1271 UINTN BufferLen;
1272 UINT16 Width;
1273 UINT16 Height;
1274 UINTN Xpos;
1275 UINTN Ypos;
1276 UINTN OffsetY1;
1277 UINTN OffsetY2;
1278 EFI_FONT_DISPLAY_INFO *FontInfo;
1279 UINTN Index;
1280
1281 if (This == NULL || Image == NULL || Blt == NULL) {
1282 return EFI_INVALID_PARAMETER;
1283 }
1284
1285 if ((Flags & EFI_HII_DRAW_FLAG_CLIP) == EFI_HII_DRAW_FLAG_CLIP && *Blt == NULL) {
1286 return EFI_INVALID_PARAMETER;
1287 }
1288
1289 if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_TRANSPARENT) {
1290 return EFI_INVALID_PARAMETER;
1291 }
1292
1293 FontInfo = NULL;
1294
1295 //
1296 // Check whether the image will be drawn transparently or opaquely.
1297 //
1298 Transparent = FALSE;
1299 if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_TRANS) {
1300 Transparent = TRUE;
1301 } else if ((Flags & EFI_HII_DRAW_FLAG_TRANSPARENT) == EFI_HII_DRAW_FLAG_FORCE_OPAQUE){
1302 Transparent = FALSE;
1303 } else {
1304 //
1305 // Now EFI_HII_DRAW_FLAG_DEFAULT is set, whether image will be drawn depending
1306 // on the image's transparency setting.
1307 //
1308 if ((Image->Flags & EFI_IMAGE_TRANSPARENT) == EFI_IMAGE_TRANSPARENT) {
1309 Transparent = TRUE;
1310 }
1311 }
1312
1313 //
1314 // Image cannot be drawn transparently if Blt points to NULL on entry.
1315 // Currently output to Screen transparently is not supported, either.
1316 //
1317 if (Transparent) {
1318 if (*Blt == NULL) {
1319 return EFI_INVALID_PARAMETER;
1320 } else if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
1321 return EFI_INVALID_PARAMETER;
1322 }
1323 }
1324
1325 Private = HII_IMAGE_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1326
1327 //
1328 // When Blt points to a non-NULL on entry, this image will be drawn onto
1329 // this bitmap or screen pointed by "*Blt" and EFI_HII_DRAW_FLAG_CLIP is implied.
1330 // Otherwise a new bitmap will be allocated to hold this image.
1331 //
1332 if (*Blt != NULL) {
1333 //
1334 // Make sure the BltX and BltY is inside the Blt area.
1335 //
1336 if ((BltX >= (*Blt)->Width) || (BltY >= (*Blt)->Height)) {
1337 return EFI_INVALID_PARAMETER;
1338 }
1339
1340 //
1341 // Clip the image by (Width, Height)
1342 //
1343
1344 Width = Image->Width;
1345 Height = Image->Height;
1346
1347 if (Width > (*Blt)->Width - (UINT16)BltX) {
1348 Width = (*Blt)->Width - (UINT16)BltX;
1349 }
1350 if (Height > (*Blt)->Height - (UINT16)BltY) {
1351 Height = (*Blt)->Height - (UINT16)BltY;
1352 }
1353
1354 //
1355 // Prepare the buffer for the temporary image.
1356 // Make sure the buffer size doesn't overflow UINTN.
1357 //
1358 BufferLen = Width * Height;
1359 if (BufferLen > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
1360 return EFI_OUT_OF_RESOURCES;
1361 }
1362 BufferLen *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
1363 BltBuffer = AllocateZeroPool (BufferLen);
1364 if (BltBuffer == NULL) {
1365 return EFI_OUT_OF_RESOURCES;
1366 }
1367
1368 if (Width == Image->Width && Height == Image->Height) {
1369 CopyMem (BltBuffer, Image->Bitmap, BufferLen);
1370 } else {
1371 for (Ypos = 0; Ypos < Height; Ypos++) {
1372 OffsetY1 = Image->Width * Ypos;
1373 OffsetY2 = Width * Ypos;
1374 for (Xpos = 0; Xpos < Width; Xpos++) {
1375 BltBuffer[OffsetY2 + Xpos] = Image->Bitmap[OffsetY1 + Xpos];
1376 }
1377 }
1378 }
1379
1380 //
1381 // Draw the image to existing bitmap or screen depending on flag.
1382 //
1383 if ((Flags & EFI_HII_DIRECT_TO_SCREEN) == EFI_HII_DIRECT_TO_SCREEN) {
1384 //
1385 // Caller should make sure the current UGA console is grarphic mode.
1386 //
1387
1388 //
1389 // Write the image directly to the output device specified by Screen.
1390 //
1391 Status = (*Blt)->Image.Screen->Blt (
1392 (*Blt)->Image.Screen,
1393 BltBuffer,
1394 EfiBltBufferToVideo,
1395 0,
1396 0,
1397 BltX,
1398 BltY,
1399 Width,
1400 Height,
1401 0
1402 );
1403 } else {
1404 //
1405 // Draw the image onto the existing bitmap specified by Bitmap.
1406 //
1407 Status = ImageToBlt (
1408 BltBuffer,
1409 BltX,
1410 BltY,
1411 Width,
1412 Height,
1413 Transparent,
1414 Blt
1415 );
1416
1417 }
1418
1419 FreePool (BltBuffer);
1420 return Status;
1421
1422 } else {
1423 //
1424 // Allocate a new bitmap to hold the incoming image.
1425 //
1426
1427 //
1428 // Make sure the final width and height doesn't overflow UINT16.
1429 //
1430 if ((BltX > (UINTN)MAX_UINT16 - Image->Width) || (BltY > (UINTN)MAX_UINT16 - Image->Height)) {
1431 return EFI_INVALID_PARAMETER;
1432 }
1433
1434 Width = Image->Width + (UINT16)BltX;
1435 Height = Image->Height + (UINT16)BltY;
1436
1437 //
1438 // Make sure the output image size doesn't overflow UINTN.
1439 //
1440 BufferLen = Width * Height;
1441 if (BufferLen > MAX_UINTN / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {
1442 return EFI_OUT_OF_RESOURCES;
1443 }
1444 BufferLen *= sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
1445 BltBuffer = AllocateZeroPool (BufferLen);
1446 if (BltBuffer == NULL) {
1447 return EFI_OUT_OF_RESOURCES;
1448 }
1449
1450 ImageOut = (EFI_IMAGE_OUTPUT *) AllocateZeroPool (sizeof (EFI_IMAGE_OUTPUT));
1451 if (ImageOut == NULL) {
1452 FreePool (BltBuffer);
1453 return EFI_OUT_OF_RESOURCES;
1454 }
1455 ImageOut->Width = Width;
1456 ImageOut->Height = Height;
1457 ImageOut->Image.Bitmap = BltBuffer;
1458
1459 //
1460 // BUGBUG: Now all the "blank" pixels are filled with system default background
1461 // color. Not sure if it need to be updated or not.
1462 //
1463 Status = GetSystemFont (Private, &FontInfo, NULL);
1464 if (EFI_ERROR (Status)) {
1465 FreePool (BltBuffer);
1466 FreePool (ImageOut);
1467 return Status;
1468 }
1469 ASSERT (FontInfo != NULL);
1470 for (Index = 0; Index < (UINTN)Width * Height; Index++) {
1471 BltBuffer[Index] = FontInfo->BackgroundColor;
1472 }
1473 FreePool (FontInfo);
1474
1475 //
1476 // Draw the incoming image to the new created image.
1477 //
1478 *Blt = ImageOut;
1479 return ImageToBlt (
1480 Image->Bitmap,
1481 BltX,
1482 BltY,
1483 Image->Width,
1484 Image->Height,
1485 Transparent,
1486 Blt
1487 );
1488
1489 }
1490 }
1491
1492
1493 /**
1494 This function renders an image to a bitmap or the screen using the specified
1495 color and options. It draws the image on an existing bitmap, allocates a new
1496 bitmap or uses the screen. The images can be clipped.
1497
1498 @param This A pointer to the EFI_HII_IMAGE_PROTOCOL instance.
1499 @param Flags Describes how the image is to be drawn.
1500 @param PackageList The package list in the HII database to search for
1501 the specified image.
1502 @param ImageId The image's id, which is unique within
1503 PackageList.
1504 @param Blt If this points to a non-NULL on entry, this points
1505 to the image, which is Width pixels wide and
1506 Height pixels high. The image will be drawn onto
1507 this image and
1508 EFI_HII_DRAW_FLAG_CLIP is implied. If this points
1509 to a NULL on entry, then a buffer will be
1510 allocated to hold the generated image and the
1511 pointer updated on exit. It is the caller's
1512 responsibility to free this buffer.
1513 @param BltX Specifies the offset from the left and top edge of
1514 the output image of the first pixel in the image.
1515 @param BltY Specifies the offset from the left and top edge of
1516 the output image of the first pixel in the image.
1517
1518 @retval EFI_SUCCESS The image was successfully drawn.
1519 @retval EFI_OUT_OF_RESOURCES Unable to allocate an output buffer for Blt.
1520 @retval EFI_INVALID_PARAMETER The Blt was NULL.
1521 @retval EFI_NOT_FOUND The image specified by ImageId is not in the database.
1522 The specified PackageList is not in the database.
1523
1524 **/
1525 EFI_STATUS
1526 EFIAPI
1527 HiiDrawImageId (
1528 IN CONST EFI_HII_IMAGE_PROTOCOL *This,
1529 IN EFI_HII_DRAW_FLAGS Flags,
1530 IN EFI_HII_HANDLE PackageList,
1531 IN EFI_IMAGE_ID ImageId,
1532 IN OUT EFI_IMAGE_OUTPUT **Blt,
1533 IN UINTN BltX,
1534 IN UINTN BltY
1535 )
1536 {
1537 EFI_STATUS Status;
1538 EFI_IMAGE_INPUT Image;
1539
1540 //
1541 // Check input parameter.
1542 //
1543 if (This == NULL || Blt == NULL) {
1544 return EFI_INVALID_PARAMETER;
1545 }
1546
1547 //
1548 // Get the specified Image.
1549 //
1550 Status = HiiGetImage (This, PackageList, ImageId, &Image);
1551 if (EFI_ERROR (Status)) {
1552 return Status;
1553 }
1554
1555 //
1556 // Draw this image.
1557 //
1558 Status = HiiDrawImage (This, Flags, &Image, Blt, BltX, BltY);
1559 if (Image.Bitmap != NULL) {
1560 FreePool (Image.Bitmap);
1561 }
1562 return Status;
1563 }
1564