OSDN Git Service

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