OSDN Git Service

should treat "-ab" as "-a -b" for shortopts="-a[0123]b".
[lha/lha.git] / src / header.c
1 /* ------------------------------------------------------------------------ */
2 /* LHa for UNIX                                                             */
3 /*              header.c -- header manipulate functions                     */
4 /*                                                                          */
5 /*      Modified                Nobutaka Watazaki                           */
6 /*                                                                          */
7 /*  Original                                                Y.Tagawa        */
8 /*  modified                                    1991.12.16  M.Oki           */
9 /*  Ver. 1.10  Symbolic Link added              1993.10.01  N.Watazaki      */
10 /*  Ver. 1.13b Symbolic Link Bug Fix            1994.08.22  N.Watazaki      */
11 /*  Ver. 1.14  Source All chagned               1995.01.14  N.Watazaki      */
12 /*  Ver. 1.14i bug fixed                        2000.10.06  t.okamoto       */
13 /*  Ver. 1.14i Contributed UTF-8 convertion for Mac OS X                    */
14 /*                                              2002.06.29  Hiroto Sakai    */
15 /*  Ver. 1.14i autoconfiscated & rewritten      2003.02.23  Koji Arai       */
16 /* ------------------------------------------------------------------------ */
17 #include "lha.h"
18
19 #define DUMP_HEADER 1           /* for debugging */
20
21 #if !STRCHR_8BIT_CLEAN
22 /* should use 8 bit clean version */
23 #undef strchr
24 #undef strrchr
25 #define strchr  xstrchr
26 #define strrchr  xstrrchr
27 #endif
28
29 static char    *get_ptr;
30 #define GET_BYTE()      (*get_ptr++ & 0xff)
31
32 #if DUMP_HEADER
33 static char    *start_ptr;
34 #define setup_get(PTR)  (start_ptr = get_ptr = (PTR))
35 #define get_byte()      dump_get_byte()
36 #define skip_bytes(len) dump_skip_bytes(len)
37 #else
38 #define setup_get(PTR)  (get_ptr = (PTR))
39 #define get_byte()      GET_BYTE()
40 #define skip_bytes(len) (get_ptr += (len))
41 #endif
42 #define put_ptr         get_ptr
43 #define setup_put(PTR)  (put_ptr = (PTR))
44 #define put_byte(c)     (*put_ptr++ = (char)(c))
45
46 int optional_archive_kanji_code = NONE;
47 int optional_system_kanji_code = NONE;
48 char *optional_archive_delim = NULL;
49 char *optional_system_delim = NULL;
50 int optional_filename_case = NONE;
51
52 #ifdef MULTIBYTE_FILENAME
53 int default_system_kanji_code = MULTIBYTE_FILENAME;
54 #else
55 int default_system_kanji_code = NONE;
56 #endif
57
58 int
59 calc_sum(p, len)
60     void *p;
61     int len;
62 {
63     int sum = 0;
64
65     while (len--) sum += *(unsigned char*)p++;
66
67     return sum & 0xff;
68 }
69
70 #if DUMP_HEADER
71 static int
72 dump_get_byte()
73 {
74     int c;
75
76     if (verbose_listing && verbose > 1)
77         printf("%02d %2d: ", get_ptr - start_ptr, 1);
78     c = GET_BYTE();
79     if (verbose_listing && verbose > 1) {
80         if (isprint(c))
81             printf("%d(0x%02x) '%c'\n", c, c, c);
82         else
83             printf("%d(0x%02x)\n", c, c);
84     }
85     return c;
86 }
87
88 static void
89 dump_skip_bytes(len)
90     int len;
91 {
92     if (len == 0) return;
93     if (verbose_listing && verbose > 1) {
94         printf("%02d %2d: ", get_ptr - start_ptr, len);
95         while (len--)
96             printf("0x%02x ", GET_BYTE());
97         printf("... ignored\n");
98     }
99     else
100         get_ptr += len;
101 }
102 #endif
103
104 static int
105 get_word()
106 {
107     int b0, b1;
108     int w;
109
110 #if DUMP_HEADER
111     if (verbose_listing && verbose > 1)
112         printf("%02d %2d: ", get_ptr - start_ptr, 2);
113 #endif
114     b0 = GET_BYTE();
115     b1 = GET_BYTE();
116     w = (b1 << 8) + b0;
117 #if DUMP_HEADER
118     if (verbose_listing && verbose > 1)
119         printf("%d(0x%04x)\n", w, w);
120 #endif
121     return w;
122 }
123
124 static void
125 put_word(v)
126     unsigned int    v;
127 {
128     put_byte(v);
129     put_byte(v >> 8);
130 }
131
132 static long
133 get_longword()
134 {
135     long b0, b1, b2, b3;
136     long l;
137
138 #if DUMP_HEADER
139     if (verbose_listing && verbose > 1)
140         printf("%02d %2d: ", get_ptr - start_ptr, 4);
141 #endif
142     b0 = GET_BYTE();
143     b1 = GET_BYTE();
144     b2 = GET_BYTE();
145     b3 = GET_BYTE();
146     l = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
147 #if DUMP_HEADER
148     if (verbose_listing && verbose > 1)
149         printf("%ld(0x%08lx)\n", l, l);
150 #endif
151     return l;
152 }
153
154 static void
155 put_longword(long v)
156 {
157     put_byte(v);
158     put_byte(v >> 8);
159     put_byte(v >> 16);
160     put_byte(v >> 24);
161 }
162
163 #ifdef HAVE_UINT64_T
164 static uint64_t
165 get_longlongword()
166 {
167     uint64_t b0, b1, b2, b3, b4, b5, b6, b7;
168     uint64_t l;
169
170 #if DUMP_HEADER
171     if (verbose_listing && verbose > 1)
172         printf("%02d %2d: ", get_ptr - start_ptr, 4);
173 #endif
174     b0 = GET_BYTE();
175     b1 = GET_BYTE();
176     b2 = GET_BYTE();
177     b3 = GET_BYTE();
178     b4 = GET_BYTE();
179     b5 = GET_BYTE();
180     b6 = GET_BYTE();
181     b7 = GET_BYTE();
182
183     l = (b7 << 24) + (b6 << 16) + (b5 << 8) + b4;
184     l <<= 32;
185     l |= (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
186 #if DUMP_HEADER
187     if (verbose_listing && verbose > 1)
188         printf("%lld(%#016llx)\n", l, l);
189 #endif
190     return l;
191 }
192
193 static void
194 put_longlongword(uint64_t v)
195 {
196     put_byte(v);
197     put_byte(v >> 8);
198     put_byte(v >> 16);
199     put_byte(v >> 24);
200     put_byte(v >> 32);
201     put_byte(v >> 40);
202     put_byte(v >> 48);
203     put_byte(v >> 56);
204 }
205 #endif
206
207 static int
208 get_bytes(buf, len, size)
209     char *buf;
210     int len, size;
211 {
212     int i;
213
214 #if DUMP_HEADER
215     if (verbose_listing && verbose > 1)
216         printf("%02d %2d: \"", get_ptr - start_ptr, len);
217
218     for (i = 0; i < len; i++) {
219         if (i < size) buf[i] = get_ptr[i];
220
221         if (verbose_listing && verbose > 1) {
222             if (isprint(buf[i]))
223                 printf("%c", buf[i]);
224             else
225                 printf("\\x%02x", (unsigned char)buf[i]);
226         }
227     }
228
229     if (verbose_listing && verbose > 1)
230         printf("\"\n");
231 #else
232     for (i = 0; i < len && i < size; i++)
233         buf[i] = get_ptr[i];
234 #endif
235
236     get_ptr += len;
237     return i;
238 }
239
240 static void
241 put_bytes(buf, len)
242     char *buf;
243     int len;
244 {
245     int i;
246     for (i = 0; i < len; i++)
247         put_byte(buf[i]);
248 }
249
250 /* added by Koji Arai */
251 void
252 convert_filename(name, len, size,
253                  from_code, to_code,
254                  from_delim, to_delim,
255                  case_to)
256     char *name;
257     int len;                    /* length of name */
258     int size;                   /* size of name buffer */
259     int from_code, to_code, case_to;
260     char *from_delim, *to_delim;
261
262 {
263     int i;
264 #ifdef MULTIBYTE_FILENAME
265     char tmp[FILENAME_LENGTH];
266     int to_code_save = NONE;
267
268     if (from_code == CODE_CAP) {
269         len = cap_to_sjis(tmp, name, sizeof(tmp));
270         strncpy(name, tmp, size);
271         name[size-1] = 0;
272         len = strlen(name);
273         from_code = CODE_SJIS;
274     }
275
276     if (to_code == CODE_CAP) {
277         to_code_save = CODE_CAP;
278         to_code = CODE_SJIS;
279     }
280
281     if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
282         for (i = 0; i < len; i++)
283             /* FIXME: provisionally fix for the Mac OS CoreFoundation */
284             if ((unsigned char)name[i] == LHA_PATHSEP)  name[i] = '/';
285         sjis_to_utf8(tmp, name, sizeof(tmp));
286         strncpy(name, tmp, size);
287         name[size-1] = 0;
288         len = strlen(name);
289         for (i = 0; i < len; i++)
290             if (name[i] == '/')  name[i] = LHA_PATHSEP;
291         from_code = CODE_UTF8;
292     }
293     else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
294         for (i = 0; i < len; i++)
295             /* FIXME: provisionally fix for the Mac OS CoreFoundation */
296             if ((unsigned char)name[i] == LHA_PATHSEP)  name[i] = '/';
297         utf8_to_sjis(tmp, name, sizeof(tmp));
298         strncpy(name, tmp, size);
299         name[size-1] = 0;
300         len = strlen(name);
301         for (i = 0; i < len; i++)
302             if (name[i] == '/')  name[i] = LHA_PATHSEP;
303         from_code = CODE_SJIS;
304     }
305 #endif
306
307     /* special case: if `name' has small lettter, not convert case. */
308     if (from_code == CODE_SJIS && case_to == TO_LOWER) {
309         for (i = 0; i < len; i++) {
310 #ifdef MULTIBYTE_FILENAME
311             if (SJIS_FIRST_P(name[i]) && SJIS_SECOND_P(name[i+1]))
312                 i++;
313             else
314 #endif
315             if (islower(name[i])) {
316                 case_to = NONE;
317                 break;
318             }
319         }
320     }
321
322     for (i = 0; i < len; i ++) {
323 #ifdef MULTIBYTE_FILENAME
324         if (from_code == CODE_EUC &&
325             (unsigned char)name[i] == 0x8e) {
326             if (to_code != CODE_SJIS) {
327                 i++;
328                 continue;
329             }
330
331             /* X0201 KANA */
332             memmove(name + i, name + i + 1, len - i);
333             len--;
334             continue;
335         }
336         if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
337             if (to_code != CODE_EUC) {
338                 continue;
339             }
340
341             if (len == size - 1) /* check overflow */
342                 len--;
343             memmove(name+i+1, name+i, len-i);
344             name[i] = 0x8e;
345             i++;
346             len++;
347             continue;
348         }
349         if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
350             int c1, c2;
351             if (to_code != CODE_SJIS) {
352                 i++;
353                 continue;
354             }
355
356             c1 = (unsigned char)name[i];
357             c2 = (unsigned char)name[i+1];
358             euc2sjis(&c1, &c2);
359             name[i] = c1;
360             name[i+1] = c2;
361             i++;
362             continue;
363         }
364         if (from_code == CODE_SJIS &&
365             SJIS_FIRST_P(name[i]) &&
366             SJIS_SECOND_P(name[i+1])) {
367             int c1, c2;
368
369             if (to_code != CODE_EUC) {
370                 i++;
371                 continue;
372             }
373
374             c1 = (unsigned char)name[i];
375             c2 = (unsigned char)name[i+1];
376             sjis2euc(&c1, &c2);
377             name[i] = c1;
378             name[i+1] = c2;
379             i++;
380             continue;
381         }
382 #endif /* MULTIBYTE_FILENAME */
383         {
384             char *ptr;
385
386             /* transpose from_delim to to_delim */
387
388             if ((ptr = strchr(from_delim, name[i])) != NULL) {
389                 name[i] = to_delim[ptr - from_delim];
390                 continue;
391             }
392         }
393
394         if (case_to == TO_UPPER && islower(name[i])) {
395             name[i] = toupper(name[i]);
396             continue;
397         }
398         if (case_to == TO_LOWER && isupper(name[i])) {
399             name[i] = tolower(name[i]);
400             continue;
401         }
402     }
403
404 #ifdef MULTIBYTE_FILENAME
405     if (to_code_save == CODE_CAP) {
406         len = sjis_to_cap(tmp, name, sizeof(tmp));
407         strncpy(name, tmp, size);
408         name[size-1] = 0;
409         len = strlen(name);
410     }
411 #endif /* MULTIBYTE_FILENAME */
412 }
413
414 /*
415  * Generic (MS-DOS style) time stamp format (localtime):
416  *
417  *  31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
418  * |<---- year-1980 --->|<- month ->|<--- day ---->|
419  *
420  *  15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
421  * |<--- hour --->|<---- minute --->|<- second/2 ->|
422  *
423  */
424
425 static time_t
426 generic_to_unix_stamp(t)
427     long t;
428 {
429     struct tm tm;
430
431 #define subbits(n, off, len) (((n) >> (off)) & ((1 << (len))-1))
432
433     tm.tm_sec  = subbits(t,  0, 5) * 2;
434     tm.tm_min  = subbits(t,  5, 6);
435     tm.tm_hour = subbits(t, 11, 5);
436     tm.tm_mday = subbits(t, 16, 5);
437     tm.tm_mon  = subbits(t, 21, 4) - 1;
438     tm.tm_year = subbits(t, 25, 7) + 80;
439     tm.tm_isdst = -1;
440
441 #if HAVE_MKTIME
442     return mktime(&tm);
443 #else
444     return timelocal(&tm);
445 #endif
446 }
447
448 static long
449 unix_to_generic_stamp(t)
450     time_t t;
451 {
452     struct tm *tm = localtime(&t);
453
454     tm->tm_year -= 80;
455     tm->tm_mon += 1;
456
457     return ((long)(tm->tm_year << 25) +
458             (tm->tm_mon  << 21) +
459             (tm->tm_mday << 16) +
460             (tm->tm_hour << 11) +
461             (tm->tm_min  << 5) +
462             (tm->tm_sec / 2));
463 }
464
465 static unsigned long
466 wintime_to_unix_stamp()
467 {
468 #if HAVE_UINT64_T
469     uint64_t t;
470     uint64_t epoch = ((uint64_t)0x019db1de << 32) + 0xd53e8000;
471                      /* 0x019db1ded53e8000ULL: 1970-01-01 00:00:00 (UTC) */
472
473     t = (unsigned long)get_longword();
474     t |= (uint64_t)(unsigned long)get_longword() << 32;
475     t = (t - epoch) / 10000000;
476     return t;
477 #else
478     int i, borrow;
479     unsigned long t, q, x;
480     unsigned long wintime[8];
481     unsigned long epoch[8] = {0x01,0x9d,0xb1,0xde, 0xd5,0x3e,0x80,0x00};
482                                 /* 1970-01-01 00:00:00 (UTC) */
483     /* wintime -= epoch */
484     borrow = 0;
485     for (i = 7; i >= 0; i--) {
486         wintime[i] = (unsigned)get_byte() - epoch[i] - borrow;
487         borrow = (wintime[i] > 0xff) ? 1 : 0;
488         wintime[i] &= 0xff;
489     }
490
491     /* q = wintime / 10000000 */
492     t = q = 0;
493     x = 10000000;               /* x: 24bit */
494     for (i = 0; i < 8; i++) {
495         t = (t << 8) + wintime[i]; /* 24bit + 8bit. t must be 32bit variable */
496         q <<= 8;                   /* q must be 32bit (time_t) */
497         q += t / x;
498         t %= x;     /* 24bit */
499     }
500     return q;
501 #endif
502 }
503
504 /*
505  * extended header
506  *
507  *             size  field name
508  *  --------------------------------
509  *  base header:         :
510  *           2 or 4  next-header size  [*1]
511  *  --------------------------------------
512  *  ext header:   1  ext-type            ^
513  *                ?  contents            | [*1] next-header size
514  *           2 or 4  next-header size    v
515  *  --------------------------------------
516  *
517  *  on level 1, 2 header:
518  *    size field is 2 bytes
519  *  on level 3 header:
520  *    size field is 4 bytes
521  */
522
523 static ssize_t
524 get_extended_header(fp, hdr, header_size, hcrc)
525     FILE *fp;
526     LzHeader *hdr;
527     size_t header_size;
528     unsigned int *hcrc;
529 {
530     char data[LZHEADER_STORAGE];
531     int name_length;
532     char dirname[FILENAME_LENGTH];
533     int dir_length = 0;
534     int i;
535     ssize_t whole_size = header_size;
536     int ext_type;
537     int n = 1 + hdr->size_field_length; /* `ext-type' + `next-header size' */
538
539     if (hdr->header_level == 0)
540         return 0;
541
542     name_length = strlen(hdr->name);
543
544     while (header_size) {
545 #if DUMP_HEADER
546         if (verbose_listing && verbose > 1)
547             printf("---\n");
548 #endif
549         setup_get(data);
550         if (sizeof(data) < header_size) {
551             error("header size (%ld) too large.", header_size);
552             exit(1);
553         }
554
555         if (fread(data, header_size, 1, fp) == 0) {
556             error("Invalid header (LHa file ?)");
557             return -1;
558         }
559
560         ext_type = get_byte();
561         switch (ext_type) {
562         case 0:
563 #if DUMP_HEADER
564             if (verbose_listing && verbose > 1) printf("     < header crc >\n");
565 #endif
566             /* header crc (CRC-16) */
567             hdr->header_crc = get_word();
568             /* clear buffer for CRC calculation. */
569             data[1] = data[2] = 0;
570             skip_bytes(header_size - n - 2);
571             break;
572         case 1:
573 #if DUMP_HEADER
574             if (verbose_listing && verbose > 1) printf("     < filename >\n");
575 #endif
576             /* filename */
577             name_length =
578                 get_bytes(hdr->name, header_size-n, sizeof(hdr->name)-1);
579             hdr->name[name_length] = 0;
580             break;
581         case 2:
582 #if DUMP_HEADER
583             if (verbose_listing && verbose > 1) printf("     < directory >\n");
584 #endif
585             /* directory */
586             dir_length = get_bytes(dirname, header_size-n, sizeof(dirname)-1);
587             dirname[dir_length] = 0;
588             break;
589         case 0x40:
590 #if DUMP_HEADER
591             if (verbose_listing && verbose > 1) printf("     < MS-DOS attribute >\n");
592 #endif
593             /* MS-DOS attribute */
594             hdr->attribute = get_word();
595             break;
596         case 0x41:
597 #if DUMP_HEADER
598             if (verbose_listing && verbose > 1) printf("     < Windows time stamp (FILETIME) >\n");
599 #endif
600             /* Windows time stamp (FILETIME structure) */
601             /* it is time in 100 nano seconds since 1601-01-01 00:00:00 */
602
603             skip_bytes(8); /* create time is ignored */
604
605             /* set last modified time */
606             if (hdr->header_level >= 2)
607                 skip_bytes(8);  /* time_t has been already set */
608             else
609                 hdr->unix_last_modified_stamp = wintime_to_unix_stamp();
610
611             skip_bytes(8); /* last access time is ignored */
612
613             break;
614         case 0x42:
615 #if DUMP_HEADER
616             if (verbose_listing && verbose > 1) printf("     < 64bits file size header >\n");
617 #endif
618 #ifdef HAVE_UINT64_T
619             /* 64bits file size header (UNLHA32 extension) */
620             hdr->packed_size = get_longlongword();
621             hdr->original_size = get_longlongword();
622 #else
623             skip_bytes(8);
624             skip_bytes(8);
625 #endif
626
627             break;
628         case 0x50:
629 #if DUMP_HEADER
630             if (verbose_listing && verbose > 1) printf("     < UNIX permission >\n");
631 #endif
632             /* UNIX permission */
633             hdr->unix_mode = get_word();
634             break;
635         case 0x51:
636 #if DUMP_HEADER
637             if (verbose_listing && verbose > 1) printf("     < UNIX gid and uid >\n");
638 #endif
639             /* UNIX gid and uid */
640             hdr->unix_gid = get_word();
641             hdr->unix_uid = get_word();
642             break;
643         case 0x52:
644 #if DUMP_HEADER
645             if (verbose_listing && verbose > 1) printf("     < UNIX group name >\n");
646 #endif
647             /* UNIX group name */
648             i = get_bytes(hdr->group, header_size-n, sizeof(hdr->group)-1);
649             hdr->group[i] = '\0';
650             break;
651         case 0x53:
652 #if DUMP_HEADER
653             if (verbose_listing && verbose > 1) printf("     < UNIX user name >\n");
654 #endif
655             /* UNIX user name */
656             i = get_bytes(hdr->user, header_size-n, sizeof(hdr->user)-1);
657             hdr->user[i] = '\0';
658             break;
659         case 0x54:
660 #if DUMP_HEADER
661             if (verbose_listing && verbose > 1) printf("     < UNIX last modifed time (time_t) >\n");
662 #endif
663             /* UNIX last modified time */
664             hdr->unix_last_modified_stamp = (time_t) get_longword();
665             break;
666         default:
667             /* other headers */
668             /* 0x39: multi-disk header
669                0x3f: uncompressed comment
670                0x42: 64bit large file size
671                0x48-0x4f(?): reserved for authenticity verification
672                0x7d: encapsulation
673                0x7e: extended attribute - platform information
674                0x7f: extended attribute - permission, owner-id and timestamp
675                      (level 3 on OS/2)
676                0xc4: compressed comment (dict size: 4096)
677                0xc5: compressed comment (dict size: 8192)
678                0xc6: compressed comment (dict size: 16384)
679                0xc7: compressed comment (dict size: 32768)
680                0xc8: compressed comment (dict size: 65536)
681                0xd0-0xdf(?): operating systemm specific information
682                0xfc: encapsulation (another opinion)
683                0xfe: extended attribute - platform information(another opinion)
684                0xff: extended attribute - permission, owner-id and timestamp
685                      (level 3 on UNLHA32) */
686             if (verbose)
687                 warning("unknown extended header 0x%02x", ext_type);
688             skip_bytes(header_size - n);
689             break;
690         }
691
692         if (hcrc)
693             *hcrc = calccrc(*hcrc, data, header_size);
694
695         if (hdr->size_field_length == 2)
696             whole_size += header_size = get_word();
697         else
698             whole_size += header_size = get_longword();
699     }
700
701     /* concatenate dirname and filename */
702     if (dir_length) {
703         if (name_length + dir_length >= sizeof(hdr->name)) {
704             warning("the length of pathname \"%s%s\" is too long.",
705                     dirname, hdr->name);
706             name_length = sizeof(hdr->name) - dir_length - 1;
707             hdr->name[name_length] = 0;
708         }
709         strcat(dirname, hdr->name); /* ok */
710         strcpy(hdr->name, dirname); /* ok */
711         name_length += dir_length;
712     }
713
714     return whole_size;
715 }
716
717 #define I_HEADER_SIZE           0               /* level 0,1,2   */
718 #define I_HEADER_CHECKSUM       1               /* level 0,1     */
719 #define I_METHOD                2               /* level 0,1,2,3 */
720 #define I_PACKED_SIZE           7               /* level 0,1,2,3 */
721 #define I_ATTRIBUTE             19              /* level 0,1,2,3 */
722 #define I_HEADER_LEVEL          20              /* level 0,1,2,3 */
723
724 #define COMMON_HEADER_SIZE      21      /* size of common part */
725
726 #define I_GENERIC_HEADER_SIZE 24 /* + name_length */
727 #define I_LEVEL0_HEADER_SIZE  36 /* + name_length (unix extended) */
728 #define I_LEVEL1_HEADER_SIZE  27 /* + name_length */
729 #define I_LEVEL2_HEADER_SIZE  26 /* + padding */
730 #define I_LEVEL3_HEADER_SIZE  32
731
732 /*
733  * level 0 header
734  *
735  *
736  * offset  size  field name
737  * ----------------------------------
738  *     0      1  header size    [*1]
739  *     1      1  header sum
740  *            ---------------------------------------
741  *     2      5  method ID                         ^
742  *     7      4  packed size    [*2]               |
743  *    11      4  original size                     |
744  *    15      2  time                              |
745  *    17      2  date                              |
746  *    19      1  attribute                         | [*1] header size (X+Y+22)
747  *    20      1  level (0x00 fixed)                |
748  *    21      1  name length                       |
749  *    22      X  pathname                          |
750  * X +22      2  file crc (CRC-16)                 |
751  * X +24      Y  ext-header(old style)             v
752  * -------------------------------------------------
753  * X+Y+24        data                              ^
754  *                 :                               | [*2] packed size
755  *                 :                               v
756  * -------------------------------------------------
757  *
758  * ext-header(old style)
759  *     0      1  ext-type ('U')
760  *     1      1  minor version
761  *     2      4  UNIX time
762  *     6      2  mode
763  *     8      2  uid
764  *    10      2  gid
765  *
766  * attribute (MS-DOS)
767  *    bit1  read only
768  *    bit2  hidden
769  *    bit3  system
770  *    bit4  volume label
771  *    bit5  directory
772  *    bit6  archive bit (need to backup)
773  *
774  */
775 static int
776 get_header_level0(fp, hdr, data)
777     FILE *fp;
778     LzHeader *hdr;
779     char *data;
780 {
781     size_t header_size;
782     ssize_t extend_size;
783     int checksum;
784     int name_length;
785     int i;
786
787     hdr->size_field_length = 2; /* in bytes */
788     hdr->header_size = header_size = get_byte();
789     checksum = get_byte();
790
791     if (fread(data + COMMON_HEADER_SIZE,
792               header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
793         error("Invalid header (LHarc file ?)");
794         return FALSE;   /* finish */
795     }
796
797     if (calc_sum(data + I_METHOD, header_size) != checksum) {
798         error("Checksum error (LHarc file?)");
799         return FALSE;
800     }
801
802     get_bytes(hdr->method, 5, sizeof(hdr->method));
803     hdr->packed_size = (unsigned long)get_longword();
804     hdr->original_size = (unsigned long)get_longword();
805     hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
806     hdr->attribute = get_byte(); /* MS-DOS attribute */
807     hdr->header_level = get_byte();
808     name_length = get_byte();
809     i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
810     hdr->name[i] = '\0';
811
812     /* defaults for other type */
813     hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
814     hdr->unix_gid = 0;
815     hdr->unix_uid = 0;
816
817     extend_size = header_size+2 - name_length - 24;
818
819     if (extend_size < 0) {
820         if (extend_size == -2) {
821             /* CRC field is not given */
822             hdr->extend_type = EXTEND_GENERIC;
823             hdr->has_crc = FALSE;
824
825             return TRUE;
826         }
827
828         error("Unkonwn header (lha file?)");
829         exit(1);
830     }
831
832     hdr->has_crc = TRUE;
833     hdr->crc = get_word();
834
835     if (extend_size == 0)
836         return TRUE;
837
838     hdr->extend_type = get_byte();
839     extend_size--;
840
841     if (hdr->extend_type == EXTEND_UNIX) {
842         if (extend_size >= 11) {
843             hdr->minor_version = get_byte();
844             hdr->unix_last_modified_stamp = (time_t) get_longword();
845             hdr->unix_mode = get_word();
846             hdr->unix_uid = get_word();
847             hdr->unix_gid = get_word();
848             extend_size -= 11;
849         } else {
850             hdr->extend_type = EXTEND_GENERIC;
851         }
852     }
853     if (extend_size > 0)
854         skip_bytes(extend_size);
855
856     hdr->header_size += 2;
857     return TRUE;
858 }
859
860 /*
861  * level 1 header
862  *
863  *
864  * offset   size  field name
865  * -----------------------------------
866  *     0       1  header size   [*1]
867  *     1       1  header sum
868  *             -------------------------------------
869  *     2       5  method ID                        ^
870  *     7       4  skip size     [*2]               |
871  *    11       4  original size                    |
872  *    15       2  time                             |
873  *    17       2  date                             |
874  *    19       1  attribute (0x20 fixed)           | [*1] header size (X+Y+25)
875  *    20       1  level (0x01 fixed)               |
876  *    21       1  name length                      |
877  *    22       X  filename                         |
878  * X+ 22       2  file crc (CRC-16)                |
879  * X+ 24       1  OS ID                            |
880  * X +25       Y  ???                              |
881  * X+Y+25      2  next-header size                 v
882  * -------------------------------------------------
883  * X+Y+27      Z  ext-header                       ^
884  *                 :                               |
885  * -----------------------------------             | [*2] skip size
886  * X+Y+Z+27       data                             |
887  *                 :                               v
888  * -------------------------------------------------
889  *
890  */
891 static int
892 get_header_level1(fp, hdr, data)
893     FILE *fp;
894     LzHeader *hdr;
895     char *data;
896 {
897     size_t header_size;
898     ssize_t extend_size;
899     int checksum;
900     int name_length;
901     int i, dummy;
902
903     hdr->size_field_length = 2; /* in bytes */
904     hdr->header_size = header_size = get_byte();
905     checksum = get_byte();
906
907     if (fread(data + COMMON_HEADER_SIZE,
908               header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
909         error("Invalid header (LHarc file ?)");
910         return FALSE;   /* finish */
911     }
912
913     if (calc_sum(data + I_METHOD, header_size) != checksum) {
914         error("Checksum error (LHarc file?)");
915         return FALSE;
916     }
917
918     get_bytes(hdr->method, 5, sizeof(hdr->method));
919     hdr->packed_size = (unsigned long)get_longword(); /* skip size */
920     hdr->original_size = (unsigned long)get_longword();
921     hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
922     hdr->attribute = get_byte(); /* 0x20 fixed */
923     hdr->header_level = get_byte();
924
925     name_length = get_byte();
926     i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
927     hdr->name[i] = '\0';
928
929     /* defaults for other type */
930     hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
931     hdr->unix_gid = 0;
932     hdr->unix_uid = 0;
933
934     hdr->has_crc = TRUE;
935     hdr->crc = get_word();
936     hdr->extend_type = get_byte();
937
938     dummy = header_size+2 - name_length - I_LEVEL1_HEADER_SIZE;
939     if (dummy > 0)
940         skip_bytes(dummy); /* skip old style extend header */
941
942     extend_size = get_word();
943     extend_size = get_extended_header(fp, hdr, extend_size, 0);
944     if (extend_size == -1)
945         return FALSE;
946
947     /* On level 1 header, size fields should be adjusted. */
948     /* the `packed_size' field contains the extended header size. */
949     /* the `header_size' field does not. */
950     hdr->packed_size -= extend_size;
951     hdr->header_size += extend_size + 2;
952
953     return TRUE;
954 }
955
956 /*
957  * level 2 header
958  *
959  *
960  * offset   size  field name
961  * --------------------------------------------------
962  *     0       2  total header size [*1]           ^
963  *             -----------------------             |
964  *     2       5  method ID                        |
965  *     7       4  packed size       [*2]           |
966  *    11       4  original size                    |
967  *    15       4  time                             |
968  *    19       1  RESERVED (0x20 fixed)            | [*1] total header size
969  *    20       1  level (0x02 fixed)               |      (X+26+(1))
970  *    21       2  file crc (CRC-16)                |
971  *    23       1  OS ID                            |
972  *    24       2  next-header size                 |
973  * -----------------------------------             |
974  *    26       X  ext-header                       |
975  *                 :                               |
976  * -----------------------------------             |
977  * X +26      (1) padding                          v
978  * -------------------------------------------------
979  * X +26+(1)      data                             ^
980  *                 :                               | [*2] packed size
981  *                 :                               v
982  * -------------------------------------------------
983  *
984  */
985 static int
986 get_header_level2(fp, hdr, data)
987     FILE *fp;
988     LzHeader *hdr;
989     char *data;
990 {
991     size_t header_size;
992     ssize_t extend_size;
993     int padding;
994     unsigned int hcrc;
995
996     hdr->size_field_length = 2; /* in bytes */
997     hdr->header_size = header_size = get_word();
998
999     if (fread(data + COMMON_HEADER_SIZE,
1000               I_LEVEL2_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
1001         error("Invalid header (LHarc file ?)");
1002         return FALSE;   /* finish */
1003     }
1004
1005     get_bytes(hdr->method, 5, sizeof(hdr->method));
1006     hdr->packed_size = (unsigned long)get_longword();
1007     hdr->original_size = (unsigned long)get_longword();
1008     hdr->unix_last_modified_stamp = get_longword();
1009     hdr->attribute = get_byte(); /* reserved */
1010     hdr->header_level = get_byte();
1011
1012     /* defaults for other type */
1013     hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
1014     hdr->unix_gid = 0;
1015     hdr->unix_uid = 0;
1016
1017     hdr->has_crc = TRUE;
1018     hdr->crc = get_word();
1019     hdr->extend_type = get_byte();
1020     extend_size = get_word();
1021
1022     INITIALIZE_CRC(hcrc);
1023     hcrc = calccrc(hcrc, data, get_ptr - data);
1024
1025     extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
1026     if (extend_size == -1)
1027         return FALSE;
1028
1029     padding = header_size - I_LEVEL2_HEADER_SIZE - extend_size;
1030     while (padding--)           /* padding should be 0 or 1 */
1031         hcrc = UPDATE_CRC(hcrc, fgetc(fp));
1032
1033     if (hdr->header_crc != hcrc)
1034         error("header CRC error");
1035
1036     return TRUE;
1037 }
1038
1039 /*
1040  * level 3 header
1041  *
1042  *
1043  * offset   size  field name
1044  * --------------------------------------------------
1045  *     0       2  size field length (4 fixed)      ^
1046  *     2       5  method ID                        |
1047  *     7       4  packed size       [*2]           |
1048  *    11       4  original size                    |
1049  *    15       4  time                             |
1050  *    19       1  RESERVED (0x20 fixed)            | [*1] total header size
1051  *    20       1  level (0x03 fixed)               |      (X+32)
1052  *    21       2  file crc (CRC-16)                |
1053  *    23       1  OS ID                            |
1054  *    24       4  total header size [*1]           |
1055  *    28       4  next-header size                 |
1056  * -----------------------------------             |
1057  *    32       X  ext-header                       |
1058  *                 :                               v
1059  * -------------------------------------------------
1060  * X +32          data                             ^
1061  *                 :                               | [*2] packed size
1062  *                 :                               v
1063  * -------------------------------------------------
1064  *
1065  */
1066 static int
1067 get_header_level3(fp, hdr, data)
1068     FILE *fp;
1069     LzHeader *hdr;
1070     char *data;
1071 {
1072     size_t header_size;
1073     ssize_t extend_size;
1074     int padding;
1075     unsigned int hcrc;
1076
1077     hdr->size_field_length = get_word();
1078
1079     if (fread(data + COMMON_HEADER_SIZE,
1080               I_LEVEL3_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
1081         error("Invalid header (LHarc file ?)");
1082         return FALSE;   /* finish */
1083     }
1084
1085     get_bytes(hdr->method, 5, sizeof(hdr->method));
1086     hdr->packed_size = (unsigned long)get_longword();
1087     hdr->original_size = (unsigned long)get_longword();
1088     hdr->unix_last_modified_stamp = get_longword();
1089     hdr->attribute = get_byte(); /* reserved */
1090     hdr->header_level = get_byte();
1091
1092     /* defaults for other type */
1093     hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
1094     hdr->unix_gid = 0;
1095     hdr->unix_uid = 0;
1096
1097     hdr->has_crc = TRUE;
1098     hdr->crc = get_word();
1099     hdr->extend_type = get_byte();
1100     hdr->header_size = header_size = get_longword();
1101     extend_size = get_longword();
1102
1103     INITIALIZE_CRC(hcrc);
1104     hcrc = calccrc(hcrc, data, get_ptr - data);
1105
1106     extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
1107     if (extend_size == -1)
1108         return FALSE;
1109
1110     padding = header_size - I_LEVEL3_HEADER_SIZE - extend_size;
1111     while (padding--)           /* padding should be 0 */
1112         hcrc = UPDATE_CRC(hcrc, fgetc(fp));
1113
1114     if (hdr->header_crc != hcrc)
1115         error("header CRC error");
1116
1117     return TRUE;
1118 }
1119
1120 boolean
1121 get_header(fp, hdr)
1122     FILE *fp;
1123     LzHeader *hdr;
1124 {
1125     char data[LZHEADER_STORAGE];
1126
1127     int archive_kanji_code = CODE_SJIS;
1128     int system_kanji_code = default_system_kanji_code;
1129     char *archive_delim = "\377\\"; /* `\' is for level 0 header and
1130                                        broken archive. */
1131     char *system_delim = "//";
1132     int filename_case = NONE;
1133     int end_mark;
1134
1135     memset(hdr, 0, sizeof(LzHeader));
1136
1137     setup_get(data);
1138
1139     if ((end_mark = getc(fp)) == EOF || end_mark == 0) {
1140         return FALSE;           /* finish */
1141     }
1142     data[0] = end_mark;
1143
1144     if (fread(data + 1, COMMON_HEADER_SIZE - 1, 1, fp) == 0) {
1145         error("Invalid header (LHarc file ?)");
1146         return FALSE;           /* finish */
1147     }
1148
1149     switch (data[I_HEADER_LEVEL]) {
1150     case 0:
1151         if (get_header_level0(fp, hdr, data) == FALSE)
1152             return FALSE;
1153         break;
1154     case 1:
1155         if (get_header_level1(fp, hdr, data) == FALSE)
1156             return FALSE;
1157         break;
1158     case 2:
1159         if (get_header_level2(fp, hdr, data) == FALSE)
1160             return FALSE;
1161         break;
1162     case 3:
1163         if (get_header_level3(fp, hdr, data) == FALSE)
1164             return FALSE;
1165         break;
1166     default:
1167         error("Unknown level header (level %d)", data[I_HEADER_LEVEL]);
1168         return FALSE;
1169     }
1170
1171     /* filename conversion */
1172     switch (hdr->extend_type) {
1173     case EXTEND_MSDOS:
1174         filename_case = convertcase ? TO_LOWER : NONE;
1175         break;
1176     case EXTEND_HUMAN:
1177     case EXTEND_OS68K:
1178     case EXTEND_XOSK:
1179     case EXTEND_UNIX:
1180     case EXTEND_JAVA:
1181         filename_case = NONE;
1182         break;
1183
1184     case EXTEND_MACOS:
1185         archive_delim = "\377/:\\";
1186                           /* `\' is for level 0 header and broken archive. */
1187         system_delim = "/://";
1188         filename_case = NONE;
1189         break;
1190
1191     default:
1192         filename_case = convertcase ? TO_LOWER : NONE;
1193         break;
1194     }
1195
1196     if (optional_archive_kanji_code)
1197         archive_kanji_code = optional_archive_kanji_code;
1198     if (optional_system_kanji_code)
1199         system_kanji_code = optional_system_kanji_code;
1200     if (optional_archive_delim)
1201         archive_delim = optional_archive_delim;
1202     if (optional_system_delim)
1203         system_delim = optional_system_delim;
1204     if (optional_filename_case)
1205         filename_case = optional_filename_case;
1206
1207     /* kanji code and delimiter conversion */
1208     convert_filename(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1209                      archive_kanji_code,
1210                      system_kanji_code,
1211                      archive_delim, system_delim, filename_case);
1212
1213     if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1214         char *p;
1215         /* split symbolic link */
1216         p = strchr(hdr->name, '|');
1217         if (p) {
1218             /* hdr->name is symbolic link name */
1219             /* hdr->realname is real name */
1220             *p = 0;
1221             strcpy(hdr->realname, p+1); /* ok */
1222         }
1223         else
1224             error("unknown symlink name \"%s\"", hdr->name);
1225     }
1226
1227     return TRUE;
1228 }
1229
1230 /* skip SFX header */
1231 int
1232 seek_lha_header(fp)
1233     FILE *fp;
1234 {
1235     unsigned char   buffer[64 * 1024]; /* max seek size */
1236     unsigned char  *p;
1237     int             n;
1238
1239     n = fread(buffer, 1, sizeof(buffer), fp);
1240
1241     for (p = buffer; p < buffer + n; p++) {
1242         if (! (p[I_METHOD]=='-' && p[I_METHOD+1]=='l' && p[I_METHOD+4]=='-'))
1243             continue;
1244         /* found "-l??-" keyword (as METHOD type string) */
1245
1246         /* level 0 or 1 header */
1247         if ((p[I_HEADER_LEVEL] == 0 || p[I_HEADER_LEVEL] == 1)
1248             && p[I_HEADER_SIZE] > 20
1249             && p[I_HEADER_CHECKSUM] == calc_sum(p+2, p[I_HEADER_SIZE])) {
1250             if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
1251                 fatal_error("cannot seek header");
1252             return 0;
1253         }
1254
1255         /* level 2 header */
1256         if (p[I_HEADER_LEVEL] == 2
1257             && p[I_HEADER_SIZE] >= 24
1258             && p[I_ATTRIBUTE] == 0x20) {
1259             if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
1260                 fatal_error("cannot seek header");
1261             return 0;
1262         }
1263     }
1264
1265     if (fseeko(fp, -n, SEEK_CUR) == -1)
1266         fatal_error("cannot seek header");
1267     return -1;
1268 }
1269
1270
1271 /* remove leading `xxxx/..' */
1272 static char *
1273 remove_leading_dots(char *path)
1274 {
1275     char *first = path;
1276     char *ptr = 0;
1277
1278     if (strcmp(first, "..") == 0) {
1279         warning("Removing leading `..' from member name.");
1280         return first+1;         /* change to "." */
1281     }
1282
1283     if (strstr(first, "..") == 0)
1284         return first;
1285
1286     while (path && *path) {
1287
1288         if (strcmp(path, "..") == 0)
1289             ptr = path = path+2;
1290         else if (strncmp(path, "../", 3) == 0)
1291             ptr = path = path+3;
1292         else
1293             path = strchr(path, '/');
1294
1295         if (path && *path == '/') {
1296             path++;
1297         }
1298     }
1299
1300     if (ptr) {
1301         warning("Removing leading `%.*s' from member name.", ptr-first, first);
1302         return ptr;
1303     }
1304
1305     return first;
1306 }
1307
1308 static int
1309 copy_path_element(char *dst, const char *src, int size)
1310 {
1311     int i;
1312
1313     if (size < 1) return 0;
1314
1315     for (i = 0; i < size; i++) {
1316         dst[i] = src[i];
1317         if (dst[i] == '\0')
1318             return i;
1319         if (dst[i] == '/') {
1320             dst[++i] = 0;
1321             return i;
1322         }
1323     }
1324
1325     dst[--i] = 0;
1326
1327     return i;
1328 }
1329
1330 /*
1331   canonicalize path
1332
1333   remove leading "xxx/../"
1334   remove "./", "././", "././ ... ./"
1335   remove duplicated "/"
1336 */
1337 static int
1338 canon_path(char *newpath, char *path, size_t size)
1339 {
1340     int len;
1341     char *p = newpath;
1342
1343     path = remove_leading_dots(path);
1344
1345     while (*path) {
1346         if (path[0] == '.' && path[1] == '/')
1347             path += 2;
1348         else {
1349             int len;
1350             len = copy_path_element(newpath, path, size);
1351
1352             path += len;
1353             newpath += len;
1354             size -= len;
1355             if (size <= 1)
1356                 break;
1357         }
1358
1359         /* remove duplicated '/' */
1360         while (*path == '/') path++;
1361     }
1362
1363     /* When newpath is empty, set "." */
1364     if (newpath == p) {
1365         strcpy(newpath, ".");
1366         newpath++;
1367     }
1368
1369     return newpath - p;         /* string length */
1370 }
1371
1372 void
1373 init_header(name, v_stat, hdr)
1374     char           *name;
1375     struct stat    *v_stat;
1376     LzHeader       *hdr;
1377 {
1378     int             len;
1379
1380     memset(hdr, 0, sizeof(LzHeader));
1381
1382     /* the `method' member is rewrote by the encoding function.
1383        but need set for empty files */
1384     memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
1385
1386     hdr->packed_size = 0;
1387     hdr->original_size = v_stat->st_size;
1388     hdr->attribute = GENERIC_ATTRIBUTE;
1389     hdr->header_level = header_level;
1390
1391     len = canon_path(hdr->name, name, sizeof(hdr->name));
1392
1393     hdr->crc = 0x0000;
1394     hdr->extend_type = EXTEND_UNIX;
1395     hdr->unix_last_modified_stamp = v_stat->st_mtime;
1396     /* since 00:00:00 JAN.1.1970 */
1397 #ifdef NOT_COMPATIBLE_MODE
1398     /* Please need your modification in this space. */
1399 #ifdef __DJGPP__
1400     hdr->unix_mode = 0;
1401     if (S_ISREG(v_stat->st_mode))
1402             hdr->unix_mode = hdr->unix_mode | UNIX_FILE_REGULAR;
1403     if (S_ISDIR(v_stat->st_mode))
1404             hdr->unix_mode = hdr->unix_mode | UNIX_FILE_DIRECTORY;
1405     if (S_ISLNK(v_stat->st_mode))
1406             hdr->unix_mode = hdr->unix_mode | UNIX_FILE_SYMLINK;
1407     if (v_stat->st_mode & S_IRUSR) 
1408             hdr->unix_mode = hdr->unix_mode | UNIX_OWNER_READ_PERM;
1409     if (v_stat->st_mode & S_IRGRP) 
1410             hdr->unix_mode = hdr->unix_mode | UNIX_GROUP_READ_PERM;
1411     if (v_stat->st_mode & S_IROTH) 
1412             hdr->unix_mode = hdr->unix_mode | UNIX_OTHER_READ_PERM;
1413     if (v_stat->st_mode & S_IWUSR) 
1414             hdr->unix_mode = hdr->unix_mode | UNIX_OWNER_WRITE_PERM;
1415     if (v_stat->st_mode & S_IWGRP) 
1416             hdr->unix_mode = hdr->unix_mode | UNIX_GROUP_WRITE_PERM;
1417     if (v_stat->st_mode & S_IWOTH) 
1418             hdr->unix_mode = hdr->unix_mode | UNIX_OTHER_WRITE_PERM;
1419     if (v_stat->st_mode & S_IXUSR) 
1420             hdr->unix_mode = hdr->unix_mode | UNIX_OWNER_EXEC_PERM;
1421     if (v_stat->st_mode & S_IXGRP) 
1422             hdr->unix_mode = hdr->unix_mode | UNIX_GROUP_EXEC_PERM;
1423     if (v_stat->st_mode & S_IXOTH) 
1424             hdr->unix_mode = hdr->unix_mode | UNIX_OTHER_EXEC_PERM;
1425     if (v_stat->st_mode & S_ISUID) 
1426             hdr->unix_mode = hdr->unix_mode | UNIX_SETUID;
1427     if (v_stat->st_mode & S_ISGID) 
1428             hdr->unix_mode = hdr->unix_mode | UNIX_SETGID;
1429 #endif /* __DJGPP__ */
1430 #else
1431     hdr->unix_mode = v_stat->st_mode;
1432 #endif
1433
1434     hdr->unix_uid = v_stat->st_uid;
1435     hdr->unix_gid = v_stat->st_gid;
1436
1437 #if INCLUDE_OWNER_NAME_IN_HEADER
1438 #if HAVE_GETPWUID
1439     {
1440         struct passwd *ent = getpwuid(hdr->unix_uid);
1441
1442         if (ent) {
1443             strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
1444             if (hdr->user[sizeof(hdr->user)-1])
1445                 hdr->user[sizeof(hdr->user)-1] = 0;
1446         }
1447     }
1448 #endif
1449 #if HAVE_GETGRGID
1450     {
1451         struct group *ent = getgrgid(hdr->unix_gid);
1452
1453         if (ent) {
1454             strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
1455             if (hdr->group[sizeof(hdr->group)-1])
1456                 hdr->group[sizeof(hdr->group)-1] = 0;
1457         }
1458     }
1459 #endif
1460 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
1461     if (is_directory(v_stat)) {
1462         memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1463         hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1464         hdr->original_size = 0;
1465         if (len > 0 && hdr->name[len - 1] != '/') {
1466             if (len < sizeof(hdr->name)-1)
1467                 strcpy(&hdr->name[len++], "/"); /* ok */
1468             else
1469                 warning("the length of dirname \"%s\" is too long.",
1470                         hdr->name);
1471         }
1472     }
1473
1474 #ifdef S_IFLNK
1475     if (is_symlink(v_stat)) {
1476         memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1477         hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1478         hdr->original_size = 0;
1479         readlink(name, hdr->realname, sizeof(hdr->realname));
1480     }
1481 #endif
1482 }
1483
1484 static void
1485 write_unix_info(hdr)
1486     LzHeader *hdr;
1487 {
1488     /* UNIX specific informations */
1489
1490     put_word(5);            /* size */
1491     put_byte(0x50);         /* permission */
1492     put_word(hdr->unix_mode);
1493
1494     put_word(7);            /* size */
1495     put_byte(0x51);         /* gid and uid */
1496     put_word(hdr->unix_gid);
1497     put_word(hdr->unix_uid);
1498
1499     if (hdr->group[0]) {
1500         int len = strlen(hdr->group);
1501         put_word(len + 3);  /* size */
1502         put_byte(0x52);     /* group name */
1503         put_bytes(hdr->group, len);
1504     }
1505
1506     if (hdr->user[0]) {
1507         int len = strlen(hdr->user);
1508         put_word(len + 3);  /* size */
1509         put_byte(0x53);     /* user name */
1510         put_bytes(hdr->user, len);
1511     }
1512
1513     if (hdr->header_level == 1) {
1514         put_word(7);        /* size */
1515         put_byte(0x54);     /* time stamp */
1516         put_longword(hdr->unix_last_modified_stamp);
1517     }
1518 }
1519
1520 static size_t
1521 write_header_level0(data, hdr, pathname)
1522     LzHeader *hdr;
1523     char *data, *pathname;
1524 {
1525     int limit;
1526     int name_length;
1527     size_t header_size;
1528
1529     setup_put(data);
1530     memset(data, 0, LZHEADER_STORAGE);
1531
1532     put_byte(0x00);             /* header size */
1533     put_byte(0x00);             /* check sum */
1534     put_bytes(hdr->method, 5);
1535     put_longword(hdr->packed_size);
1536     put_longword(hdr->original_size);
1537     put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1538     put_byte(hdr->attribute);
1539     put_byte(hdr->header_level); /* level 0 */
1540
1541     /* write pathname (level 0 header contains the directory part) */
1542     name_length = strlen(pathname);
1543     if (generic_format)
1544         limit = 255 - I_GENERIC_HEADER_SIZE + 2;
1545     else
1546         limit = 255 - I_LEVEL0_HEADER_SIZE + 2;
1547
1548     if (name_length > limit) {
1549         warning("the length of pathname \"%s\" is too long.", pathname);
1550         name_length = limit;
1551     }
1552     put_byte(name_length);
1553     put_bytes(pathname, name_length);
1554     put_word(hdr->crc);
1555
1556     if (generic_format) {
1557         header_size = I_GENERIC_HEADER_SIZE + name_length - 2;
1558         data[I_HEADER_SIZE] = header_size;
1559         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1560     } else {
1561         /* write old-style extend header */
1562         put_byte(EXTEND_UNIX);
1563         put_byte(CURRENT_UNIX_MINOR_VERSION);
1564         put_longword(hdr->unix_last_modified_stamp);
1565         put_word(hdr->unix_mode);
1566         put_word(hdr->unix_uid);
1567         put_word(hdr->unix_gid);
1568
1569         /* size of extended header is 12 */
1570         header_size = I_LEVEL0_HEADER_SIZE + name_length - 2;
1571         data[I_HEADER_SIZE] = header_size;
1572         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1573     }
1574
1575     return header_size + 2;
1576 }
1577
1578 static size_t
1579 write_header_level1(data, hdr, pathname)
1580     LzHeader *hdr;
1581     char *data, *pathname;
1582 {
1583     int name_length, dir_length, limit;
1584     char *basename, *dirname;
1585     size_t header_size;
1586     char *extend_header_top;
1587     size_t extend_header_size;
1588
1589     basename = strrchr(pathname, LHA_PATHSEP);
1590     if (basename) {
1591         basename++;
1592         name_length = strlen(basename);
1593         dirname = pathname;
1594         dir_length = basename - dirname;
1595     }
1596     else {
1597         basename = pathname;
1598         name_length = strlen(basename);
1599         dirname = "";
1600         dir_length = 0;
1601     }
1602
1603     setup_put(data);
1604     memset(data, 0, LZHEADER_STORAGE);
1605
1606     put_byte(0x00);             /* header size */
1607     put_byte(0x00);             /* check sum */
1608     put_bytes(hdr->method, 5);
1609     put_longword(hdr->packed_size);
1610     put_longword(hdr->original_size);
1611     put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1612     put_byte(0x20);
1613     put_byte(hdr->header_level); /* level 1 */
1614
1615     /* level 1 header: write filename (basename only) */
1616     limit = 255 - I_LEVEL1_HEADER_SIZE + 2;
1617     if (name_length > limit) {
1618         put_byte(0);            /* name length */
1619     }
1620     else {
1621         put_byte(name_length);
1622         put_bytes(basename, name_length);
1623     }
1624
1625     put_word(hdr->crc);
1626
1627     if (generic_format)
1628         put_byte(0x00);
1629     else
1630         put_byte(EXTEND_UNIX);
1631
1632     /* write extend header from here. */
1633
1634     extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1635     header_size = extend_header_top - data - 2;
1636
1637     /* write filename and dirname */
1638
1639     if (name_length > limit) {
1640         put_word(name_length + 3); /* size */
1641         put_byte(0x01);         /* filename */
1642         put_bytes(basename, name_length);
1643     }
1644
1645     if (dir_length > 0) {
1646         put_word(dir_length + 3); /* size */
1647         put_byte(0x02);         /* dirname */
1648         put_bytes(dirname, dir_length);
1649     }
1650
1651     if (!generic_format)
1652         write_unix_info(hdr);
1653
1654     put_word(0x0000);           /* next header size */
1655
1656     extend_header_size = put_ptr - extend_header_top;
1657     /* On level 1 header, the packed size field is contains the ext-header */
1658     hdr->packed_size += put_ptr - extend_header_top;
1659
1660     /* put `skip size' */
1661     setup_put(data + I_PACKED_SIZE);
1662     put_longword(hdr->packed_size);
1663
1664     data[I_HEADER_SIZE] = header_size;
1665     data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1666
1667     return header_size + extend_header_size + 2;
1668 }
1669
1670 static size_t
1671 write_header_level2(data, hdr, pathname)
1672     LzHeader *hdr;
1673     char *data, *pathname;
1674 {
1675     int name_length, dir_length;
1676     char *basename, *dirname;
1677     size_t header_size;
1678     char *extend_header_top;
1679     char *headercrc_ptr;
1680     unsigned int hcrc;
1681
1682     basename = strrchr(pathname, LHA_PATHSEP);
1683     if (basename) {
1684         basename++;
1685         name_length = strlen(basename);
1686         dirname = pathname;
1687         dir_length = basename - dirname;
1688     }
1689     else {
1690         basename = pathname;
1691         name_length = strlen(basename);
1692         dirname = "";
1693         dir_length = 0;
1694     }
1695
1696     setup_put(data);
1697     memset(data, 0, LZHEADER_STORAGE);
1698
1699     put_word(0x0000);           /* header size */
1700     put_bytes(hdr->method, 5);
1701     put_longword(hdr->packed_size);
1702     put_longword(hdr->original_size);
1703     put_longword(hdr->unix_last_modified_stamp);
1704     put_byte(0x20);
1705     put_byte(hdr->header_level); /* level 2 */
1706
1707     put_word(hdr->crc);
1708
1709     if (generic_format)
1710         put_byte(0x00);
1711     else
1712         put_byte(EXTEND_UNIX);
1713
1714     /* write extend header from here. */
1715
1716     extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1717
1718     /* write common header */
1719     put_word(5);
1720     put_byte(0x00);
1721     headercrc_ptr = put_ptr;
1722     put_word(0x0000);           /* header CRC */
1723
1724     /* write filename and dirname */
1725     /* must have this header, even if the name_length is 0. */
1726     put_word(name_length + 3);  /* size */
1727     put_byte(0x01);             /* filename */
1728     put_bytes(basename, name_length);
1729
1730     if (dir_length > 0) {
1731         put_word(dir_length + 3); /* size */
1732         put_byte(0x02);         /* dirname */
1733         put_bytes(dirname, dir_length);
1734     }
1735
1736     if (!generic_format)
1737         write_unix_info(hdr);
1738
1739     put_word(0x0000);           /* next header size */
1740
1741     header_size = put_ptr - data;
1742     if ((header_size & 0xff) == 0) {
1743         /* cannot put zero at the first byte on level 2 header. */
1744         /* adjust header size. */
1745         put_byte(0);            /* padding */
1746         header_size++;
1747     }
1748
1749     /* put header size */
1750     setup_put(data + I_HEADER_SIZE);
1751     put_word(header_size);
1752
1753     /* put header CRC in extended header */
1754     INITIALIZE_CRC(hcrc);
1755     hcrc = calccrc(hcrc, data, (unsigned int) header_size);
1756     setup_put(headercrc_ptr);
1757     put_word(hcrc);
1758
1759     return header_size;
1760 }
1761
1762 void
1763 write_header(fp, hdr)
1764     FILE           *fp;
1765     LzHeader       *hdr;
1766 {
1767     size_t header_size;
1768     char data[LZHEADER_STORAGE];
1769
1770     int archive_kanji_code = CODE_SJIS;
1771     int system_kanji_code = default_system_kanji_code;
1772     char *archive_delim = "\377";
1773     char *system_delim = "/";
1774     int filename_case = NONE;
1775     char pathname[FILENAME_LENGTH];
1776
1777     if (optional_archive_kanji_code)
1778         archive_kanji_code = optional_archive_kanji_code;
1779     if (optional_system_kanji_code)
1780         system_kanji_code = optional_system_kanji_code;
1781
1782     if (generic_format && convertcase)
1783         filename_case = TO_UPPER;
1784
1785     if (hdr->header_level == 0) {
1786         archive_delim = "\\";
1787     }
1788
1789     if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1790         char *p;
1791         p = strchr(hdr->name, '|');
1792         if (p) {
1793             error("symlink name \"%s\" contains '|' char. change it into '_'",
1794                   hdr->name);
1795             *p = '_';
1796         }
1797         if (xsnprintf(pathname, sizeof(pathname),
1798                       "%s|%s", hdr->name, hdr->realname) == -1)
1799             error("file name is too long (%s -> %s)", hdr->name, hdr->realname);
1800     }
1801     else {
1802         strncpy(pathname, hdr->name, sizeof(pathname));
1803         pathname[sizeof(pathname)-1] = 0;
1804     }
1805
1806     convert_filename(pathname, strlen(pathname), sizeof(pathname),
1807                      system_kanji_code,
1808                      archive_kanji_code,
1809                      system_delim, archive_delim, filename_case);
1810
1811     switch (hdr->header_level) {
1812     case 0:
1813         header_size = write_header_level0(data, hdr, pathname);
1814         break;
1815     case 1:
1816         header_size = write_header_level1(data, hdr, pathname);
1817         break;
1818     case 2:
1819         header_size = write_header_level2(data, hdr, pathname);
1820         break;
1821     default:
1822         error("Unknown level header (level %d)", hdr->header_level);
1823         exit(1);
1824     }
1825
1826     if (fwrite(data, header_size, 1, fp) == 0)
1827         fatal_error("Cannot write to temporary file");
1828 }
1829
1830 #if MULTIBYTE_FILENAME
1831
1832 #if defined(__APPLE__)  /* Added by Hiroto Sakai */
1833
1834 #include <CoreFoundation/CFString.h>
1835 #include <CoreFoundation/CFStringEncodingExt.h>
1836
1837 /* this is not need for Mac OS X v 10.2 later */
1838 enum {
1839   kCFStringEncodingAllowLossyConversion = 1,
1840   kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1841   kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1842   kCFStringEncodingSubstituteCombinings = (1 << 3),
1843   kCFStringEncodingComposeCombinings = (1 << 4),
1844   kCFStringEncodingIgnoreCombinings = (1 << 5),
1845   kCFStringEncodingUseCanonical = (1 << 6),
1846   kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1847   kCFStringEncodingPrependBOM = (1 << 8),
1848   kCFStringEncodingDisableCorporateArea = (1 << 9),
1849   kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1850 };
1851
1852 static int
1853 ConvertEncodingToUTF8(const char* inCStr,
1854                       char* outUTF8Buffer,
1855                       int outUTF8BufferLength,
1856                       unsigned long scriptEncoding,
1857                       unsigned long flags)
1858 {
1859     unsigned long unicodeChars;
1860     unsigned long srcCharsUsed;
1861     unsigned long usedByteLen = 0;
1862     UniChar uniStr[512];
1863     unsigned long cfResult;
1864
1865     cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1866                                               flags,
1867                                               (char *)inCStr,
1868                                               strlen(inCStr),
1869                                               &srcCharsUsed,
1870                                               uniStr,
1871                                               512,
1872                                               &unicodeChars);
1873     if (cfResult == 0) {
1874         cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1875                                                   flags,
1876                                                   uniStr,
1877                                                   unicodeChars,
1878                                                   &srcCharsUsed,
1879                                                   (char*)outUTF8Buffer,
1880                                                   outUTF8BufferLength - 1,
1881                                                   &usedByteLen);
1882         outUTF8Buffer[usedByteLen] = '\0';
1883     }
1884
1885     return cfResult;
1886 }
1887
1888 static int
1889 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1890                       int inUTF8BufLength,
1891                       char* outCStrBuffer,
1892                       int outCStrBufferLength,
1893                       unsigned long scriptEncoding,
1894                       unsigned long flags)
1895 {
1896     unsigned long unicodeChars;
1897     unsigned long srcCharsUsed;
1898     unsigned long usedByteLen = 0;
1899     UniChar uniStr[256];
1900     unsigned long cfResult;
1901
1902     cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1903                                               flags,
1904                                               (char*)inUTF8Buf,
1905                                               inUTF8BufLength,
1906                                               &srcCharsUsed,
1907                                               uniStr,
1908                                               255,
1909                                               &unicodeChars);
1910     if (cfResult == 0) {
1911         cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1912                                                   flags,
1913                                                   uniStr,
1914                                                   unicodeChars,
1915                                                   &srcCharsUsed,
1916                                                   (char*)outCStrBuffer,
1917                                                   outCStrBufferLength - 1,
1918                                                   &usedByteLen);
1919         outCStrBuffer[usedByteLen] = '\0';
1920     }
1921
1922     return cfResult;
1923 }
1924
1925 #elif HAVE_ICONV
1926 #include <iconv.h>
1927
1928 static int
1929 ConvertEncodingByIconv(const char *src, char *dst, int dstsize,
1930                        const char *srcEnc, const char *dstEnc)
1931 {
1932     iconv_t ic;
1933     static char szTmpBuf[2048];
1934     char *src_p;
1935     char *dst_p;
1936     size_t sLen;
1937     size_t iLen;
1938
1939     dst_p = &szTmpBuf[0];
1940     iLen = (size_t)sizeof(szTmpBuf)-1;
1941     src_p = (char *)src;
1942     sLen = (size_t)strlen(src);
1943     memset(szTmpBuf, 0, sizeof(szTmpBuf));
1944     memset(dst, 0, dstsize);
1945
1946     ic = iconv_open(dstEnc, srcEnc);
1947     if (ic == (iconv_t)-1) {
1948         error("iconv_open() failure: %s", strerror(errno));
1949         return -1;
1950     }
1951
1952     if (iconv(ic, &src_p, &sLen, &dst_p, &iLen) == (size_t)-1) {
1953         error("iconv() failure: %s", strerror(errno));
1954         iconv_close(ic);
1955         return -1;
1956     }
1957
1958     strncpy(dst, szTmpBuf, dstsize);
1959
1960     iconv_close(ic);
1961
1962     return 0;
1963 }
1964 #endif /* defined(__APPLE__) */
1965
1966 char *
1967 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1968 {
1969 #if defined(__APPLE__)
1970   dst[0] = '\0';
1971   if (ConvertEncodingToUTF8(src, dst, dstsize,
1972                             kCFStringEncodingDOSJapanese,
1973                             kCFStringEncodingUseHFSPlusCanonical) == 0)
1974       return dst;
1975 #elif HAVE_ICONV
1976   if (ConvertEncodingByIconv(src, dst, dstsize, "SJIS", "UTF-8") != -1)
1977       return dst;
1978 #else
1979   error("not support utf-8 conversion");
1980 #endif
1981
1982   if (dstsize < 1) return dst;
1983   dst[dstsize-1] = 0;
1984   return strncpy(dst, src, dstsize-1);
1985 }
1986
1987 char *
1988 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1989 {
1990 #if defined(__APPLE__)
1991   int srclen;
1992
1993   dst[0] = '\0';
1994   srclen = strlen(src);
1995   if (ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1996                             kCFStringEncodingDOSJapanese,
1997                             kCFStringEncodingUseHFSPlusCanonical) == 0)
1998       return dst;
1999 #elif HAVE_ICONV
2000   if (ConvertEncodingByIconv(src, dst, dstsize, "UTF-8", "SJIS") != -1)
2001       return dst;
2002 #else
2003   error("not support utf-8 conversion");
2004 #endif
2005
2006   if (dstsize < 1) return dst;
2007   dst[dstsize-1] = 0;
2008   return strncpy(dst, src, dstsize-1);
2009 }
2010
2011 /*
2012  * SJIS <-> EUC ÊÑ´¹´Ø¿ô
2013  * ¡ÖÆüËܸì¾ðÊó½èÍý¡×   ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
2014  *  ¤è¤êÈ´¿è(by Koji Arai)
2015  */
2016 void
2017 euc2sjis(int *p1, int *p2)
2018 {
2019     unsigned char c1 = *p1 & 0x7f;
2020     unsigned char c2 = *p2 & 0x7f;
2021     int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
2022     int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
2023     *p1 = ((c1 + 1) >> 1) + rowoff;
2024     *p2 += celoff - 0x80;
2025 }
2026
2027 void
2028 sjis2euc(int *p1, int *p2)
2029 {
2030     unsigned char c1 = *p1;
2031     unsigned char c2 = *p2;
2032     int adjust = c2 < 0x9f;
2033     int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
2034     int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
2035     *p1 = ((c1 - rowoff) << 1) - adjust;
2036     *p2 -= celoff;
2037
2038     *p1 |= 0x80;
2039     *p2 |= 0x80;
2040 }
2041
2042 static int
2043 hex2int(int c)
2044 {
2045     switch (c) {
2046     case '0': case '1': case '2': case '3': case '4':
2047     case '5': case '6': case '7': case '8': case '9':
2048         return c - '0';
2049
2050     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
2051         return c - 'a' + 10;
2052
2053     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
2054         return c - 'A' + 10;
2055     default:
2056         return -1;
2057     }
2058 }
2059
2060 static int
2061 int2hex(int c)
2062 {
2063     switch (c) {
2064     case 0: case 1: case 2: case 3: case 4:
2065     case 5: case 6: case 7: case 8: case 9:
2066         return c + '0';
2067
2068     case 10: case 11: case 12: case 13: case 14: case 15:
2069         return c + 'a' - 10;
2070
2071     default:
2072         return -1;
2073     }
2074 }
2075
2076 int
2077 cap_to_sjis(char *dst, const char *src, size_t dstsize)
2078 {
2079     int i, j;
2080     size_t len = strlen(src);
2081     int a, b;
2082
2083     for (i = j = 0; i < len && i < dstsize; i++) {
2084         if (src[i] != ':') {
2085             dst[j++] = src[i];
2086             continue;
2087         }
2088
2089         i++;
2090         a = hex2int((unsigned char)src[i]);
2091         b = hex2int((unsigned char)src[i+1]);
2092
2093         if (a == -1 || b == -1) {
2094             /* leave as it */
2095             dst[j++] = ':';
2096             strncpy(dst+j, src+i, dstsize-j);
2097             dst[dstsize-1] = 0;
2098             return strlen(dst);
2099         }
2100
2101         i++;
2102
2103         dst[j++] = a * 16 + b;
2104     }
2105     dst[j] = 0;
2106     return j;
2107 }
2108
2109 int
2110 sjis_to_cap(char *dst, const char *src, size_t dstsize)
2111 {
2112     int i, j;
2113     size_t len = strlen(src);
2114     int a, b;
2115
2116     for (i = j = 0; i < len && i < dstsize; i++) {
2117         if (src[i] == ':') {
2118             strncpy(dst+j, ":3a", dstsize-j);
2119             dst[dstsize-1] = 0;
2120             j = strlen(dst);
2121             continue;
2122         }
2123         if (isprint(src[i])) {
2124             dst[j++] = src[i];
2125             continue;
2126         }
2127
2128         if (j + 3 >= dstsize) {
2129             dst[j] = 0;
2130             return j;
2131         }
2132
2133         a = int2hex((unsigned char)src[i] / 16);
2134         b = int2hex((unsigned char)src[i] % 16);
2135
2136         dst[j++] = ':';
2137         dst[j++] = a;
2138         dst[j++] = b;
2139     }
2140     dst[j] = 0;
2141     return j;
2142 }
2143 #endif /* MULTIBYTE_FILENAME */