OSDN Git Service

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