OSDN Git Service

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