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());
97 printf("... ignored\n");
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++) {
180 if (i < size) buf[i] = get_ptr[i];
182 if (verbose_listing && verbose > 1) {
184 printf("%c", buf[i]);
186 printf("\\x%02x", (unsigned char)buf[i]);
190 if (verbose_listing && verbose > 1)
193 for (i = 0; i < len && i < size; i++)
207 for (i = 0; i < len; i++)
211 /* added by Koji Arai */
213 convert_filename(name, len, size,
215 from_delim, to_delim,
220 int from_code, to_code, case_to;
221 char *from_delim, *to_delim;
225 #ifdef MULTIBYTE_FILENAME
226 char tmp[FILENAME_LENGTH];
228 if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
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 sjis_to_utf8(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_UTF8;
240 else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
241 for (i = 0; i < len; i++)
242 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
243 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
244 utf8_to_sjis(tmp, name, sizeof(tmp));
245 strncpy(name, tmp, size);
248 for (i = 0; i < len; i++)
249 if (name[i] == '/') name[i] = LHA_PATHSEP;
250 from_code = CODE_SJIS;
254 /* special case: if `name' has small lettter, not convert case. */
255 if (from_code == CODE_SJIS && case_to == TO_LOWER) {
256 for (i = 0; i < len; i++) {
257 #ifdef MULTIBYTE_FILENAME
258 if (SJIS_FIRST_P(name[i]) && SJIS_SECOND_P(name[i+1]))
262 if (islower(name[i])) {
269 for (i = 0; i < len; i ++) {
270 #ifdef MULTIBYTE_FILENAME
271 if (from_code == CODE_EUC &&
272 (unsigned char)name[i] == 0x8e) {
273 if (to_code != CODE_SJIS) {
279 memmove(name + i, name + i + 1, len - i);
283 if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
284 if (to_code != CODE_EUC) {
288 if (len == size - 1) /* check overflow */
290 memmove(name+i+1, name+i, len-i);
296 if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
298 if (to_code != CODE_SJIS) {
303 c1 = (unsigned char)name[i];
304 c2 = (unsigned char)name[i+1];
311 if (from_code == CODE_SJIS &&
312 SJIS_FIRST_P(name[i]) &&
313 SJIS_SECOND_P(name[i+1])) {
316 if (to_code != CODE_EUC) {
321 c1 = (unsigned char)name[i];
322 c2 = (unsigned char)name[i+1];
329 #endif /* MULTIBYTE_FILENAME */
333 /* transpose from_delim to to_delim */
335 if ((ptr = strchr(from_delim, name[i])) != NULL) {
336 name[i] = to_delim[ptr - from_delim];
341 if (case_to == TO_UPPER && islower(name[i])) {
342 name[i] = toupper(name[i]);
345 if (case_to == TO_LOWER && isupper(name[i])) {
346 name[i] = tolower(name[i]);
352 /* ------------------------------------------------------------------------ */
354 /* Generic stamp format: */
356 /* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 */
357 /* |<------- year ----->|<- month ->|<--- day ---->| */
359 /* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */
360 /* |<--- hour --->|<---- minute --->|<- second*2 ->| */
362 /* ------------------------------------------------------------------------ */
365 * NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
366 * returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or TZSET.
370 #include <sys/timeb.h>
373 #if !defined(HAVE_MKTIME) && !defined(HAVE_TIMELOCAL)
379 extern long timezone; /* not defined in time.h */
388 return buf.timezone * 60L;
389 #elif HAVE_STRUCT_TM_TM_GMTOFF
393 return -localtime(&tt)->tm_gmtoff;
394 #elif GETTIMEOFDAY_HAS_2ND_ARG
397 gettimeofday(&tp, &tzp);/* specific to 4.3BSD */
399 * return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L *
402 return (tzp.tz_minuteswest * 60L);
404 /* Compile error will be caused */
405 CANNOT GET TIMEZONE INFORMATION ON YOUR SYSTEM.
406 TAKE THE ANOTHER WAY.
411 /* ------------------------------------------------------------------------ */
413 generic_to_unix_stamp(t)
416 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
420 * special case: if MSDOS format date and time were zero, then we
421 * set time to be zero here too.
426 dostm.tm_sec = (t & 0x1f) * 2;
427 dostm.tm_min = t >> 5 & 0x3f;
428 dostm.tm_hour = t >> 11 & 0x1f;
429 dostm.tm_mday = t >> 16 & 0x1f;
430 dostm.tm_mon = (t >> (16+5) & 0x0f) - 1; /* 0..11 */
431 dostm.tm_year = (t >> (16+9) & 0x7f) + 80;
435 return (time_t) mktime(&dostm);
436 #else /* HAVE_TIMELOCAL is defined */
437 return (time_t) timelocal(&dostm);
440 #else /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
441 int year, month, day, hour, min, sec;
443 static unsigned int dsboy[12] = {0, 31, 59, 90, 120, 151,
444 181, 212, 243, 273, 304, 334};
448 * special case: if MSDOS format date and time were zero, then we
449 * set time to be zero here too.
454 year = ((int) (t >> 16 + 9) & 0x7f) + 1980;
455 month = (int) (t >> 16 + 5) & 0x0f; /* 1..12 means Jan..Dec */
456 day = (int) (t >> 16) & 0x1f; /* 1..31 means 1st,...31st */
458 hour = ((int) t >> 11) & 0x1f;
459 min = ((int) t >> 5) & 0x3f;
460 sec = ((int) t & 0x1f) * 2;
462 /* Calculate days since 1970.01.01 */
463 days = (365 * (year - 1970) + /* days due to whole years */
464 (year - 1970 + 1) / 4 + /* days due to leap years */
465 dsboy[month - 1] + /* days since beginning of this year */
466 day - 1); /* days since beginning of month */
468 if ((year % 4 == 0) &&
469 (year % 100 != 0 || year % 400 == 0) && /* 1999.5.24 t.oka */
470 (month >= 3)) /* if this is a leap year and month */
471 days++; /* is March or later, add a day */
473 /* Knowing the days, we can find seconds */
474 longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
475 longtime += gettz(); /* adjust for timezone */
477 /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00. */
478 return (time_t) longtime;
479 #endif /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
482 /* ------------------------------------------------------------------------ */
484 unix_to_generic_stamp(t)
487 struct tm *tm = localtime(&t);
489 return ((((long) (tm->tm_year - 80)) << 25) +
490 (((long) (tm->tm_mon + 1)) << 21) +
491 (((long) tm->tm_mday) << 16) +
492 (long) ((tm->tm_hour << 11) +
498 wintime_to_unix_stamp()
502 uint64_t epoch = 0x019db1ded53e8000; /* 1970-01-01 00:00:00 (UTC) */
505 t += (uint64_t)get_longword() << 32;
506 t = (t - epoch) / 10000000;
510 unsigned long t, q, x;
511 unsigned long wintime[8];
512 unsigned long epoch[8] = {0x01,0x9d,0xb1,0xde, 0xd5,0x3e,0x80,0x00};
513 /* 1970-01-01 00:00:00 (UTC) */
514 /* wintime -= epoch */
516 for (i = 7; i >= 0; i--) {
517 wintime[i] = (unsigned)get_byte() - epoch[i] - borrow;
518 borrow = (wintime[i] > 0xff) ? 1 : 0;
522 /* q = wintime / 10000000 */
524 x = 10000000; /* x: 24bit */
525 for (i = 0; i < 8; i++) {
526 t = (t << 8) + wintime[i]; /* 24bit + 8bit. t must be 32bit variable */
527 q <<= 8; /* q must be 32bit (time_t) */
535 /* ------------------------------------------------------------------------ */
536 /* build header functions */
537 /* ------------------------------------------------------------------------ */
543 * --------------------------------
545 * 2 or 4 next-header size [*1]
546 * --------------------------------------
547 * ext header: 1 ext-type ^
548 * ? contents | [*1] next-header size
549 * 2 or 4 next-header size v
550 * --------------------------------------
552 * on level 1, 2 header:
553 * size field is 2 bytes
555 * size field is 4 bytes
559 get_extended_header(fp, hdr, header_size, hcrc)
565 char data[LZHEADER_STORAGE];
567 char dirname[FILENAME_LENGTH];
570 ssize_t whole_size = header_size;
572 int n = 1 + hdr->size_field_length; /* `ext-type' + `next-header size' */
574 if (hdr->header_level == 0)
577 name_length = strlen(hdr->name);
579 while (header_size) {
581 if (sizeof(data) < header_size) {
582 error("header size (%ld) too large.", header_size);
586 if (fread(data, header_size, 1, fp) == 0) {
587 error("Invalid header (LHa file ?)");
591 ext_type = get_byte();
594 /* header crc (CRC-16) */
595 hdr->header_crc = get_word();
596 /* clear buffer for CRC calculation. */
597 data[1] = data[2] = 0;
598 skip_bytes(header_size - n - 2);
603 get_bytes(hdr->name, header_size-n, sizeof(hdr->name)-1);
604 hdr->name[name_length] = 0;
608 dir_length = get_bytes(dirname, header_size-n, sizeof(dirname)-1);
609 dirname[dir_length] = 0;
612 /* MS-DOS attribute */
613 hdr->attribute = get_word();
616 /* Windows time stamp (FILETIME structure) */
617 /* it is time in 100 nano seconds since 1601-01-01 00:00:00 */
619 skip_bytes(8); /* create time is ignored */
621 /* set last modified time */
622 if (hdr->header_level >= 2)
623 skip_bytes(8); /* time_t has been already set */
625 hdr->unix_last_modified_stamp = wintime_to_unix_stamp();
627 skip_bytes(8); /* last access time is ignored */
631 /* UNIX permission */
632 hdr->unix_mode = get_word();
635 /* UNIX gid and uid */
636 hdr->unix_gid = get_word();
637 hdr->unix_uid = get_word();
640 /* UNIX group name */
641 i = get_bytes(hdr->group, header_size-n, sizeof(hdr->group)-1);
642 hdr->group[i] = '\0';
646 i = get_bytes(hdr->user, header_size-n, sizeof(hdr->user)-1);
650 /* UNIX last modified time */
651 hdr->unix_last_modified_stamp = (time_t) get_longword();
655 /* 0x39: multi-disk header
656 0x3f: uncompressed comment
657 0x42: 64bit large file size
658 0x48-0x4f(?): reserved for authenticity verification
660 0x7e: extended attribute - platform information
661 0x7f: extended attribute - permission, owner-id and timestamp
663 0xc4: compressed comment (dict size: 4096)
664 0xc5: compressed comment (dict size: 8192)
665 0xc6: compressed comment (dict size: 16384)
666 0xc7: compressed comment (dict size: 32768)
667 0xc8: compressed comment (dict size: 65536)
668 0xd0-0xdf(?): operating systemm specific information
669 0xfc: encapsulation (another opinion)
670 0xfe: extended attribute - platform information(another opinion)
671 0xff: extended attribute - permission, owner-id and timestamp
672 (level 3 on UNLHA32) */
674 warning("unknown extended header 0x%02x", ext_type);
675 skip_bytes(header_size - n);
680 *hcrc = calccrc(*hcrc, data, header_size);
682 if (hdr->size_field_length == 2)
683 whole_size += header_size = get_word();
685 whole_size += header_size = get_longword();
688 /* concatenate dirname and filename */
690 if (name_length + dir_length >= sizeof(hdr->name)) {
691 warning("the length of pathname \"%s%s\" is too long.",
693 name_length = sizeof(hdr->name) - dir_length - 1;
694 hdr->name[name_length] = 0;
696 strcat(dirname, hdr->name);
697 strcpy(hdr->name, dirname);
698 name_length += dir_length;
704 #define I_HEADER_SIZE 0 /* level 0,1,2 */
705 #define I_HEADER_CHECKSUM 1 /* level 0,1 */
706 #define I_METHOD 2 /* level 0,1,2,3 */
707 #define I_PACKED_SIZE 7 /* level 0,1,2,3 */
708 #define I_ATTRIBUTE 19 /* level 0,1,2,3 */
709 #define I_HEADER_LEVEL 20 /* level 0,1,2,3 */
711 #define COMMON_HEADER_SIZE 21 /* size of common part */
713 #define I_GENERIC_HEADER_SIZE 24 /* + name_length */
714 #define I_LEVEL0_HEADER_SIZE 36 /* + name_length (unix extended) */
715 #define I_LEVEL1_HEADER_SIZE 27 /* + name_length */
716 #define I_LEVEL2_HEADER_SIZE 26 /* + padding */
717 #define I_LEVEL3_HEADER_SIZE 32
723 * offset size field name
724 * ----------------------------------
725 * 0 1 header size [*1]
727 * ---------------------------------------
729 * 7 4 packed size [*2] |
730 * 11 4 original size |
733 * 19 1 attribute | [*1] header size (X+Y+22)
734 * 20 1 level (0x00 fixed) |
737 * X +22 2 file crc (CRC-16) |
738 * X +24 Y ext-header(old style) v
739 * -------------------------------------------------
741 * : | [*2] packed size
743 * -------------------------------------------------
745 * ext-header(old style)
759 * bit6 archive bit (need to backup)
763 get_header_level0(fp, hdr, data)
774 hdr->size_field_length = 2; /* in bytes */
775 hdr->header_size = header_size = get_byte();
776 checksum = get_byte();
778 if (fread(data + COMMON_HEADER_SIZE,
779 header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
780 error("Invalid header (LHarc file ?)");
781 return FALSE; /* finish */
784 if (calc_sum(data + I_METHOD, header_size) != checksum) {
785 error("Checksum error (LHarc file?)");
789 get_bytes(hdr->method, 5, sizeof(hdr->method));
790 hdr->packed_size = get_longword();
791 hdr->original_size = get_longword();
792 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
793 hdr->attribute = get_byte(); /* MS-DOS attribute */
794 hdr->header_level = get_byte();
795 name_length = get_byte();
796 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
799 /* defaults for other type */
800 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
804 extend_size = header_size+2 - name_length - 24;
806 if (extend_size < 0) {
807 if (extend_size == -2) {
808 /* CRC field is not given */
809 hdr->extend_type = EXTEND_GENERIC;
810 hdr->has_crc = FALSE;
815 error("Unkonwn header (lha file?)");
820 hdr->crc = get_word();
822 if (extend_size == 0)
825 hdr->extend_type = get_byte();
828 if (hdr->extend_type == EXTEND_UNIX) {
829 if (extend_size >= 11) {
830 hdr->minor_version = get_byte();
831 hdr->unix_last_modified_stamp = (time_t) get_longword();
832 hdr->unix_mode = get_word();
833 hdr->unix_uid = get_word();
834 hdr->unix_gid = get_word();
837 hdr->extend_type = EXTEND_GENERIC;
841 skip_bytes(extend_size);
843 hdr->header_size += 2;
851 * offset size field name
852 * -----------------------------------
853 * 0 1 header size [*1]
855 * -------------------------------------
857 * 7 4 skip size [*2] |
858 * 11 4 original size |
861 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
862 * 20 1 level (0x01 fixed) |
865 * X+ 22 2 file crc (CRC-16) |
868 * X+Y+25 2 next-header size v
869 * -------------------------------------------------
870 * X+Y+27 Z ext-header ^
872 * ----------------------------------- | [*2] skip size
875 * -------------------------------------------------
879 get_header_level1(fp, hdr, data)
890 hdr->size_field_length = 2; /* in bytes */
891 hdr->header_size = header_size = get_byte();
892 checksum = get_byte();
894 if (fread(data + COMMON_HEADER_SIZE,
895 header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
896 error("Invalid header (LHarc file ?)");
897 return FALSE; /* finish */
900 if (calc_sum(data + I_METHOD, header_size) != checksum) {
901 error("Checksum error (LHarc file?)");
905 get_bytes(hdr->method, 5, sizeof(hdr->method));
906 hdr->packed_size = get_longword(); /* skip size */
907 hdr->original_size = get_longword();
908 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
909 hdr->attribute = get_byte(); /* 0x20 fixed */
910 hdr->header_level = get_byte();
912 name_length = get_byte();
913 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
916 /* defaults for other type */
917 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
922 hdr->crc = get_word();
923 hdr->extend_type = get_byte();
925 dummy = header_size+2 - name_length - I_LEVEL1_HEADER_SIZE;
927 skip_bytes(dummy); /* skip old style extend header */
929 extend_size = get_word();
930 extend_size = get_extended_header(fp, hdr, extend_size, 0);
931 if (extend_size == -1)
934 /* On level 1 header, size fields should be adjusted. */
935 /* the `packed_size' field contains the extended header size. */
936 /* the `header_size' field does not. */
937 hdr->packed_size -= extend_size;
938 hdr->header_size += extend_size + 2;
947 * offset size field name
948 * --------------------------------------------------
949 * 0 2 total header size [*1] ^
950 * ----------------------- |
952 * 7 4 packed size [*2] |
953 * 11 4 original size |
955 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
956 * 20 1 level (0x02 fixed) | (X+26+(1))
957 * 21 2 file crc (CRC-16) |
959 * 24 2 next-header size |
960 * ----------------------------------- |
963 * ----------------------------------- |
964 * X +26 (1) padding v
965 * -------------------------------------------------
967 * : | [*2] packed size
969 * -------------------------------------------------
973 get_header_level2(fp, hdr, data)
983 hdr->size_field_length = 2; /* in bytes */
984 hdr->header_size = header_size = get_word();
986 if (fread(data + COMMON_HEADER_SIZE,
987 I_LEVEL2_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
988 error("Invalid header (LHarc file ?)");
989 return FALSE; /* finish */
992 get_bytes(hdr->method, 5, sizeof(hdr->method));
993 hdr->packed_size = get_longword();
994 hdr->original_size = get_longword();
995 hdr->unix_last_modified_stamp = get_longword();
996 hdr->attribute = get_byte(); /* reserved */
997 hdr->header_level = get_byte();
999 /* defaults for other type */
1000 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
1004 hdr->has_crc = TRUE;
1005 hdr->crc = get_word();
1006 hdr->extend_type = get_byte();
1007 extend_size = get_word();
1009 INITIALIZE_CRC(hcrc);
1010 hcrc = calccrc(hcrc, data, get_ptr - data);
1012 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
1013 if (extend_size == -1)
1016 padding = header_size - I_LEVEL2_HEADER_SIZE - extend_size;
1017 while (padding--) /* padding should be 0 or 1 */
1018 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
1020 if (hdr->header_crc != hcrc)
1021 error("header CRC error");
1030 * offset size field name
1031 * --------------------------------------------------
1032 * 0 2 size field length (4 fixed) ^
1034 * 7 4 packed size [*2] |
1035 * 11 4 original size |
1037 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
1038 * 20 1 level (0x03 fixed) | (X+32)
1039 * 21 2 file crc (CRC-16) |
1041 * 24 4 total header size [*1] |
1042 * 28 4 next-header size |
1043 * ----------------------------------- |
1046 * -------------------------------------------------
1048 * : | [*2] packed size
1050 * -------------------------------------------------
1054 get_header_level3(fp, hdr, data)
1060 ssize_t extend_size;
1064 hdr->size_field_length = get_word();
1066 if (fread(data + COMMON_HEADER_SIZE,
1067 I_LEVEL3_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
1068 error("Invalid header (LHarc file ?)");
1069 return FALSE; /* finish */
1072 get_bytes(hdr->method, 5, sizeof(hdr->method));
1073 hdr->packed_size = get_longword();
1074 hdr->original_size = get_longword();
1075 hdr->unix_last_modified_stamp = get_longword();
1076 hdr->attribute = get_byte(); /* reserved */
1077 hdr->header_level = get_byte();
1079 /* defaults for other type */
1080 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
1084 hdr->has_crc = TRUE;
1085 hdr->crc = get_word();
1086 hdr->extend_type = get_byte();
1087 hdr->header_size = header_size = get_longword();
1088 extend_size = get_longword();
1090 INITIALIZE_CRC(hcrc);
1091 hcrc = calccrc(hcrc, data, get_ptr - data);
1093 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
1094 if (extend_size == -1)
1097 padding = header_size - I_LEVEL3_HEADER_SIZE - extend_size;
1098 while (padding--) /* padding should be 0 */
1099 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
1101 if (hdr->header_crc != hcrc)
1102 error("header CRC error");
1112 char data[LZHEADER_STORAGE];
1114 int archive_kanji_code = CODE_SJIS;
1115 int system_kanji_code = default_system_kanji_code;
1116 char *archive_delim = "\377\\"; /* `\' is for level 0 header and
1118 char *system_delim = "//";
1119 int filename_case = NONE;
1122 memset(hdr, 0, sizeof(LzHeader));
1126 if ((end_mark = getc(fp)) == EOF || end_mark == 0) {
1127 return FALSE; /* finish */
1131 if (fread(data + 1, COMMON_HEADER_SIZE - 1, 1, fp) == 0) {
1132 error("Invalid header (LHarc file ?)");
1133 return FALSE; /* finish */
1136 switch (data[I_HEADER_LEVEL]) {
1138 if (get_header_level0(fp, hdr, data) == FALSE)
1142 if (get_header_level1(fp, hdr, data) == FALSE)
1146 if (get_header_level2(fp, hdr, data) == FALSE)
1150 if (get_header_level3(fp, hdr, data) == FALSE)
1154 error("Unknown level header (level %d)", data[I_HEADER_LEVEL]);
1158 /* filename conversion */
1159 switch (hdr->extend_type) {
1161 filename_case = noconvertcase ? NONE : TO_LOWER;
1168 filename_case = NONE;
1172 archive_delim = "\377/:\\";
1173 /* `\' is for level 0 header and broken archive. */
1174 system_delim = "/://";
1175 filename_case = NONE;
1179 filename_case = noconvertcase ? NONE : TO_LOWER;
1183 if (optional_archive_kanji_code)
1184 archive_kanji_code = optional_archive_kanji_code;
1185 if (optional_system_kanji_code)
1186 system_kanji_code = optional_system_kanji_code;
1187 if (optional_archive_delim)
1188 archive_delim = optional_archive_delim;
1189 if (optional_system_delim)
1190 system_delim = optional_system_delim;
1191 if (optional_filename_case)
1192 filename_case = optional_filename_case;
1194 /* kanji code and delimiter conversion */
1195 convert_filename(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1198 archive_delim, system_delim, filename_case);
1200 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1202 /* split symbolic link */
1203 p = strchr(hdr->name, '|');
1205 /* hdr->name is symbolic link name */
1206 /* hdr->realname is real name */
1208 strncpy(hdr->realname, p+1, sizeof(hdr->realname));
1211 error("unknown symlink name \"%s\"", hdr->name);
1217 /* skip SFX header */
1222 unsigned char buffer[64 * 1024]; /* max seek size */
1226 n = fread(buffer, 1, sizeof(buffer), fp);
1228 for (p = buffer; p < buffer + n; p++) {
1229 if (! (p[I_METHOD]=='-' && p[I_METHOD+1]=='l' && p[I_METHOD+4]=='-'))
1231 /* found "-l??-" keyword (as METHOD type string) */
1233 /* size and checksum validate check */
1235 /* level 0 or 1 header */
1236 if ((p[I_HEADER_LEVEL] == 0 || p[I_HEADER_LEVEL] == 1)
1237 && p[I_HEADER_SIZE] > 20
1238 && p[I_HEADER_CHECKSUM] == calc_sum(p+2, p[I_HEADER_SIZE])) {
1239 if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
1240 fatal_error("cannot seek header");
1244 /* level 2 header */
1245 if (p[I_HEADER_LEVEL] == 2
1246 && p[I_HEADER_SIZE] >= 24
1247 && p[I_ATTRIBUTE] == 0x20) {
1248 if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
1249 fatal_error("cannot seek header");
1254 if (fseek(fp, -n, SEEK_CUR) == -1)
1255 fatal_error("cannot seek header");
1259 /* ------------------------------------------------------------------------ */
1261 init_header(name, v_stat, hdr)
1263 struct stat *v_stat;
1268 memset(hdr, 0, sizeof(LzHeader));
1270 /* the `method' member is rewrote by the encoding function.
1271 but need set for empty files */
1272 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
1274 hdr->packed_size = 0;
1275 hdr->original_size = v_stat->st_size;
1276 hdr->attribute = GENERIC_ATTRIBUTE;
1277 hdr->header_level = header_level;
1278 strcpy(hdr->name, name);
1281 hdr->extend_type = EXTEND_UNIX;
1282 hdr->unix_last_modified_stamp = v_stat->st_mtime;
1283 /* since 00:00:00 JAN.1.1970 */
1284 #ifdef NOT_COMPATIBLE_MODE
1285 /* Please need your modification in this space. */
1287 hdr->unix_mode = v_stat->st_mode;
1290 hdr->unix_uid = v_stat->st_uid;
1291 hdr->unix_gid = v_stat->st_gid;
1293 #if INCLUDE_OWNER_NAME_IN_HEADER
1296 struct passwd *ent = getpwuid(hdr->unix_uid);
1299 strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
1300 if (hdr->user[sizeof(hdr->user)-1])
1301 hdr->user[sizeof(hdr->user)-1] = 0;
1307 struct group *ent = getgrgid(hdr->unix_gid);
1310 strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
1311 if (hdr->group[sizeof(hdr->group)-1])
1312 hdr->group[sizeof(hdr->group)-1] = 0;
1316 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
1317 if (is_directory(v_stat)) {
1318 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1319 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1320 hdr->original_size = 0;
1321 if (len > 0 && hdr->name[len - 1] != '/')
1322 strcpy(&hdr->name[len++], "/");
1326 if (is_symlink(v_stat)) {
1327 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1328 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1329 hdr->original_size = 0;
1330 readlink(name, hdr->realname, sizeof(hdr->realname));
1336 write_unix_info(hdr)
1339 /* UNIX specific informations */
1341 put_word(5); /* size */
1342 put_byte(0x50); /* permission */
1343 put_word(hdr->unix_mode);
1345 put_word(7); /* size */
1346 put_byte(0x51); /* gid and uid */
1347 put_word(hdr->unix_gid);
1348 put_word(hdr->unix_uid);
1350 if (hdr->group[0]) {
1351 int len = strlen(hdr->group);
1352 put_word(len + 3); /* size */
1353 put_byte(0x52); /* group name */
1354 put_bytes(hdr->group, len);
1358 int len = strlen(hdr->user);
1359 put_word(len + 3); /* size */
1360 put_byte(0x53); /* user name */
1361 put_bytes(hdr->user, len);
1364 if (hdr->header_level == 1) {
1365 put_word(7); /* size */
1366 put_byte(0x54); /* time stamp */
1367 put_longword(hdr->unix_last_modified_stamp);
1371 /* ------------------------------------------------------------------------ */
1372 /* Write unix extended header or generic header. */
1375 write_header_level0(data, hdr, pathname)
1377 char *data, *pathname;
1384 memset(data, 0, LZHEADER_STORAGE);
1386 put_byte(0x00); /* header size */
1387 put_byte(0x00); /* check sum */
1388 put_bytes(hdr->method, 5);
1389 put_longword(hdr->packed_size);
1390 put_longword(hdr->original_size);
1391 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1392 put_byte(hdr->attribute);
1393 put_byte(hdr->header_level); /* level 0 */
1395 /* write pathname (level 0 header contains the directory part) */
1396 name_length = strlen(pathname);
1398 limit = 255 - I_GENERIC_HEADER_SIZE + 2;
1400 limit = 255 - I_LEVEL0_HEADER_SIZE + 2;
1402 if (name_length > limit) {
1403 warning("the length of pathname \"%s\" is too long.", pathname);
1404 name_length = limit;
1406 put_byte(name_length);
1407 put_bytes(pathname, name_length);
1410 if (generic_format) {
1411 header_size = I_GENERIC_HEADER_SIZE + name_length - 2;
1412 data[I_HEADER_SIZE] = header_size;
1413 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1415 /* write old-style extend header */
1416 put_byte(EXTEND_UNIX);
1417 put_byte(CURRENT_UNIX_MINOR_VERSION);
1418 put_longword(hdr->unix_last_modified_stamp);
1419 put_word(hdr->unix_mode);
1420 put_word(hdr->unix_uid);
1421 put_word(hdr->unix_gid);
1423 /* size of extended header is 12 */
1424 header_size = I_LEVEL0_HEADER_SIZE + name_length - 2;
1425 data[I_HEADER_SIZE] = header_size;
1426 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1429 return header_size + 2;
1433 write_header_level1(data, hdr, pathname)
1435 char *data, *pathname;
1437 int name_length, dir_length, limit;
1438 char *basename, *dirname;
1440 char *extend_header_top;
1441 size_t extend_header_size;
1443 basename = strrchr(pathname, LHA_PATHSEP);
1446 name_length = strlen(basename);
1448 dir_length = basename - dirname;
1451 basename = pathname;
1452 name_length = strlen(basename);
1458 memset(data, 0, LZHEADER_STORAGE);
1460 put_byte(0x00); /* header size */
1461 put_byte(0x00); /* check sum */
1462 put_bytes(hdr->method, 5);
1463 put_longword(hdr->packed_size);
1464 put_longword(hdr->original_size);
1465 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1467 put_byte(hdr->header_level); /* level 1 */
1469 /* level 1 header: write filename (basename only) */
1470 limit = 255 - I_LEVEL1_HEADER_SIZE + 2;
1471 if (name_length > limit) {
1472 put_byte(0); /* name length */
1475 put_byte(name_length);
1476 put_bytes(basename, name_length);
1484 put_byte(EXTEND_UNIX);
1486 /* write extend header from here. */
1488 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1489 header_size = extend_header_top - data - 2;
1491 /* write filename and dirname */
1493 if (name_length > limit) {
1494 put_word(name_length + 3); /* size */
1495 put_byte(0x01); /* filename */
1496 put_bytes(basename, name_length);
1499 if (dir_length > 0) {
1500 put_word(dir_length + 3); /* size */
1501 put_byte(0x02); /* dirname */
1502 put_bytes(dirname, dir_length);
1505 if (!generic_format)
1506 write_unix_info(hdr);
1508 put_word(0x0000); /* next header size */
1510 extend_header_size = put_ptr - extend_header_top;
1511 /* On level 1 header, the packed size field is contains the ext-header */
1512 hdr->packed_size += put_ptr - extend_header_top;
1514 /* put `skip size' */
1515 setup_put(data + I_PACKED_SIZE);
1516 put_longword(hdr->packed_size);
1518 data[I_HEADER_SIZE] = header_size;
1519 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1521 return header_size + extend_header_size + 2;
1525 write_header_level2(data, hdr, pathname)
1527 char *data, *pathname;
1529 int name_length, dir_length;
1530 char *basename, *dirname;
1532 char *extend_header_top;
1533 char *headercrc_ptr;
1536 basename = strrchr(pathname, LHA_PATHSEP);
1539 name_length = strlen(basename);
1541 dir_length = basename - dirname;
1544 basename = pathname;
1545 name_length = strlen(basename);
1551 memset(data, 0, LZHEADER_STORAGE);
1553 put_word(0x0000); /* header size */
1554 put_bytes(hdr->method, 5);
1555 put_longword(hdr->packed_size);
1556 put_longword(hdr->original_size);
1557 put_longword(hdr->unix_last_modified_stamp);
1559 put_byte(hdr->header_level); /* level 2 */
1566 put_byte(EXTEND_UNIX);
1568 /* write extend header from here. */
1570 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1572 /* write common header */
1575 headercrc_ptr = put_ptr;
1576 put_word(0x0000); /* header CRC */
1578 /* write filename and dirname */
1579 /* must have this header, even if the name_length is 0. */
1580 put_word(name_length + 3); /* size */
1581 put_byte(0x01); /* filename */
1582 put_bytes(basename, name_length);
1584 if (dir_length > 0) {
1585 put_word(dir_length + 3); /* size */
1586 put_byte(0x02); /* dirname */
1587 put_bytes(dirname, dir_length);
1590 if (!generic_format)
1591 write_unix_info(hdr);
1593 put_word(0x0000); /* next header size */
1595 header_size = put_ptr - data;
1596 if ((header_size & 0xff) == 0) {
1597 /* cannot put zero at the first byte on level 2 header. */
1598 /* adjust header size. */
1599 put_byte(0); /* padding */
1603 /* put hader size */
1604 setup_put(data + I_HEADER_SIZE);
1605 put_word(header_size);
1607 /* put hader CRC in extended header */
1608 INITIALIZE_CRC(hcrc);
1609 hcrc = calccrc(hcrc, data, (unsigned int) header_size);
1610 setup_put(headercrc_ptr);
1617 write_header(fp, hdr)
1622 char data[LZHEADER_STORAGE];
1624 int archive_kanji_code = CODE_SJIS;
1625 int system_kanji_code = default_system_kanji_code;
1626 char *archive_delim = "\377";
1627 char *system_delim = "/";
1628 int filename_case = NONE;
1629 char pathname[FILENAME_LENGTH];
1631 if (optional_archive_kanji_code)
1632 archive_kanji_code = optional_archive_kanji_code;
1633 if (optional_system_kanji_code)
1634 system_kanji_code = optional_system_kanji_code;
1637 filename_case = TO_UPPER;
1639 if (hdr->header_level == HEADER_LEVEL0) {
1640 archive_delim = "\\";
1643 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1645 p = strchr(hdr->name, '|');
1647 error("symlink name \"%s\" contains '|' char. change it into '_'",
1651 if (xsnprintf(pathname, sizeof(pathname),
1652 "%s|%s", hdr->name, hdr->realname) == -1)
1653 error("file name is too long (%s -> %s)", hdr->name, hdr->realname);
1656 strncpy(pathname, hdr->name, sizeof(pathname));
1657 pathname[sizeof(pathname)-1] = 0;
1660 convert_filename(pathname, strlen(pathname), sizeof(pathname),
1663 system_delim, archive_delim, filename_case);
1665 switch (hdr->header_level) {
1667 header_size = write_header_level0(data, hdr, pathname);
1670 header_size = write_header_level1(data, hdr, pathname);
1673 header_size = write_header_level2(data, hdr, pathname);
1676 error("Unknown level header (level %d)", hdr->header_level);
1680 if (fwrite(data, header_size, 1, fp) == 0)
1681 fatal_error("Cannot write to temporary file");
1684 #if MULTIBYTE_FILENAME
1686 #if defined(__APPLE__)
1688 #include <CoreFoundation/CFString.h>
1689 #include <CoreFoundation/CFStringEncodingExt.h>
1691 /* this is not need for Mac OS X v 10.2 later */
1693 kCFStringEncodingAllowLossyConversion = 1,
1694 kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1695 kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1696 kCFStringEncodingSubstituteCombinings = (1 << 3),
1697 kCFStringEncodingComposeCombinings = (1 << 4),
1698 kCFStringEncodingIgnoreCombinings = (1 << 5),
1699 kCFStringEncodingUseCanonical = (1 << 6),
1700 kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1701 kCFStringEncodingPrependBOM = (1 << 8),
1702 kCFStringEncodingDisableCorporateArea = (1 << 9),
1703 kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1707 ConvertEncodingToUTF8(const char* inCStr,
1708 char* outUTF8Buffer,
1709 int outUTF8BufferLength,
1710 unsigned long scriptEncoding,
1711 unsigned long flags)
1713 unsigned long unicodeChars;
1714 unsigned long srcCharsUsed;
1715 unsigned long usedByteLen = 0;
1716 UniChar uniStr[512];
1717 unsigned long cfResult;
1719 cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1727 if (cfResult == 0) {
1728 cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1733 (char*)outUTF8Buffer,
1734 outUTF8BufferLength - 1,
1736 outUTF8Buffer[usedByteLen] = '\0';
1743 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1744 int inUTF8BufLength,
1745 char* outCStrBuffer,
1746 int outCStrBufferLength,
1747 unsigned long scriptEncoding,
1748 unsigned long flags)
1750 unsigned long unicodeChars;
1751 unsigned long srcCharsUsed;
1752 unsigned long usedByteLen = 0;
1753 UniChar uniStr[256];
1754 unsigned long cfResult;
1756 cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1764 if (cfResult == 0) {
1765 cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1770 (char*)outCStrBuffer,
1771 outCStrBufferLength - 1,
1773 outCStrBuffer[usedByteLen] = '\0';
1783 ConvertEncodingByIconv(const char *src, char *dst, int dstsize,
1784 const char *srcEnc, const char *dstEnc)
1787 static char szTmpBuf[2048];
1793 dst_p = &szTmpBuf[0];
1794 iLen = (size_t)sizeof(szTmpBuf)-1;
1795 src_p = (char *)src;
1796 sLen = (size_t)strlen(src);
1797 memset(szTmpBuf, 0, sizeof(szTmpBuf));
1798 memset(dst, 0, dstsize);
1800 ic = iconv_open(dstEnc, srcEnc);
1801 if (ic == (iconv_t)-1) {
1802 error("iconv_open() failure: %s", strerror(errno));
1806 if (iconv(ic, &src_p, &sLen, &dst_p, &iLen) == (size_t)-1) {
1807 error("iconv() failure: %s", strerror(errno));
1812 strncpy(dst, szTmpBuf, dstsize);
1818 #endif /* defined(__APPLE__) */
1821 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1823 #if defined(__APPLE__)
1825 if (ConvertEncodingToUTF8(src, dst, dstsize,
1826 kCFStringEncodingDOSJapanese,
1827 kCFStringEncodingUseHFSPlusCanonical) == 0)
1830 if (ConvertEncodingByIconv(src, dst, dstsize, "SJIS", "UTF-8") != -1)
1833 error("not support utf-8 conversion");
1836 if (dstsize < 1) return dst;
1838 return strncpy(dst, src, dstsize-1);
1842 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1844 #if defined(__APPLE__)
1848 srclen = strlen(src);
1849 if (ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1850 kCFStringEncodingDOSJapanese,
1851 kCFStringEncodingUseHFSPlusCanonical) == 0)
1854 if (ConvertEncodingByIconv(src, dst, dstsize, "UTF-8", "SJIS") != -1)
1857 error("not support utf-8 conversion");
1860 if (dstsize < 1) return dst;
1862 return strncpy(dst, src, dstsize-1);
1866 * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1867 * ¡ÖÆüËܸì¾ðÊó½èÍý¡× ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1868 * ¤è¤êÈ´¿è(by Koji Arai)
1871 euc2sjis(int *p1, int *p2)
1873 unsigned char c1 = *p1 & 0x7f;
1874 unsigned char c2 = *p2 & 0x7f;
1875 int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1876 int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1877 *p1 = ((c1 + 1) >> 1) + rowoff;
1878 *p2 += celoff - 0x80;
1882 sjis2euc(int *p1, int *p2)
1884 unsigned char c1 = *p1;
1885 unsigned char c2 = *p2;
1886 int adjust = c2 < 0x9f;
1887 int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1888 int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1889 *p1 = ((c1 - rowoff) << 1) - adjust;
1895 #endif /* MULTIBYTE_FILENAME */