OSDN Git Service

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