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 /* Ver. 1.14i autoconfiscated & rewritten 2003.02.23 Koji Arai */
14 /* ------------------------------------------------------------------------ */
17 #define DUMP_HEADER 1 /* for debugging */
19 #if !STRCHR_8BIT_CLEAN
20 /* should use 8 bit clean version */
23 #define strchr xstrchr
24 #define strrchr xstrrchr
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;
63 while (len--) sum += *p++;
74 if (verbose_listing && verbose > 1)
75 printf("%02d %2d: ", get_ptr - start_ptr, 1);
77 if (verbose_listing && verbose > 1) {
79 printf("%d(0x%02x) '%c'\n", c, c, c);
81 printf("%d(0x%02x)\n", c, c);
91 if (verbose_listing && verbose > 1) {
92 printf("%02d %2d: ", get_ptr - start_ptr, len);
94 printf("0x%02x ", GET_BYTE());
95 printf("... ignored\n");
109 if (verbose_listing && verbose > 1)
110 printf("%02d %2d: ", get_ptr - start_ptr, 2);
116 if (verbose_listing && verbose > 1)
117 printf("%d(0x%04x)\n", w, w);
137 if (verbose_listing && verbose > 1)
138 printf("%02d %2d: ", get_ptr - start_ptr, 4);
144 l = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
146 if (verbose_listing && verbose > 1)
147 printf("%ld(0x%08lx)\n", l, l);
163 get_bytes(buf, len, size)
170 if (verbose_listing && verbose > 1)
171 printf("%02d %2d: \"", get_ptr - start_ptr, len);
173 for (i = 0; i < len; i++) {
174 if (i < size) buf[i] = get_ptr[i];
176 if (verbose_listing && verbose > 1) {
178 printf("%c", buf[i]);
180 printf("\\x%02x", (unsigned char)buf[i]);
184 if (verbose_listing && verbose > 1)
187 for (i = 0; i < len && i < size; i++)
201 for (i = 0; i < len; i++)
205 /* added by Koji Arai */
207 convert_filename(name, len, size,
209 from_delim, to_delim,
214 int from_code, to_code, case_to;
215 char *from_delim, *to_delim;
219 #ifdef MULTIBYTE_FILENAME
220 char tmp[FILENAME_LENGTH];
222 if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
223 for (i = 0; i < len; i++)
224 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
225 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
226 sjis_to_utf8(tmp, name, sizeof(tmp));
227 strncpy(name, tmp, size);
230 for (i = 0; i < len; i++)
231 if (name[i] == '/') name[i] = LHA_PATHSEP;
232 from_code = CODE_UTF8;
234 else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
235 for (i = 0; i < len; i++)
236 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
237 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
238 utf8_to_sjis(tmp, name, sizeof(tmp));
239 strncpy(name, tmp, size);
242 for (i = 0; i < len; i++)
243 if (name[i] == '/') name[i] = LHA_PATHSEP;
244 from_code = CODE_SJIS;
248 /* special case: if `name' has small lettter, not convert case. */
249 if (from_code == CODE_SJIS && case_to == TO_LOWER) {
250 for (i = 0; i < len; i++) {
251 #ifdef MULTIBYTE_FILENAME
252 if (SJIS_FIRST_P(name[i]) && SJIS_SECOND_P(name[i+1]))
256 if (islower(name[i])) {
263 for (i = 0; i < len; i ++) {
264 #ifdef MULTIBYTE_FILENAME
265 if (from_code == CODE_EUC &&
266 (unsigned char)name[i] == 0x8e) {
267 if (to_code != CODE_SJIS) {
273 memmove(name + i, name + i + 1, len - i);
277 if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
278 if (to_code != CODE_EUC) {
282 if (len == size - 1) /* check overflow */
284 memmove(name+i+1, name+i, len-i);
290 if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
292 if (to_code != CODE_SJIS) {
297 c1 = (unsigned char)name[i];
298 c2 = (unsigned char)name[i+1];
305 if (from_code == CODE_SJIS &&
306 SJIS_FIRST_P(name[i]) &&
307 SJIS_SECOND_P(name[i+1])) {
310 if (to_code != CODE_EUC) {
315 c1 = (unsigned char)name[i];
316 c2 = (unsigned char)name[i+1];
323 #endif /* MULTIBYTE_FILENAME */
327 /* transpose from_delim to to_delim */
329 if ((ptr = strchr(from_delim, name[i])) != NULL) {
330 name[i] = to_delim[ptr - from_delim];
335 if (case_to == TO_UPPER && islower(name[i])) {
336 name[i] = toupper(name[i]);
339 if (case_to == TO_LOWER && isupper(name[i])) {
340 name[i] = tolower(name[i]);
347 * Generic (MS-DOS style) time stamp format:
349 * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
350 * |<------- year ----->|<- month ->|<--- day ---->|
352 * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
353 * |<--- hour --->|<---- minute --->|<- second*2 ->|
358 generic_to_unix_stamp(t)
364 * special case: if MSDOS format date and time were zero, then we
365 * set time to be zero here too.
370 dostm.tm_sec = (t & 0x1f) * 2;
371 dostm.tm_min = t >> 5 & 0x3f;
372 dostm.tm_hour = t >> 11 & 0x1f;
373 dostm.tm_mday = t >> 16 & 0x1f;
374 dostm.tm_mon = (t >> (16+5) & 0x0f) - 1; /* 0..11 */
375 dostm.tm_year = (t >> (16+9) & 0x7f) + 80;
379 return mktime(&dostm);
381 return timelocal(&dostm);
386 unix_to_generic_stamp(t)
389 struct tm *tm = localtime(&t);
394 return ((long)(tm->tm_year << 25) +
396 (tm->tm_mday << 16) +
397 (tm->tm_hour << 11) +
403 wintime_to_unix_stamp()
407 uint64_t epoch = 0x019db1ded53e8000; /* 1970-01-01 00:00:00 (UTC) */
410 t += (uint64_t)get_longword() << 32;
411 t = (t - epoch) / 10000000;
415 unsigned long t, q, x;
416 unsigned long wintime[8];
417 unsigned long epoch[8] = {0x01,0x9d,0xb1,0xde, 0xd5,0x3e,0x80,0x00};
418 /* 1970-01-01 00:00:00 (UTC) */
419 /* wintime -= epoch */
421 for (i = 7; i >= 0; i--) {
422 wintime[i] = (unsigned)get_byte() - epoch[i] - borrow;
423 borrow = (wintime[i] > 0xff) ? 1 : 0;
427 /* q = wintime / 10000000 */
429 x = 10000000; /* x: 24bit */
430 for (i = 0; i < 8; i++) {
431 t = (t << 8) + wintime[i]; /* 24bit + 8bit. t must be 32bit variable */
432 q <<= 8; /* q must be 32bit (time_t) */
444 * --------------------------------
446 * 2 or 4 next-header size [*1]
447 * --------------------------------------
448 * ext header: 1 ext-type ^
449 * ? contents | [*1] next-header size
450 * 2 or 4 next-header size v
451 * --------------------------------------
453 * on level 1, 2 header:
454 * size field is 2 bytes
456 * size field is 4 bytes
460 get_extended_header(fp, hdr, header_size, hcrc)
466 char data[LZHEADER_STORAGE];
468 char dirname[FILENAME_LENGTH];
471 ssize_t whole_size = header_size;
473 int n = 1 + hdr->size_field_length; /* `ext-type' + `next-header size' */
475 if (hdr->header_level == 0)
478 name_length = strlen(hdr->name);
480 while (header_size) {
482 if (sizeof(data) < header_size) {
483 error("header size (%ld) too large.", header_size);
487 if (fread(data, header_size, 1, fp) == 0) {
488 error("Invalid header (LHa file ?)");
492 ext_type = get_byte();
495 /* header crc (CRC-16) */
496 hdr->header_crc = get_word();
497 /* clear buffer for CRC calculation. */
498 data[1] = data[2] = 0;
499 skip_bytes(header_size - n - 2);
504 get_bytes(hdr->name, header_size-n, sizeof(hdr->name)-1);
505 hdr->name[name_length] = 0;
509 dir_length = get_bytes(dirname, header_size-n, sizeof(dirname)-1);
510 dirname[dir_length] = 0;
513 /* MS-DOS attribute */
514 hdr->attribute = get_word();
517 /* Windows time stamp (FILETIME structure) */
518 /* it is time in 100 nano seconds since 1601-01-01 00:00:00 */
520 skip_bytes(8); /* create time is ignored */
522 /* set last modified time */
523 if (hdr->header_level >= 2)
524 skip_bytes(8); /* time_t has been already set */
526 hdr->unix_last_modified_stamp = wintime_to_unix_stamp();
528 skip_bytes(8); /* last access time is ignored */
532 /* UNIX permission */
533 hdr->unix_mode = get_word();
536 /* UNIX gid and uid */
537 hdr->unix_gid = get_word();
538 hdr->unix_uid = get_word();
541 /* UNIX group name */
542 i = get_bytes(hdr->group, header_size-n, sizeof(hdr->group)-1);
543 hdr->group[i] = '\0';
547 i = get_bytes(hdr->user, header_size-n, sizeof(hdr->user)-1);
551 /* UNIX last modified time */
552 hdr->unix_last_modified_stamp = (time_t) get_longword();
556 /* 0x39: multi-disk header
557 0x3f: uncompressed comment
558 0x42: 64bit large file size
559 0x48-0x4f(?): reserved for authenticity verification
561 0x7e: extended attribute - platform information
562 0x7f: extended attribute - permission, owner-id and timestamp
564 0xc4: compressed comment (dict size: 4096)
565 0xc5: compressed comment (dict size: 8192)
566 0xc6: compressed comment (dict size: 16384)
567 0xc7: compressed comment (dict size: 32768)
568 0xc8: compressed comment (dict size: 65536)
569 0xd0-0xdf(?): operating systemm specific information
570 0xfc: encapsulation (another opinion)
571 0xfe: extended attribute - platform information(another opinion)
572 0xff: extended attribute - permission, owner-id and timestamp
573 (level 3 on UNLHA32) */
575 warning("unknown extended header 0x%02x", ext_type);
576 skip_bytes(header_size - n);
581 *hcrc = calccrc(*hcrc, data, header_size);
583 if (hdr->size_field_length == 2)
584 whole_size += header_size = get_word();
586 whole_size += header_size = get_longword();
589 /* concatenate dirname and filename */
591 if (name_length + dir_length >= sizeof(hdr->name)) {
592 warning("the length of pathname \"%s%s\" is too long.",
594 name_length = sizeof(hdr->name) - dir_length - 1;
595 hdr->name[name_length] = 0;
597 strcat(dirname, hdr->name);
598 strcpy(hdr->name, dirname);
599 name_length += dir_length;
605 #define I_HEADER_SIZE 0 /* level 0,1,2 */
606 #define I_HEADER_CHECKSUM 1 /* level 0,1 */
607 #define I_METHOD 2 /* level 0,1,2,3 */
608 #define I_PACKED_SIZE 7 /* level 0,1,2,3 */
609 #define I_ATTRIBUTE 19 /* level 0,1,2,3 */
610 #define I_HEADER_LEVEL 20 /* level 0,1,2,3 */
612 #define COMMON_HEADER_SIZE 21 /* size of common part */
614 #define I_GENERIC_HEADER_SIZE 24 /* + name_length */
615 #define I_LEVEL0_HEADER_SIZE 36 /* + name_length (unix extended) */
616 #define I_LEVEL1_HEADER_SIZE 27 /* + name_length */
617 #define I_LEVEL2_HEADER_SIZE 26 /* + padding */
618 #define I_LEVEL3_HEADER_SIZE 32
624 * offset size field name
625 * ----------------------------------
626 * 0 1 header size [*1]
628 * ---------------------------------------
630 * 7 4 packed size [*2] |
631 * 11 4 original size |
634 * 19 1 attribute | [*1] header size (X+Y+22)
635 * 20 1 level (0x00 fixed) |
638 * X +22 2 file crc (CRC-16) |
639 * X +24 Y ext-header(old style) v
640 * -------------------------------------------------
642 * : | [*2] packed size
644 * -------------------------------------------------
646 * ext-header(old style)
660 * bit6 archive bit (need to backup)
664 get_header_level0(fp, hdr, data)
675 hdr->size_field_length = 2; /* in bytes */
676 hdr->header_size = header_size = get_byte();
677 checksum = get_byte();
679 if (fread(data + COMMON_HEADER_SIZE,
680 header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
681 error("Invalid header (LHarc file ?)");
682 return FALSE; /* finish */
685 if (calc_sum(data + I_METHOD, header_size) != checksum) {
686 error("Checksum error (LHarc file?)");
690 get_bytes(hdr->method, 5, sizeof(hdr->method));
691 hdr->packed_size = get_longword();
692 hdr->original_size = get_longword();
693 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
694 hdr->attribute = get_byte(); /* MS-DOS attribute */
695 hdr->header_level = get_byte();
696 name_length = get_byte();
697 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
700 /* defaults for other type */
701 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
705 extend_size = header_size+2 - name_length - 24;
707 if (extend_size < 0) {
708 if (extend_size == -2) {
709 /* CRC field is not given */
710 hdr->extend_type = EXTEND_GENERIC;
711 hdr->has_crc = FALSE;
716 error("Unkonwn header (lha file?)");
721 hdr->crc = get_word();
723 if (extend_size == 0)
726 hdr->extend_type = get_byte();
729 if (hdr->extend_type == EXTEND_UNIX) {
730 if (extend_size >= 11) {
731 hdr->minor_version = get_byte();
732 hdr->unix_last_modified_stamp = (time_t) get_longword();
733 hdr->unix_mode = get_word();
734 hdr->unix_uid = get_word();
735 hdr->unix_gid = get_word();
738 hdr->extend_type = EXTEND_GENERIC;
742 skip_bytes(extend_size);
744 hdr->header_size += 2;
752 * offset size field name
753 * -----------------------------------
754 * 0 1 header size [*1]
756 * -------------------------------------
758 * 7 4 skip size [*2] |
759 * 11 4 original size |
762 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
763 * 20 1 level (0x01 fixed) |
766 * X+ 22 2 file crc (CRC-16) |
769 * X+Y+25 2 next-header size v
770 * -------------------------------------------------
771 * X+Y+27 Z ext-header ^
773 * ----------------------------------- | [*2] skip size
776 * -------------------------------------------------
780 get_header_level1(fp, hdr, data)
791 hdr->size_field_length = 2; /* in bytes */
792 hdr->header_size = header_size = get_byte();
793 checksum = get_byte();
795 if (fread(data + COMMON_HEADER_SIZE,
796 header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
797 error("Invalid header (LHarc file ?)");
798 return FALSE; /* finish */
801 if (calc_sum(data + I_METHOD, header_size) != checksum) {
802 error("Checksum error (LHarc file?)");
806 get_bytes(hdr->method, 5, sizeof(hdr->method));
807 hdr->packed_size = get_longword(); /* skip size */
808 hdr->original_size = get_longword();
809 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
810 hdr->attribute = get_byte(); /* 0x20 fixed */
811 hdr->header_level = get_byte();
813 name_length = get_byte();
814 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
817 /* defaults for other type */
818 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
823 hdr->crc = get_word();
824 hdr->extend_type = get_byte();
826 dummy = header_size+2 - name_length - I_LEVEL1_HEADER_SIZE;
828 skip_bytes(dummy); /* skip old style extend header */
830 extend_size = get_word();
831 extend_size = get_extended_header(fp, hdr, extend_size, 0);
832 if (extend_size == -1)
835 /* On level 1 header, size fields should be adjusted. */
836 /* the `packed_size' field contains the extended header size. */
837 /* the `header_size' field does not. */
838 hdr->packed_size -= extend_size;
839 hdr->header_size += extend_size + 2;
848 * offset size field name
849 * --------------------------------------------------
850 * 0 2 total header size [*1] ^
851 * ----------------------- |
853 * 7 4 packed size [*2] |
854 * 11 4 original size |
856 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
857 * 20 1 level (0x02 fixed) | (X+26+(1))
858 * 21 2 file crc (CRC-16) |
860 * 24 2 next-header size |
861 * ----------------------------------- |
864 * ----------------------------------- |
865 * X +26 (1) padding v
866 * -------------------------------------------------
868 * : | [*2] packed size
870 * -------------------------------------------------
874 get_header_level2(fp, hdr, data)
884 hdr->size_field_length = 2; /* in bytes */
885 hdr->header_size = header_size = get_word();
887 if (fread(data + COMMON_HEADER_SIZE,
888 I_LEVEL2_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
889 error("Invalid header (LHarc file ?)");
890 return FALSE; /* finish */
893 get_bytes(hdr->method, 5, sizeof(hdr->method));
894 hdr->packed_size = get_longword();
895 hdr->original_size = get_longword();
896 hdr->unix_last_modified_stamp = get_longword();
897 hdr->attribute = get_byte(); /* reserved */
898 hdr->header_level = get_byte();
900 /* defaults for other type */
901 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
906 hdr->crc = get_word();
907 hdr->extend_type = get_byte();
908 extend_size = get_word();
910 INITIALIZE_CRC(hcrc);
911 hcrc = calccrc(hcrc, data, get_ptr - data);
913 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
914 if (extend_size == -1)
917 padding = header_size - I_LEVEL2_HEADER_SIZE - extend_size;
918 while (padding--) /* padding should be 0 or 1 */
919 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
921 if (hdr->header_crc != hcrc)
922 error("header CRC error");
931 * offset size field name
932 * --------------------------------------------------
933 * 0 2 size field length (4 fixed) ^
935 * 7 4 packed size [*2] |
936 * 11 4 original size |
938 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
939 * 20 1 level (0x03 fixed) | (X+32)
940 * 21 2 file crc (CRC-16) |
942 * 24 4 total header size [*1] |
943 * 28 4 next-header size |
944 * ----------------------------------- |
947 * -------------------------------------------------
949 * : | [*2] packed size
951 * -------------------------------------------------
955 get_header_level3(fp, hdr, data)
965 hdr->size_field_length = get_word();
967 if (fread(data + COMMON_HEADER_SIZE,
968 I_LEVEL3_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
969 error("Invalid header (LHarc file ?)");
970 return FALSE; /* finish */
973 get_bytes(hdr->method, 5, sizeof(hdr->method));
974 hdr->packed_size = get_longword();
975 hdr->original_size = get_longword();
976 hdr->unix_last_modified_stamp = get_longword();
977 hdr->attribute = get_byte(); /* reserved */
978 hdr->header_level = get_byte();
980 /* defaults for other type */
981 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
986 hdr->crc = get_word();
987 hdr->extend_type = get_byte();
988 hdr->header_size = header_size = get_longword();
989 extend_size = get_longword();
991 INITIALIZE_CRC(hcrc);
992 hcrc = calccrc(hcrc, data, get_ptr - data);
994 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
995 if (extend_size == -1)
998 padding = header_size - I_LEVEL3_HEADER_SIZE - extend_size;
999 while (padding--) /* padding should be 0 */
1000 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
1002 if (hdr->header_crc != hcrc)
1003 error("header CRC error");
1013 char data[LZHEADER_STORAGE];
1015 int archive_kanji_code = CODE_SJIS;
1016 int system_kanji_code = default_system_kanji_code;
1017 char *archive_delim = "\377\\"; /* `\' is for level 0 header and
1019 char *system_delim = "//";
1020 int filename_case = NONE;
1023 memset(hdr, 0, sizeof(LzHeader));
1027 if ((end_mark = getc(fp)) == EOF || end_mark == 0) {
1028 return FALSE; /* finish */
1032 if (fread(data + 1, COMMON_HEADER_SIZE - 1, 1, fp) == 0) {
1033 error("Invalid header (LHarc file ?)");
1034 return FALSE; /* finish */
1037 switch (data[I_HEADER_LEVEL]) {
1039 if (get_header_level0(fp, hdr, data) == FALSE)
1043 if (get_header_level1(fp, hdr, data) == FALSE)
1047 if (get_header_level2(fp, hdr, data) == FALSE)
1051 if (get_header_level3(fp, hdr, data) == FALSE)
1055 error("Unknown level header (level %d)", data[I_HEADER_LEVEL]);
1059 /* filename conversion */
1060 switch (hdr->extend_type) {
1062 filename_case = noconvertcase ? NONE : TO_LOWER;
1069 filename_case = NONE;
1073 archive_delim = "\377/:\\";
1074 /* `\' is for level 0 header and broken archive. */
1075 system_delim = "/://";
1076 filename_case = NONE;
1080 filename_case = noconvertcase ? NONE : TO_LOWER;
1084 if (optional_archive_kanji_code)
1085 archive_kanji_code = optional_archive_kanji_code;
1086 if (optional_system_kanji_code)
1087 system_kanji_code = optional_system_kanji_code;
1088 if (optional_archive_delim)
1089 archive_delim = optional_archive_delim;
1090 if (optional_system_delim)
1091 system_delim = optional_system_delim;
1092 if (optional_filename_case)
1093 filename_case = optional_filename_case;
1095 /* kanji code and delimiter conversion */
1096 convert_filename(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1099 archive_delim, system_delim, filename_case);
1101 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1103 /* split symbolic link */
1104 p = strchr(hdr->name, '|');
1106 /* hdr->name is symbolic link name */
1107 /* hdr->realname is real name */
1109 strncpy(hdr->realname, p+1, sizeof(hdr->realname));
1112 error("unknown symlink name \"%s\"", hdr->name);
1118 /* skip SFX header */
1123 unsigned char buffer[64 * 1024]; /* max seek size */
1127 n = fread(buffer, 1, sizeof(buffer), fp);
1129 for (p = buffer; p < buffer + n; p++) {
1130 if (! (p[I_METHOD]=='-' && p[I_METHOD+1]=='l' && p[I_METHOD+4]=='-'))
1132 /* found "-l??-" keyword (as METHOD type string) */
1134 /* level 0 or 1 header */
1135 if ((p[I_HEADER_LEVEL] == 0 || p[I_HEADER_LEVEL] == 1)
1136 && p[I_HEADER_SIZE] > 20
1137 && p[I_HEADER_CHECKSUM] == calc_sum(p+2, p[I_HEADER_SIZE])) {
1138 if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
1139 fatal_error("cannot seek header");
1143 /* level 2 header */
1144 if (p[I_HEADER_LEVEL] == 2
1145 && p[I_HEADER_SIZE] >= 24
1146 && p[I_ATTRIBUTE] == 0x20) {
1147 if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
1148 fatal_error("cannot seek header");
1153 if (fseek(fp, -n, SEEK_CUR) == -1)
1154 fatal_error("cannot seek header");
1159 init_header(name, v_stat, hdr)
1161 struct stat *v_stat;
1166 memset(hdr, 0, sizeof(LzHeader));
1168 /* the `method' member is rewrote by the encoding function.
1169 but need set for empty files */
1170 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
1172 hdr->packed_size = 0;
1173 hdr->original_size = v_stat->st_size;
1174 hdr->attribute = GENERIC_ATTRIBUTE;
1175 hdr->header_level = header_level;
1176 strcpy(hdr->name, name);
1179 hdr->extend_type = EXTEND_UNIX;
1180 hdr->unix_last_modified_stamp = v_stat->st_mtime;
1181 /* since 00:00:00 JAN.1.1970 */
1182 #ifdef NOT_COMPATIBLE_MODE
1183 /* Please need your modification in this space. */
1185 hdr->unix_mode = v_stat->st_mode;
1188 hdr->unix_uid = v_stat->st_uid;
1189 hdr->unix_gid = v_stat->st_gid;
1191 #if INCLUDE_OWNER_NAME_IN_HEADER
1194 struct passwd *ent = getpwuid(hdr->unix_uid);
1197 strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
1198 if (hdr->user[sizeof(hdr->user)-1])
1199 hdr->user[sizeof(hdr->user)-1] = 0;
1205 struct group *ent = getgrgid(hdr->unix_gid);
1208 strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
1209 if (hdr->group[sizeof(hdr->group)-1])
1210 hdr->group[sizeof(hdr->group)-1] = 0;
1214 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
1215 if (is_directory(v_stat)) {
1216 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1217 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1218 hdr->original_size = 0;
1219 if (len > 0 && hdr->name[len - 1] != '/')
1220 strcpy(&hdr->name[len++], "/");
1224 if (is_symlink(v_stat)) {
1225 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1226 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1227 hdr->original_size = 0;
1228 readlink(name, hdr->realname, sizeof(hdr->realname));
1234 write_unix_info(hdr)
1237 /* UNIX specific informations */
1239 put_word(5); /* size */
1240 put_byte(0x50); /* permission */
1241 put_word(hdr->unix_mode);
1243 put_word(7); /* size */
1244 put_byte(0x51); /* gid and uid */
1245 put_word(hdr->unix_gid);
1246 put_word(hdr->unix_uid);
1248 if (hdr->group[0]) {
1249 int len = strlen(hdr->group);
1250 put_word(len + 3); /* size */
1251 put_byte(0x52); /* group name */
1252 put_bytes(hdr->group, len);
1256 int len = strlen(hdr->user);
1257 put_word(len + 3); /* size */
1258 put_byte(0x53); /* user name */
1259 put_bytes(hdr->user, len);
1262 if (hdr->header_level == 1) {
1263 put_word(7); /* size */
1264 put_byte(0x54); /* time stamp */
1265 put_longword(hdr->unix_last_modified_stamp);
1270 write_header_level0(data, hdr, pathname)
1272 char *data, *pathname;
1279 memset(data, 0, LZHEADER_STORAGE);
1281 put_byte(0x00); /* header size */
1282 put_byte(0x00); /* check sum */
1283 put_bytes(hdr->method, 5);
1284 put_longword(hdr->packed_size);
1285 put_longword(hdr->original_size);
1286 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1287 put_byte(hdr->attribute);
1288 put_byte(hdr->header_level); /* level 0 */
1290 /* write pathname (level 0 header contains the directory part) */
1291 name_length = strlen(pathname);
1293 limit = 255 - I_GENERIC_HEADER_SIZE + 2;
1295 limit = 255 - I_LEVEL0_HEADER_SIZE + 2;
1297 if (name_length > limit) {
1298 warning("the length of pathname \"%s\" is too long.", pathname);
1299 name_length = limit;
1301 put_byte(name_length);
1302 put_bytes(pathname, name_length);
1305 if (generic_format) {
1306 header_size = I_GENERIC_HEADER_SIZE + name_length - 2;
1307 data[I_HEADER_SIZE] = header_size;
1308 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1310 /* write old-style extend header */
1311 put_byte(EXTEND_UNIX);
1312 put_byte(CURRENT_UNIX_MINOR_VERSION);
1313 put_longword(hdr->unix_last_modified_stamp);
1314 put_word(hdr->unix_mode);
1315 put_word(hdr->unix_uid);
1316 put_word(hdr->unix_gid);
1318 /* size of extended header is 12 */
1319 header_size = I_LEVEL0_HEADER_SIZE + name_length - 2;
1320 data[I_HEADER_SIZE] = header_size;
1321 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1324 return header_size + 2;
1328 write_header_level1(data, hdr, pathname)
1330 char *data, *pathname;
1332 int name_length, dir_length, limit;
1333 char *basename, *dirname;
1335 char *extend_header_top;
1336 size_t extend_header_size;
1338 basename = strrchr(pathname, LHA_PATHSEP);
1341 name_length = strlen(basename);
1343 dir_length = basename - dirname;
1346 basename = pathname;
1347 name_length = strlen(basename);
1353 memset(data, 0, LZHEADER_STORAGE);
1355 put_byte(0x00); /* header size */
1356 put_byte(0x00); /* check sum */
1357 put_bytes(hdr->method, 5);
1358 put_longword(hdr->packed_size);
1359 put_longword(hdr->original_size);
1360 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1362 put_byte(hdr->header_level); /* level 1 */
1364 /* level 1 header: write filename (basename only) */
1365 limit = 255 - I_LEVEL1_HEADER_SIZE + 2;
1366 if (name_length > limit) {
1367 put_byte(0); /* name length */
1370 put_byte(name_length);
1371 put_bytes(basename, name_length);
1379 put_byte(EXTEND_UNIX);
1381 /* write extend header from here. */
1383 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1384 header_size = extend_header_top - data - 2;
1386 /* write filename and dirname */
1388 if (name_length > limit) {
1389 put_word(name_length + 3); /* size */
1390 put_byte(0x01); /* filename */
1391 put_bytes(basename, name_length);
1394 if (dir_length > 0) {
1395 put_word(dir_length + 3); /* size */
1396 put_byte(0x02); /* dirname */
1397 put_bytes(dirname, dir_length);
1400 if (!generic_format)
1401 write_unix_info(hdr);
1403 put_word(0x0000); /* next header size */
1405 extend_header_size = put_ptr - extend_header_top;
1406 /* On level 1 header, the packed size field is contains the ext-header */
1407 hdr->packed_size += put_ptr - extend_header_top;
1409 /* put `skip size' */
1410 setup_put(data + I_PACKED_SIZE);
1411 put_longword(hdr->packed_size);
1413 data[I_HEADER_SIZE] = header_size;
1414 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1416 return header_size + extend_header_size + 2;
1420 write_header_level2(data, hdr, pathname)
1422 char *data, *pathname;
1424 int name_length, dir_length;
1425 char *basename, *dirname;
1427 char *extend_header_top;
1428 char *headercrc_ptr;
1431 basename = strrchr(pathname, LHA_PATHSEP);
1434 name_length = strlen(basename);
1436 dir_length = basename - dirname;
1439 basename = pathname;
1440 name_length = strlen(basename);
1446 memset(data, 0, LZHEADER_STORAGE);
1448 put_word(0x0000); /* header size */
1449 put_bytes(hdr->method, 5);
1450 put_longword(hdr->packed_size);
1451 put_longword(hdr->original_size);
1452 put_longword(hdr->unix_last_modified_stamp);
1454 put_byte(hdr->header_level); /* level 2 */
1461 put_byte(EXTEND_UNIX);
1463 /* write extend header from here. */
1465 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1467 /* write common header */
1470 headercrc_ptr = put_ptr;
1471 put_word(0x0000); /* header CRC */
1473 /* write filename and dirname */
1474 /* must have this header, even if the name_length is 0. */
1475 put_word(name_length + 3); /* size */
1476 put_byte(0x01); /* filename */
1477 put_bytes(basename, name_length);
1479 if (dir_length > 0) {
1480 put_word(dir_length + 3); /* size */
1481 put_byte(0x02); /* dirname */
1482 put_bytes(dirname, dir_length);
1485 if (!generic_format)
1486 write_unix_info(hdr);
1488 put_word(0x0000); /* next header size */
1490 header_size = put_ptr - data;
1491 if ((header_size & 0xff) == 0) {
1492 /* cannot put zero at the first byte on level 2 header. */
1493 /* adjust header size. */
1494 put_byte(0); /* padding */
1498 /* put hader size */
1499 setup_put(data + I_HEADER_SIZE);
1500 put_word(header_size);
1502 /* put hader CRC in extended header */
1503 INITIALIZE_CRC(hcrc);
1504 hcrc = calccrc(hcrc, data, (unsigned int) header_size);
1505 setup_put(headercrc_ptr);
1512 write_header(fp, hdr)
1517 char data[LZHEADER_STORAGE];
1519 int archive_kanji_code = CODE_SJIS;
1520 int system_kanji_code = default_system_kanji_code;
1521 char *archive_delim = "\377";
1522 char *system_delim = "/";
1523 int filename_case = NONE;
1524 char pathname[FILENAME_LENGTH];
1526 if (optional_archive_kanji_code)
1527 archive_kanji_code = optional_archive_kanji_code;
1528 if (optional_system_kanji_code)
1529 system_kanji_code = optional_system_kanji_code;
1532 filename_case = TO_UPPER;
1534 if (hdr->header_level == HEADER_LEVEL0) {
1535 archive_delim = "\\";
1538 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1540 p = strchr(hdr->name, '|');
1542 error("symlink name \"%s\" contains '|' char. change it into '_'",
1546 if (xsnprintf(pathname, sizeof(pathname),
1547 "%s|%s", hdr->name, hdr->realname) == -1)
1548 error("file name is too long (%s -> %s)", hdr->name, hdr->realname);
1551 strncpy(pathname, hdr->name, sizeof(pathname));
1552 pathname[sizeof(pathname)-1] = 0;
1555 convert_filename(pathname, strlen(pathname), sizeof(pathname),
1558 system_delim, archive_delim, filename_case);
1560 switch (hdr->header_level) {
1562 header_size = write_header_level0(data, hdr, pathname);
1565 header_size = write_header_level1(data, hdr, pathname);
1568 header_size = write_header_level2(data, hdr, pathname);
1571 error("Unknown level header (level %d)", hdr->header_level);
1575 if (fwrite(data, header_size, 1, fp) == 0)
1576 fatal_error("Cannot write to temporary file");
1579 #if MULTIBYTE_FILENAME
1581 #if defined(__APPLE__) /* Added by Hiroto Sakai */
1583 #include <CoreFoundation/CFString.h>
1584 #include <CoreFoundation/CFStringEncodingExt.h>
1586 /* this is not need for Mac OS X v 10.2 later */
1588 kCFStringEncodingAllowLossyConversion = 1,
1589 kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1590 kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1591 kCFStringEncodingSubstituteCombinings = (1 << 3),
1592 kCFStringEncodingComposeCombinings = (1 << 4),
1593 kCFStringEncodingIgnoreCombinings = (1 << 5),
1594 kCFStringEncodingUseCanonical = (1 << 6),
1595 kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1596 kCFStringEncodingPrependBOM = (1 << 8),
1597 kCFStringEncodingDisableCorporateArea = (1 << 9),
1598 kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1602 ConvertEncodingToUTF8(const char* inCStr,
1603 char* outUTF8Buffer,
1604 int outUTF8BufferLength,
1605 unsigned long scriptEncoding,
1606 unsigned long flags)
1608 unsigned long unicodeChars;
1609 unsigned long srcCharsUsed;
1610 unsigned long usedByteLen = 0;
1611 UniChar uniStr[512];
1612 unsigned long cfResult;
1614 cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1622 if (cfResult == 0) {
1623 cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1628 (char*)outUTF8Buffer,
1629 outUTF8BufferLength - 1,
1631 outUTF8Buffer[usedByteLen] = '\0';
1638 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1639 int inUTF8BufLength,
1640 char* outCStrBuffer,
1641 int outCStrBufferLength,
1642 unsigned long scriptEncoding,
1643 unsigned long flags)
1645 unsigned long unicodeChars;
1646 unsigned long srcCharsUsed;
1647 unsigned long usedByteLen = 0;
1648 UniChar uniStr[256];
1649 unsigned long cfResult;
1651 cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1659 if (cfResult == 0) {
1660 cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1665 (char*)outCStrBuffer,
1666 outCStrBufferLength - 1,
1668 outCStrBuffer[usedByteLen] = '\0';
1678 ConvertEncodingByIconv(const char *src, char *dst, int dstsize,
1679 const char *srcEnc, const char *dstEnc)
1682 static char szTmpBuf[2048];
1688 dst_p = &szTmpBuf[0];
1689 iLen = (size_t)sizeof(szTmpBuf)-1;
1690 src_p = (char *)src;
1691 sLen = (size_t)strlen(src);
1692 memset(szTmpBuf, 0, sizeof(szTmpBuf));
1693 memset(dst, 0, dstsize);
1695 ic = iconv_open(dstEnc, srcEnc);
1696 if (ic == (iconv_t)-1) {
1697 error("iconv_open() failure: %s", strerror(errno));
1701 if (iconv(ic, &src_p, &sLen, &dst_p, &iLen) == (size_t)-1) {
1702 error("iconv() failure: %s", strerror(errno));
1707 strncpy(dst, szTmpBuf, dstsize);
1713 #endif /* defined(__APPLE__) */
1716 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1718 #if defined(__APPLE__)
1720 if (ConvertEncodingToUTF8(src, dst, dstsize,
1721 kCFStringEncodingDOSJapanese,
1722 kCFStringEncodingUseHFSPlusCanonical) == 0)
1725 if (ConvertEncodingByIconv(src, dst, dstsize, "SJIS", "UTF-8") != -1)
1728 error("not support utf-8 conversion");
1731 if (dstsize < 1) return dst;
1733 return strncpy(dst, src, dstsize-1);
1737 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1739 #if defined(__APPLE__)
1743 srclen = strlen(src);
1744 if (ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1745 kCFStringEncodingDOSJapanese,
1746 kCFStringEncodingUseHFSPlusCanonical) == 0)
1749 if (ConvertEncodingByIconv(src, dst, dstsize, "UTF-8", "SJIS") != -1)
1752 error("not support utf-8 conversion");
1755 if (dstsize < 1) return dst;
1757 return strncpy(dst, src, dstsize-1);
1761 * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1762 * ¡ÖÆüËܸì¾ðÊó½èÍý¡× ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1763 * ¤è¤êÈ´¿è(by Koji Arai)
1766 euc2sjis(int *p1, int *p2)
1768 unsigned char c1 = *p1 & 0x7f;
1769 unsigned char c2 = *p2 & 0x7f;
1770 int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1771 int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1772 *p1 = ((c1 + 1) >> 1) + rowoff;
1773 *p2 += celoff - 0x80;
1777 sjis2euc(int *p1, int *p2)
1779 unsigned char c1 = *p1;
1780 unsigned char c2 = *p2;
1781 int adjust = c2 < 0x9f;
1782 int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1783 int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1784 *p1 = ((c1 - rowoff) << 1) - adjust;
1790 #endif /* MULTIBYTE_FILENAME */