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 #ifndef NO_STRING_H
25 #include <string.h>
26 #else
27 #include <strings.h>
28 #endif
29 #include <stdlib.h>
30 
31 #include "timidity.h"
32 #include "common.h"
33 #include "arc.h"
34 #include "strtab.h"
35 #include "zip.h"
36 #include "unlzh.h"
37 #include "explode.h"
38 
39 char *arc_lib_version = ARC_LIB_VERSION;
40 
41 #define GZIP_ASCIIFLAG		(1u<<0)
42 #define GZIP_MULTIPARTFLAG	(1u<<1)
43 #define GZIP_EXTRAFLAG		(1u<<2)
44 #define GZIP_FILEFLAG		(1u<<3)
45 #define GZIP_COMMFLAG		(1u<<4)
46 #define GZIP_ENCFLAG		(1u<<5)
47 
48 #ifndef TRUE
49 #define TRUE			1
50 #endif /* TRUE */
51 #ifndef FALSE
52 #define FALSE			0
53 #endif /* FALSE */
54 #define ABORT			-1
55 
56 ArchiveHandler arc_handler;
57 static MBlockList arc_buffer;
58 
59 typedef struct _ArchiveFileList
60 {
61     char *archive_name;
62     ArchiveEntryNode *entry_list;
63     struct _ArchiveFileList *next;
64 } ArchiveFileList;
65 static ArchiveFileList *arc_filelist = NULL;
66 
67 static struct
68 {
69     char *ext;
70     int type;
71 } archive_ext_list[] =
72 {
73     {".tar",	ARCHIVE_TAR},
74     {".tar.gz",	ARCHIVE_TGZ},
75     {".tgz",	ARCHIVE_TGZ},
76     {".zip",	ARCHIVE_ZIP},
77     {".neo",	ARCHIVE_ZIP},
78     {".lzh",	ARCHIVE_LZH},
79     {".lha",	ARCHIVE_LZH},
80     {".mime",	ARCHIVE_MIME},
81     {PATH_STRING, ARCHIVE_DIR},
82     {NULL, -1}
83 };
84 
skip_gzip_header(URL url)85 int skip_gzip_header(URL url)
86 {
87     unsigned char flags;
88     int m1, method;
89 
90     /* magic */
91     m1 = url_getc(url);
92     if(m1 == 0)
93     {
94 	url_skip(url, 128 - 1);
95 	m1 = url_getc(url);
96     }
97     if(m1 != 0x1f)
98 	return -1;
99     if(url_getc(url) != 0x8b)
100 	return -1;
101 
102     /* method */
103     method = url_getc(url);
104     switch(method)
105     {
106       case 8:			/* deflated */
107 	method = ARCHIVEC_DEFLATED;
108 	break;
109       default:
110 	return -1;
111     }
112     /* flags */
113     flags = url_getc(url);
114     if(flags & GZIP_ENCFLAG)
115 	return -1;
116     /* time */
117     url_getc(url); url_getc(url); url_getc(url); url_getc(url);
118 
119     url_getc(url);		/* extra flags */
120     url_getc(url);		/* OS type */
121 
122     if(flags & GZIP_MULTIPARTFLAG)
123     {
124 	/* part number */
125 	url_getc(url); url_getc(url);
126     }
127 
128     if(flags & GZIP_EXTRAFLAG)
129     {
130 	unsigned short len;
131 	int i;
132 
133 	/* extra field */
134 
135 	len = url_getc(url);
136 	len |= ((unsigned short)url_getc(url)) << 8;
137 	for(i = 0; i < len; i++)
138 	    url_getc(url);
139     }
140 
141     if(flags & GZIP_FILEFLAG)
142     {
143 	/* file name */
144 	int c;
145 
146 	do
147 	{
148 	    c = url_getc(url);
149 	    if(c == EOF)
150 		return -1;
151 	} while(c != '\0');
152     }
153 
154     if(flags & GZIP_COMMFLAG)
155     {
156 	/* comment */
157 	int c;
158 
159 	do
160 	{
161 	    c = url_getc(url);
162 	    if(c == EOF)
163 		return -1;
164 	} while(c != '\0');
165     }
166 
167     return method;
168 }
169 
parse_gzip_header_bytes(char * gz,long maxparse,int * hdrsiz)170 int parse_gzip_header_bytes(char *gz, long maxparse, int *hdrsiz)
171 {
172     URL url = url_mem_open(gz, maxparse, 0);
173     int method;
174 
175     if(!url)
176 	return -1;
177     method = skip_gzip_header(url);
178     *hdrsiz = url_tell(url);
179     url_close(url);
180     return method;
181 }
182 
183 void (* arc_error_handler)(char *error_message) = NULL;
184 
arc_cant_open(char * s)185 static void arc_cant_open(char *s)
186 {
187     if(arc_error_handler != NULL)
188     {
189 	char buff[BUFSIZ];
190 	snprintf(buff, sizeof(buff), "%s: Can't open", s);
191 	arc_error_handler(buff);
192     }
193 }
194 
get_archive_type(char * archive_name)195 int get_archive_type(char *archive_name)
196 {
197     int i, len;
198     char *p;
199     int archive_name_length, delim;
200 
201 #ifdef SUPPORT_SOCKET
202     int type = url_check_type(archive_name);
203     if(type == URL_news_t)
204 	return ARCHIVE_MIME;
205     if(type == URL_newsgroup_t)
206 	return ARCHIVE_NEWSGROUP;
207 #endif /* SUPPORT_SOCKET */
208 
209     if(strncmp(archive_name, "mail:", 5) == 0 ||
210        strncmp(archive_name, "mime:", 5) == 0)
211 	return ARCHIVE_MIME;
212 
213     if((p = strrchr(archive_name, '#')) != NULL)
214     {
215 	archive_name_length = p - archive_name;
216 	delim = '#';
217     }
218     else
219     {
220 	archive_name_length = strlen(archive_name);
221 	delim = '\0';
222     }
223 
224     for(i = 0; archive_ext_list[i].ext; i++)
225     {
226 	len = strlen(archive_ext_list[i].ext);
227 	if(len <= archive_name_length &&
228 	   strncasecmp(archive_name + archive_name_length - len,
229 		       archive_ext_list[i].ext, len) == 0 &&
230 	   archive_name[archive_name_length] == delim)
231 	    return archive_ext_list[i].type; /* Found */
232     }
233 
234     if(url_check_type(archive_name) == URL_dir_t)
235 	return ARCHIVE_DIR;
236 
237     return -1;			/* Not found */
238 }
239 
find_arc_filelist(char * basename)240 static ArchiveFileList *find_arc_filelist(char *basename)
241 {
242     ArchiveFileList *p;
243 
244     for(p = arc_filelist; p; p = p->next)
245     {
246 	if(strcmp(basename, p->archive_name) == 0)
247 	    return p;
248     }
249     return NULL;
250 }
251 
arc_parse_entry(URL url,int archive_type)252 ArchiveEntryNode *arc_parse_entry(URL url, int archive_type)
253 {
254     ArchiveEntryNode *entry_first, *entry_last, *entry;
255     ArchiveEntryNode *(* next_header_entry)(void);
256     int gzip_method;
257     URL orig;
258 
259     orig = NULL;
260     switch(archive_type)
261     {
262       case ARCHIVE_TAR:
263 	next_header_entry = next_tar_entry;
264 	break;
265       case ARCHIVE_TGZ:
266 	gzip_method = skip_gzip_header(url);
267 	if(gzip_method != ARCHIVEC_DEFLATED)
268 	{
269 	    url_close(url);
270 	    return NULL;
271 	}
272 	orig = url;
273 	if((url = url_inflate_open(orig, -1, 0)) == NULL)
274 	    return NULL;
275 	next_header_entry = next_tar_entry;
276 	break;
277       case ARCHIVE_ZIP:
278 	next_header_entry = next_zip_entry;
279 	break;
280       case ARCHIVE_LZH:
281 	next_header_entry = next_lzh_entry;
282 	break;
283       case ARCHIVE_MIME:
284 	if(!IS_URL_SEEK_SAFE(url))
285 	{
286 	    orig = url;
287 	    if((url = url_cache_open(orig, 0)) == NULL)
288 		return NULL;
289 	}
290 	next_header_entry = next_mime_entry;
291 	break;
292       default:
293 	return NULL;
294     }
295 
296     arc_handler.isfile = (url->type == URL_file_t);
297     arc_handler.url = url;
298     arc_handler.counter = 0;
299     entry_first = entry_last = NULL;
300     arc_handler.pos = 0;
301     while((entry = next_header_entry()) != NULL)
302     {
303 	if(entry_first != NULL)
304 	    entry_last->next = entry;
305 	else
306 	    entry_first = entry_last = entry;
307 	while(entry_last->next)
308 	    entry_last = entry_last->next;
309 	arc_handler.counter++;
310     }
311     url_close(url);
312     if(orig)
313 	url_close(orig);
314     return entry_first;		/* Note that NULL if no archive file */
315 }
316 
add_arc_filelist(char * basename,int archive_type)317 static ArchiveFileList *add_arc_filelist(char *basename, int archive_type)
318 {
319     URL url;
320     ArchiveFileList *afl;
321     ArchiveEntryNode *entry;
322 
323     switch(archive_type)
324     {
325       case ARCHIVE_TAR:
326       case ARCHIVE_TGZ:
327       case ARCHIVE_ZIP:
328       case ARCHIVE_LZH:
329       case ARCHIVE_MIME:
330 	break;
331       default:
332 	return NULL;
333     }
334 
335     if((url = url_open(basename)) == NULL)
336     {
337 	arc_cant_open(basename);
338 	return NULL;
339     }
340 
341     entry = arc_parse_entry(url, archive_type);
342 
343     afl = (ArchiveFileList *)safe_malloc(sizeof(ArchiveFileList));
344     afl->archive_name = safe_strdup(basename);
345     afl->entry_list = entry;
346     afl->next = arc_filelist;
347     arc_filelist = afl;
348     return afl;
349 }
350 
regist_archive(char * archive_filename)351 static ArchiveFileList *regist_archive(char *archive_filename)
352 {
353     int archive_type;
354 
355     if((archive_type = get_archive_type(archive_filename)) < 0)
356 	return NULL;		/* Unknown archive */
357     archive_filename = url_expand_home_dir(archive_filename);
358     if(find_arc_filelist(archive_filename))
359 	return NULL;		/* Already registerd */
360     return add_arc_filelist(archive_filename, archive_type);
361 }
362 
arc_expand_newfile(StringTable * s,ArchiveFileList * afl,char * pattern)363 static int arc_expand_newfile(StringTable *s, ArchiveFileList *afl,
364 			      char *pattern)
365 {
366     ArchiveEntryNode *entry;
367     char *p;
368 
369     for(entry = afl->entry_list; entry; entry = entry->next)
370     {
371 	if(arc_case_wildmat(entry->name, pattern))
372 	{
373 	    p = new_segment(&arc_buffer, strlen(afl->archive_name) +
374 			    strlen(entry->name) + 2);
375 	    strcpy(p, afl->archive_name);
376 	    strcat(p, "#");
377 	    strcat(p, entry->name);
378 	    if(put_string_table(s, p, strlen(p)) == NULL)
379 		return -1;
380 	}
381     }
382     return 0;
383 }
384 
expand_archive_names(int * nfiles_in_out,char ** files)385 char **expand_archive_names(int *nfiles_in_out, char **files)
386 {
387     int i, nfiles, arc_type;
388     char *infile_name;
389     char *base, *pattern, *p, buff[BUFSIZ];
390     char *one_file[1];
391     int one;
392     ArchiveFileList *afl;
393 
394     /* Recusive global */
395     static MBlockList *pool;
396     static StringTable stab;
397     static int error_flag = 0;
398     static int depth = 0;
399 
400     if(depth == 0)
401     {
402 	error_flag = 0;
403 	init_string_table(&stab);
404 	pool = &arc_buffer;
405     }
406 
407     nfiles = *nfiles_in_out;
408 
409     for(i = 0; i < nfiles; i++)
410     {
411 	infile_name = url_expand_home_dir(files[i]);
412 	if((p = strrchr(infile_name, '#')) == NULL)
413 	{
414 	    base = infile_name;
415 	    pattern = "*";
416 	}
417 	else
418 	{
419 	    int len = p - infile_name;
420 	    base = new_segment(pool, len + 1); /* +1 for '\0' */
421 	    memcpy(base, infile_name, len);
422 	    base[len] = '\0';
423 	    pattern = p + 1;
424 	}
425 
426 	if((afl = find_arc_filelist(base)) != NULL)
427 	{
428 	    if(arc_expand_newfile(&stab, afl, pattern) == -1)
429 		goto abort_expand;
430 	    continue;
431 	}
432 
433 	arc_type = get_archive_type(base);
434 	if(arc_type == -1)
435 	{
436 	    if(put_string_table(&stab, infile_name, strlen(infile_name))
437 	       == NULL)
438 		goto abort_expand;
439 	    continue;
440 	}
441 
442 #ifdef SUPPORT_SOCKET
443 	if(arc_type == ARCHIVE_NEWSGROUP)
444 	{
445 	    URL url;
446 	    int len1, len2;
447 	    char *news_prefix;
448 
449 	    if((url = url_newsgroup_open(base)) == NULL)
450 	    {
451 		arc_cant_open(base);
452 		continue;
453 	    }
454 
455 	    strncpy(buff, base, sizeof(buff)-1);
456 	    p = strchr(buff + 7, '/') + 1; /* news://..../ */
457 	    *p = '\0';
458 	    news_prefix = strdup_mblock(pool, buff);
459 	    len1 = strlen(news_prefix);
460 
461 	    while(url_gets(url, buff, sizeof(buff)))
462 	    {
463 		len2 = strlen(buff);
464 		p = (char *)new_segment(pool, len1 + len2 + 1);
465 		strcpy(p, news_prefix);
466 		strcpy(p + len1, buff);
467 		one_file[0] = p;
468 		one = 1;
469 		depth++;
470 		expand_archive_names(&one, one_file);
471 		depth--;
472 	    }
473 	    url_close(url);
474 	    if(error_flag)
475 		goto abort_expand;
476 	    continue;
477 	}
478 #endif /* SUPPORT_SOCKET */
479 
480 	if(arc_type == ARCHIVE_DIR)
481 	{
482 	    URL url;
483 	    int len1, len2;
484 
485 	    if((url = url_dir_open(base)) == NULL)
486 	    {
487 		arc_cant_open(base);
488 		continue;
489 	    }
490 
491 	    if(strncmp(base, "dir:", 4) == 0)
492 		base += 4;
493 	    len1 = strlen(base);
494 	    if(IS_PATH_SEP(base[len1 - 1]))
495 		len1--;
496 	    while(url_gets(url, buff, sizeof(buff)))
497 	    {
498 		if(strcmp(buff, ".") == 0 || strcmp(buff, "..") == 0)
499 		    continue;
500 
501 		len2 = strlen(buff);
502 		p = (char *)new_segment(pool, len1 + len2 + 2);
503 		strcpy(p, base);
504 		p[len1] = PATH_SEP;
505 		strcpy(p + len1 + 1, buff);
506 		one_file[0] = p;
507 		one = 1;
508 		depth++;
509 		expand_archive_names(&one, one_file);
510 		depth--;
511 	    }
512 	    url_close(url);
513 	    if(error_flag)
514 		goto abort_expand;
515 	    continue;
516 	}
517 
518 	if((afl = add_arc_filelist(base, arc_type)) != NULL)
519 	{
520 	    if(arc_expand_newfile(&stab, afl, pattern) == -1)
521 		goto abort_expand;
522 	}
523     }
524 
525     if(depth)
526 	return NULL;
527     *nfiles_in_out = stab.nstring;
528     reuse_mblock(pool);
529     return make_string_array(&stab); /* It is possible NULL */
530 
531   abort_expand:
532     error_flag = 1;
533     if(depth)
534 	return NULL;
535     delete_string_table(&stab);
536     free_global_mblock();
537     *nfiles_in_out = 0;
538     return NULL;
539 }
540 
new_entry_node(char * name,int len)541 ArchiveEntryNode *new_entry_node(char *name, int len)
542 {
543     ArchiveEntryNode *entry;
544     entry = (ArchiveEntryNode *)safe_malloc(sizeof(ArchiveEntryNode));
545     memset(entry, 0, sizeof(ArchiveEntryNode));
546     entry->name = (char *)safe_malloc(len + 1);
547     memcpy(entry->name, name, len);
548     entry->name[len] = '\0';
549     return entry;
550 }
551 
free_entry_node(ArchiveEntryNode * entry)552 void free_entry_node(ArchiveEntryNode *entry)
553 {
554     free(entry->name);
555     if(entry->cache != NULL)
556 	free(entry->cache);
557     free(entry);
558 }
559 
560 
561 static char *compress_buff;
562 long   compress_buff_len;
arc_compress_func(char * buff,long size,void * user_val)563 static long arc_compress_func(char *buff, long size, void *user_val)
564 {
565     if(compress_buff_len <= 0)
566 	return 0;
567     if(size > compress_buff_len)
568 	size = compress_buff_len;
569     memcpy(buff, compress_buff, size);
570     compress_buff += size;
571     compress_buff_len -= size;
572     return size;
573 }
574 
arc_compress(void * buff,long bufsiz,int compress_level,long * compressed_size)575 void *arc_compress(void *buff, long bufsiz,
576 		   int compress_level, long *compressed_size)
577 {
578     DeflateHandler compressor;
579     long allocated, offset, space, nbytes;
580     char *compressed;
581 
582     compress_buff = (char *)buff;
583     compress_buff_len = bufsiz;
584     compressor = open_deflate_handler(arc_compress_func, NULL,
585 				      compress_level);
586     allocated = 1024;
587     compressed = (char *)safe_malloc(allocated);
588     offset = 0;
589     space = allocated;
590     while((nbytes = zip_deflate(compressor, compressed + offset, space)) > 0)
591     {
592 	offset += nbytes;
593 	space -= nbytes;
594 	if(space == 0)
595 	{
596 	    space = allocated;
597 	    allocated += space;
598 	    compressed = (char *)safe_realloc(compressed, allocated);
599 	}
600     }
601     close_deflate_handler(compressor);
602     if(offset == 0)
603     {
604 	free(buff);
605 	return NULL;
606     }
607     *compressed_size = offset;
608     return compressed;
609 }
610 
arc_decompress(void * buff,long bufsiz,long * decompressed_size)611 void *arc_decompress(void *buff, long bufsiz, long *decompressed_size)
612 {
613     InflateHandler decompressor;
614     long allocated, offset, space, nbytes;
615     char *decompressed;
616 
617     compress_buff = (char *)buff;
618     compress_buff_len = bufsiz;
619     decompressor = open_inflate_handler(arc_compress_func, NULL);
620     allocated = 1024;
621     decompressed = (char *)safe_malloc(allocated);
622     offset = 0;
623     space = allocated;
624     while((nbytes = zip_inflate(decompressor, decompressed + offset, space)) > 0)
625     {
626 	offset += nbytes;
627 	space -= nbytes;
628 	if(space == 0)
629 	{
630 	    space = allocated;
631 	    allocated += space;
632 	    decompressed = (char *)safe_realloc(decompressed, allocated);
633 	}
634     }
635     close_inflate_handler(decompressor);
636     if(offset == 0)
637     {
638 	free(buff);
639 	return NULL;
640     }
641     *decompressed_size = offset;
642     return decompressed;
643 }
644 
free_archive_files(void)645 void free_archive_files(void)
646 {
647     ArchiveEntryNode *entry, *ecur;
648     ArchiveFileList *acur;
649 
650     while(arc_filelist)
651     {
652 	acur = arc_filelist;
653 	arc_filelist = arc_filelist->next;
654 	entry = acur->entry_list;
655 	while(entry)
656 	{
657 	    ecur = entry;
658 	    entry = entry->next;
659 	    free_entry_node(ecur);
660 	}
661 	free(acur->archive_name);
662 	free(acur);
663     }
664 }
665 
666 /******************************************************************************
667 * url_arc
668 *****************************************************************************/
669 typedef struct _URL_arc
670 {
671     char common[sizeof(struct _URL)];
672     URL instream;
673     long pos, size;
674     int comptype;
675     void *decoder;
676 } URL_arc;
677 
678 static long url_arc_read(URL url, void *buff, long n);
679 static long url_arc_tell(URL url);
680 static void url_arc_close(URL url);
681 
archiver_read_func(char * buff,long buff_size,void * v)682 static long archiver_read_func(char *buff, long buff_size, void *v)
683 {
684     URL_arc *url;
685     long n;
686 
687     url = (URL_arc *)v;
688 
689     if(url->size < 0)
690 	n = buff_size;
691     else
692     {
693 	n = url->size - url->pos;
694 	if(n > buff_size)
695 	    n = buff_size;
696     }
697 
698     if(n <= 0)
699 	return 0;
700     n = url_read(url->instream, buff, n);
701     if(n <= 0)
702 	return n;
703 
704     return n;
705 }
706 
url_arc_open(char * name)707 URL url_arc_open(char *name)
708 {
709     URL_arc *url;
710     char *base, *p;
711     int len;
712     ArchiveFileList *afl;
713     ArchiveEntryNode *entry;
714     URL instream;
715 
716     if((p = strrchr(name, '#')) == NULL)
717 	return NULL;
718     len = p - name;
719     base = new_segment(&arc_buffer, len + 1);
720     memcpy(base, name, len);
721     base[len] = '\0';
722     base = url_expand_home_dir(base);
723 
724     if((afl = find_arc_filelist(base)) == NULL)
725 	afl = regist_archive(base);
726 	reuse_mblock(&arc_buffer);	/* free `base' */
727     if(afl == NULL)
728 	return NULL;
729     name += len + 1;
730 
731     /* skip path separators right after '#' */
732     for(;;)
733     {
734 	if (*name != PATH_SEP
735 		#if PATH_SEP != '/'	/* slash is always processed */
736 			&& *name != '/'
737 		#endif
738 		#if defined(PATH_SEP2) && (PATH_SEP2 != '/')
739 			&& *name != PATH_SEP2
740 		#endif
741 		)
742 		break;
743 	name++;
744     }
745 
746     for(entry = afl->entry_list; entry; entry = entry->next)
747     {
748 	if(strcasecmp(entry->name, name) == 0)
749 	    break;
750     }
751     if(entry == NULL)
752 	return NULL;
753 
754     if(entry->cache != NULL)
755 	instream = url_mem_open((char *)entry->cache + entry->start,
756 				entry->compsize, 0);
757     else
758     {
759 	if((instream = url_file_open(base)) == NULL)
760 	    return NULL;
761 	url_seek(instream, entry->start, 0);
762     }
763 
764     url = (URL_arc *)alloc_url(sizeof(URL_arc));
765     if(url == NULL)
766     {
767 	url_errno = errno;
768 	return NULL;
769     }
770 
771     /* open decoder */
772     switch(entry->comptype)
773     {
774       case ARCHIVEC_STORED:	/* No compression */
775       case ARCHIVEC_LZHED_LH0:	/* -lh0- */
776       case ARCHIVEC_LZHED_LZ4:	/* -lz4- */
777 	url->decoder = NULL;
778 
779       case ARCHIVEC_DEFLATED:	/* deflate */
780 	url->decoder =
781 	    (void *)open_inflate_handler(archiver_read_func, url);
782 	if(url->decoder == NULL)
783 	{
784 	    url_arc_close((URL)url);
785 	    return NULL;
786 	}
787 	break;
788 
789       case ARCHIVEC_IMPLODED_LIT8:
790       case ARCHIVEC_IMPLODED_LIT4:
791       case ARCHIVEC_IMPLODED_NOLIT8:
792       case ARCHIVEC_IMPLODED_NOLIT4:
793 	url->decoder =
794 	    (void *)open_explode_handler(archiver_read_func,
795 					 entry->comptype - ARCHIVEC_IMPLODED - 1,
796 					 entry->compsize, entry->origsize, url);
797 	if(url->decoder == NULL)
798 	{
799 	    url_arc_close((URL)url);
800 	    return NULL;
801 	}
802 	break;
803 
804       case ARCHIVEC_LZHED_LH1:	/* -lh1- */
805       case ARCHIVEC_LZHED_LH2:	/* -lh2- */
806       case ARCHIVEC_LZHED_LH3:	/* -lh3- */
807       case ARCHIVEC_LZHED_LH4:	/* -lh4- */
808       case ARCHIVEC_LZHED_LH5:	/* -lh5- */
809       case ARCHIVEC_LZHED_LZS:	/* -lzs- */
810       case ARCHIVEC_LZHED_LZ5:	/* -lz5- */
811       case ARCHIVEC_LZHED_LHD:	/* -lhd- */
812       case ARCHIVEC_LZHED_LH6:	/* -lh6- */
813       case ARCHIVEC_LZHED_LH7:	/* -lh7- */
814 	url->decoder =
815 	    (void *)open_unlzh_handler(
816 				       archiver_read_func,
817 				       lzh_methods[entry->comptype - ARCHIVEC_LZHED - 1],
818 				       entry->compsize, entry->origsize, url);
819 	if(url->decoder == NULL)
820 	{
821 	    url_arc_close((URL)url);
822 	    return NULL;
823 	}
824 	break;
825       default:
826 	url_arc_close((URL)url);
827 	return NULL;
828     }
829 
830 
831     /* common members */
832     URLm(url, type)      = URL_arc_t;
833     URLm(url, url_read)  = url_arc_read;
834     URLm(url, url_gets)  = NULL;
835     URLm(url, url_fgetc) = NULL;
836     URLm(url, url_seek)  = NULL;
837     URLm(url, url_tell)  = url_arc_tell;
838     URLm(url, url_close) = url_arc_close;
839 
840     /* private members */
841     url->instream = instream;
842     url->pos = 0;
843     url->size = entry->origsize;
844     url->comptype = entry->comptype;
845     return (URL)url;
846 }
847 
url_arc_read(URL url,void * vp,long bufsiz)848 static long url_arc_read(URL url, void *vp, long bufsiz)
849 {
850     URL_arc *urlp = (URL_arc *)url;
851     long n = 0;
852     int comptype;
853     void *decoder;
854     char *buff = (char *)vp;
855 
856     if(urlp->pos == -1)
857 	return 0;
858 
859     comptype = urlp->comptype;
860     decoder = urlp->decoder;
861     switch(comptype)
862     {
863       case ARCHIVEC_STORED:
864       case ARCHIVEC_LZHED_LH0:	/* -lh0- */
865       case ARCHIVEC_LZHED_LZ4:	/* -lz4- */
866 	n = archiver_read_func(buff, bufsiz, (void *)urlp);
867 	break;
868 
869       case ARCHIVEC_DEFLATED:
870 	n = zip_inflate((InflateHandler)decoder, buff, bufsiz);
871 	break;
872 
873       case ARCHIVEC_IMPLODED_LIT8:
874       case ARCHIVEC_IMPLODED_LIT4:
875       case ARCHIVEC_IMPLODED_NOLIT8:
876       case ARCHIVEC_IMPLODED_NOLIT4:
877 	n = explode((ExplodeHandler)decoder, buff, bufsiz);
878 	break;
879 
880       case ARCHIVEC_LZHED_LH1:	/* -lh1- */
881       case ARCHIVEC_LZHED_LH2:	/* -lh2- */
882       case ARCHIVEC_LZHED_LH3:	/* -lh3- */
883       case ARCHIVEC_LZHED_LH4:	/* -lh4- */
884       case ARCHIVEC_LZHED_LH5:	/* -lh5- */
885       case ARCHIVEC_LZHED_LZS:	/* -lzs- */
886       case ARCHIVEC_LZHED_LZ5:	/* -lz5- */
887       case ARCHIVEC_LZHED_LHD:	/* -lhd- */
888       case ARCHIVEC_LZHED_LH6:	/* -lh6- */
889       case ARCHIVEC_LZHED_LH7:	/* -lh7- */
890 	n = unlzh((UNLZHHandler)decoder, buff, bufsiz);
891 	break;
892 
893       case ARCHIVEC_UU:		/* uu encoded */
894       case ARCHIVEC_B64:	/* base64 encoded */
895       case ARCHIVEC_QS:		/* quoted string encoded */
896       case ARCHIVEC_HQX:	/* HQX encoded */
897 	n = url_read((URL)decoder, buff, bufsiz);
898 	break;
899     }
900 
901     if(n > 0)
902 	urlp->pos += n;
903     return n;
904 }
905 
url_arc_tell(URL url)906 static long url_arc_tell(URL url)
907 {
908     return ((URL_arc *)url)->pos;
909 }
910 
url_arc_close(URL url)911 static void url_arc_close(URL url)
912 {
913     URL_arc *urlp = (URL_arc *)url;
914     void *decoder;
915     int save_errno = errno;
916 
917     /* 1. close decoder
918 	* 2. close decode_stream
919 	    * 3. free url
920 		*/
921 
922     decoder = urlp->decoder;
923     if(decoder != NULL)
924     {
925 	switch(urlp->comptype)
926 	{
927 	  case ARCHIVEC_DEFLATED:
928 	    close_inflate_handler((InflateHandler)decoder);
929 	    break;
930 
931 	  case ARCHIVEC_IMPLODED_LIT8:
932 	  case ARCHIVEC_IMPLODED_LIT4:
933 	  case ARCHIVEC_IMPLODED_NOLIT8:
934 	  case ARCHIVEC_IMPLODED_NOLIT4:
935 	    close_explode_handler((ExplodeHandler)decoder);
936 	    break;
937 
938 	  case ARCHIVEC_LZHED_LH1: /* -lh1- */
939 	  case ARCHIVEC_LZHED_LH2: /* -lh2- */
940 	  case ARCHIVEC_LZHED_LH3: /* -lh3- */
941 	  case ARCHIVEC_LZHED_LH4: /* -lh4- */
942 	  case ARCHIVEC_LZHED_LH5: /* -lh5- */
943 	  case ARCHIVEC_LZHED_LZS: /* -lzs- */
944 	  case ARCHIVEC_LZHED_LZ5: /* -lz5- */
945 	  case ARCHIVEC_LZHED_LHD: /* -lhd- */
946 	  case ARCHIVEC_LZHED_LH6: /* -lh6- */
947 	  case ARCHIVEC_LZHED_LH7: /* -lh7- */
948 	    close_unlzh_handler((UNLZHHandler)decoder);
949 	    break;
950 
951 	  case ARCHIVEC_UU:	/* uu encoded */
952 	  case ARCHIVEC_B64:	/* base64 encoded */
953 	  case ARCHIVEC_QS:	/* quoted string encoded */
954 	  case ARCHIVEC_HQX:	/* HQX encoded */
955 	    url_close((URL)decoder);
956 	    break;
957 	}
958     }
959 
960     if(urlp->instream != NULL)
961 	url_close(urlp->instream);
962     free(urlp);
963     errno = save_errno;
964 }
965 
966 
967 
968 /************** wildmat ***************/
969 /* What character marks an inverted character class? */
970 #define NEGATE_CLASS		'!'
971 
972 /* Is "*" a common pattern? */
973 #define OPTIMIZE_JUST_STAR
974 
975 /* Do tar(1) matching rules, which ignore a trailing slash? */
976 #undef MATCH_TAR_PATTERN
977 
978 /* Define if case is ignored */
979 #define MATCH_CASE_IGNORE
980 
981 #include <ctype.h>
982 #define TEXT_CASE_CHAR(c) (toupper(c))
983 #define CHAR_CASE_COMP(a, b) (TEXT_CASE_CHAR(a) == TEXT_CASE_CHAR(b))
984 
ParseHex(char * p,int * val)985 static char *ParseHex(char *p, int *val)
986 {
987     int i, v;
988 
989     *val = 0;
990     for(i = 0; i < 2; i++)
991     {
992 	v = *p++;
993 	if('0' <= v && v <= '9')
994 	    v = v - '0';
995 	else if('A' <= v && v <= 'F')
996 	    v = v - 'A' + 10;
997 	else if('a' <= v && v <= 'f')
998 	    v = v - 'a' + 10;
999 	else
1000 	    return NULL;
1001 	*val = (*val << 4 | v);
1002     }
1003     return p;
1004 }
1005 
1006 /*
1007  *  Match text and p, return TRUE, FALSE, or ABORT.
1008  */
DoMatch(char * text,char * p)1009 static int DoMatch(char *text, char *p)
1010 {
1011     register int	last;
1012     register int	matched;
1013     register int	reverse;
1014 
1015     for ( ; *p; text++, p++) {
1016 	if (*text == '\0' && *p != '*')
1017 	    return ABORT;
1018 	switch (*p) {
1019 	case '\\':
1020 	    p++;
1021 	    if(*p == 'x')
1022 	    {
1023 		int c;
1024 		if((p = ParseHex(++p, &c)) == NULL)
1025 		    return ABORT;
1026 		if(*text != c)
1027 		    return FALSE;
1028 		continue;
1029 	    }
1030 	    /* Literal match with following character. */
1031 
1032 	    /* FALLTHROUGH */
1033 	default:
1034 	    if (*text != *p)
1035 		return FALSE;
1036 	    continue;
1037 	case '?':
1038 	    /* Match anything. */
1039 	    continue;
1040 	case '*':
1041 	    while (*++p == '*')
1042 		/* Consecutive stars act just like one. */
1043 		continue;
1044 	    if (*p == '\0')
1045 		/* Trailing star matches everything. */
1046 		return TRUE;
1047 	    while (*text)
1048 		if ((matched = DoMatch(text++, p)) != FALSE)
1049 		    return matched;
1050 	    return ABORT;
1051 	case '[':
1052 	    reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
1053 	    if (reverse)
1054 		/* Inverted character class. */
1055 		p++;
1056 	    matched = FALSE;
1057 	    if (p[1] == ']' || p[1] == '-')
1058 		if (*++p == *text)
1059 		    matched = TRUE;
1060 	    for (last = *p; *++p && *p != ']'; last = *p)
1061 		/* This next line requires a good C compiler. */
1062 		if (*p == '-' && p[1] != ']'
1063 		    ? *text <= *++p && *text >= last : *text == *p)
1064 		    matched = TRUE;
1065 	    if (matched == reverse)
1066 		return FALSE;
1067 	    continue;
1068 	}
1069     }
1070 
1071 #ifdef	MATCH_TAR_PATTERN
1072     if (*text == '/')
1073 	return TRUE;
1074 #endif	/* MATCH_TAR_ATTERN */
1075     return *text == '\0';
1076 }
1077 
DoCaseMatch(char * text,char * p)1078 static int DoCaseMatch(char *text, char *p)
1079 {
1080     register int	last;
1081     register int	matched;
1082     register int	reverse;
1083 
1084     for(; *p; text++, p++)
1085     {
1086 	if(*text == '\0' && *p != '*')
1087 	    return ABORT;
1088 	switch (*p)
1089 	{
1090 	  case '\\':
1091 	    p++;
1092 	    if(*p == 'x')
1093 	    {
1094 		int c;
1095 		if((p = ParseHex(++p, &c)) == NULL)
1096 		    return ABORT;
1097 		if(!CHAR_CASE_COMP(*text, c))
1098 		    return FALSE;
1099 		continue;
1100 	    }
1101 	    /* Literal match with following character. */
1102 
1103 	    /* FALLTHROUGH */
1104 	  default:
1105 	    if(!CHAR_CASE_COMP(*text, *p))
1106 		return FALSE;
1107 	    continue;
1108 	  case '?':
1109 	    /* Match anything. */
1110 	    continue;
1111 	  case '*':
1112 	    while(*++p == '*')
1113 		/* Consecutive stars act just like one. */
1114 		continue;
1115 	    if(*p == '\0')
1116 		/* Trailing star matches everything. */
1117 		return TRUE;
1118 	    while(*text)
1119 		if((matched = DoCaseMatch(text++, p)) != FALSE)
1120 		    return matched;
1121 	    return ABORT;
1122 	case '[':
1123 	    reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
1124 	    if(reverse)
1125 		/* Inverted character class. */
1126 		p++;
1127 	    matched = FALSE;
1128 	    if(p[1] == ']' || p[1] == '-')
1129 	    {
1130 		if(*++p == *text)
1131 		    matched = TRUE;
1132 	    }
1133 	    for(last = TEXT_CASE_CHAR(*p); *++p && *p != ']';
1134 		last = TEXT_CASE_CHAR(*p))
1135 	    {
1136 		/* This next line requires a good C compiler. */
1137 		if(*p == '-' && p[1] != ']')
1138 		{
1139 		    p++;
1140 		    if(TEXT_CASE_CHAR(*text) <= TEXT_CASE_CHAR(*p) &&
1141 		       TEXT_CASE_CHAR(*text) >= last)
1142 			matched = TRUE;
1143 		}
1144 		else
1145 		{
1146 		    if(CHAR_CASE_COMP(*text, *p))
1147 			matched = TRUE;
1148 		}
1149 	    }
1150 	    if(matched == reverse)
1151 		return FALSE;
1152 	    continue;
1153 	}
1154     }
1155 
1156 #ifdef	MATCH_TAR_PATTERN
1157     if (*text == '/')
1158 	return TRUE;
1159 #endif	/* MATCH_TAR_ATTERN */
1160     return *text == '\0';
1161 }
1162 
1163 /*
1164 **  User-level routine.  Returns TRUE or FALSE.
1165 */
arc_wildmat(char * text,char * p)1166 int arc_wildmat(char *text, char *p)
1167 {
1168 #ifdef	OPTIMIZE_JUST_STAR
1169     if (p[0] == '*' && p[1] == '\0')
1170 	return TRUE;
1171 #endif /* OPTIMIZE_JUST_STAR */
1172     return DoMatch(text, p) == TRUE;
1173 }
1174 
arc_case_wildmat(char * text,char * p)1175 int arc_case_wildmat(char *text, char *p)
1176 {
1177 #ifdef	OPTIMIZE_JUST_STAR
1178     if (p[0] == '*' && p[1] == '\0')
1179 	return TRUE;
1180 #endif /* OPTIMIZE_JUST_STAR */
1181     return DoCaseMatch(text, p) == TRUE;
1182 }
1183