OSDN Git Service

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