OSDN Git Service

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