OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
Images.c
Go to the documentation of this file.
1
8#include <Uefi.h>
9
12
13#include <Library/BaseLib.h>
14#include <Library/MemoryAllocationLib.h>
15#include <Library/DebugLib.h>
17#include <Library/OcPngLib.h>
18
19#include "OpenCanopy.h"
20
21//
22// Disk label palette.
23//
24STATIC
25CONST UINT8
27 [0x00] = 255,
28 [0xf6] = 238,
29 [0xf7] = 221,
30 [0x2a] = 204,
31 [0xf8] = 187,
32 [0xf9] = 170,
33 [0x55] = 153,
34 [0xfa] = 136,
35 [0xfb] = 119,
36 [0x80] = 102,
37 [0xfc] = 85,
38 [0xfd] = 68,
39 [0xab] = 51,
40 [0xfe] = 34,
41 [0xff] = 17,
42 [0xd6] = 0
43};
44
45EFI_STATUS
47 OUT GUI_IMAGE *Image,
48 IN VOID *IcnsImage,
49 IN UINT32 IcnsImageSize,
50 IN UINT8 Scale,
51 IN UINT32 MatchWidth,
52 IN UINT32 MatchHeight,
53 IN BOOLEAN AllowLess
54 )
55{
56 EFI_STATUS Status;
57 UINT32 Offset;
58 UINT32 RecordLength;
59 UINT32 ImageSize;
60 UINT32 DecodedBytes;
61 APPLE_ICNS_RECORD *Record;
62 APPLE_ICNS_RECORD *RecordIT32;
63 APPLE_ICNS_RECORD *RecordT8MK;
64
65 ASSERT (Scale == 1 || Scale == 2);
66
67 //
68 // We do not need to support 'it32' 128x128 icon format,
69 // because Finder automatically converts the icons to PNG-based
70 // when assigning volume icon.
71 //
72
73 if (IcnsImageSize < sizeof (APPLE_ICNS_RECORD)*2) {
74 return EFI_INVALID_PARAMETER;
75 }
76
77 Record = IcnsImage;
78 if ((Record->Type != APPLE_ICNS_MAGIC) || (SwapBytes32 (Record->Size) != IcnsImageSize)) {
79 return EFI_SECURITY_VIOLATION;
80 }
81
82 RecordIT32 = NULL;
83 RecordT8MK = NULL;
84
85 Offset = sizeof (APPLE_ICNS_RECORD);
86 while (Offset < IcnsImageSize - sizeof (APPLE_ICNS_RECORD)) {
87 Record = (APPLE_ICNS_RECORD *)((UINT8 *)IcnsImage + Offset);
88 RecordLength = SwapBytes32 (Record->Size);
89
90 //
91 // 1. Record smaller than its header and 1 32-bit word is invalid.
92 // 32-bit is required by some entries like IT32 (see below).
93 // 2. Record overflowing UINT32 is invalid.
94 // 3. Record larger than file size is invalid.
95 //
96 if ( (RecordLength < sizeof (APPLE_ICNS_RECORD) + sizeof (UINT32))
97 || BaseOverflowAddU32 (Offset, RecordLength, &Offset)
98 || (Offset > IcnsImageSize))
99 {
100 return EFI_SECURITY_VIOLATION;
101 }
102
103 if ( ((Scale == 1) && (Record->Type == APPLE_ICNS_IC07))
104 || ((Scale == 2) && (Record->Type == APPLE_ICNS_IC13)))
105 {
106 Status = GuiPngToImage (
107 Image,
108 Record->Data,
109 RecordLength - sizeof (APPLE_ICNS_RECORD),
110 TRUE
111 );
112
113 if (!EFI_ERROR (Status) && (MatchWidth > 0) && (MatchHeight > 0)) {
114 if (AllowLess
115 ? ( (Image->Width > MatchWidth * Scale) || (Image->Height > MatchWidth * Scale)
116 || (Image->Width == 0) || (Image->Height == 0))
117 : ((Image->Width != MatchWidth * Scale) || (Image->Height != MatchHeight * Scale)))
118 {
119 FreePool (Image->Buffer);
120 DEBUG ((
121 DEBUG_INFO,
122 "OCUI: Expected %dx%d, actual %dx%d, allow less: %d\n",
123 MatchWidth * Scale,
124 MatchHeight * Scale,
125 Image->Width,
126 Image->Height,
127 AllowLess
128 ));
129 Status = EFI_UNSUPPORTED;
130 }
131 }
132
133 return Status;
134 }
135
136 if (Scale == 1) {
137 if (Record->Type == APPLE_ICNS_IT32) {
138 RecordIT32 = Record;
139 } else if (Record->Type == APPLE_ICNS_T8MK) {
140 RecordT8MK = Record;
141 }
142
143 if ((RecordT8MK != NULL) && (RecordIT32 != NULL)) {
144 Image->Width = MatchWidth;
145 Image->Height = MatchHeight;
146 ImageSize = (MatchWidth * MatchHeight) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
147 Image->Buffer = AllocateZeroPool (ImageSize);
148
149 if (Image->Buffer == NULL) {
150 return EFI_OUT_OF_RESOURCES;
151 }
152
153 //
154 // We have to add an additional UINT32 for IT32, since it has a reserved field.
155 //
156 DecodedBytes = DecompressMaskedRLE24 (
157 (UINT8 *)Image->Buffer,
158 ImageSize,
159 RecordIT32->Data + sizeof (UINT32),
160 SwapBytes32 (RecordIT32->Size) - sizeof (APPLE_ICNS_RECORD) - sizeof (UINT32),
161 RecordT8MK->Data,
162 SwapBytes32 (RecordT8MK->Size) - sizeof (APPLE_ICNS_RECORD),
163 TRUE
164 );
165
166 if (DecodedBytes != ImageSize) {
167 FreePool (Image->Buffer);
168 return EFI_UNSUPPORTED;
169 }
170
171 return EFI_SUCCESS;
172 }
173 }
174 }
175
176 return EFI_NOT_FOUND;
177}
178
179EFI_STATUS
181 OUT GUI_IMAGE *Image,
182 IN VOID *RawData,
183 IN UINT32 DataLength,
184 IN UINT8 Scale,
185 IN BOOLEAN Inverted
186 )
187{
188 APPLE_DISK_LABEL *Label;
189 UINT32 PixelIdx;
190
191 ASSERT (RawData != NULL);
192 ASSERT (Scale == 1 || Scale == 2);
193
194 if (DataLength < sizeof (APPLE_DISK_LABEL)) {
195 return EFI_INVALID_PARAMETER;
196 }
197
198 Label = RawData;
199 Image->Width = SwapBytes16 (Label->Width);
200 Image->Height = SwapBytes16 (Label->Height);
201
202 if ( (Image->Width > APPLE_DISK_LABEL_MAX_WIDTH * Scale)
203 || (Image->Height > APPLE_DISK_LABEL_MAX_HEIGHT * Scale)
204 || (DataLength != sizeof (APPLE_DISK_LABEL) + Image->Width * Image->Height))
205 {
206 DEBUG ((DEBUG_INFO, "OCUI: Invalid label has %dx%d dims at %u size\n", Image->Width, Image->Height, DataLength));
207 return EFI_SECURITY_VIOLATION;
208 }
209
210 Image->Buffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)AllocatePool (
211 Image->Width * Image->Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
212 );
213
214 if (Image->Buffer == NULL) {
215 return EFI_OUT_OF_RESOURCES;
216 }
217
218 if (Inverted) {
219 for (PixelIdx = 0; PixelIdx < Image->Width * Image->Height; PixelIdx++) {
220 Image->Buffer[PixelIdx].Blue = 0;
221 Image->Buffer[PixelIdx].Green = 0;
222 Image->Buffer[PixelIdx].Red = 0;
223 Image->Buffer[PixelIdx].Reserved = 255 - gAppleDiskLabelImagePalette[Label->Data[PixelIdx]];
224 }
225 } else {
226 for (PixelIdx = 0; PixelIdx < Image->Width * Image->Height; PixelIdx++) {
227 Image->Buffer[PixelIdx].Blue = 255 - gAppleDiskLabelImagePalette[Label->Data[PixelIdx]];
228 Image->Buffer[PixelIdx].Green = 255 - gAppleDiskLabelImagePalette[Label->Data[PixelIdx]];
229 Image->Buffer[PixelIdx].Red = 255 - gAppleDiskLabelImagePalette[Label->Data[PixelIdx]];
230 Image->Buffer[PixelIdx].Reserved = 255 - gAppleDiskLabelImagePalette[Label->Data[PixelIdx]];
231 }
232 }
233
234 return EFI_SUCCESS;
235}
236
237EFI_STATUS
239 OUT GUI_IMAGE *Image,
240 IN VOID *ImageData,
241 IN UINTN ImageDataSize,
242 IN BOOLEAN PremultiplyAlpha
243 )
244{
245 EFI_STATUS Status;
246 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BufferWalker;
247 UINTN Index;
248 UINT8 TmpChannel;
249
250 Status = OcDecodePng (
251 ImageData,
252 ImageDataSize,
253 (VOID **)&Image->Buffer,
254 &Image->Width,
255 &Image->Height,
256 NULL
257 );
258
259 if (EFI_ERROR (Status)) {
260 DEBUG ((DEBUG_INFO, "OCUI: DecodePNG - %r\n", Status));
261 return Status;
262 }
263
264 if (PremultiplyAlpha) {
265 BufferWalker = Image->Buffer;
266 for (Index = 0; Index < (UINTN)Image->Width * Image->Height; ++Index) {
267 TmpChannel = (UINT8)((BufferWalker->Blue * BufferWalker->Reserved) / 0xFF);
268 BufferWalker->Blue = (UINT8)((BufferWalker->Red * BufferWalker->Reserved) / 0xFF);
269 BufferWalker->Green = (UINT8)((BufferWalker->Green * BufferWalker->Reserved) / 0xFF);
270 BufferWalker->Red = TmpChannel;
271 ++BufferWalker;
272 }
273 }
274
275 return EFI_SUCCESS;
276}
277
278EFI_STATUS
280 OUT GUI_IMAGE *SelectedImage,
281 IN CONST GUI_IMAGE *SourceImage,
282 IN CONST EFI_GRAPHICS_OUTPUT_BLT_PIXEL *HighlightPixel
283 )
284{
285 EFI_GRAPHICS_OUTPUT_BLT_PIXEL PremulPixel;
286
287 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Buffer;
288 UINT32 ColumnOffset;
289 BOOLEAN OneSet;
290 UINT32 FirstUnsetX;
291 UINT32 IndexY;
292 UINT32 RowOffset;
293
294 ASSERT (SelectedImage != NULL);
295 ASSERT (SourceImage != NULL);
296 ASSERT (SourceImage->Buffer != NULL);
297 ASSERT (HighlightPixel != NULL);
298 //
299 // The multiplication cannot wrap around because the original allocation sane.
300 //
301 Buffer = AllocateCopyPool (
302 SourceImage->Width * SourceImage->Height * sizeof (*SourceImage->Buffer),
303 SourceImage->Buffer
304 );
305 if (Buffer == NULL) {
306 return EFI_OUT_OF_RESOURCES;
307 }
308
309 PremulPixel.Blue = (UINT8)((HighlightPixel->Blue * HighlightPixel->Reserved) / 0xFF);
310 PremulPixel.Green = (UINT8)((HighlightPixel->Green * HighlightPixel->Reserved) / 0xFF);
311 PremulPixel.Red = (UINT8)((HighlightPixel->Red * HighlightPixel->Reserved) / 0xFF);
312 PremulPixel.Reserved = HighlightPixel->Reserved;
313
314 for (
315 IndexY = 0, RowOffset = 0;
316 IndexY < SourceImage->Height;
317 ++IndexY, RowOffset += SourceImage->Width
318 )
319 {
320 FirstUnsetX = 0;
321 OneSet = FALSE;
322
323 for (ColumnOffset = 0; ColumnOffset < SourceImage->Width; ++ColumnOffset) {
324 if (SourceImage->Buffer[RowOffset + ColumnOffset].Reserved != 0) {
325 OneSet = TRUE;
326 GuiBlendPixelSolid (&Buffer[RowOffset + ColumnOffset], &PremulPixel);
327 if (FirstUnsetX != 0) {
328 //
329 // Set all fully transparent pixels between two not fully transparent
330 // pixels to the highlighter pixel.
331 //
332 while (FirstUnsetX < ColumnOffset) {
333 CopyMem (
334 &Buffer[RowOffset + FirstUnsetX],
335 &PremulPixel,
336 sizeof (*Buffer)
337 );
338 ++FirstUnsetX;
339 }
340
341 FirstUnsetX = 0;
342 }
343 } else if ((FirstUnsetX == 0) && OneSet) {
344 FirstUnsetX = ColumnOffset;
345 }
346 }
347 }
348
349 SelectedImage->Width = SourceImage->Width;
350 SelectedImage->Height = SourceImage->Height;
351 SelectedImage->Buffer = Buffer;
352 return EFI_SUCCESS;
353}
#define APPLE_DISK_LABEL_MAX_WIDTH
#define APPLE_DISK_LABEL_MAX_HEIGHT
#define APPLE_ICNS_IC07
Definition AppleIcon.h:24
#define APPLE_ICNS_IT32
Definition AppleIcon.h:26
#define APPLE_ICNS_T8MK
Definition AppleIcon.h:27
#define APPLE_ICNS_MAGIC
Definition AppleIcon.h:19
#define APPLE_ICNS_IC13
Definition AppleIcon.h:25
struct APPLE_ICNS_RECORD_ APPLE_ICNS_RECORD
VOID GuiBlendPixelSolid(IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BackPixel, IN CONST EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FrontPixel)
Definition Blending.c:98
EFI_STATUS GuiLabelToImage(OUT GUI_IMAGE *Image, IN VOID *RawData, IN UINT32 DataLength, IN UINT8 Scale, IN BOOLEAN Inverted)
Definition Images.c:180
EFI_STATUS GuiIcnsToImageIcon(OUT GUI_IMAGE *Image, IN VOID *IcnsImage, IN UINT32 IcnsImageSize, IN UINT8 Scale, IN UINT32 MatchWidth, IN UINT32 MatchHeight, IN BOOLEAN AllowLess)
Definition Images.c:46
EFI_STATUS GuiCreateHighlightedImage(OUT GUI_IMAGE *SelectedImage, IN CONST GUI_IMAGE *SourceImage, IN CONST EFI_GRAPHICS_OUTPUT_BLT_PIXEL *HighlightPixel)
Definition Images.c:279
EFI_STATUS GuiPngToImage(OUT GUI_IMAGE *Image, IN VOID *ImageData, IN UINTN ImageDataSize, IN BOOLEAN PremultiplyAlpha)
Definition Images.c:238
STATIC CONST UINT8 gAppleDiskLabelImagePalette[256]
Definition Images.c:26
UINT32 DecompressMaskedRLE24(OUT UINT8 *Dst, IN UINT32 DstLen, IN UINT8 *Src, IN UINT32 SrcLen, IN UINT8 *Mask, IN UINT32 MaskLen, IN BOOLEAN Premultiply)
EFI_STATUS OcDecodePng(IN VOID *Buffer, IN UINTN Size, OUT VOID **RawData, OUT UINT32 *Width, OUT UINT32 *Height, OUT BOOLEAN *HasAlphaType OPTIONAL)
Definition OcPng.c:64
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
#define ASSERT(x)
Definition coder.h:55