OSDN Git Service

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