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 
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 
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,
name_file_check(char * s)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 
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;
try_mmap(char * path,long * size)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 
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 
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);
w32_mmap(char * fname,long * size_ret,HANDLE * hFilePtr,HANDLE * hMapPtr)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) */
w32_munmap(void * ptr,long size,HANDLE hFile,HANDLE hMap)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 
url_file_open(char * fname)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 
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;
url_file_read(URL url,void * buff,long n)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;
url_file_gets(URL url,char * buff,int n)346 	urlp->restlen -= i;
347     }
348 
349     return n;
350 }
351 
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 
380 static long url_hqxdecode_tell(URL url)
url_file_fgetc(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 
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
url_file_close(URL url)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