OSDN Git Service

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