1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21
22 /*
23 * pax ico format
24 */
25
26 #include <paxlib.h>
27 #include <ccode.h>
28 #include <swap.h>
29 #include <tm.h>
30
31 #define ICO_HEADER 6
32 #define ICO_DIRECTORY 16
33
34 #define ICO_MAGIC 0
35 #define ICO_TYPE 1
36
37 #define ICO_PNG_COLORS 0
38 #define ICO_PNG_PLANES 1
39 #define ICO_PNG_BPP 32
40
41 typedef struct Ico_header_s
42 {
43 uint16_t magic;
44 uint16_t type;
45 uint16_t count;
46 } Ico_header_t;
47
48 typedef struct Ico_directory_s
49 {
50 uint8_t width;
51 uint8_t height;
52 uint8_t colors;
53 uint8_t magic;
54 uint16_t panes;
55 uint16_t bpp;
56 uint32_t size;
57 uint32_t offset;
58 } Ico_directory_t;
59
60 typedef struct Ico_s
61 {
62 Sfio_t* head;
63 Sfio_t* data;
64 unsigned char* cur;
65 int mode;
66 int entries;
67 char name[32];
68 unsigned char dir[1];
69 } Ico_t;
70
71 static int
ico_done(Pax_t * pax,register Paxarchive_t * ap)72 ico_done(Pax_t* pax, register Paxarchive_t* ap)
73 {
74 register Ico_t* ico = (Ico_t*)ap->data;
75
76 if (!ico)
77 return -1;
78 if (ico->data)
79 sfclose(ico->data);
80 if (ico->head)
81 sfclose(ico->head);
82 free(ico);
83 ap->data = 0;
84 return 0;
85 }
86
87 static int
ico_getprologue(Pax_t * pax,Paxformat_t * fp,register Paxarchive_t * ap,Paxfile_t * f,register unsigned char * p,size_t size)88 ico_getprologue(Pax_t* pax, Paxformat_t* fp, register Paxarchive_t* ap, Paxfile_t* f, register unsigned char* p, size_t size)
89 {
90 register Ico_t* ico;
91 size_t m;
92 size_t n;
93
94 if (size < ICO_HEADER + ICO_DIRECTORY)
95 return 0;
96 if (swapget(3, p, 2) != ICO_MAGIC || swapget(3, p+2, 2) != ICO_TYPE || p[9] != 0 && p[9] != 255)
97 return 0;
98 if (paxseek(pax, ap, ICO_HEADER, SEEK_SET, 1) != ICO_HEADER)
99 return 0;
100 m = swapget(3, p+4, 2);
101 n = m * ICO_DIRECTORY;
102 if (!(ico = newof(0, Ico_t, 1, n - 1)))
103 return paxnospace(pax);
104 umask(ico->mode = umask(0));
105 ico->mode = X_IFREG | (0666 & ~ico->mode);
106 ico->entries = m;
107 if (paxread(pax, ap, ico->dir, n, n, 0) <= 0)
108 {
109 free(ico);
110 return 0;
111 }
112 ico->cur = ico->dir;
113 ap->data = ico;
114 return 1;
115 }
116
117 static int
ico_getheader(Pax_t * pax,register Paxarchive_t * ap,register Paxfile_t * f)118 ico_getheader(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f)
119 {
120 register Ico_t* ico = (Ico_t*)ap->data;
121 register unsigned char* p;
122 int width;
123 int height;
124 size_t offset;
125 size_t size;
126
127 if (ap->entry > ico->entries)
128 {
129 ap->io->eof = 1;
130 return 0;
131 }
132 p = ico->cur;
133 ico->cur += ICO_DIRECTORY;
134 width = p[0] ? p[0] : 256;
135 height = p[1] ? p[1] : 256;
136 size = swapget(3, p+8, 4);
137 offset = swapget(3, p+12, 4);
138 sfsprintf(ico->name, sizeof(ico->name), "ico-%d-c%dp%db%dw%dh%d.ico", ap->entry, p[2], (int)swapget(3, p+4, 2), (int)swapget(3, p+6, 2), width, height);
139 f->name = ico->name;
140 f->linktype = PAX_NOLINK;
141 f->linkpath = 0;
142 f->st->st_mode = ico->mode;
143 f->st->st_uid = pax->uid;
144 f->st->st_gid = pax->gid;
145 f->st->st_size = size;
146 f->st->st_mtime = time(NiL);
147 f->st->st_nlink = 1;
148 if (paxseek(pax, ap, offset, SEEK_SET, 1) != offset)
149 return -1;
150 return 1;
151 }
152
153 static int
ico_getdata(Pax_t * pax,register Paxarchive_t * ap,register Paxfile_t * f,int fd)154 ico_getdata(Pax_t* pax, register Paxarchive_t* ap, register Paxfile_t* f, int fd)
155 {
156 register Ico_t* ico = (Ico_t*)ap->data;
157 Sfio_t* sp;
158 ssize_t n;
159 size_t z;
160 unsigned char* dir;
161 unsigned char hdr[ICO_HEADER];
162
163 if (fd < 0 || !f->st->st_size)
164 return 1;
165 if (!(sp = paxpart(pax, ap, f->st->st_size)))
166 return -1;
167 swapput(3, hdr+0, 2, ICO_MAGIC);
168 swapput(3, hdr+2, 2, ICO_TYPE);
169 swapput(3, hdr+4, 2, 1);
170 sfwrite(sp, hdr, ICO_HEADER);
171 if (paxdata(pax, ap, f, fd, hdr, ICO_HEADER))
172 return -1;
173 dir = ico->cur - ICO_DIRECTORY;
174 swapput(3, dir+12, 4, ICO_HEADER + ICO_DIRECTORY);
175 if (paxdata(pax, ap, f, fd, dir, ICO_DIRECTORY))
176 return -1;
177 while ((n = sfread(sp, pax->buf, sizeof(pax->buf))) > 0)
178 if (paxdata(pax, ap, f, fd, pax->buf, n))
179 return -1;
180 if (n)
181 (*pax->errorf)(NiL, pax, 2, "%s: %s: unexpected EOF", ap->name, f->name);
182 return 1;
183 }
184
185 static int
ico_putprologue(Pax_t * pax,register Paxarchive_t * ap,int append)186 ico_putprologue(Pax_t* pax, register Paxarchive_t* ap, int append)
187 {
188 register Ico_t* ico = (Ico_t*)ap->data;
189 unsigned char hdr[ICO_HEADER];
190
191 if (!ico)
192 {
193 if (!(ico = newof(0, Ico_t, 1, 0)) || !(ico->head = sfstropen()) || !(ico->data = sftmp(64 * 1024)))
194 return paxnospace(pax);
195 swapput(3, hdr+0, 2, ICO_MAGIC);
196 swapput(3, hdr+2, 2, ICO_TYPE);
197 swapput(3, hdr+4, 2, 0);
198 sfwrite(ico->head, hdr, ICO_HEADER);
199 ap->data = ico;
200 }
201 return 1;
202 }
203
204 static int
ico_putheader(Pax_t * pax,Paxarchive_t * ap,Paxfile_t * f)205 ico_putheader(Pax_t* pax, Paxarchive_t* ap, Paxfile_t* f)
206 {
207 return 1;
208 }
209
210 static int
ico_putdata(Pax_t * pax,Paxarchive_t * ap,Paxfile_t * f,int fd)211 ico_putdata(Pax_t* pax, Paxarchive_t* ap, Paxfile_t* f, int fd)
212 {
213 register Ico_t* ico = (Ico_t*)ap->data;
214 Sfio_t* sp;
215 unsigned char* p;
216 int d;
217 ssize_t n;
218 size_t z;
219 uint32_t size;
220 unsigned char dir[ICO_HEADER+ICO_DIRECTORY];
221
222 if (!(sp = sfnew(NiL, NiL, SF_UNBOUND, fd, SF_READ)))
223 return paxnospace(pax);
224 d = 1;
225 z = f->st->st_size;
226 do
227 {
228 if ((n = sizeof(pax->buf)) > z)
229 n = z;
230 if ((n = sfread(sp, pax->buf, n)) <= 0)
231 {
232 if (pax->errorf)
233 (*pax->errorf)(NiL, pax, 2, "%s: %s: read error", ap->name, f->name);
234 return -1;
235 }
236 p = (unsigned char*)pax->buf;
237 if (d)
238 {
239 if (n < ICO_HEADER + ICO_DIRECTORY)
240 {
241 if (pax->errorf)
242 (*pax->errorf)(NiL, pax, 2, "%s: %s: read error", ap->name, f->name);
243 return -1;
244 }
245 if (swapget(3, p+0, 2) == ICO_MAGIC && swapget(3, p+2, 2) == ICO_TYPE)
246 {
247 sfwrite(ico->head, p+ICO_HEADER, ICO_DIRECTORY);
248 p += ICO_HEADER + ICO_DIRECTORY;
249 n -= ICO_HEADER + ICO_DIRECTORY;
250 z -= ICO_HEADER + ICO_DIRECTORY;
251 }
252 else if (!memcmp(p, "\x89PNG\x0d\x0a\x1a\x0a", 8))
253 {
254 dir[0] = (d = swapget(0, p+16, 4)) < 256 ? d : 0;
255 dir[1] = (d = swapget(0, p+20, 4)) < 256 ? d : 0;
256 dir[2] = ICO_PNG_COLORS;
257 dir[3] = 0;
258 swapput(3, dir+4, 2, ICO_PNG_PLANES);
259 swapput(3, dir+6, 2, ICO_PNG_BPP);
260 swapput(3, dir+8, 2, f->st->st_size);
261 swapput(3, dir+12, 2, 0);
262 sfwrite(ico->head, dir, ICO_DIRECTORY);
263 }
264 else
265 {
266 if (pax->errorf)
267 (*pax->errorf)(NiL, pax, 2, "%s: %s: not an icon resource or image", ap->name, f->name);
268 return -1;
269 }
270 d = 0;
271 }
272 sfwrite(ico->data, p, n);
273 } while (z -= n);
274 if (sfclose(sp))
275 {
276 if (pax->errorf)
277 (*pax->errorf)(NiL, pax, 2, "%s: %s: write error", ap->name, f->name);
278 return -1;
279 }
280 return n;
281 }
282
283 static off_t
ico_putepilogue(Pax_t * pax,Paxarchive_t * ap)284 ico_putepilogue(Pax_t* pax, Paxarchive_t* ap)
285 {
286 register Ico_t* ico = (Ico_t*)ap->data;
287 register unsigned char* p;
288 unsigned char* b;
289 int i;
290 uint32_t size;
291 uint32_t offset;
292
293 b = p = (unsigned char*)sfstrbase(ico->head);
294 swapput(3, p+4, 2, ap->entry);
295 p += ICO_HEADER;
296 size = offset = ICO_HEADER + ap->entries * ICO_DIRECTORY;
297 for (i = 0; i < ap->entry; i++)
298 {
299 swapput(3, p+12, 4, offset);
300 offset += swapget(3, p+8, 4);
301 p += ICO_DIRECTORY;
302 }
303 paxwrite(pax, ap, b, size);
304 sfseek(ico->data, 0, SEEK_SET);
305 while ((i = sfread(ico->data, pax->buf, sizeof(pax->buf))) > 0)
306 paxwrite(pax, ap, pax->buf, i);
307 if (i < 0)
308 {
309 if (pax->errorf)
310 (*pax->errorf)(NiL, pax, 2, "%s: write error", ap->name);
311 return -1;
312 }
313 return 1;
314 }
315
316 Paxformat_t pax_ico_format =
317 {
318 "ico",
319 0,
320 "windows icon file",
321 0,
322 PAX_ARCHIVE|PAX_NOHARDLINKS|PAX_IN|PAX_OUT,
323 PAX_DEFBUFFER,
324 PAX_DEFBLOCKS,
325 0,
326 PAXNEXT(ico),
327 0,
328 ico_done,
329 ico_getprologue,
330 ico_getheader,
331 ico_getdata,
332 0,
333 0,
334 ico_putprologue,
335 ico_putheader,
336 ico_putdata,
337 0,
338 ico_putepilogue,
339 };
340
341 PAXLIB(ico)
342