OSDN Git Service

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