1 /*
2 Copyright (C) 2000 Masanao Izumo <mo@goice.co.jp>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #ifndef NO_STRING_H
23 #include <string.h>
24 #else
25 #include <strings.h>
26 #endif
27 #include "libarc/url.h"
28
29 #define DECODEBUFSIZ 255 /* Must be power of 3 */
30 #define INFOBYTES 128
31
32 typedef struct _URL_hqxdecode
33 {
34 char common[sizeof(struct _URL)];
35 URL reader;
36 long rpos;
37 int beg, end, eof, eod;
38 unsigned char decodebuf[DECODEBUFSIZ];
39 long datalen, rsrclen, restlen;
40 int dsoff, rsoff, zoff;
41 int stage, dataonly, autoclose;
42 } URL_hqxdecode;
43
44 static long url_hqxdecode_read(URL url, void *buff, long n);
45 static int url_hqxdecode_fgetc(URL url);
46 static long url_hqxdecode_tell(URL url);
47 static void url_hqxdecode_close(URL url);
48
url_hqxdecode_open(URL reader,int dataonly,int autoclose)49 URL url_hqxdecode_open(URL reader, int dataonly, int autoclose)
50 {
51 URL_hqxdecode *url;
52
53 url = (URL_hqxdecode *)alloc_url(sizeof(URL_hqxdecode));
54 if(url == NULL)
55 {
56 if(autoclose)
57 url_close(reader);
58 url_errno = errno;
59 return NULL;
60 }
61
62 /* common members */
63 URLm(url, type) = URL_hqxdecode_t;
64 URLm(url, url_read) = url_hqxdecode_read;
65 URLm(url, url_gets) = NULL;
66 URLm(url, url_fgetc) = url_hqxdecode_fgetc;
67 URLm(url, url_seek) = NULL;
68 URLm(url, url_tell) = url_hqxdecode_tell;
69 URLm(url, url_close) = url_hqxdecode_close;
70
71 /* private members */
72 url->reader = reader;
73 url->rpos = 0;
74 url->beg = 0;
75 url->end = 0;
76 url->eof = url->eod = 0;
77 memset(url->decodebuf, 0, sizeof(url->decodebuf));
78 url->datalen = -1;
79 url->rsrclen = -1;
80 url->restlen = 0;
81 url->stage = 0;
82 url->dataonly = dataonly;
83 url->autoclose = autoclose;
84
85 return (URL)url;
86 }
87
hqxgetchar(URL reader)88 static int hqxgetchar(URL reader)
89 {
90 int c;
91 static int hqx_decode_table[256] =
92 {
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
98 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x00, 0x00,
99 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x00,
100 0x14, 0x15, EOF, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
102 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x00,
103 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x00,
104 0x2c, 0x2d, 0x2e, 0x2f, 0x00, 0x00, 0x00, 0x00,
105 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x00,
106 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x00, 0x00,
107 0x3d, 0x3e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00
108 };
109
110 do
111 {
112 if((c = url_getc(reader)) == EOF)
113 return EOF;
114 } while(c == '\r' || c == '\n');
115 return hqx_decode_table[c];
116 }
117
hqxdecode_chunk(URL url,unsigned char * p)118 static int hqxdecode_chunk(URL url, unsigned char *p)
119 {
120 int c1, c2, c3, c4;
121 int n;
122
123 n = 0;
124 if((c1 = hqxgetchar(url)) == EOF)
125 return 0;
126 if((c2 = hqxgetchar(url)) == EOF)
127 return 0;
128 p[n++] = ((c1 << 2) | ((c2 & 0x30) >> 4));
129 if((c3 = hqxgetchar(url)) == EOF)
130 return n;
131 p[n++] = (((c2 & 0xf) << 4) | ((c3 & 0x3c) >> 2));
132 if((c4 = hqxgetchar(url)) == EOF)
133 return n;
134 p[n++] = (((c3 & 0x03) << 6) | c4);
135 return n;
136 }
137
convert_int32(unsigned char * p)138 static uint32 convert_int32(unsigned char *p)
139 {
140 return ((uint32)p[3]) |
141 (((uint32)p[2]) << 8) |
142 (((uint32)p[1]) << 16) |
143 (((uint32)p[0]) << 24);
144 }
145
hqxdecode_header(URL_hqxdecode * urlp)146 static int hqxdecode_header(URL_hqxdecode *urlp)
147 {
148 int i, n;
149 unsigned char *p, *q;
150 URL url;
151 int hlen, nlen;
152
153 n = 0;
154 p = urlp->decodebuf;
155 q = urlp->decodebuf + INFOBYTES;
156 url = urlp->reader;
157 while(n < DECODEBUFSIZ - INFOBYTES - 2)
158 {
159 i = hqxdecode_chunk(url, q + n);
160 n += i;
161 if(i != 3)
162 {
163 urlp->eod = 1;
164 break;
165 }
166 }
167
168 memset(p, 0, INFOBYTES);
169 nlen = q[0];
170 hlen = nlen + 22;
171
172 if(n < hlen)
173 {
174 urlp->eof = 1;
175 return -1; /* Error */
176 }
177
178 urlp->datalen = (long)convert_int32(q + hlen - 10);
179 urlp->rsrclen = (long)convert_int32(q + hlen - 6);
180 urlp->dsoff = (((urlp->datalen + 127) >> 7) << 7) - urlp->datalen;
181 urlp->rsoff = (((urlp->rsrclen + 127) >> 7) << 7) - urlp->rsrclen;
182 urlp->zoff = 0;
183
184 p[1] = nlen;
185 memcpy(p + 2, q + 1, nlen);
186 memcpy(p + 65, q + hlen - 20, 4+4+2); /* type, author, flags */
187 memcpy(p + 83, q + hlen - 10, 4+4); /* datalen, rsrclen */
188 /* 91: create time (4) */
189 /* 95: modify time (4) */
190
191 q += hlen;
192 n -= hlen;
193 for(i = 0; i < n; i++)
194 p[INFOBYTES + i] = q[i];
195 return INFOBYTES + n;
196 }
197
hqxdecode(URL_hqxdecode * urlp)198 static int hqxdecode(URL_hqxdecode *urlp)
199 {
200 int i, n;
201 unsigned char *p;
202 URL url;
203
204 if(urlp->eod)
205 {
206 urlp->eof = 1;
207 return 1;
208 }
209
210 if(urlp->stage == 0)
211 {
212 n = hqxdecode_header(urlp);
213 if(n == -1)
214 return 1;
215 urlp->end = n;
216
217 if(urlp->dataonly)
218 {
219 urlp->beg = INFOBYTES;
220 urlp->restlen = urlp->datalen;
221 }
222 else
223 {
224 urlp->beg = 0;
225 urlp->restlen = urlp->datalen + INFOBYTES;
226 }
227
228 urlp->stage = 1;
229 return 0;
230 }
231
232 p = urlp->decodebuf;
233 url = urlp->reader;
234 n = 0;
235
236 if(urlp->restlen == 0)
237 {
238 if(urlp->dataonly)
239 {
240 urlp->eof = 1;
241 return 1;
242 }
243
244 if(urlp->stage == 2)
245 {
246 urlp->zoff = urlp->rsoff;
247 urlp->eof = 1;
248 return 1;
249 }
250
251 urlp->zoff = urlp->dsoff;
252 urlp->stage = 2;
253
254 n = urlp->end - urlp->beg;
255 if(n <= 2)
256 {
257 for(i = 0; i < n; i++)
258 p[i] = p[i + urlp->beg];
259 n += hqxdecode_chunk(url, p + n);
260 if(n <= 2)
261 {
262 urlp->eof = 1;
263 return 1;
264 }
265 urlp->rpos += urlp->beg;
266 urlp->beg = 0;
267 urlp->end = n;
268 }
269 urlp->restlen = urlp->rsrclen;
270
271 /* skip 2 byte (crc) */
272 urlp->beg += 2;
273 urlp->rpos -= 2;
274
275 n = urlp->beg;
276 }
277
278 while(n < DECODEBUFSIZ)
279 {
280 i = hqxdecode_chunk(url, p + n);
281 n += i;
282 if(i != 3)
283 {
284 urlp->eod = 1;
285 break;
286 }
287 }
288
289 urlp->rpos += urlp->beg;
290 urlp->beg = 0;
291 urlp->end = n;
292
293 if(n == 0)
294 {
295 urlp->eof = 1;
296 return 1;
297 }
298
299 return 0;
300 }
301
url_hqxdecode_read(URL url,void * buff,long size)302 static long url_hqxdecode_read(URL url, void *buff, long size)
303 {
304 URL_hqxdecode *urlp = (URL_hqxdecode *)url;
305 char *p = (char *)buff;
306 long n;
307 int i;
308
309 n = 0;
310 while(n < size)
311 {
312 if(urlp->zoff > 0)
313 {
314 i = urlp->zoff;
315 if(i > size - n)
316 i = size - n;
317 memset(p + n, 0, i);
318 urlp->zoff -= i;
319 urlp->rpos += i;
320 n += i;
321 continue;
322 }
323
324 if(urlp->eof)
325 break;
326
327 if(urlp->restlen == 0 || urlp->beg == urlp->end)
328 {
329 hqxdecode(urlp);
330 continue;
331 }
332
333 i = urlp->end - urlp->beg;
334 if(i > urlp->restlen)
335 i = urlp->restlen;
336 if(i > size - n)
337 i = size - n;
338 memcpy(p + n, urlp->decodebuf + urlp->beg, i);
339 urlp->beg += i;
340 n += i;
341 urlp->restlen -= i;
342 }
343
344 return n;
345 }
346
url_hqxdecode_fgetc(URL url)347 static int url_hqxdecode_fgetc(URL url)
348 {
349 URL_hqxdecode *urlp = (URL_hqxdecode *)url;
350 int c;
351
352 retry_read:
353 if(urlp->zoff > 0)
354 {
355 urlp->zoff--;
356 urlp->rpos++;
357 return 0;
358 }
359
360 if(urlp->eof)
361 return EOF;
362
363 if(urlp->restlen == 0 || urlp->beg == urlp->end)
364 {
365 hqxdecode(urlp);
366 goto retry_read;
367 }
368
369 c = (int)urlp->decodebuf[urlp->beg++];
370 urlp->restlen--;
371
372 return c;
373 }
374
url_hqxdecode_tell(URL url)375 static long url_hqxdecode_tell(URL url)
376 {
377 URL_hqxdecode *urlp = (URL_hqxdecode *)url;
378
379 if(urlp->dataonly)
380 return urlp->rpos + urlp->beg - INFOBYTES;
381 return urlp->rpos + urlp->beg;
382 }
383
url_hqxdecode_close(URL url)384 static void url_hqxdecode_close(URL url)
385 {
386 URL_hqxdecode *urlp = (URL_hqxdecode *)url;
387
388 if(urlp->autoclose)
389 url_close(urlp->reader);
390 free(url);
391 }
392
393 #ifdef HQXDECODE_MAIN
main(int argc,char ** argv)394 void main(int argc, char** argv)
395 {
396 URL hqxdecoder;
397 char buff[256], *filename;
398 int c;
399
400 if(argc != 2)
401 {
402 fprintf(stderr, "Usage: %s hqx-filename\n", argv[0]);
403 exit(1);
404 }
405 filename = argv[1];
406
407 if((hqxdecoder = url_file_open(filename)) == NULL)
408 {
409 perror(argv[1]);
410 exit(1);
411 }
412
413 for(;;)
414 {
415 if(url_readline(hqxdecoder, buff, sizeof(buff)) == NULL)
416 {
417 fprintf(stderr, "%s: Not a hqx-file\n", filename);
418 url_close(hqxdecoder);
419 exit(1);
420 }
421 if((strncmp(buff, "(This file", 10) == 0) ||
422 (strncmp(buff, "(Convert with", 13) == 0))
423 break;
424 }
425
426 while((c = url_getc(hqxdecoder)) != EOF)
427 if(c == ':')
428 break;
429 if(c == EOF)
430 {
431 fprintf(stderr, "%s: Not a hqx-file\n", filename);
432 url_close(hqxdecoder);
433 exit(1);
434 }
435
436 hqxdecoder = url_hqxdecode_open(hqxdecoder, 0, 1);
437 #if HQXDECODE_MAIN
438 while((c = url_getc(hqxdecoder)) != EOF)
439 putchar(c);
440 #else
441 while((c = url_read(hqxdecoder, buff, sizeof(buff))) > 0)
442 write(1, buff, c);
443 #endif
444 url_close(hqxdecoder);
445 exit(0);
446 }
447
448 #endif /* HQXDECODE_MAIN */
449