OSDN Git Service

* src/header.c (get_header): use the extend header, user/group name.
[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;
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                 for (i = 0; i < header_size - 3; i++)
702                     hdr->group[i] = get_byte();
703                 hdr->group[i] = '\0';
704                                 break;
705                         case 0x53:
706                                 /*
707                                  * UNIX user name
708                                  */
709                 for (i = 0; i < header_size - 3; i++)
710                     hdr->user[i] = get_byte();
711                 hdr->user[i] = '\0';
712                                 break;
713                         case 0x54:
714                                 /*
715                                  * UNIX last modified time
716                                  */
717                                 if (hdr->extend_type == EXTEND_UNIX)
718                                         hdr->unix_last_modified_stamp = (time_t) get_longword();
719                                 break;
720                         default:
721                                 /*
722                                  * other headers
723                                  */
724                                 setup_get(get_ptr + header_size - 3);
725                                 break;
726                         }
727                 }
728                 if (hdr->header_level != 2 && get_ptr - ptr != 2) {
729                         hdr->packed_size -= get_ptr - ptr - 2;
730                         hdr->header_size += get_ptr - ptr - 2;
731                 }
732         }
733
734         switch (hdr->extend_type) {
735         case EXTEND_MSDOS:
736         archive_delim = "\xff\\";
737         system_delim = "//";
738         filename_case = noconvertcase ? NONE : TO_LOWER;
739
740         /* fall through */
741         case EXTEND_HUMAN:
742                 if (hdr->header_level == 2)
743                         hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
744                 else
745                         hdr->unix_last_modified_stamp =
746                                 generic_to_unix_stamp(hdr->last_modified_stamp);
747                 break;
748
749 #ifdef OSK
750         case EXTEND_OS68K:
751         case EXTEND_XOSK:
752 #endif
753         case EXTEND_UNIX:
754         archive_delim = "\xff";
755         system_delim = "//";
756         filename_case = NONE;
757
758                 break;
759
760         case EXTEND_MACOS:
761         archive_delim = "\xff/:";
762         system_delim = "/:/";
763         filename_case = NONE;
764
765                 hdr->unix_last_modified_stamp =
766                         generic_to_unix_stamp(hdr->last_modified_stamp, sizeof(hdr->name));
767                 break;
768
769         default:
770         archive_delim = "\xff\\";
771         system_delim = "//";
772         filename_case = noconvertcase ? NONE : TO_LOWER;
773         /* pending: if small letter is included in filename,
774            the generic_to_unix_filename() do not case conversion,
775            but this code does not consider it. */
776
777                 if (hdr->header_level == 2)
778                         hdr->unix_last_modified_stamp = hdr->last_modified_stamp;
779                 else
780                         hdr->unix_last_modified_stamp =
781                                 generic_to_unix_stamp(hdr->last_modified_stamp);
782         }
783
784     /* filename kanji code and delimiter conversion */
785     if (optional_archive_kanji_code)
786         archive_kanji_code = optional_archive_kanji_code;
787     if (optional_system_kanji_code)
788         system_kanji_code = optional_system_kanji_code;
789     if (optional_archive_delim)
790         archive_delim = optional_archive_delim;
791     if (optional_system_delim)
792         system_delim = optional_system_delim;
793     if (optional_filename_case)
794         filename_case = optional_filename_case;
795
796         if (dir_length) {
797                 strcat(dirname, hdr->name);
798                 strcpy(hdr->name, dirname);
799                 name_length += dir_length;
800         }
801
802     filename_conv(hdr->name, name_length, sizeof(hdr->name),
803                   archive_kanji_code,
804                   system_kanji_code,
805                   archive_delim, system_delim, filename_case);
806
807         return TRUE;
808 }
809
810 /* ------------------------------------------------------------------------ */
811 void
812 init_header(name, v_stat, hdr)
813         char           *name;
814         struct stat    *v_stat;
815         LzHeader       *hdr;
816 {
817         int             len;
818
819     int system_kanji_code = default_system_kanji_code;
820     char *archive_delim = "";
821     char *system_delim = "";
822     int filename_case = NONE;
823
824     if (optional_system_kanji_code)
825         system_kanji_code = optional_system_kanji_code;
826
827         if (compress_method == LZHUFF5_METHOD_NUM)  /* Changed N.Watazaki */
828                 bcopy(LZHUFF5_METHOD, hdr->method, METHOD_TYPE_STRAGE);
829         else if (compress_method)
830                 bcopy(LZHUFF1_METHOD, hdr->method, METHOD_TYPE_STRAGE);
831         else
832                 bcopy(LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
833
834         hdr->packed_size = 0;
835         hdr->original_size = v_stat->st_size;
836         hdr->last_modified_stamp = unix_to_generic_stamp(v_stat->st_mtime);
837         hdr->attribute = GENERIC_ATTRIBUTE;
838         hdr->header_level = header_level;
839         strcpy(hdr->name, name);
840         len = strlen(name);
841         hdr->crc = 0x0000;
842         hdr->extend_type = EXTEND_UNIX;
843         hdr->unix_last_modified_stamp = v_stat->st_mtime;
844         /* since 00:00:00 JAN.1.1970 */
845 #ifdef NOT_COMPATIBLE_MODE
846         /* Please need your modification in this space. */
847 #else
848         hdr->unix_mode = v_stat->st_mode;
849 #endif
850
851         hdr->unix_uid = v_stat->st_uid;
852         hdr->unix_gid = v_stat->st_gid;
853
854 #if HAVE_GETPWUID
855     {
856         struct passwd *ent = getpwuid(hdr->unix_uid);
857
858         if (ent) {
859             strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
860             if (hdr->user[sizeof(hdr->user)-1])
861                 hdr->user[sizeof(hdr->user)-1] = 0;
862         }
863     }
864 #endif
865 #if HAVE_GETGRGID
866     {
867         struct group *ent = getgrgid(hdr->unix_gid);
868
869         if (ent) {
870             strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
871             if (hdr->group[sizeof(hdr->group)-1])
872                 hdr->group[sizeof(hdr->group)-1] = 0;
873         }
874     }
875 #endif
876         if (is_directory(v_stat)) {
877                 bcopy(LZHDIRS_METHOD, hdr->method, METHOD_TYPE_STRAGE);
878                 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
879                 hdr->original_size = 0;
880                 if (len > 0 && hdr->name[len - 1] != '/')
881                         strcpy(&hdr->name[len++], "/");
882         }
883
884 #ifdef S_IFLNK  
885         if (is_symlink(v_stat)) {
886                 char    lkname[257];
887                 int             len;    
888                 bcopy(LZHDIRS_METHOD, hdr->method, METHOD_TYPE_STRAGE);
889                 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
890                 hdr->original_size = 0;
891                 len = readlink(name, lkname, 256);
892                 lkname[len] = (char)'\0';
893                 sprintf(hdr->name, "%s|%s", hdr->name, lkname);
894         }
895 #endif
896
897         if (generic_format) {
898         filename_case = TO_UPPER;
899         archive_delim = "\\";
900     }
901
902     filename_conv(hdr->name, len, sizeof(hdr->name),
903                   system_kanji_code,
904                   system_kanji_code, /* no change code */
905                   system_delim, archive_delim, filename_case);
906 }
907
908 /* ------------------------------------------------------------------------ */
909 /* Write unix extended header or generic header. */
910 void
911 write_header(nafp, hdr)
912         FILE           *nafp;
913         LzHeader       *hdr;
914 {
915         int             header_size;
916         int             name_length;
917         char            data[LZHEADER_STRAGE];
918         char           *p;
919         char           *headercrc_ptr;
920     int archive_kanji_code = CODE_SJIS;
921     int system_kanji_code = default_system_kanji_code;
922
923     if (optional_archive_kanji_code)
924         archive_kanji_code = optional_archive_kanji_code;
925     if (optional_system_kanji_code)
926         system_kanji_code = optional_system_kanji_code;
927
928         bzero(data, LZHEADER_STRAGE);
929         bcopy(hdr->method, data + I_METHOD, METHOD_TYPE_STRAGE);
930         setup_put(data + I_PACKED_SIZE);
931         put_longword(hdr->packed_size);
932         put_longword(hdr->original_size);
933
934         if (hdr->header_level == HEADER_LEVEL2)
935                 put_longword((long) hdr->unix_last_modified_stamp);
936         else
937                 put_longword(hdr->last_modified_stamp);
938
939         switch (hdr->header_level) {
940         case HEADER_LEVEL0:
941                 put_byte(hdr->attribute);
942                 break;
943         case HEADER_LEVEL1:
944         case HEADER_LEVEL2:
945                 put_byte(0x20);
946                 break;
947         }
948
949         put_byte(hdr->header_level);
950
951     filename_conv(hdr->name, strlen(hdr->name), sizeof(hdr->name),
952                   system_kanji_code,
953                   archive_kanji_code, /* no change code */
954                   "\xff\\/", "\xff\xff\xff", NONE);
955
956         if (hdr->header_level != HEADER_LEVEL2) {
957                 if (p = (char *) strrchr(hdr->name, DELIM2))
958                         name_length = strlen(++p);
959                 else
960                         name_length = strlen(hdr->name);
961                 put_byte(name_length);
962                 bcopy(p ? p : hdr->name, data + I_NAME, name_length);
963                 setup_put(data + I_NAME + name_length);
964         }
965
966         put_word(hdr->crc);
967         if (header_level == HEADER_LEVEL0) {
968                 if (generic_format) {
969                         header_size = I_GENERIC_HEADER_BOTTOM - 2 + name_length;
970                         data[I_HEADER_SIZE] = header_size;
971                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
972                 } else {
973                         /* write old-style extend header */
974                         put_byte(EXTEND_UNIX);
975                         put_byte(CURRENT_UNIX_MINOR_VERSION);
976                         put_longword((long) hdr->unix_last_modified_stamp);
977                         put_word(hdr->unix_mode);
978                         put_word(hdr->unix_uid);
979                         put_word(hdr->unix_gid);
980                         header_size = I_UNIX_EXTEND_BOTTOM - 2 + name_length;
981                         data[I_HEADER_SIZE] = header_size;
982                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
983                 }
984         } else {
985                 /* write extend header. */
986                 char           *ptr;
987
988                 if (generic_format)
989                         put_byte(0x00);
990                 else
991                         put_byte(EXTEND_UNIX);
992
993                 ptr = put_ptr;
994                 if (hdr->header_level == HEADER_LEVEL2) {
995                         /* write common header */
996                         put_word(5);
997                         put_byte(0x00);
998                         headercrc_ptr = put_ptr;
999                         put_word(0x0000);
1000                 }
1001
1002                 if (generic_format) {
1003                         header_size = put_ptr - data;   /* +2 for last 0x0000 */
1004                 } else {
1005                         put_word(5);
1006                         if (hdr->header_level == HEADER_LEVEL1)
1007                                 header_size = put_ptr - data - 2;
1008                         put_byte(0x50); /* permission */
1009                         put_word(hdr->unix_mode);
1010                         put_word(7);
1011                         put_byte(0x51); /* gid and uid */
1012                         put_word(hdr->unix_gid);
1013                         put_word(hdr->unix_uid);
1014
1015             {
1016                 int i, len = strlen(hdr->group);
1017                 put_word(len + 3);
1018                 put_byte(0x52); /* group name */
1019                 for (i = 0; i < len; i++)
1020                     put_byte(hdr->group[i]);
1021
1022                 len = strlen(hdr->user);
1023                 put_word(len + 3);
1024                 put_byte(0x53); /* user name */
1025                 for (i = 0; i < len; i++)
1026                     put_byte(hdr->user[i]);
1027             }
1028
1029                         if (p = (char *) strrchr(hdr->name, DELIM2)) {
1030                                 int             i;
1031
1032                                 name_length = p - hdr->name + 1;
1033                                 put_word(name_length + 3);
1034                                 put_byte(2);    /* dirname */
1035                                 for (i = 0; i < name_length; i++)
1036                                         put_byte(hdr->name[i]);
1037                         }
1038                 }               /* if generic .. */
1039
1040                 if (header_level != HEADER_LEVEL2) {
1041                         if (!generic_format) {
1042                                 put_word(7);
1043                                 put_byte(0x54); /* time stamp */
1044                                 put_longword(hdr->unix_last_modified_stamp);
1045                         }
1046                         hdr->packed_size += put_ptr - ptr;
1047                         ptr = put_ptr;
1048                         setup_put(data + I_PACKED_SIZE);
1049                         put_longword(hdr->packed_size);
1050                         put_ptr = ptr;
1051                         data[I_HEADER_SIZE] = header_size;
1052                         data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1053                 } else {                /* header level 2 */
1054                         int             i;
1055                         if (p = (char *) strrchr(hdr->name, DELIM2))
1056                                 name_length = strlen(++p);
1057                         else {
1058                                 p = hdr->name;
1059                                 name_length = strlen(hdr->name);
1060                         }
1061                         put_word(name_length + 3);
1062                         put_byte(1);    /* filename */
1063                         for (i = 0; i < name_length; i++)
1064                                 put_byte(*p++);
1065                 }               /* if he.. != HEAD_LV2 */
1066                 header_size = put_ptr - data;
1067         }
1068
1069         if (header_level == HEADER_LEVEL2) {
1070                 unsigned short  hcrc;
1071                 setup_put(data + I_HEADER_SIZE);
1072                 put_word(header_size + 2);
1073                 /* common header */
1074                 hcrc = calc_header_crc(data, (unsigned int) header_size + 2);
1075                 setup_put(headercrc_ptr);
1076                 put_word(hcrc);
1077         }
1078
1079         if (fwrite(data, sizeof(char), header_size + 2, nafp) == 0)
1080                 fatal_error("Cannot write to temporary file");
1081
1082     filename_conv(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1083                   archive_kanji_code,
1084                   system_kanji_code,
1085                   "\xff\\/", "///", NONE);
1086 }
1087
1088 /*
1089  * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1090  * ¡ÖÆüËܸì¾ðÊó½èÍý¡×   ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1091  *      ¤è¤êÈ´¿è(by Koji Arai)
1092  */
1093 void
1094 euc2sjis(int *p1, int *p2)
1095 {
1096     unsigned char c1 = *p1 & 0x7f;
1097     unsigned char c2 = *p2 & 0x7f;
1098     int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1099     int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1100     *p1 = ((c1 + 1) >> 1) + rowoff;
1101     *p2 += celoff - 0x80;
1102 }
1103
1104 void
1105 sjis2euc(int *p1, int *p2)
1106 {
1107     unsigned char c1 = *p1;
1108     unsigned char c2 = *p2;
1109     int adjust = c2 < 0x9f;
1110     int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1111     int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1112     *p1 = ((c1 - rowoff) << 1) - adjust;
1113     *p2 -= celoff;
1114
1115     *p1 |= 0x80;
1116     *p2 |= 0x80;
1117 }
1118
1119 /* Local Variables: */
1120 /* mode:c */
1121 /* tab-width:4 */
1122 /* compile-command:"gcc -c header.c" */
1123 /* End: */
1124 /* vi: set tabstop=4: */