OSDN Git Service

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