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