OSDN Git Service

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