]> code.delx.au - refind/blob - libeg/load_icns.c
Documentation updates for 0.10.3 release.
[refind] / libeg / load_icns.c
1 /*
2 * libeg/load_icns.c
3 * Loading function for .icns Apple icon images
4 *
5 * Copyright (c) 2006 Christoph Pfisterer
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include "libegint.h"
38
39 #define MAX_ICNS_SIZES 4
40
41 //
42 // Decompress .icns RLE data
43 //
44
45 VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT8 *PixelData, IN UINTN PixelCount)
46 {
47 UINT8 *cp;
48 UINT8 *cp_end;
49 UINT8 *pp;
50 UINTN pp_left;
51 UINTN len, i;
52 UINT8 value;
53
54 // setup variables
55 cp = *CompData;
56 cp_end = cp + *CompLen;
57 pp = PixelData;
58 pp_left = PixelCount;
59
60 // decode
61 while (cp + 1 < cp_end && pp_left > 0) {
62 len = *cp++;
63 if (len & 0x80) { // compressed data: repeat next byte
64 len -= 125;
65 if (len > pp_left)
66 break;
67 value = *cp++;
68 for (i = 0; i < len; i++) {
69 *pp = value;
70 pp += 4;
71 }
72 } else { // uncompressed data: copy bytes
73 len++;
74 if (len > pp_left || cp + len > cp_end)
75 break;
76 for (i = 0; i < len; i++) {
77 *pp = *cp++;
78 pp += 4;
79 }
80 }
81 pp_left -= len;
82 }
83
84 if (pp_left > 0) {
85 Print(L" egDecompressIcnsRLE: still need %d bytes of pixel data\n", pp_left);
86 }
87
88 // record what's left of the compressed data stream
89 *CompData = cp;
90 *CompLen = (UINTN)(cp_end - cp);
91 }
92
93 //
94 // Load Apple .icns icons
95 //
96
97 EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha)
98 {
99 EG_IMAGE *NewImage;
100 UINT8 *Ptr, *BufferEnd, *DataPtr, *MaskPtr;
101 UINT32 BlockLen, DataLen, MaskLen;
102 UINTN PixelCount, i;
103 UINT8 *CompData;
104 UINTN CompLen;
105 UINT8 *SrcPtr;
106 EG_PIXEL *DestPtr;
107 UINTN SizesToTry[MAX_ICNS_SIZES + 1] = {IconSize, 128, 48, 32, 16};
108 UINTN SizeToTry = 0;
109
110 if (FileDataLength < 8 || FileData == NULL ||
111 FileData[0] != 'i' || FileData[1] != 'c' || FileData[2] != 'n' || FileData[3] != 's') {
112 // not an icns file...
113 return NULL;
114 }
115
116 for (;;) {
117 DataPtr = NULL;
118 DataLen = 0;
119 MaskPtr = NULL;
120 MaskLen = 0;
121
122 do {
123 IconSize = SizesToTry[SizeToTry];
124 Ptr = FileData + 8;
125 BufferEnd = FileData + FileDataLength;
126 // iterate over tagged blocks in the file
127 while (Ptr + 8 <= BufferEnd) {
128 BlockLen = ((UINT32)Ptr[4] << 24) + ((UINT32)Ptr[5] << 16) + ((UINT32)Ptr[6] << 8) + (UINT32)Ptr[7];
129 if (Ptr + BlockLen > BufferEnd) // block continues beyond end of file
130 break;
131
132 // extract the appropriate blocks for each pixel size
133 if (IconSize == 128) {
134 if (Ptr[0] == 'i' && Ptr[1] == 't' && Ptr[2] == '3' && Ptr[3] == '2') {
135 if (Ptr[8] == 0 && Ptr[9] == 0 && Ptr[10] == 0 && Ptr[11] == 0) {
136 DataPtr = Ptr + 12;
137 DataLen = BlockLen - 12;
138 }
139 } else if (Ptr[0] == 't' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {
140 MaskPtr = Ptr + 8;
141 MaskLen = BlockLen - 8;
142 }
143
144 } else if (IconSize == 48) {
145 if (Ptr[0] == 'i' && Ptr[1] == 'h' && Ptr[2] == '3' && Ptr[3] == '2') {
146 DataPtr = Ptr + 8;
147 DataLen = BlockLen - 8;
148 } else if (Ptr[0] == 'h' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {
149 MaskPtr = Ptr + 8;
150 MaskLen = BlockLen - 8;
151 }
152
153 } else if (IconSize == 32) {
154 if (Ptr[0] == 'i' && Ptr[1] == 'l' && Ptr[2] == '3' && Ptr[3] == '2') {
155 DataPtr = Ptr + 8;
156 DataLen = BlockLen - 8;
157 } else if (Ptr[0] == 'l' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {
158 MaskPtr = Ptr + 8;
159 MaskLen = BlockLen - 8;
160 }
161
162 } else if (IconSize == 16) {
163 if (Ptr[0] == 'i' && Ptr[1] == 's' && Ptr[2] == '3' && Ptr[3] == '2') {
164 DataPtr = Ptr + 8;
165 DataLen = BlockLen - 8;
166 } else if (Ptr[0] == 's' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') {
167 MaskPtr = Ptr + 8;
168 MaskLen = BlockLen - 8;
169 }
170
171 }
172
173 Ptr += BlockLen;
174 }
175 } while ((DataPtr == NULL) && (SizeToTry++ < MAX_ICNS_SIZES));
176
177 break;
178 }
179
180 if (DataPtr == NULL)
181 return NULL; // no image found
182
183 // allocate image structure and buffer
184 NewImage = egCreateImage(IconSize, IconSize, WantAlpha);
185 if (NewImage == NULL)
186 return NULL;
187 PixelCount = IconSize * IconSize;
188
189 if (DataLen < PixelCount * 3) {
190
191 // pixel data is compressed, RGB planar
192 CompData = DataPtr;
193 CompLen = DataLen;
194 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
195 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, g), PixelCount);
196 egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, b), PixelCount);
197 // possible assertion: CompLen == 0
198 if (CompLen > 0) {
199 Print(L" egLoadICNSIcon: %d bytes of compressed data left\n", CompLen);
200 }
201
202 } else {
203
204 // pixel data is uncompressed, RGB interleaved
205 SrcPtr = DataPtr;
206 DestPtr = NewImage->PixelData;
207 for (i = 0; i < PixelCount; i++, DestPtr++) {
208 DestPtr->r = *SrcPtr++;
209 DestPtr->g = *SrcPtr++;
210 DestPtr->b = *SrcPtr++;
211 }
212
213 }
214
215 // add/set alpha plane
216 if (MaskPtr != NULL && MaskLen >= PixelCount && WantAlpha)
217 egInsertPlane(MaskPtr, PLPTR(NewImage, a), PixelCount);
218 else
219 egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount);
220
221 // FUTURE: scale to originally requested size if we had to load another size
222
223 return NewImage;
224 } // EG_IMAGE * egDecodeICNS()
225
226 /* EOF */