OSDN Git Service

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