OSDN Git Service

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