OSDN Git Service

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