OSDN Git Service

* src/lha.h, src/header.c: CoreFoundation header inclusion moved to
[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 #if !STRCHR_8BIT_CLEAN
17 /* should use 8 bit clean version */
18 #undef strchr
19 #undef strrchr
20 #define strchr  xstrchr
21 #define strrchr  xstrrchr
22 #endif
23
24 /* ------------------------------------------------------------------------ */
25 static char    *get_ptr;
26
27 int optional_archive_kanji_code = NONE;
28 int optional_system_kanji_code = NONE;
29 char *optional_archive_delim = NULL;
30 char *optional_system_delim = NULL;
31 int optional_filename_case = NONE;
32
33 #ifdef MULTIBYTE_FILENAME
34 int default_system_kanji_code = MULTIBYTE_FILENAME;
35 #else
36 int default_system_kanji_code = NONE;
37 #endif
38
39 /* ------------------------------------------------------------------------ */
40 int
41 calc_sum(p, len)
42         register char  *p;
43         register int    len;
44 {
45         register int    sum;
46
47         for (sum = 0; len; len--)
48                 sum += *p++;
49
50         return sum & 0xff;
51 }
52
53 /* ------------------------------------------------------------------------ */
54 static unsigned short
55 get_word()
56 {
57         int             b0, b1;
58
59         b0 = get_byte();
60         b1 = get_byte();
61         return (b1 << 8) + b0;
62 }
63
64 /* ------------------------------------------------------------------------ */
65 static void
66 put_word(v)
67         unsigned int    v;
68 {
69         put_byte(v);
70         put_byte(v >> 8);
71 }
72
73 /* ------------------------------------------------------------------------ */
74 static long
75 get_longword()
76 {
77         long            b0, b1, b2, b3;
78
79         b0 = get_byte();
80         b1 = get_byte();
81         b2 = get_byte();
82         b3 = get_byte();
83         return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
84 }
85
86 /* ------------------------------------------------------------------------ */
87 static void
88 put_longword(v)
89         long            v;
90 {
91         put_byte(v);
92         put_byte(v >> 8);
93         put_byte(v >> 16);
94         put_byte(v >> 24);
95 }
96
97 #if 0   /* no use */
98 /* ------------------------------------------------------------------------ */
99 static void
100 msdos_to_unix_filename(name, len)
101         register char  *name;
102         register int    len;
103 {
104         register int    i;
105
106 #ifdef MULTIBYTE_FILENAME
107         for (i = 0; i < len; i++) {
108                 if (MULTIBYTE_FIRST_P(name[i]) &&
109                     MULTIBYTE_SECOND_P(name[i + 1]))
110                         i++;
111                 else if (name[i] == '\\')
112                         name[i] = '/';
113                 else if (!noconvertcase && isupper(name[i]))
114                         name[i] = tolower(name[i]);
115         }
116 #else
117         for (i = 0; i < len; i++) {
118                 if (name[i] == '\\')
119                         name[i] = '/';
120                 else if (!noconvertcase && isupper(name[i]))
121                         name[i] = tolower(name[i]);
122         }
123 #endif
124 }
125
126 /* ------------------------------------------------------------------------ */
127 static void
128 generic_to_unix_filename(name, len)
129         register char  *name;
130         register int    len;
131 {
132         register int    i;
133         boolean         lower_case_used = FALSE;
134
135 #ifdef MULTIBYTE_FILENAME
136         for (i = 0; i < len; i++) {
137                 if (MULTIBYTE_FIRST_P(name[i]) &&
138                     MULTIBYTE_SECOND_P(name[i + 1]))
139                         i++;
140                 else if (islower(name[i])) {
141                         lower_case_used = TRUE;
142                         break;
143                 }
144         }
145         for (i = 0; i < len; i++) {
146                 if (MULTIBYTE_FIRST_P(name[i]) &&
147                     MULTIBYTE_SECOND_P(name[i + 1]))
148                         i++;
149                 else if (name[i] == '\\')
150                         name[i] = '/';
151                 else if (!noconvertcase && !lower_case_used && isupper(name[i]))
152                         name[i] = tolower(name[i]);
153         }
154 #else
155         for (i = 0; i < len; i++)
156                 if (islower(name[i])) {
157                         lower_case_used = TRUE;
158                         break;
159                 }
160         for (i = 0; i < len; i++) {
161                 if (name[i] == '\\')
162                         name[i] = '/';
163                 else if (!noconvertcase && !lower_case_used && isupper(name[i]))
164                         name[i] = tolower(name[i]);
165         }
166 #endif
167 }
168
169 /* ------------------------------------------------------------------------ */
170 static void
171 macos_to_unix_filename(name, len)
172         register char  *name;
173         register int    len;
174 {
175         register int    i;
176
177         for (i = 0; i < len; i++) {
178                 if (name[i] == ':')
179                         name[i] = '/';
180                 else if (name[i] == '/')
181                         name[i] = ':';
182         }
183 }
184
185 /* ------------------------------------------------------------------------ */
186 static void
187 unix_to_generic_filename(name, len)
188         register char  *name;
189         register int    len;
190 {
191         register int    i;
192
193         for (i = 0; i < len; i++) {
194                 if (name[i] == '/')
195                         name[i] = '\\';
196                 else if (islower(name[i]))
197                         name[i] = toupper(name[i]);
198         }
199 }
200 #endif /* 0 */
201
202 /* added by Koji Arai */
203 static void
204 convert_filename(name, len, size,
205                  from_code, to_code,
206                  from_delim, to_delim,
207                  case_to)
208         register char  *name;
209         register int    len;
210         register int    size;
211     int from_code, to_code, case_to;
212     char *from_delim, *to_delim;
213
214 {
215         register int    i;
216 #ifdef MULTIBYTE_FILENAME
217     char tmp[256];              /* 256 is sizeof(LzHeader.name) */
218
219     if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
220         for (i = 0; i < len; i++)
221             if ((unsigned char)name[i] == LHA_PATHSEP)  name[i] = '/';
222         sjis_to_utf8(tmp, name, sizeof(tmp));
223         strncpy(name, tmp, size);
224         name[size-1] = 0;
225         len = strlen(name);
226         for (i = 0; i < len; i++)
227             if (name[i] == '/')  name[i] = LHA_PATHSEP;
228         from_code = CODE_UTF8;
229     }
230     else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
231         for (i = 0; i < len; i++)
232             if ((unsigned char)name[i] == LHA_PATHSEP)  name[i] = '/';
233         utf8_to_sjis(tmp, name, sizeof(tmp));
234         strncpy(name, tmp, size);
235         name[size-1] = 0;
236         len = strlen(name);
237         for (i = 0; i < len; i++)
238             if (name[i] == '/')  name[i] = LHA_PATHSEP;
239         from_code = CODE_SJIS;
240     }
241 #endif
242
243         for (i = 0; i < len; i ++) {
244 #ifdef MULTIBYTE_FILENAME
245         if (from_code == CODE_EUC &&
246             (unsigned char)name[i] == 0x8e) {
247             if (to_code != CODE_SJIS) {
248                 i++;
249                 continue;
250             }
251
252             /* X0201 KANA */
253             memmove(name + i, name + i + 1, len - i);
254             len--;
255             continue;
256         }
257         if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
258             if (to_code != CODE_EUC) {
259                 continue;
260             }
261
262             if (len == size - 1) /* check overflow */
263                 len--;
264             memmove(name+i+1, name+i, len-i);
265             name[i] = 0x8e;
266             i++;
267             len++;
268             continue;
269         }
270                 if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
271                         int c1, c2;
272             if (to_code != CODE_SJIS) {
273                 i++;
274                 continue;
275             }
276
277                         c1 = (unsigned char)name[i];
278             c2 = (unsigned char)name[i+1];
279                         euc2sjis(&c1, &c2);
280                         name[i] = c1;
281             name[i+1] = c2;
282                         i++;
283             continue;
284                 }
285         if (from_code == CODE_SJIS &&
286             SJC_FIRST_P(name[i]) &&
287             SJC_SECOND_P(name[i+1])) {
288                         int c1, c2;
289
290             if (to_code != CODE_EUC) {
291                 i++;
292                 continue;
293             }
294
295                         c1 = (unsigned char)name[i];
296             c2 = (unsigned char)name[i+1];
297                         sjis2euc(&c1, &c2);
298                         name[i] = c1;
299             name[i+1] = c2;
300                         i++;
301             continue;
302         }
303 #endif /* MULTIBYTE_FILENAME */
304         {
305             char *ptr;
306
307             /* transpose from_delim to to_delim */
308
309             if ((ptr = strchr(from_delim, name[i])) != NULL) {
310                 name[i] = to_delim[ptr - from_delim];
311                 continue;
312             }
313         }
314
315                 if (case_to == TO_UPPER && islower(name[i])) {
316                         name[i] = toupper(name[i]);
317             continue;
318         }
319         if (case_to == TO_LOWER && isupper(name[i])) {
320                         name[i] = tolower(name[i]);
321             continue;
322         }
323         }
324 }
325
326 /* ------------------------------------------------------------------------ */
327 /*                                                                                                                                                      */
328 /* Generic stamp format:                                                                                                        */
329 /*                                                                                                                                                      */
330 /* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16                                                      */
331 /* |<-------- year ------->|<- month ->|<-- day -->|                                            */
332 /*                                                                                                                                                      */
333 /* 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0                                                      */
334 /* |<--- hour --->|<---- minute --->|<- second*2 ->|                                            */
335 /*                                                                                                                                                      */
336 /* ------------------------------------------------------------------------ */
337
338 /*
339  * NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
340  * returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or TZSET.
341  */
342
343 /* choose one */
344 #if defined(HAVE_MKTIME)
345 #ifdef HAVE_TIMELOCAL
346 #undef HAVE_TIMELOCAL
347 #endif
348 #endif                          /* defined(HAVE_MKTIME) */
349
350 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
351 #ifdef HAVE_TZSET
352 #undef HAVE_TZSET
353 #endif
354 #endif                          /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
355
356 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) || defined(HAVE_TZSET)
357 #ifdef HAVE_FTIME
358 #undef HAVE_FTIME
359 #endif
360 #endif
361
362 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) || defined(HAVE_TZSET) || defined(HAVE_FTIME)
363 #ifdef HAVE_GETTIMEOFDAY
364 #undef HAVE_GETTIMEOFDAY
365 #endif
366 #else
367 #ifndef HAVE_GETTIMEOFDAY
368 #define HAVE_GETTIMEOFDAY               /* use gettimeofday() */
369 #endif
370 #endif
371
372 #ifdef HAVE_FTIME
373 #include <sys/timeb.h>
374 #endif
375
376 /*
377  * You may define as : #define TIMEZONE_HOOK            \ extern long
378  * timezone ;   \ extern void tzset();
379  */
380 #ifdef TIMEZONE_HOOK
381 TIMEZONE_HOOK
382 /* Which do you like better, `TIMEZONE_HOOK' or `TIMEZONE_HOOK;' ? */
383 #endif
384
385 #if defined(HAVE_TZSET) && defined(_MINIX)
386 extern long     timezone;               /* not defined in time.h */
387 #endif
388
389 /* ------------------------------------------------------------------------ */
390 #if defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY) || defined(HAVE_TZSET)
391 static long
392 gettz()
393 #ifdef HAVE_TZSET
394 {
395         tzset();
396         return timezone;
397 }
398 #endif
399
400 /* ------------------------------------------------------------------------ */
401 #if !defined(HAVE_TZSET) && defined(HAVE_FTIME)
402 {
403         struct timeb    buf;
404
405         ftime(&buf);
406         return buf.timezone * 60L;
407 }
408 #endif
409
410 /* ------------------------------------------------------------------------ */
411 #if !defined(HAVE_TZSET) && !defined(HAVE_FTIME)        /* maybe defined(HAVE_GETTIMEOFDAY) */
412 {
413 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
414         time_t tt;
415
416         time(&tt);
417         return -localtime(&tt)->tm_gmtoff;
418 #else /* HAVE_STRUCT_TM_TM_GMTOFF */
419         struct timeval  tp;
420         struct timezone tzp;
421         gettimeofday(&tp, &tzp);/* specific to 4.3BSD */
422         /*
423          * return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L *
424          * 60L : 0));
425          */
426         return (tzp.tz_minuteswest * 60L);
427 #endif /* HAVE_STRUCT_TM_TM_GMTOFF */
428 }
429 #endif
430 #endif                          /* defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY) ||
431                      * defined(HAVE_TZSET) */
432
433 /* ------------------------------------------------------------------------ */
434 #ifdef NOT_USED
435 static struct tm *
436 msdos_to_unix_stamp_tm(a)
437         long            a;
438 {
439         static struct tm t;
440
441         t.tm_sec = (a & 0x1f) * 2;
442         t.tm_min = (a >> 5) & 0x3f;
443         t.tm_hour = (a >> 11) & 0x1f;
444         t.tm_mday = (a >> 16) & 0x1f;
445         t.tm_mon = ((a >> 16 + 5) & 0x0f) - 1;
446         t.tm_year = ((a >> 16 + 9) & 0x7f) + 80;
447         return &t;
448 }
449 #endif
450
451 /* ------------------------------------------------------------------------ */
452 static          time_t
453 generic_to_unix_stamp(t)
454         long            t;
455 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
456 {
457         struct tm       dostm;
458
459         /*
460          * special case:  if MSDOS format date and time were zero, then we
461          * set time to be zero here too.
462          */
463         if (t == 0)
464                 return (time_t) 0;
465
466         dostm.tm_sec = (t & 0x1f) * 2;
467         dostm.tm_min = t >> 5 & 0x3f;
468         dostm.tm_hour = t >> 11 & 0x1f;
469         dostm.tm_mday = t >> 16 & 0x1f;
470         dostm.tm_mon = (t >> 16 + 5 & 0x0f) - 1;        /* 0..11 */
471         dostm.tm_year = (t >> 16 + 9 & 0x7f) + 80;
472 #if 0
473         dostm.tm_isdst = 0;     /* correct? */
474 #endif
475         dostm.tm_isdst = -1;    /* correct? */
476 #ifdef HAVE_MKTIME
477         return (time_t) mktime(&dostm);
478 #else                           /* maybe defined(HAVE_TIMELOCAL) */
479         return (time_t) timelocal(&dostm);
480 #endif
481 }
482
483 #else                           /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
484 {
485         int             year, month, day, hour, min, sec;
486         long            longtime;
487         static unsigned int dsboy[12] = {0, 31, 59, 90, 120, 151,
488         181, 212, 243, 273, 304, 334};
489         unsigned int    days;
490
491         /*
492          * special case:  if MSDOS format date and time were zero, then we
493          * set time to be zero here too.
494          */
495         if (t == 0)
496                 return (time_t) 0;
497
498         year = ((int) (t >> 16 + 9) & 0x7f) + 1980;
499         month = (int) (t >> 16 + 5) & 0x0f;     /* 1..12 means Jan..Dec */
500         day = (int) (t >> 16) & 0x1f;   /* 1..31 means 1st,...31st */
501
502         hour = ((int) t >> 11) & 0x1f;
503         min = ((int) t >> 5) & 0x3f;
504         sec = ((int) t & 0x1f) * 2;
505
506         /* Calculate days since 1970.01.01 */
507         days = (365 * (year - 1970) +   /* days due to whole years */
508                 (year - 1970 + 1) / 4 + /* days due to leap years */
509                 dsboy[month - 1] +      /* days since beginning of this year */
510                 day - 1);       /* days since beginning of month */
511
512         if ((year % 4 == 0) &&
513                 (year % 100 != 0 || year % 400 == 0) &&         /* 1999.5.24 t.oka */
514             (month >= 3))       /* if this is a leap year and month */
515                 days++;         /* is March or later, add a day */
516
517         /* Knowing the days, we can find seconds */
518         longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
519         longtime += gettz();    /* adjust for timezone */
520
521         /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00.  */
522         return (time_t) longtime;
523 }
524 #endif                          /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
525
526 /* ------------------------------------------------------------------------ */
527 static long
528 unix_to_generic_stamp(t)
529         time_t          t;
530 {
531         struct tm      *tm = localtime(&t);
532
533         return ((((long) (tm->tm_year - 80)) << 25) +
534                 (((long) (tm->tm_mon + 1)) << 21) +
535                 (((long) tm->tm_mday) << 16) +
536                 (long) ((tm->tm_hour << 11) +
537                         (tm->tm_min << 5) +
538                         (tm->tm_sec / 2)));
539 }
540
541 /* ------------------------------------------------------------------------ */
542 /* build header functions                                                                                                       */
543 /* ------------------------------------------------------------------------ */
544 boolean
545 get_header(fp, hdr)
546         FILE           *fp;
547         register LzHeader *hdr;
548 {
549         int             header_size;
550         int             name_length;
551         char            data[LZHEADER_STRAGE];
552         char            dirname[FILENAME_LENGTH];
553         int             dir_length = 0;
554         int             checksum;
555         int             i;
556         char           *ptr;
557         int                             extend_size;
558         int                             dmy;
559
560     int archive_kanji_code = CODE_SJIS;
561     int system_kanji_code = default_system_kanji_code;
562     char *archive_delim = "";
563     char *system_delim = "";
564     int filename_case = NONE;
565
566         memset(hdr, 0, sizeof(LzHeader));
567
568         if (((header_size = getc(fp)) == EOF) || (header_size == 0)) {
569                 return FALSE;   /* finish */
570         }
571
572         if (fread(data + I_HEADER_CHECKSUM,
573                   sizeof(char), header_size - 1, fp) < header_size - 1) {
574                 fatal_error("Invalid header (LHarc file ?)");
575                 return FALSE;   /* finish */
576         }
577         setup_get(data + I_HEADER_LEVEL);
578         hdr->header_level = get_byte();
579         if (hdr->header_level != 2 &&
580             fread(data + header_size, sizeof(char), 2, fp) < 2) {
581                 fatal_error("Invalid header (LHarc file ?)");
582                 return FALSE;   /* finish */
583         }
584
585         if (hdr->header_level >= 3) {
586                 fatal_error("Unknown level header (level %d)", hdr->header_level);
587                 return FALSE;
588         }
589
590         setup_get(data + I_HEADER_CHECKSUM);
591         checksum = get_byte();
592
593         if (hdr->header_level == 2) {
594                 hdr->header_size = header_size + checksum*256;
595         } else {
596                 hdr->header_size = header_size;
597         }
598         memcpy(hdr->method, data + I_METHOD, METHOD_TYPE_STRAGE);
599         setup_get(data + I_PACKED_SIZE);
600         hdr->packed_size = get_longword();
601         hdr->original_size = get_longword();
602         hdr->last_modified_stamp = get_longword();
603         hdr->attribute = get_byte();
604
605         if ((hdr->header_level = get_byte()) != 2) {
606                 if (calc_sum(data + I_METHOD, header_size) != checksum)
607                         warning("Checksum error (LHarc file?)");
608                 name_length = get_byte();
609                 for (i = 0; i < name_length; i++)
610                         hdr->name[i] = (char) get_byte();
611                 hdr->name[name_length] = '\0';
612         }
613         else {
614                 hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
615                 name_length = 0;
616         }
617
618         /* defaults for other type */
619         hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
620         hdr->unix_gid = 0;
621         hdr->unix_uid = 0;
622
623         if (hdr->header_level == 0) {
624                 extend_size = header_size - name_length -22;
625                 if (extend_size < 0) {
626                         if (extend_size == -2) {
627                                 hdr->extend_type = EXTEND_GENERIC;
628                                 hdr->has_crc = FALSE;
629                         } else {
630                                 error("Unkonwn header (lha file?)");
631                 exit(1);
632                         }
633                 } else {
634                         hdr->has_crc = TRUE;
635                         hdr->crc = get_word();
636                 }
637
638                 if (extend_size >= 1) {
639                         hdr->extend_type = get_byte();
640                         extend_size--;
641                 }
642                 if (hdr->extend_type == EXTEND_UNIX) {
643                         if (extend_size >= 11) {
644                                 hdr->minor_version = get_byte();
645                                 hdr->unix_last_modified_stamp = (time_t) get_longword();
646                                 hdr->unix_mode = get_word();
647                                 hdr->unix_uid = get_word();
648                                 hdr->unix_gid = get_word();
649                                 extend_size -= 11;
650                         } else {
651                                 hdr->extend_type = EXTEND_GENERIC;
652                         }
653                 }
654                 while (extend_size-- > 0)
655                         dmy = get_byte();
656                 if (hdr->extend_type == EXTEND_UNIX)
657                         return TRUE;
658         } else if (hdr->header_level == 1) {
659                 hdr->has_crc = TRUE;
660                 extend_size = header_size - name_length-25;
661                 hdr->crc = get_word();
662                 hdr->extend_type = get_byte();
663                 while (extend_size-- > 0)
664                         dmy = get_byte();
665         } else { /* level 2 */
666                 hdr->has_crc = TRUE;
667                 hdr->crc = get_word();
668                 hdr->extend_type = get_byte();
669         }               
670
671         if (hdr->header_level > 0) {
672                 /* Extend Header */
673                 if (hdr->header_level != 2)
674                         setup_get(data + hdr->header_size);
675                 ptr = get_ptr;
676                 while ((header_size = get_word()) != 0) {
677                         if (hdr->header_level != 2 &&
678                         ((data + LZHEADER_STRAGE - get_ptr < header_size) ||
679                          fread(get_ptr, sizeof(char), header_size, fp) < header_size)) {
680                                 fatal_error("Invalid header (LHa file ?)");
681                                 return FALSE;
682                         }
683                         switch (get_byte()) {
684                         case 0:
685                                 /*
686                                  * header crc
687                                  */
688                                 setup_get(get_ptr + header_size - 3);
689                                 break;
690                         case 1:
691                                 /*
692                                  * filename
693                                  */
694                                 for (i = 0; i < header_size - 3; i++)
695                                         hdr->name[i] = (char) get_byte();
696                                 hdr->name[header_size - 3] = '\0';
697                                 name_length = header_size - 3;
698                                 break;
699                         case 2:
700                                 /*
701                                  * directory
702                                  */
703                                 for (i = 0; i < header_size - 3; i++)
704                                         dirname[i] = (char) get_byte();
705                                 dirname[header_size - 3] = '\0';
706                                 dir_length = header_size - 3;
707                                 break;
708                         case 0x40:
709                                 /*
710                                  * MS-DOS attribute
711                                  */
712                                 if (hdr->extend_type == EXTEND_MSDOS ||
713                                     hdr->extend_type == EXTEND_HUMAN ||
714                                     hdr->extend_type == EXTEND_GENERIC)
715                                         hdr->attribute = get_word();
716                                 break;
717                         case 0x50:
718                                 /*
719                                  * UNIX permission
720                                  */
721                                 if (hdr->extend_type == EXTEND_UNIX)
722                                         hdr->unix_mode = get_word();
723                                 break;
724                         case 0x51:
725                                 /*
726                                  * UNIX gid and uid
727                                  */
728                                 if (hdr->extend_type == EXTEND_UNIX) {
729                                         hdr->unix_gid = get_word();
730                                         hdr->unix_uid = get_word();
731                                 }
732                                 break;
733                         case 0x52:
734                                 /*
735                                  * UNIX group name
736                                  */
737                 for (i = 0; i < header_size - 3; i++)
738                     hdr->group[i] = get_byte();
739                 hdr->group[i] = '\0';
740                                 break;
741                         case 0x53:
742                                 /*
743                                  * UNIX user name
744                                  */
745                 for (i = 0; i < header_size - 3; i++)
746                     hdr->user[i] = get_byte();
747                 hdr->user[i] = '\0';
748                                 break;
749                         case 0x54:
750                                 /*
751                                  * UNIX last modified time
752                                  */
753                                 if (hdr->extend_type == EXTEND_UNIX)
754                                         hdr->unix_last_modified_stamp = (time_t) get_longword();
755                                 break;
756                         default:
757                                 /*
758                                  * other headers
759                                  */
760                                 setup_get(get_ptr + header_size - 3);
761                                 break;
762                         }
763                 }
764                 if (hdr->header_level != 2 && get_ptr - ptr != 2) {
765                         hdr->packed_size -= get_ptr - ptr - 2;
766                         hdr->header_size += get_ptr - ptr - 2;
767                 }
768         }
769
770         switch (hdr->extend_type) {
771         case EXTEND_MSDOS:
772         archive_delim = "\xff\\";
773         system_delim = "//";
774         filename_case = noconvertcase ? NONE : TO_LOWER;
775
776         /* fall through */
777         case EXTEND_HUMAN:
778                 if (hdr->header_level == 2)
779                         hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
780                 else
781                         hdr->unix_last_modified_stamp =
782                                 generic_to_unix_stamp(hdr->last_modified_stamp);
783                 break;
784
785 #ifdef OSK
786         case EXTEND_OS68K:
787         case EXTEND_XOSK:
788 #endif
789         case EXTEND_UNIX:
790         archive_delim = "\xff";
791         system_delim = "//";
792         filename_case = NONE;
793
794                 break;
795
796         case EXTEND_MACOS:
797         archive_delim = "\xff/:";
798         system_delim = "/:/";
799         filename_case = NONE;
800
801                 hdr->unix_last_modified_stamp =
802                         generic_to_unix_stamp(hdr->last_modified_stamp, sizeof(hdr->name));
803                 break;
804
805         default:
806         archive_delim = "\xff\\";
807         system_delim = "//";
808         filename_case = noconvertcase ? NONE : TO_LOWER;
809         /* FIXME: if small letter is included in filename,
810            the generic_to_unix_filename() do not case conversion,
811            but this code does not consider it. */
812
813                 if (hdr->header_level == 2)
814                         hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
815                 else
816                         hdr->unix_last_modified_stamp =
817                                 generic_to_unix_stamp(hdr->last_modified_stamp);
818         }
819
820     /* filename kanji code and delimiter conversion */
821     if (optional_archive_kanji_code)
822         archive_kanji_code = optional_archive_kanji_code;
823     if (optional_system_kanji_code)
824         system_kanji_code = optional_system_kanji_code;
825     if (optional_archive_delim)
826         archive_delim = optional_archive_delim;
827     if (optional_system_delim)
828         system_delim = optional_system_delim;
829     if (optional_filename_case)
830         filename_case = optional_filename_case;
831
832         if (dir_length) {
833                 strcat(dirname, hdr->name);
834                 strcpy(hdr->name, dirname);
835                 name_length += dir_length;
836         }
837
838     convert_filename(hdr->name, name_length, sizeof(hdr->name),
839                      archive_kanji_code,
840                      system_kanji_code,
841                      archive_delim, system_delim, filename_case);
842
843         return TRUE;
844 }
845
846 /* ------------------------------------------------------------------------ */
847 void
848 init_header(name, v_stat, hdr)
849         char           *name;
850         struct stat    *v_stat;
851         LzHeader       *hdr;
852 {
853         int             len;
854
855     int system_kanji_code = default_system_kanji_code;
856     char *archive_delim = "";
857     char *system_delim = "";
858     int filename_case = NONE;
859
860     memset(hdr, 0, sizeof(LzHeader));
861
862     if (optional_system_kanji_code)
863         system_kanji_code = optional_system_kanji_code;
864
865         if (compress_method == LZHUFF5_METHOD_NUM)  /* Changed N.Watazaki */
866                 memcpy(hdr->method, LZHUFF5_METHOD, METHOD_TYPE_STRAGE);
867         else if (compress_method)
868                 memcpy(hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE);
869         else
870                 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE);
871
872         hdr->packed_size = 0;
873         hdr->original_size = v_stat->st_size;
874         hdr->last_modified_stamp = unix_to_generic_stamp(v_stat->st_mtime);
875         hdr->attribute = GENERIC_ATTRIBUTE;
876         hdr->header_level = header_level;
877         strcpy(hdr->name, name);
878         len = strlen(name);
879         hdr->crc = 0x0000;
880         hdr->extend_type = EXTEND_UNIX;
881         hdr->unix_last_modified_stamp = v_stat->st_mtime;
882         /* since 00:00:00 JAN.1.1970 */
883 #ifdef NOT_COMPATIBLE_MODE
884         /* Please need your modification in this space. */
885 #else
886         hdr->unix_mode = v_stat->st_mode;
887 #endif
888
889         hdr->unix_uid = v_stat->st_uid;
890         hdr->unix_gid = v_stat->st_gid;
891
892 #if INCLUDE_OWNER_NAME_IN_HEADER
893 #if HAVE_GETPWUID
894     {
895         struct passwd *ent = getpwuid(hdr->unix_uid);
896
897         if (ent) {
898             strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
899             if (hdr->user[sizeof(hdr->user)-1])
900                 hdr->user[sizeof(hdr->user)-1] = 0;
901         }
902     }
903 #endif
904 #if HAVE_GETGRGID
905     {
906         struct group *ent = getgrgid(hdr->unix_gid);
907
908         if (ent) {
909             strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
910             if (hdr->group[sizeof(hdr->group)-1])
911                 hdr->group[sizeof(hdr->group)-1] = 0;
912         }
913     }
914 #endif
915 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
916         if (is_directory(v_stat)) {
917                 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STRAGE);
918                 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
919                 hdr->original_size = 0;
920                 if (len > 0 && hdr->name[len - 1] != '/')
921                         strcpy(&hdr->name[len++], "/");
922         }
923
924 #ifdef S_IFLNK  
925         if (is_symlink(v_stat)) {
926                 char    lkname[256];    /* FIXME: no enough space */
927                 int             len;    
928                 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STRAGE);
929                 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
930                 hdr->original_size = 0;
931                 len = readlink(name, lkname, sizeof(lkname));
932                 if (xsnprintf(hdr->name, sizeof(hdr->name),
933                       "%s|%.*s", hdr->name, len, lkname) == -1)
934             error("file name is too long (%s -> %.*s)", hdr->name, len, lkname);
935         }
936 #endif
937
938         if (generic_format) {
939         filename_case = TO_UPPER;
940         archive_delim = "\\";
941     }
942
943     convert_filename(hdr->name, len, sizeof(hdr->name),
944                      system_kanji_code,
945                      system_kanji_code, /* no change code */
946                      system_delim, archive_delim, filename_case);
947 }
948
949 /* ------------------------------------------------------------------------ */
950 /* Write unix extended header or generic header. */
951 void
952 write_header(nafp, hdr)
953         FILE           *nafp;
954         LzHeader       *hdr;
955 {
956         int             header_size;
957         int             name_length;
958         char            data[LZHEADER_STRAGE];
959         char           *p;
960         char           *headercrc_ptr;
961     int archive_kanji_code = CODE_SJIS;
962     int system_kanji_code = default_system_kanji_code;
963         char            lzname[256];
964
965     if (optional_archive_kanji_code)
966         archive_kanji_code = optional_archive_kanji_code;
967     if (optional_system_kanji_code)
968         system_kanji_code = optional_system_kanji_code;
969
970         memset(data, 0, LZHEADER_STRAGE);
971         memcpy(data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE);
972         setup_put(data + I_PACKED_SIZE);
973         put_longword(hdr->packed_size);
974         put_longword(hdr->original_size);
975
976         if (hdr->header_level == HEADER_LEVEL2)
977                 put_longword((long) hdr->unix_last_modified_stamp);
978         else
979                 put_longword(hdr->last_modified_stamp);
980
981         switch (hdr->header_level) {
982         case HEADER_LEVEL0:
983                 put_byte(hdr->attribute);
984                 break;
985         case HEADER_LEVEL1:
986         case HEADER_LEVEL2:
987                 put_byte(0x20);
988                 break;
989         }
990
991         put_byte(hdr->header_level);
992
993     strncpy(lzname, hdr->name, sizeof(lzname));
994     convert_filename(lzname, strlen(lzname), sizeof(lzname),
995                      system_kanji_code,
996                      archive_kanji_code,
997                      "\xff\\/", "\xff\xff\xff", NONE);
998
999         if (hdr->header_level != HEADER_LEVEL2) {
1000                 if (p = strrchr(lzname, LHA_PATHSEP))
1001                         name_length = strlen(++p);
1002                 else
1003                         name_length = strlen(lzname);
1004                 put_byte(name_length);
1005                 memcpy(data + I_NAME, p ? p : lzname, name_length);
1006                 setup_put(data + I_NAME + name_length);
1007         }
1008
1009         put_word(hdr->crc);
1010         if (header_level == HEADER_LEVEL0) {
1011                 if (generic_format) {
1012                         header_size = I_GENERIC_HEADER_BOTTOM - 2 + name_length;
1013                         data[I_HEADER_SIZE] = header_size;
1014                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1015                 } else {
1016                         /* write old-style extend header */
1017                         put_byte(EXTEND_UNIX);
1018                         put_byte(CURRENT_UNIX_MINOR_VERSION);
1019                         put_longword((long) hdr->unix_last_modified_stamp);
1020                         put_word(hdr->unix_mode);
1021                         put_word(hdr->unix_uid);
1022                         put_word(hdr->unix_gid);
1023                         header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length;
1024                         data[I_HEADER_SIZE] = header_size;
1025                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1026                 }
1027         } else {
1028                 /* write extend header. */
1029                 char           *ptr;
1030
1031                 if (generic_format)
1032                         put_byte(0x00);
1033                 else
1034                         put_byte(EXTEND_UNIX);
1035
1036                 ptr = put_ptr;
1037                 if (hdr->header_level == HEADER_LEVEL2) {
1038                         /* write common header */
1039                         put_word(5);
1040                         put_byte(0x00);
1041                         headercrc_ptr = put_ptr;
1042                         put_word(0x0000);
1043                 }
1044
1045                 if (generic_format) {
1046                         header_size = put_ptr - data;   /* +2 for last 0x0000 */
1047                 } else {
1048                         put_word(5);
1049                         if (hdr->header_level == HEADER_LEVEL1)
1050                                 header_size = put_ptr - data - 2;
1051                         put_byte(0x50); /* permission */
1052                         put_word(hdr->unix_mode);
1053                         put_word(7);
1054                         put_byte(0x51); /* gid and uid */
1055                         put_word(hdr->unix_gid);
1056                         put_word(hdr->unix_uid);
1057
1058             {
1059                 int i, len = strlen(hdr->group);
1060                 put_word(len + 3);
1061                 put_byte(0x52); /* group name */
1062                 for (i = 0; i < len; i++)
1063                     put_byte(hdr->group[i]);
1064
1065                 len = strlen(hdr->user);
1066                 put_word(len + 3);
1067                 put_byte(0x53); /* user name */
1068                 for (i = 0; i < len; i++)
1069                     put_byte(hdr->user[i]);
1070             }
1071
1072                         if (p = strrchr(lzname, LHA_PATHSEP)) {
1073                                 int             i;
1074
1075                                 name_length = p - lzname + 1;
1076                                 put_word(name_length + 3);
1077                                 put_byte(2);    /* dirname */
1078                                 for (i = 0; i < name_length; i++)
1079                                         put_byte(lzname[i]);
1080                         }
1081                 }               /* if generic .. */
1082
1083                 if (header_level != HEADER_LEVEL2) {
1084                         if (!generic_format) {
1085                                 put_word(7);
1086                                 put_byte(0x54); /* time stamp */
1087                                 put_longword(hdr->unix_last_modified_stamp);
1088                         }
1089                         hdr->packed_size += put_ptr - ptr;
1090                         ptr = put_ptr;
1091                         setup_put(data + I_PACKED_SIZE);
1092                         put_longword(hdr->packed_size);
1093                         put_ptr = ptr;
1094                         data[I_HEADER_SIZE] = header_size;
1095                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1096                 } else {                /* header level 2 */
1097                         int             i;
1098                         if (p = strrchr(lzname, LHA_PATHSEP))
1099                                 name_length = strlen(++p);
1100                         else {
1101                                 p = lzname;
1102                                 name_length = strlen(lzname);
1103                         }
1104                         put_word(name_length + 3);
1105                         put_byte(1);    /* filename */
1106                         for (i = 0; i < name_length; i++)
1107                                 put_byte(*p++);
1108                 }               /* if he.. != HEAD_LV2 */
1109                 header_size = put_ptr - data;
1110         }
1111
1112         if (header_level == HEADER_LEVEL2) {
1113                 unsigned short  hcrc;
1114                 setup_put(data + I_HEADER_SIZE);
1115                 put_word(header_size + 2);
1116                 /* common header */
1117                 hcrc = calc_header_crc(data, (unsigned int) header_size + 2);
1118                 setup_put(headercrc_ptr);
1119                 put_word(hcrc);
1120         }
1121
1122         if (fwrite(data, header_size + 2, 1, nafp) == 0)
1123                 fatal_error("Cannot write to temporary file");
1124 }
1125
1126 #ifdef __APPLE__
1127
1128 #include <CoreFoundation/CFString.h>
1129 #include <CoreFoundation/CFStringEncodingExt.h>
1130
1131 /* this is not need for Mac OS X v 10.2 later */
1132 enum {
1133   kCFStringEncodingAllowLossyConversion = 1,
1134   kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1135   kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1136   kCFStringEncodingSubstituteCombinings = (1 << 3),
1137   kCFStringEncodingComposeCombinings = (1 << 4),
1138   kCFStringEncodingIgnoreCombinings = (1 << 5),
1139   kCFStringEncodingUseCanonical = (1 << 6),
1140   kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1141   kCFStringEncodingPrependBOM = (1 << 8),
1142   kCFStringEncodingDisableCorporateArea = (1 << 9),
1143   kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1144 };
1145
1146 static int
1147 ConvertEncodingToUTF8(const char* inCStr,
1148                       char* outUTF8Buffer,
1149                       int outUTF8BufferLength,
1150                       unsigned long scriptEncoding,
1151                       unsigned long flags)
1152 {
1153     unsigned long unicodeChars;
1154     unsigned long srcCharsUsed;
1155     unsigned long usedByteLen = 0;
1156     UniChar uniStr[512];
1157     unsigned long cfResult;
1158
1159     cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1160                                               flags,
1161                                               (char *)inCStr,
1162                                               strlen(inCStr),
1163                                               &srcCharsUsed,
1164                                               uniStr,
1165                                               512,
1166                                               &unicodeChars);
1167     if (cfResult == 0) {
1168         cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1169                                                   flags,
1170                                                   uniStr,
1171                                                   unicodeChars,
1172                                                   &srcCharsUsed,
1173                                                   (char*)outUTF8Buffer,
1174                                                   outUTF8BufferLength - 1,
1175                                                   &usedByteLen);
1176         outUTF8Buffer[usedByteLen] = '\0';
1177     }
1178
1179     return cfResult;
1180 }
1181
1182 static int
1183 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1184                       int inUTF8BufLength,
1185                       char* outCStrBuffer,
1186                       int outCStrBufferLength,
1187                       unsigned long scriptEncoding,
1188                       unsigned long flags)
1189 {
1190     unsigned long unicodeChars;
1191     unsigned long srcCharsUsed;
1192     unsigned long usedByteLen = 0;
1193     UniChar uniStr[256];
1194     unsigned long cfResult;
1195
1196     cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1197                                               flags,
1198                                               (char*)inUTF8Buf,
1199                                               inUTF8BufLength,
1200                                               &srcCharsUsed,
1201                                               uniStr,
1202                                               255,
1203                                               &unicodeChars);
1204     if (cfResult == 0) {
1205         cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1206                                                   flags,
1207                                                   uniStr,
1208                                                   unicodeChars,
1209                                                   &srcCharsUsed,
1210                                                   (char*)outCStrBuffer,
1211                                                   outCStrBufferLength - 1,
1212                                                   &usedByteLen);
1213         outCStrBuffer[usedByteLen] = '\0';
1214     }
1215
1216     return cfResult;
1217 }
1218 #endif /* __APPLE__ */
1219
1220 char *
1221 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1222 {
1223 #ifdef __APPLE__
1224   dst[0] = '\0';
1225   ConvertEncodingToUTF8(src, dst, dstsize,
1226                         kCFStringEncodingDOSJapanese,
1227                         kCFStringEncodingUseHFSPlusCanonical);
1228
1229 #else
1230   /* not supported */
1231 #endif
1232   return dst;
1233 }
1234
1235 char *
1236 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1237 {
1238 #ifdef __APPLE__
1239   int srclen;
1240
1241   dst[0] = '\0';
1242   srclen = strlen(src);
1243   ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1244                         kCFStringEncodingDOSJapanese,
1245                         kCFStringEncodingUseHFSPlusCanonical);
1246 #else
1247   /* not supported */
1248 #endif
1249   return dst;
1250 }
1251
1252 /*
1253  * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1254  * ¡ÖÆüËܸì¾ðÊó½èÍý¡×   ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1255  *      ¤è¤êÈ´¿è(by Koji Arai)
1256  */
1257 void
1258 euc2sjis(int *p1, int *p2)
1259 {
1260     unsigned char c1 = *p1 & 0x7f;
1261     unsigned char c2 = *p2 & 0x7f;
1262     int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1263     int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1264     *p1 = ((c1 + 1) >> 1) + rowoff;
1265     *p2 += celoff - 0x80;
1266 }
1267
1268 void
1269 sjis2euc(int *p1, int *p2)
1270 {
1271     unsigned char c1 = *p1;
1272     unsigned char c2 = *p2;
1273     int adjust = c2 < 0x9f;
1274     int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1275     int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1276     *p1 = ((c1 - rowoff) << 1) - adjust;
1277     *p2 -= celoff;
1278
1279     *p1 |= 0x80;
1280     *p2 |= 0x80;
1281 }
1282
1283 /* Local Variables: */
1284 /* mode:c */
1285 /* tab-width:4 */
1286 /* compile-command:"gcc -c header.c" */
1287 /* End: */
1288 /* vi: set tabstop=4: */