OSDN Git Service

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