1 /* ------------------------------------------------------------------------ */
3 /* header.c -- header manipulate functions */
5 /* Modified Nobutaka Watazaki */
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 /* ------------------------------------------------------------------------ */
16 #define DUMP_HEADER 1 /* for debugging */
18 #if !STRCHR_8BIT_CLEAN
19 /* should use 8 bit clean version */
22 #define strchr xstrchr
23 #define strrchr xstrrchr
26 /* ------------------------------------------------------------------------ */
28 #define GET_BYTE() (*get_ptr++ & 0xff)
31 static char *start_ptr;
32 #define setup_get(PTR) (start_ptr = get_ptr = (PTR))
33 #define get_byte() dump_get_byte()
34 #define skip_bytes(len) dump_skip_bytes(len)
36 #define setup_get(PTR) (get_ptr = (PTR))
37 #define get_byte() GET_BYTE()
38 #define skip_bytes(len) (get_ptr += (len))
40 #define put_ptr get_ptr
41 #define setup_put(PTR) (put_ptr = (PTR))
42 #define put_byte(c) (*put_ptr++ = (char)(c))
44 int optional_archive_kanji_code = NONE;
45 int optional_system_kanji_code = NONE;
46 char *optional_archive_delim = NULL;
47 char *optional_system_delim = NULL;
48 int optional_filename_case = NONE;
50 #ifdef MULTIBYTE_FILENAME
51 int default_system_kanji_code = MULTIBYTE_FILENAME;
53 int default_system_kanji_code = NONE;
56 /* ------------------------------------------------------------------------ */
64 for (sum = 0; len; len--)
76 if (verbose_listing && verbose > 1)
77 printf("%02d %2d: ", get_ptr - start_ptr, 1);
79 if (verbose_listing && verbose > 1) {
81 printf("%d(0x%02x) '%c'\n", c, c, c);
83 printf("%d(0x%02x)\n", c, c);
93 if (verbose_listing && verbose > 1) {
94 printf("%02d %2d:", get_ptr - start_ptr, len);
96 printf(" 0x%02x", GET_BYTE());
104 /* ------------------------------------------------------------------------ */
112 if (verbose_listing && verbose > 1)
113 printf("%02d %2d: ", get_ptr - start_ptr, 2);
119 if (verbose_listing && verbose > 1)
120 printf("%d(0x%04x)\n", w, w);
125 /* ------------------------------------------------------------------------ */
134 /* ------------------------------------------------------------------------ */
142 if (verbose_listing && verbose > 1)
143 printf("%02d %2d: ", get_ptr - start_ptr, 4);
149 l = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
151 if (verbose_listing && verbose > 1)
152 printf("%ld(0x%08lx)\n", l, l);
157 /* ------------------------------------------------------------------------ */
169 get_bytes(buf, len, size)
176 if (verbose_listing && verbose > 1)
177 printf("%02d %2d: ", get_ptr - start_ptr, len);
179 for (i = 0; i < len && i < size; i++)
183 if (verbose_listing && verbose > 1)
184 printf("\"%*.*s\"\n", i, i, buf);
195 for (i = 0; i < len; i++)
199 /* added by Koji Arai */
201 convert_filename(name, len, size,
203 from_delim, to_delim,
208 int from_code, to_code, case_to;
209 char *from_delim, *to_delim;
213 #ifdef MULTIBYTE_FILENAME
214 char tmp[FILENAME_LENGTH];
216 if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
217 for (i = 0; i < len; i++)
218 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
219 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
220 sjis_to_utf8(tmp, name, sizeof(tmp));
221 strncpy(name, tmp, size);
224 for (i = 0; i < len; i++)
225 if (name[i] == '/') name[i] = LHA_PATHSEP;
226 from_code = CODE_UTF8;
228 else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
229 for (i = 0; i < len; i++)
230 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
231 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
232 utf8_to_sjis(tmp, name, sizeof(tmp));
233 strncpy(name, tmp, size);
236 for (i = 0; i < len; i++)
237 if (name[i] == '/') name[i] = LHA_PATHSEP;
238 from_code = CODE_SJIS;
242 /* special case: if `name' has small lettter, not convert case. */
243 if (from_code == CODE_SJIS && case_to == TO_LOWER) {
244 for (i = 0; i < len; i++) {
245 #ifdef MULTIBYTE_FILENAME
246 if (SJIS_FIRST_P(name[i]))
250 if (islower(name[i])) {
257 for (i = 0; i < len; i ++) {
258 #ifdef MULTIBYTE_FILENAME
259 if (from_code == CODE_EUC &&
260 (unsigned char)name[i] == 0x8e) {
261 if (to_code != CODE_SJIS) {
267 memmove(name + i, name + i + 1, len - i);
271 if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
272 if (to_code != CODE_EUC) {
276 if (len == size - 1) /* check overflow */
278 memmove(name+i+1, name+i, len-i);
284 if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
286 if (to_code != CODE_SJIS) {
291 c1 = (unsigned char)name[i];
292 c2 = (unsigned char)name[i+1];
299 if (from_code == CODE_SJIS &&
300 SJIS_FIRST_P(name[i]) &&
301 SJIS_SECOND_P(name[i+1])) {
304 if (to_code != CODE_EUC) {
309 c1 = (unsigned char)name[i];
310 c2 = (unsigned char)name[i+1];
317 #endif /* MULTIBYTE_FILENAME */
321 /* transpose from_delim to to_delim */
323 if ((ptr = strchr(from_delim, name[i])) != NULL) {
324 name[i] = to_delim[ptr - from_delim];
329 if (case_to == TO_UPPER && islower(name[i])) {
330 name[i] = toupper(name[i]);
333 if (case_to == TO_LOWER && isupper(name[i])) {
334 name[i] = tolower(name[i]);
340 /* ------------------------------------------------------------------------ */
342 /* Generic stamp format: */
344 /* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 */
345 /* |<-------- year ------->|<- month ->|<-- day -->| */
347 /* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */
348 /* |<--- hour --->|<---- minute --->|<- second*2 ->| */
350 /* ------------------------------------------------------------------------ */
353 * NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
354 * returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or TZSET.
358 #if defined(HAVE_MKTIME)
359 #ifdef HAVE_TIMELOCAL
360 #undef HAVE_TIMELOCAL
362 #endif /* defined(HAVE_MKTIME) */
364 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
368 #endif /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
370 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) || defined(HAVE_TZSET)
376 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) || defined(HAVE_TZSET) || defined(HAVE_FTIME)
377 #ifdef HAVE_GETTIMEOFDAY
378 #undef HAVE_GETTIMEOFDAY
381 #ifndef HAVE_GETTIMEOFDAY
382 #define HAVE_GETTIMEOFDAY /* use gettimeofday() */
387 #include <sys/timeb.h>
391 * You may define as : #define TIMEZONE_HOOK \ extern long
392 * timezone ; \ extern void tzset();
396 /* Which do you like better, `TIMEZONE_HOOK' or `TIMEZONE_HOOK;' ? */
399 #if defined(HAVE_TZSET) && defined(_MINIX)
400 extern long timezone; /* not defined in time.h */
403 /* ------------------------------------------------------------------------ */
404 #if defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY) || defined(HAVE_TZSET)
414 /* ------------------------------------------------------------------------ */
415 #if !defined(HAVE_TZSET) && defined(HAVE_FTIME)
420 return buf.timezone * 60L;
424 /* ------------------------------------------------------------------------ */
425 #if !defined(HAVE_TZSET) && !defined(HAVE_FTIME) /* maybe defined(HAVE_GETTIMEOFDAY) */
427 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
431 return -localtime(&tt)->tm_gmtoff;
432 #else /* HAVE_STRUCT_TM_TM_GMTOFF */
435 gettimeofday(&tp, &tzp);/* specific to 4.3BSD */
437 * return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L *
440 return (tzp.tz_minuteswest * 60L);
441 #endif /* HAVE_STRUCT_TM_TM_GMTOFF */
444 #endif /* defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY) ||
445 * defined(HAVE_TZSET) */
447 /* ------------------------------------------------------------------------ */
449 generic_to_unix_stamp(t)
451 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
456 * special case: if MSDOS format date and time were zero, then we
457 * set time to be zero here too.
462 dostm.tm_sec = (t & 0x1f) * 2;
463 dostm.tm_min = t >> 5 & 0x3f;
464 dostm.tm_hour = t >> 11 & 0x1f;
465 dostm.tm_mday = t >> 16 & 0x1f;
466 dostm.tm_mon = (t >> (16+5) & 0x0f) - 1; /* 0..11 */
467 dostm.tm_year = (t >> (16+9) & 0x7f) + 80;
469 dostm.tm_isdst = 0; /* correct? */
471 dostm.tm_isdst = -1; /* correct? */
473 return (time_t) mktime(&dostm);
474 #else /* maybe defined(HAVE_TIMELOCAL) */
475 return (time_t) timelocal(&dostm);
479 #else /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
481 int year, month, day, hour, min, sec;
483 static unsigned int dsboy[12] = {0, 31, 59, 90, 120, 151,
484 181, 212, 243, 273, 304, 334};
488 * special case: if MSDOS format date and time were zero, then we
489 * set time to be zero here too.
494 year = ((int) (t >> 16 + 9) & 0x7f) + 1980;
495 month = (int) (t >> 16 + 5) & 0x0f; /* 1..12 means Jan..Dec */
496 day = (int) (t >> 16) & 0x1f; /* 1..31 means 1st,...31st */
498 hour = ((int) t >> 11) & 0x1f;
499 min = ((int) t >> 5) & 0x3f;
500 sec = ((int) t & 0x1f) * 2;
502 /* Calculate days since 1970.01.01 */
503 days = (365 * (year - 1970) + /* days due to whole years */
504 (year - 1970 + 1) / 4 + /* days due to leap years */
505 dsboy[month - 1] + /* days since beginning of this year */
506 day - 1); /* days since beginning of month */
508 if ((year % 4 == 0) &&
509 (year % 100 != 0 || year % 400 == 0) && /* 1999.5.24 t.oka */
510 (month >= 3)) /* if this is a leap year and month */
511 days++; /* is March or later, add a day */
513 /* Knowing the days, we can find seconds */
514 longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
515 longtime += gettz(); /* adjust for timezone */
517 /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00. */
518 return (time_t) longtime;
520 #endif /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
522 /* ------------------------------------------------------------------------ */
524 unix_to_generic_stamp(t)
527 struct tm *tm = localtime(&t);
529 return ((((long) (tm->tm_year - 80)) << 25) +
530 (((long) (tm->tm_mon + 1)) << 21) +
531 (((long) tm->tm_mday) << 16) +
532 (long) ((tm->tm_hour << 11) +
537 /* ------------------------------------------------------------------------ */
538 /* build header functions */
539 /* ------------------------------------------------------------------------ */
545 * --------------------------------
547 * 2 or 4 next-header size [*1]
548 * --------------------------------------
549 * ext header: 1 ext-type ^
550 * ? contents | [*1] next-header size
551 * 2 or 4 next-header size v
552 * --------------------------------------
554 * on level 1, 2 header:
555 * size field is 2 bytes
557 * size field is 4 bytes
560 get_extended_header(fp, hdr, header_size, hcrc)
566 char data[LZHEADER_STORAGE];
568 char dirname[FILENAME_LENGTH];
571 long whole_size = header_size;
573 int n = 1 + hdr->size_field_length; /* `ext-type' + `next-header size' */
575 if (hdr->header_level == 0)
578 name_length = strlen(hdr->name);
580 while (header_size) {
582 if (sizeof(data) < header_size) {
583 error("header size (%ld) too large.", header_size);
587 if (fread(data, header_size, 1, fp) == 0) {
588 error("Invalid header (LHa file ?)");
592 ext_type = get_byte();
595 /* header crc (CRC-16) */
596 hdr->header_crc = get_word();
597 /* clear buffer for CRC calculation. */
598 data[1] = data[2] = 0;
599 skip_bytes(header_size - n - 2);
604 get_bytes(hdr->name, header_size-n, sizeof(hdr->name)-1);
605 hdr->name[name_length] = 0;
609 dir_length = get_bytes(dirname, header_size-n, sizeof(dirname)-1);
610 dirname[dir_length] = 0;
613 /* MS-DOS attribute */
614 hdr->attribute = get_word();
617 /* Windows time stamp (FILETIME structure) */
619 message("extended header 0x%02x(Windows time stamp) ignored",
621 skip_bytes(header_size - n); /* ignored */
624 /* UNIX permission */
625 hdr->unix_mode = get_word();
628 /* UNIX gid and uid */
629 hdr->unix_gid = get_word();
630 hdr->unix_uid = get_word();
633 /* UNIX group name */
634 i = get_bytes(hdr->group, header_size-n, sizeof(hdr->group)-1);
635 hdr->group[i] = '\0';
639 i = get_bytes(hdr->user, header_size-n, sizeof(hdr->user)-1);
643 /* UNIX last modified time */
644 hdr->unix_last_modified_stamp = (time_t) get_longword();
649 /* 0x39: multi-disk header
650 0x3f: uncompressed comment
651 0x42: 64bit large file size
652 0x48-0x4f(?): reserved for authenticity verification
654 0x7e: extended attribute -platform information
655 0x7f: extended attribute -permission, owner-id and timestamp
657 0xc4: compressed comment (dict size: 4096)
658 0xc5: compressed comment (dict size: 8192)
659 0xc6: compressed comment (dict size: 16384)
660 0xc7: compressed comment (dict size: 32768)
661 0xc8: compressed comment (dict size: 65536)
662 0xd0-0xdf(?): operating systemm specific information
663 0xfc: encapsulation (another opinion)
664 0xfe: extended attribute -platform information (another opinion)
665 0xff: extended attribute -permission, owner-id and timestamp
666 (level 3 on UNLHA32) */
668 warning("unknown extended header 0x%02x", ext_type);
669 skip_bytes(header_size - n);
675 *hcrc = calccrc(*hcrc, data, header_size);
677 if (hdr->size_field_length == 2)
678 whole_size += header_size = get_word();
680 whole_size += header_size = get_longword();
683 /* concatenate dirname and filename */
685 if (name_length + dir_length >= sizeof(hdr->name)) {
686 warning("the length of pathname \"%s%s\" is too long.",
688 name_length = sizeof(hdr->name) - dir_length - 1;
689 hdr->name[name_length] = 0;
691 strcat(dirname, hdr->name);
692 strcpy(hdr->name, dirname);
693 name_length += dir_length;
703 * offset size field name
704 * ----------------------------------
705 * 0 1 header size [*1]
707 * ---------------------------------------
709 * 7 4 packed size [*2] |
710 * 11 4 original size |
713 * 19 1 attribute | [*1] header size (X+Y+22)
714 * 20 1 level (0x00 fixed) |
717 * X +22 2 file crc (CRC-16) |
718 * X +24 Y ext-header(old style) v
719 * -------------------------------------------------
723 * ext-header(old style)
737 * bit6 archive bit (need to backup)
741 get_header_level0(fp, hdr, data)
752 hdr->size_field_length = 2; /* in bytes */
753 hdr->header_size = header_size = get_byte();
754 checksum = get_byte();
756 if (fread(data+I_NAME_LENGTH, header_size+2-I_NAME_LENGTH, 1, fp) == 0) {
757 error("Invalid header (LHarc file ?)");
758 return FALSE; /* finish */
761 if (calc_sum(data + I_METHOD, header_size) != checksum) {
762 error("Checksum error (LHarc file?)");
766 get_bytes(hdr->method, 5, sizeof(hdr->method));
767 hdr->packed_size = get_longword();
768 hdr->original_size = get_longword();
769 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
770 hdr->attribute = get_byte(); /* MS-DOS attribute */
771 hdr->header_level = get_byte();
772 name_length = get_byte();
773 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
776 /* defaults for other type */
777 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
781 extend_size = header_size+2 - name_length - 24;
783 if (extend_size < 0) {
784 if (extend_size == -2) {
785 /* CRC field is not given */
786 hdr->extend_type = EXTEND_GENERIC;
787 hdr->has_crc = FALSE;
792 error("Unkonwn header (lha file?)");
797 hdr->crc = get_word();
799 if (extend_size == 0)
802 hdr->extend_type = get_byte();
805 if (hdr->extend_type == EXTEND_UNIX) {
806 if (extend_size >= 11) {
807 hdr->minor_version = get_byte();
808 hdr->unix_last_modified_stamp = (time_t) get_longword();
809 hdr->unix_mode = get_word();
810 hdr->unix_uid = get_word();
811 hdr->unix_gid = get_word();
814 hdr->extend_type = EXTEND_GENERIC;
818 skip_bytes(extend_size);
820 hdr->header_size += 2;
828 * offset size field name
829 * -----------------------------------
830 * 0 1 header size [*1]
832 * -------------------------------------
834 * 7 4 skip size [*2] |
835 * 11 4 original size |
838 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
839 * 20 1 level (0x01 fixed) |
842 * X+ 22 2 file crc (CRC-16) |
845 * X+Y+25 2 next-header size v
846 * -------------------------------------------------
847 * X+Y+27 Z ext-header ^
849 * ----------------------------------- | [*2] skip size
852 * -------------------------------------------------
856 get_header_level1(fp, hdr, data)
861 int header_size, extend_size;
866 hdr->size_field_length = 2; /* in bytes */
867 hdr->header_size = header_size = get_byte();
868 checksum = get_byte();
870 if (fread(data+I_NAME_LENGTH, header_size+2-I_NAME_LENGTH, 1, fp) == 0) {
871 error("Invalid header (LHarc file ?)");
872 return FALSE; /* finish */
875 if (calc_sum(data + I_METHOD, header_size) != checksum) {
876 error("Checksum error (LHarc file?)");
880 get_bytes(hdr->method, 5, sizeof(hdr->method));
881 hdr->packed_size = get_longword(); /* skip size */
882 hdr->original_size = get_longword();
883 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
884 hdr->attribute = get_byte(); /* 0x20 fixed */
885 hdr->header_level = get_byte();
887 name_length = get_byte();
888 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
891 /* defaults for other type */
892 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
897 hdr->crc = get_word();
898 hdr->extend_type = get_byte();
900 dummy = header_size+2 - name_length - 27;
902 skip_bytes(dummy); /* skip old style extend header */
904 extend_size = get_word();
905 extend_size = get_extended_header(fp, hdr, extend_size, 0);
906 if (extend_size == -1)
909 /* On level 1 header, size fields should be adjusted. */
910 /* the `packed_size' field contains the extended header size. */
911 /* the `header_size' field does not. */
912 hdr->packed_size -= extend_size;
913 hdr->header_size += extend_size + 2;
922 * offset size field name
923 * --------------------------------------------------
924 * 0 2 total header size [*1] ^
925 * ----------------------- |
927 * 7 4 packed size [*2] |
928 * 11 4 original size |
930 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
931 * 20 1 level (0x02 fixed) | (X+26+(1))
932 * 21 2 file crc (CRC-16) |
934 * 24 2 next-header size |
935 * ----------------------------------- |
938 * ----------------------------------- |
939 * X +26 (1) padding v
940 * -------------------------------------------------
942 * : | [*2] packed size
944 * -------------------------------------------------
948 get_header_level2(fp, hdr, data)
953 int header_size, extend_size;
957 hdr->size_field_length = 2; /* in bytes */
958 hdr->header_size = header_size = get_word();
960 if (fread(data + I_NAME_LENGTH, 26 - I_NAME_LENGTH, 1, fp) == 0) {
961 error("Invalid header (LHarc file ?)");
962 return FALSE; /* finish */
965 get_bytes(hdr->method, 5, sizeof(hdr->method));
966 hdr->packed_size = get_longword();
967 hdr->original_size = get_longword();
968 hdr->unix_last_modified_stamp = get_longword();
969 hdr->attribute = get_byte(); /* reserved */
970 hdr->header_level = get_byte();
972 /* defaults for other type */
973 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
978 hdr->crc = get_word();
979 hdr->extend_type = get_byte();
980 extend_size = get_word();
982 INITIALIZE_CRC(hcrc);
983 hcrc = calccrc(hcrc, data, get_ptr - data);
985 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
986 if (extend_size == -1)
989 padding = header_size - 26 - extend_size;
990 while (padding--) /* padding should be 0 or 1 */
991 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
993 if (hdr->header_crc != hcrc)
994 error("header CRC error");
1003 * offset size field name
1004 * --------------------------------------------------
1005 * 0 2 size field length (4 fixed) ^
1007 * 7 4 packed size [*2] |
1008 * 11 4 original size |
1010 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
1011 * 20 1 level (0x03 fixed) | (X+32)
1012 * 21 2 file crc (CRC-16) |
1014 * 24 4 total header size [*1] |
1015 * 28 4 next-header size |
1016 * ----------------------------------- |
1019 * -------------------------------------------------
1021 * : | [*2] packed size
1023 * -------------------------------------------------
1027 get_header_level3(fp, hdr, data)
1032 long header_size, extend_size;
1036 hdr->size_field_length = get_word();
1038 if (fread(data + I_NAME_LENGTH, 32 - I_NAME_LENGTH, 1, fp) == 0) {
1039 error("Invalid header (LHarc file ?)");
1040 return FALSE; /* finish */
1043 get_bytes(hdr->method, 5, sizeof(hdr->method));
1044 hdr->packed_size = get_longword();
1045 hdr->original_size = get_longword();
1046 hdr->unix_last_modified_stamp = get_longword();
1047 hdr->attribute = get_byte(); /* reserved */
1048 hdr->header_level = get_byte();
1050 /* defaults for other type */
1051 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
1055 hdr->has_crc = TRUE;
1056 hdr->crc = get_word();
1057 hdr->extend_type = get_byte();
1058 hdr->header_size = header_size = get_longword();
1059 extend_size = get_longword();
1061 INITIALIZE_CRC(hcrc);
1062 hcrc = calccrc(hcrc, data, get_ptr - data);
1064 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
1065 if (extend_size == -1)
1068 padding = header_size - 32 - extend_size;
1069 while (padding--) /* padding should be 0 */
1070 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
1072 if (hdr->header_crc != hcrc)
1073 error("header CRC error");
1083 char data[LZHEADER_STORAGE];
1085 int archive_kanji_code = CODE_SJIS;
1086 int system_kanji_code = default_system_kanji_code;
1087 char *archive_delim = "\377\\"; /* `\' is for level 0 header and
1089 char *system_delim = "//";
1090 int filename_case = NONE;
1093 memset(hdr, 0, sizeof(LzHeader));
1097 if ((end_mark = getc(fp)) == EOF || end_mark == 0) {
1098 return FALSE; /* finish */
1102 if (fread(data + 1, I_NAME_LENGTH - 1, 1, fp) == 0) {
1103 error("Invalid header (LHarc file ?)");
1104 return FALSE; /* finish */
1107 switch (data[I_HEADER_LEVEL]) {
1109 if (get_header_level0(fp, hdr, data) == FALSE)
1113 if (get_header_level1(fp, hdr, data) == FALSE)
1117 if (get_header_level2(fp, hdr, data) == FALSE)
1121 if (get_header_level3(fp, hdr, data) == FALSE)
1125 error("Unknown level header (level %d)", data[I_HEADER_LEVEL]);
1129 /* filename conversion */
1130 switch (hdr->extend_type) {
1132 filename_case = noconvertcase ? NONE : TO_LOWER;
1139 filename_case = NONE;
1143 archive_delim = "\377/:\\";
1144 /* `\' is for level 0 header and broken archive. */
1145 system_delim = "/://";
1146 filename_case = NONE;
1150 filename_case = noconvertcase ? NONE : TO_LOWER;
1154 if (optional_archive_kanji_code)
1155 archive_kanji_code = optional_archive_kanji_code;
1156 if (optional_system_kanji_code)
1157 system_kanji_code = optional_system_kanji_code;
1158 if (optional_archive_delim)
1159 archive_delim = optional_archive_delim;
1160 if (optional_system_delim)
1161 system_delim = optional_system_delim;
1162 if (optional_filename_case)
1163 filename_case = optional_filename_case;
1165 /* kanji code and delimiter conversion */
1166 convert_filename(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1169 archive_delim, system_delim, filename_case);
1174 /* ------------------------------------------------------------------------ */
1176 init_header(name, v_stat, hdr)
1178 struct stat *v_stat;
1183 memset(hdr, 0, sizeof(LzHeader));
1185 /* the `method' member is rewrote by the encoding function.
1186 but need set for empty files */
1187 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
1189 hdr->packed_size = 0;
1190 hdr->original_size = v_stat->st_size;
1191 hdr->attribute = GENERIC_ATTRIBUTE;
1192 hdr->header_level = header_level;
1193 strcpy(hdr->name, name);
1196 hdr->extend_type = EXTEND_UNIX;
1197 hdr->unix_last_modified_stamp = v_stat->st_mtime;
1198 /* since 00:00:00 JAN.1.1970 */
1199 #ifdef NOT_COMPATIBLE_MODE
1200 /* Please need your modification in this space. */
1202 hdr->unix_mode = v_stat->st_mode;
1205 hdr->unix_uid = v_stat->st_uid;
1206 hdr->unix_gid = v_stat->st_gid;
1208 #if INCLUDE_OWNER_NAME_IN_HEADER
1211 struct passwd *ent = getpwuid(hdr->unix_uid);
1214 strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
1215 if (hdr->user[sizeof(hdr->user)-1])
1216 hdr->user[sizeof(hdr->user)-1] = 0;
1222 struct group *ent = getgrgid(hdr->unix_gid);
1225 strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
1226 if (hdr->group[sizeof(hdr->group)-1])
1227 hdr->group[sizeof(hdr->group)-1] = 0;
1231 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
1232 if (is_directory(v_stat)) {
1233 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1234 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1235 hdr->original_size = 0;
1236 if (len > 0 && hdr->name[len - 1] != '/')
1237 strcpy(&hdr->name[len++], "/");
1241 if (is_symlink(v_stat)) {
1242 char lkname[FILENAME_LENGTH];
1244 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1245 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1246 hdr->original_size = 0;
1247 len = readlink(name, lkname, sizeof(lkname));
1248 if (xsnprintf(hdr->name, sizeof(hdr->name),
1249 "%s|%.*s", hdr->name, len, lkname) == -1)
1250 error("file name is too long (%s -> %.*s)", hdr->name, len, lkname);
1256 write_unix_info(hdr)
1259 /* UNIX specific informations */
1261 put_word(5); /* size */
1262 put_byte(0x50); /* permission */
1263 put_word(hdr->unix_mode);
1265 put_word(7); /* size */
1266 put_byte(0x51); /* gid and uid */
1267 put_word(hdr->unix_gid);
1268 put_word(hdr->unix_uid);
1270 if (hdr->group[0]) {
1271 int len = strlen(hdr->group);
1272 put_word(len + 3); /* size */
1273 put_byte(0x52); /* group name */
1274 put_bytes(hdr->group, len);
1278 int len = strlen(hdr->user);
1279 put_word(len + 3); /* size */
1280 put_byte(0x53); /* user name */
1281 put_bytes(hdr->user, len);
1284 if (hdr->header_level == 1) {
1285 put_word(7); /* size */
1286 put_byte(0x54); /* time stamp */
1287 put_longword(hdr->unix_last_modified_stamp);
1291 /* ------------------------------------------------------------------------ */
1292 /* Write unix extended header or generic header. */
1295 write_header_level0(data, hdr, pathname)
1297 char *data, *pathname;
1304 memset(data, 0, LZHEADER_STORAGE);
1306 put_byte(0x00); /* header size */
1307 put_byte(0x00); /* check sum */
1308 put_bytes(hdr->method, 5);
1309 put_longword(hdr->packed_size);
1310 put_longword(hdr->original_size);
1311 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1312 put_byte(hdr->attribute);
1313 put_byte(hdr->header_level); /* level 0 */
1315 /* write pathname (level 0 header contains the directory part) */
1316 name_length = strlen(pathname);
1318 limit = 255 - I_GENERIC_HEADER_BOTTOM + 2;
1320 limit = 255 - I_UNIX_EXTEND_BOTTOM + 2;
1322 if (name_length > limit) {
1323 warning("the length of pathname \"%s\" is too long.", pathname);
1324 name_length = limit;
1326 put_byte(name_length);
1327 put_bytes(pathname, name_length);
1330 if (generic_format) {
1331 header_size = I_GENERIC_HEADER_BOTTOM + name_length - 2;
1332 data[I_HEADER_SIZE] = header_size;
1333 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1335 /* write old-style extend header */
1336 put_byte(EXTEND_UNIX);
1337 put_byte(CURRENT_UNIX_MINOR_VERSION);
1338 put_longword(hdr->unix_last_modified_stamp);
1339 put_word(hdr->unix_mode);
1340 put_word(hdr->unix_uid);
1341 put_word(hdr->unix_gid);
1343 /* size of extended header is 12 */
1344 header_size = I_UNIX_EXTEND_BOTTOM + name_length - 2;
1345 data[I_HEADER_SIZE] = header_size;
1346 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1349 return header_size + 2;
1353 write_header_level1(data, hdr, pathname)
1355 char *data, *pathname;
1357 int name_length, dir_length, limit;
1358 char *basename, *dirname;
1360 char *extend_header_top;
1361 int extend_header_size;
1363 basename = strrchr(pathname, LHA_PATHSEP);
1366 name_length = strlen(basename);
1368 dir_length = basename - dirname;
1371 basename = pathname;
1372 name_length = strlen(basename);
1378 memset(data, 0, LZHEADER_STORAGE);
1380 put_byte(0x00); /* header size */
1381 put_byte(0x00); /* check sum */
1382 put_bytes(hdr->method, 5);
1383 put_longword(hdr->packed_size);
1384 put_longword(hdr->original_size);
1385 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1387 put_byte(hdr->header_level); /* level 1 */
1389 /* level 1 header: write filename (basename only) */
1390 limit = 255 - 27 + 2;
1391 if (name_length > limit) {
1392 put_byte(0); /* name length */
1395 put_byte(name_length);
1396 put_bytes(basename, name_length);
1404 put_byte(EXTEND_UNIX);
1406 /* write extend header from here. */
1408 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1409 header_size = extend_header_top - data - 2;
1411 /* write filename and dirname */
1413 if (name_length > limit) {
1414 put_word(name_length + 3); /* size */
1415 put_byte(0x01); /* filename */
1416 put_bytes(basename, name_length);
1419 if (dir_length > 0) {
1420 put_word(dir_length + 3); /* size */
1421 put_byte(0x02); /* dirname */
1422 put_bytes(dirname, dir_length);
1425 if (!generic_format)
1426 write_unix_info(hdr);
1428 put_word(0x0000); /* next header size */
1430 extend_header_size = put_ptr - extend_header_top;
1431 /* On level 1 header, the packed size field is contains the ext-header */
1432 hdr->packed_size += put_ptr - extend_header_top;
1434 /* put `skip size' */
1435 setup_put(data + I_PACKED_SIZE);
1436 put_longword(hdr->packed_size);
1438 data[I_HEADER_SIZE] = header_size;
1439 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1441 return header_size + extend_header_size + 2;
1445 write_header_level2(data, hdr, pathname)
1447 char *data, *pathname;
1449 int name_length, dir_length;
1450 char *basename, *dirname;
1452 char *extend_header_top;
1453 char *headercrc_ptr;
1456 basename = strrchr(pathname, LHA_PATHSEP);
1459 name_length = strlen(basename);
1461 dir_length = basename - dirname;
1464 basename = pathname;
1465 name_length = strlen(basename);
1471 memset(data, 0, LZHEADER_STORAGE);
1473 put_word(0x0000); /* header size */
1474 put_bytes(hdr->method, 5);
1475 put_longword(hdr->packed_size);
1476 put_longword(hdr->original_size);
1477 put_longword(hdr->unix_last_modified_stamp);
1479 put_byte(hdr->header_level); /* level 2 */
1486 put_byte(EXTEND_UNIX);
1488 /* write extend header from here. */
1490 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1492 /* write common header */
1495 headercrc_ptr = put_ptr;
1496 put_word(0x0000); /* header CRC */
1498 /* write filename and dirname */
1499 /* must have this header, even if the name_length is 0. */
1500 put_word(name_length + 3); /* size */
1501 put_byte(0x01); /* filename */
1502 put_bytes(basename, name_length);
1504 if (dir_length > 0) {
1505 put_word(dir_length + 3); /* size */
1506 put_byte(0x02); /* dirname */
1507 put_bytes(dirname, dir_length);
1510 if (!generic_format)
1511 write_unix_info(hdr);
1513 put_word(0x0000); /* next header size */
1515 header_size = put_ptr - data;
1516 if ((header_size & 0xff) == 0) {
1517 /* cannot put zero at the first byte on level 2 header. */
1518 /* adjust header size. */
1519 put_byte(0); /* padding */
1523 /* put hader size */
1524 setup_put(data + I_HEADER_SIZE);
1525 put_word(header_size);
1527 /* put hader CRC in extended header */
1528 INITIALIZE_CRC(hcrc);
1529 hcrc = calccrc(hcrc, data, (unsigned int) header_size);
1530 setup_put(headercrc_ptr);
1537 write_header(fp, hdr)
1542 char data[LZHEADER_STORAGE];
1544 int archive_kanji_code = CODE_SJIS;
1545 int system_kanji_code = default_system_kanji_code;
1546 char *archive_delim = "\377";
1547 char *system_delim = "/";
1548 int filename_case = NONE;
1549 char pathname[FILENAME_LENGTH];
1551 if (optional_archive_kanji_code)
1552 archive_kanji_code = optional_archive_kanji_code;
1553 if (optional_system_kanji_code)
1554 system_kanji_code = optional_system_kanji_code;
1557 filename_case = TO_UPPER;
1559 if (hdr->header_level == HEADER_LEVEL0) {
1560 archive_delim = "\\";
1563 strncpy(pathname, hdr->name, sizeof(pathname));
1564 pathname[sizeof(pathname)-1] = 0;
1565 convert_filename(pathname, strlen(pathname), sizeof(pathname),
1568 system_delim, archive_delim, filename_case);
1570 switch (hdr->header_level) {
1572 header_size = write_header_level0(data, hdr, pathname);
1575 header_size = write_header_level1(data, hdr, pathname);
1578 header_size = write_header_level2(data, hdr, pathname);
1581 error("Unknown level header (level %d)", hdr->header_level);
1585 if (fwrite(data, header_size, 1, fp) == 0)
1586 fatal_error("Cannot write to temporary file");
1589 #if MULTIBYTE_FILENAME
1591 #if defined(__APPLE__)
1593 #include <CoreFoundation/CFString.h>
1594 #include <CoreFoundation/CFStringEncodingExt.h>
1596 /* this is not need for Mac OS X v 10.2 later */
1598 kCFStringEncodingAllowLossyConversion = 1,
1599 kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1600 kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1601 kCFStringEncodingSubstituteCombinings = (1 << 3),
1602 kCFStringEncodingComposeCombinings = (1 << 4),
1603 kCFStringEncodingIgnoreCombinings = (1 << 5),
1604 kCFStringEncodingUseCanonical = (1 << 6),
1605 kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1606 kCFStringEncodingPrependBOM = (1 << 8),
1607 kCFStringEncodingDisableCorporateArea = (1 << 9),
1608 kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1612 ConvertEncodingToUTF8(const char* inCStr,
1613 char* outUTF8Buffer,
1614 int outUTF8BufferLength,
1615 unsigned long scriptEncoding,
1616 unsigned long flags)
1618 unsigned long unicodeChars;
1619 unsigned long srcCharsUsed;
1620 unsigned long usedByteLen = 0;
1621 UniChar uniStr[512];
1622 unsigned long cfResult;
1624 cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1632 if (cfResult == 0) {
1633 cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1638 (char*)outUTF8Buffer,
1639 outUTF8BufferLength - 1,
1641 outUTF8Buffer[usedByteLen] = '\0';
1648 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1649 int inUTF8BufLength,
1650 char* outCStrBuffer,
1651 int outCStrBufferLength,
1652 unsigned long scriptEncoding,
1653 unsigned long flags)
1655 unsigned long unicodeChars;
1656 unsigned long srcCharsUsed;
1657 unsigned long usedByteLen = 0;
1658 UniChar uniStr[256];
1659 unsigned long cfResult;
1661 cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1669 if (cfResult == 0) {
1670 cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1675 (char*)outCStrBuffer,
1676 outCStrBufferLength - 1,
1678 outCStrBuffer[usedByteLen] = '\0';
1688 ConvertEncodingByIconv(const char *src, char *dst, int dstsize,
1689 const char *srcEnc, const char *dstEnc)
1692 static char szTmpBuf[2048];
1698 dst_p = &szTmpBuf[0];
1699 iLen = (size_t)sizeof(szTmpBuf)-1;
1700 src_p = (char *)src;
1701 sLen = (size_t)strlen(src);
1702 memset(szTmpBuf, 0, sizeof(szTmpBuf));
1703 memset(dst, 0, dstsize);
1705 ic = iconv_open(dstEnc, srcEnc);
1706 if (ic == (iconv_t)-1) {
1707 error("iconv_open() failure: %s", strerror(errno));
1711 if (iconv(ic, &src_p, &sLen, &dst_p, &iLen) == (size_t)-1) {
1712 error("iconv() failure: %s", strerror(errno));
1717 strncpy(dst, szTmpBuf, dstsize);
1723 #endif /* defined(__APPLE__) */
1726 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1728 #if defined(__APPLE__)
1730 if (ConvertEncodingToUTF8(src, dst, dstsize,
1731 kCFStringEncodingDOSJapanese,
1732 kCFStringEncodingUseHFSPlusCanonical) == 0)
1735 if (ConvertEncodingByIconv(src, dst, dstsize, "SJIS", "UTF-8") != -1)
1738 error("not support utf-8 conversion");
1741 if (dstsize < 1) return dst;
1743 return strncpy(dst, src, dstsize-1);
1747 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1749 #if defined(__APPLE__)
1753 srclen = strlen(src);
1754 if (ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1755 kCFStringEncodingDOSJapanese,
1756 kCFStringEncodingUseHFSPlusCanonical) == 0)
1759 if (ConvertEncodingByIconv(src, dst, dstsize, "UTF-8", "SJIS") != -1)
1762 error("not support utf-8 conversion");
1765 if (dstsize < 1) return dst;
1767 return strncpy(dst, src, dstsize-1);
1771 * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1772 * ¡ÖÆüËܸì¾ðÊó½èÍý¡× ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1773 * ¤è¤êÈ´¿è(by Koji Arai)
1776 euc2sjis(int *p1, int *p2)
1778 unsigned char c1 = *p1 & 0x7f;
1779 unsigned char c2 = *p2 & 0x7f;
1780 int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1781 int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1782 *p1 = ((c1 + 1) >> 1) + rowoff;
1783 *p2 += celoff - 0x80;
1787 sjis2euc(int *p1, int *p2)
1789 unsigned char c1 = *p1;
1790 unsigned char c2 = *p2;
1791 int adjust = c2 < 0x9f;
1792 int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1793 int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1794 *p1 = ((c1 - rowoff) << 1) - adjust;
1800 #endif /* MULTIBYTE_FILENAME */
1802 /* Local Variables: */
1805 /* compile-command:"gcc -c header.c" */
1807 /* vi: set tabstop=4: */