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