OSDN Git Service

* src/header.c (get_header): Should convert kanji code and path
[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         } else if (hdr->header_level == 1) {
657                 hdr->has_crc = TRUE;
658                 extend_size = header_size - name_length-25;
659                 hdr->crc = get_word();
660                 hdr->extend_type = get_byte();
661                 while (extend_size-- > 0)
662                         dmy = get_byte();
663         } else { /* level 2 */
664                 hdr->has_crc = TRUE;
665                 hdr->crc = get_word();
666                 hdr->extend_type = get_byte();
667         }               
668
669         if (hdr->header_level > 0) {
670                 /* Extend Header */
671                 if (hdr->header_level != 2)
672                         setup_get(data + hdr->header_size);
673                 ptr = get_ptr;
674                 while ((header_size = get_word()) != 0) {
675                         if (hdr->header_level != 2 &&
676                         ((data + LZHEADER_STRAGE - get_ptr < header_size) ||
677                          fread(get_ptr, sizeof(char), header_size, fp) < header_size)) {
678                                 fatal_error("Invalid header (LHa file ?)");
679                                 return FALSE;
680                         }
681                         switch (get_byte()) {
682                         case 0:
683                                 /*
684                                  * header crc
685                                  */
686                                 setup_get(get_ptr + header_size - 3);
687                                 break;
688                         case 1:
689                                 /*
690                                  * filename
691                                  */
692                                 for (i = 0; i < header_size - 3; i++)
693                                         hdr->name[i] = (char) get_byte();
694                                 hdr->name[header_size - 3] = '\0';
695                                 name_length = header_size - 3;
696                                 break;
697                         case 2:
698                                 /*
699                                  * directory
700                                  */
701                                 for (i = 0; i < header_size - 3; i++)
702                                         dirname[i] = (char) get_byte();
703                                 dirname[header_size - 3] = '\0';
704                                 dir_length = header_size - 3;
705                                 break;
706                         case 0x40:
707                                 /*
708                                  * MS-DOS attribute
709                                  */
710                                 if (hdr->extend_type == EXTEND_MSDOS ||
711                                     hdr->extend_type == EXTEND_HUMAN ||
712                                     hdr->extend_type == EXTEND_GENERIC)
713                                         hdr->attribute = get_word();
714                                 break;
715                         case 0x50:
716                                 /*
717                                  * UNIX permission
718                                  */
719                                 if (hdr->extend_type == EXTEND_UNIX)
720                                         hdr->unix_mode = get_word();
721                                 break;
722                         case 0x51:
723                                 /*
724                                  * UNIX gid and uid
725                                  */
726                                 if (hdr->extend_type == EXTEND_UNIX) {
727                                         hdr->unix_gid = get_word();
728                                         hdr->unix_uid = get_word();
729                                 }
730                                 break;
731                         case 0x52:
732                                 /*
733                                  * UNIX group name
734                                  */
735                 for (i = 0; i < header_size - 3; i++)
736                     hdr->group[i] = get_byte();
737                 hdr->group[i] = '\0';
738                                 break;
739                         case 0x53:
740                                 /*
741                                  * UNIX user name
742                                  */
743                 for (i = 0; i < header_size - 3; i++)
744                     hdr->user[i] = get_byte();
745                 hdr->user[i] = '\0';
746                                 break;
747                         case 0x54:
748                                 /*
749                                  * UNIX last modified time
750                                  */
751                                 if (hdr->extend_type == EXTEND_UNIX)
752                                         hdr->unix_last_modified_stamp = (time_t) get_longword();
753                                 break;
754                         default:
755                                 /*
756                                  * other headers
757                                  */
758                                 setup_get(get_ptr + header_size - 3);
759                                 break;
760                         }
761                 }
762                 if (hdr->header_level != 2 && get_ptr - ptr != 2) {
763                         hdr->packed_size -= get_ptr - ptr - 2;
764                         hdr->header_size += get_ptr - ptr - 2;
765                 }
766         }
767
768         switch (hdr->extend_type) {
769         case EXTEND_MSDOS:
770         archive_delim = "\xff\\";
771                           /* `\' is for level 0 header and broken archive. */
772         system_delim = "//";
773         filename_case = noconvertcase ? NONE : TO_LOWER;
774
775         /* fall through */
776         case EXTEND_HUMAN:
777                 if (hdr->header_level == 2)
778                         hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
779                 else
780                         hdr->unix_last_modified_stamp =
781                                 generic_to_unix_stamp(hdr->last_modified_stamp);
782                 break;
783
784 #ifdef OSK
785         case EXTEND_OS68K:
786         case EXTEND_XOSK:
787 #endif
788         case EXTEND_UNIX:
789         archive_delim = "\xff\\";
790                           /* `\' is for level 0 header and broken archive. */
791         system_delim = "//";
792         filename_case = NONE;
793
794                 break;
795
796         case EXTEND_MACOS:
797         archive_delim = "\xff/:\\";
798                           /* `\' is for level 0 header and broken archive. */
799         system_delim = "/://";
800         filename_case = NONE;
801
802                 hdr->unix_last_modified_stamp =
803                         generic_to_unix_stamp(hdr->last_modified_stamp, sizeof(hdr->name));
804                 break;
805
806         default:
807         archive_delim = "\xff\\";
808                           /* `\' is for level 0 header and broken archive. */
809         system_delim = "//";
810         filename_case = noconvertcase ? NONE : TO_LOWER;
811         /* FIXME: if small letter is included in filename,
812            the generic_to_unix_filename() do not case conversion,
813            but this code does not consider it. */
814
815                 if (hdr->header_level == 2)
816                         hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
817                 else
818                         hdr->unix_last_modified_stamp =
819                                 generic_to_unix_stamp(hdr->last_modified_stamp);
820         }
821
822     /* filename kanji code and delimiter conversion */
823     if (optional_archive_kanji_code)
824         archive_kanji_code = optional_archive_kanji_code;
825     if (optional_system_kanji_code)
826         system_kanji_code = optional_system_kanji_code;
827     if (optional_archive_delim)
828         archive_delim = optional_archive_delim;
829     if (optional_system_delim)
830         system_delim = optional_system_delim;
831     if (optional_filename_case)
832         filename_case = optional_filename_case;
833
834         if (dir_length) {
835                 strcat(dirname, hdr->name);
836                 strcpy(hdr->name, dirname);
837                 name_length += dir_length;
838         }
839
840     convert_filename(hdr->name, name_length, sizeof(hdr->name),
841                      archive_kanji_code,
842                      system_kanji_code,
843                      archive_delim, system_delim, filename_case);
844
845         return TRUE;
846 }
847
848 /* ------------------------------------------------------------------------ */
849 void
850 init_header(name, v_stat, hdr)
851         char           *name;
852         struct stat    *v_stat;
853         LzHeader       *hdr;
854 {
855         int             len;
856
857     memset(hdr, 0, sizeof(LzHeader));
858
859         if (compress_method == LZHUFF5_METHOD_NUM)  /* Changed N.Watazaki */
860                 memcpy(hdr->method, LZHUFF5_METHOD, METHOD_TYPE_STRAGE);
861         else if (compress_method)
862                 memcpy(hdr->method, LZHUFF1_METHOD, METHOD_TYPE_STRAGE);
863         else
864                 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STRAGE);
865
866         hdr->packed_size = 0;
867         hdr->original_size = v_stat->st_size;
868         hdr->last_modified_stamp = unix_to_generic_stamp(v_stat->st_mtime);
869         hdr->attribute = GENERIC_ATTRIBUTE;
870         hdr->header_level = header_level;
871         strcpy(hdr->name, name);
872         len = strlen(name);
873         hdr->crc = 0x0000;
874         hdr->extend_type = EXTEND_UNIX;
875         hdr->unix_last_modified_stamp = v_stat->st_mtime;
876         /* since 00:00:00 JAN.1.1970 */
877 #ifdef NOT_COMPATIBLE_MODE
878         /* Please need your modification in this space. */
879 #else
880         hdr->unix_mode = v_stat->st_mode;
881 #endif
882
883         hdr->unix_uid = v_stat->st_uid;
884         hdr->unix_gid = v_stat->st_gid;
885
886 #if INCLUDE_OWNER_NAME_IN_HEADER
887 #if HAVE_GETPWUID
888     {
889         struct passwd *ent = getpwuid(hdr->unix_uid);
890
891         if (ent) {
892             strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
893             if (hdr->user[sizeof(hdr->user)-1])
894                 hdr->user[sizeof(hdr->user)-1] = 0;
895         }
896     }
897 #endif
898 #if HAVE_GETGRGID
899     {
900         struct group *ent = getgrgid(hdr->unix_gid);
901
902         if (ent) {
903             strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
904             if (hdr->group[sizeof(hdr->group)-1])
905                 hdr->group[sizeof(hdr->group)-1] = 0;
906         }
907     }
908 #endif
909 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
910         if (is_directory(v_stat)) {
911                 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STRAGE);
912                 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
913                 hdr->original_size = 0;
914                 if (len > 0 && hdr->name[len - 1] != '/')
915                         strcpy(&hdr->name[len++], "/");
916         }
917
918 #ifdef S_IFLNK  
919         if (is_symlink(v_stat)) {
920                 char    lkname[256];    /* FIXME: no enough space */
921                 int             len;    
922                 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STRAGE);
923                 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
924                 hdr->original_size = 0;
925                 len = readlink(name, lkname, sizeof(lkname));
926                 if (xsnprintf(hdr->name, sizeof(hdr->name),
927                       "%s|%.*s", hdr->name, len, lkname) == -1)
928             error("file name is too long (%s -> %.*s)", hdr->name, len, lkname);
929         }
930 #endif
931 }
932
933 /* ------------------------------------------------------------------------ */
934 /* Write unix extended header or generic header. */
935 void
936 write_header(nafp, hdr)
937         FILE           *nafp;
938         LzHeader       *hdr;
939 {
940         int             header_size;
941         int             name_length;
942         char            data[LZHEADER_STRAGE];
943         char           *p;
944         char           *headercrc_ptr;
945
946     int archive_kanji_code = CODE_SJIS;
947     int system_kanji_code = default_system_kanji_code;
948     char *archive_delim = "\xff";
949     char *system_delim = "/";
950     int filename_case = NONE;
951         char lzname[256];
952
953     if (optional_archive_kanji_code)
954         archive_kanji_code = optional_archive_kanji_code;
955     if (optional_system_kanji_code)
956         system_kanji_code = optional_system_kanji_code;
957
958         memset(data, 0, LZHEADER_STRAGE);
959         memcpy(data + I_METHOD, hdr->method, METHOD_TYPE_STRAGE);
960         setup_put(data + I_PACKED_SIZE);
961         put_longword(hdr->packed_size);
962         put_longword(hdr->original_size);
963
964         if (hdr->header_level == HEADER_LEVEL2)
965                 put_longword((long) hdr->unix_last_modified_stamp);
966         else
967                 put_longword(hdr->last_modified_stamp);
968
969         switch (hdr->header_level) {
970         case HEADER_LEVEL0:
971                 put_byte(hdr->attribute);
972                 break;
973         case HEADER_LEVEL1:
974         case HEADER_LEVEL2:
975                 put_byte(0x20);
976                 break;
977         }
978
979         put_byte(hdr->header_level);
980
981     if (generic_format)
982         filename_case = TO_UPPER;
983
984         if (hdr->header_level == HEADER_LEVEL0) {
985         archive_delim = "\\";
986     }
987
988     strncpy(lzname, hdr->name, sizeof(lzname));
989     convert_filename(lzname, strlen(lzname), sizeof(lzname),
990                      system_kanji_code,
991                      archive_kanji_code,
992                      system_delim, archive_delim, filename_case);
993
994         if (hdr->header_level != HEADER_LEVEL2) {
995         if (hdr->header_level == HEADER_LEVEL0 ||
996             (p = strchr(lzname, LHA_PATHSEP)) == 0)
997             p = lzname;
998         else
999             ++p;
1000         /* level 0 header: write pathname (contain the directory part) */
1001         /* level 1 header: write filename (basename) */
1002         name_length = strlen(p);
1003                 put_byte(name_length);
1004                 memcpy(data + I_NAME, p, name_length);
1005                 setup_put(data + I_NAME + name_length);
1006         }
1007
1008         put_word(hdr->crc);
1009         if (header_level == HEADER_LEVEL0) {
1010                 if (generic_format) {
1011                         header_size = I_GENERIC_HEADER_BOTTOM - 2 + name_length;
1012                         data[I_HEADER_SIZE] = header_size;
1013                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1014                 } else {
1015                         /* write old-style extend header */
1016                         put_byte(EXTEND_UNIX);
1017                         put_byte(CURRENT_UNIX_MINOR_VERSION);
1018                         put_longword((long) hdr->unix_last_modified_stamp);
1019                         put_word(hdr->unix_mode);
1020                         put_word(hdr->unix_uid);
1021                         put_word(hdr->unix_gid);
1022                         header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length;
1023                         data[I_HEADER_SIZE] = header_size;
1024                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1025                 }
1026         } else {
1027                 /* write extend header. */
1028                 char           *ptr;
1029
1030                 if (generic_format)
1031                         put_byte(0x00);
1032                 else
1033                         put_byte(EXTEND_UNIX);
1034
1035                 ptr = put_ptr;
1036                 if (hdr->header_level == HEADER_LEVEL2) {
1037                         /* write common header */
1038                         put_word(5);
1039                         put_byte(0x00);
1040                         headercrc_ptr = put_ptr;
1041                         put_word(0x0000);
1042                 }
1043
1044                 if (generic_format) {
1045                         header_size = put_ptr - data;   /* +2 for last 0x0000 */
1046                 } else {
1047                         put_word(5);
1048                         if (hdr->header_level == HEADER_LEVEL1)
1049                                 header_size = put_ptr - data - 2;
1050                         put_byte(0x50); /* permission */
1051                         put_word(hdr->unix_mode);
1052                         put_word(7);
1053                         put_byte(0x51); /* gid and uid */
1054                         put_word(hdr->unix_gid);
1055                         put_word(hdr->unix_uid);
1056
1057             {
1058                 int i, len = strlen(hdr->group);
1059                 put_word(len + 3);
1060                 put_byte(0x52); /* group name */
1061                 for (i = 0; i < len; i++)
1062                     put_byte(hdr->group[i]);
1063
1064                 len = strlen(hdr->user);
1065                 put_word(len + 3);
1066                 put_byte(0x53); /* user name */
1067                 for (i = 0; i < len; i++)
1068                     put_byte(hdr->user[i]);
1069             }
1070
1071                         if (p = strrchr(lzname, LHA_PATHSEP)) {
1072                                 int             i;
1073
1074                                 name_length = p - lzname + 1;
1075                                 put_word(name_length + 3);
1076                                 put_byte(2);    /* dirname */
1077                                 for (i = 0; i < name_length; i++)
1078                                         put_byte(lzname[i]);
1079                         }
1080                 }               /* if generic .. */
1081
1082                 if (header_level != HEADER_LEVEL2) {
1083                         if (!generic_format) {
1084                                 put_word(7);
1085                                 put_byte(0x54); /* time stamp */
1086                                 put_longword(hdr->unix_last_modified_stamp);
1087                         }
1088                         hdr->packed_size += put_ptr - ptr;
1089                         ptr = put_ptr;
1090                         setup_put(data + I_PACKED_SIZE);
1091                         put_longword(hdr->packed_size);
1092                         put_ptr = ptr;
1093                         data[I_HEADER_SIZE] = header_size;
1094                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1095                 } else {                /* header level 2 */
1096                         int             i;
1097                         if (p = strrchr(lzname, LHA_PATHSEP))
1098                                 name_length = strlen(++p);
1099                         else {
1100                                 p = lzname;
1101                                 name_length = strlen(lzname);
1102                         }
1103                         put_word(name_length + 3);
1104                         put_byte(1);    /* filename */
1105                         for (i = 0; i < name_length; i++)
1106                                 put_byte(*p++);
1107                 }               /* if he.. != HEAD_LV2 */
1108                 header_size = put_ptr - data;
1109         }
1110
1111         if (header_level == HEADER_LEVEL2) {
1112                 unsigned short  hcrc;
1113                 setup_put(data + I_HEADER_SIZE);
1114                 put_word(header_size + 2);
1115                 /* common header */
1116                 hcrc = calc_header_crc(data, (unsigned int) header_size + 2);
1117                 setup_put(headercrc_ptr);
1118                 put_word(hcrc);
1119         }
1120
1121         if (fwrite(data, header_size + 2, 1, nafp) == 0)
1122                 fatal_error("Cannot write to temporary file");
1123 }
1124
1125 #ifdef __APPLE__
1126
1127 #include <CoreFoundation/CFString.h>
1128 #include <CoreFoundation/CFStringEncodingExt.h>
1129
1130 /* this is not need for Mac OS X v 10.2 later */
1131 enum {
1132   kCFStringEncodingAllowLossyConversion = 1,
1133   kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1134   kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1135   kCFStringEncodingSubstituteCombinings = (1 << 3),
1136   kCFStringEncodingComposeCombinings = (1 << 4),
1137   kCFStringEncodingIgnoreCombinings = (1 << 5),
1138   kCFStringEncodingUseCanonical = (1 << 6),
1139   kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1140   kCFStringEncodingPrependBOM = (1 << 8),
1141   kCFStringEncodingDisableCorporateArea = (1 << 9),
1142   kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1143 };
1144
1145 static int
1146 ConvertEncodingToUTF8(const char* inCStr,
1147                       char* outUTF8Buffer,
1148                       int outUTF8BufferLength,
1149                       unsigned long scriptEncoding,
1150                       unsigned long flags)
1151 {
1152     unsigned long unicodeChars;
1153     unsigned long srcCharsUsed;
1154     unsigned long usedByteLen = 0;
1155     UniChar uniStr[512];
1156     unsigned long cfResult;
1157
1158     cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1159                                               flags,
1160                                               (char *)inCStr,
1161                                               strlen(inCStr),
1162                                               &srcCharsUsed,
1163                                               uniStr,
1164                                               512,
1165                                               &unicodeChars);
1166     if (cfResult == 0) {
1167         cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1168                                                   flags,
1169                                                   uniStr,
1170                                                   unicodeChars,
1171                                                   &srcCharsUsed,
1172                                                   (char*)outUTF8Buffer,
1173                                                   outUTF8BufferLength - 1,
1174                                                   &usedByteLen);
1175         outUTF8Buffer[usedByteLen] = '\0';
1176     }
1177
1178     return cfResult;
1179 }
1180
1181 static int
1182 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1183                       int inUTF8BufLength,
1184                       char* outCStrBuffer,
1185                       int outCStrBufferLength,
1186                       unsigned long scriptEncoding,
1187                       unsigned long flags)
1188 {
1189     unsigned long unicodeChars;
1190     unsigned long srcCharsUsed;
1191     unsigned long usedByteLen = 0;
1192     UniChar uniStr[256];
1193     unsigned long cfResult;
1194
1195     cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1196                                               flags,
1197                                               (char*)inUTF8Buf,
1198                                               inUTF8BufLength,
1199                                               &srcCharsUsed,
1200                                               uniStr,
1201                                               255,
1202                                               &unicodeChars);
1203     if (cfResult == 0) {
1204         cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1205                                                   flags,
1206                                                   uniStr,
1207                                                   unicodeChars,
1208                                                   &srcCharsUsed,
1209                                                   (char*)outCStrBuffer,
1210                                                   outCStrBufferLength - 1,
1211                                                   &usedByteLen);
1212         outCStrBuffer[usedByteLen] = '\0';
1213     }
1214
1215     return cfResult;
1216 }
1217 #endif /* __APPLE__ */
1218
1219 char *
1220 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1221 {
1222 #ifdef __APPLE__
1223   dst[0] = '\0';
1224   ConvertEncodingToUTF8(src, dst, dstsize,
1225                         kCFStringEncodingDOSJapanese,
1226                         kCFStringEncodingUseHFSPlusCanonical);
1227
1228 #else
1229   /* not supported */
1230 #endif
1231   return dst;
1232 }
1233
1234 char *
1235 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1236 {
1237 #ifdef __APPLE__
1238   int srclen;
1239
1240   dst[0] = '\0';
1241   srclen = strlen(src);
1242   ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1243                         kCFStringEncodingDOSJapanese,
1244                         kCFStringEncodingUseHFSPlusCanonical);
1245 #else
1246   /* not supported */
1247 #endif
1248   return dst;
1249 }
1250
1251 /*
1252  * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1253  * ¡ÖÆüËܸì¾ðÊó½èÍý¡×   ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1254  *      ¤è¤êÈ´¿è(by Koji Arai)
1255  */
1256 void
1257 euc2sjis(int *p1, int *p2)
1258 {
1259     unsigned char c1 = *p1 & 0x7f;
1260     unsigned char c2 = *p2 & 0x7f;
1261     int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1262     int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1263     *p1 = ((c1 + 1) >> 1) + rowoff;
1264     *p2 += celoff - 0x80;
1265 }
1266
1267 void
1268 sjis2euc(int *p1, int *p2)
1269 {
1270     unsigned char c1 = *p1;
1271     unsigned char c2 = *p2;
1272     int adjust = c2 < 0x9f;
1273     int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1274     int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1275     *p1 = ((c1 - rowoff) << 1) - adjust;
1276     *p2 -= celoff;
1277
1278     *p1 |= 0x80;
1279     *p2 |= 0x80;
1280 }
1281
1282 /* Local Variables: */
1283 /* mode:c */
1284 /* tab-width:4 */
1285 /* compile-command:"gcc -c header.c" */
1286 /* End: */
1287 /* vi: set tabstop=4: */