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 Contributed UTF-8 convertion for Mac OS X */
14 /* 2002.06.29 Hiroto Sakai */
15 /* Ver. 1.14i autoconfiscated & rewritten 2003.02.23 Koji Arai */
16 /* ------------------------------------------------------------------------ */
19 #define DUMP_HEADER 1 /* for debugging */
21 #if !STRCHR_8BIT_CLEAN
22 /* should use 8 bit clean version */
25 #define strchr xstrchr
26 #define strrchr xstrrchr
30 #define GET_BYTE() (*get_ptr++ & 0xff)
33 static char *start_ptr;
34 #define setup_get(PTR) (start_ptr = get_ptr = (PTR))
35 #define get_byte() dump_get_byte()
36 #define skip_bytes(len) dump_skip_bytes(len)
38 #define setup_get(PTR) (get_ptr = (PTR))
39 #define get_byte() GET_BYTE()
40 #define skip_bytes(len) (get_ptr += (len))
42 #define put_ptr get_ptr
43 #define setup_put(PTR) (put_ptr = (PTR))
44 #define put_byte(c) (*put_ptr++ = (char)(c))
46 int optional_archive_kanji_code = NONE;
47 int optional_system_kanji_code = NONE;
48 char *optional_archive_delim = NULL;
49 char *optional_system_delim = NULL;
50 int optional_filename_case = NONE;
52 #ifdef MULTIBYTE_FILENAME
53 int default_system_kanji_code = MULTIBYTE_FILENAME;
55 int default_system_kanji_code = NONE;
65 while (len--) sum += *p++;
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");
111 if (verbose_listing && verbose > 1)
112 printf("%02d %2d: ", get_ptr - start_ptr, 2);
118 if (verbose_listing && verbose > 1)
119 printf("%d(0x%04x)\n", w, w);
139 if (verbose_listing && verbose > 1)
140 printf("%02d %2d: ", get_ptr - start_ptr, 4);
146 l = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
148 if (verbose_listing && verbose > 1)
149 printf("%ld(0x%08lx)\n", l, l);
165 get_bytes(buf, len, size)
172 if (verbose_listing && verbose > 1)
173 printf("%02d %2d: \"", get_ptr - start_ptr, len);
175 for (i = 0; i < len; i++) {
176 if (i < size) buf[i] = get_ptr[i];
178 if (verbose_listing && verbose > 1) {
180 printf("%c", buf[i]);
182 printf("\\x%02x", (unsigned char)buf[i]);
186 if (verbose_listing && verbose > 1)
189 for (i = 0; i < len && i < size; i++)
203 for (i = 0; i < len; i++)
207 /* added by Koji Arai */
209 convert_filename(name, len, size,
211 from_delim, to_delim,
216 int from_code, to_code, case_to;
217 char *from_delim, *to_delim;
221 #ifdef MULTIBYTE_FILENAME
222 char tmp[FILENAME_LENGTH];
224 if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
225 for (i = 0; i < len; i++)
226 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
227 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
228 sjis_to_utf8(tmp, name, sizeof(tmp));
229 strncpy(name, tmp, size);
232 for (i = 0; i < len; i++)
233 if (name[i] == '/') name[i] = LHA_PATHSEP;
234 from_code = CODE_UTF8;
236 else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
237 for (i = 0; i < len; i++)
238 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
239 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
240 utf8_to_sjis(tmp, name, sizeof(tmp));
241 strncpy(name, tmp, size);
244 for (i = 0; i < len; i++)
245 if (name[i] == '/') name[i] = LHA_PATHSEP;
246 from_code = CODE_SJIS;
250 /* special case: if `name' has small lettter, not convert case. */
251 if (from_code == CODE_SJIS && case_to == TO_LOWER) {
252 for (i = 0; i < len; i++) {
253 #ifdef MULTIBYTE_FILENAME
254 if (SJIS_FIRST_P(name[i]) && SJIS_SECOND_P(name[i+1]))
258 if (islower(name[i])) {
265 for (i = 0; i < len; i ++) {
266 #ifdef MULTIBYTE_FILENAME
267 if (from_code == CODE_EUC &&
268 (unsigned char)name[i] == 0x8e) {
269 if (to_code != CODE_SJIS) {
275 memmove(name + i, name + i + 1, len - i);
279 if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
280 if (to_code != CODE_EUC) {
284 if (len == size - 1) /* check overflow */
286 memmove(name+i+1, name+i, len-i);
292 if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
294 if (to_code != CODE_SJIS) {
299 c1 = (unsigned char)name[i];
300 c2 = (unsigned char)name[i+1];
307 if (from_code == CODE_SJIS &&
308 SJIS_FIRST_P(name[i]) &&
309 SJIS_SECOND_P(name[i+1])) {
312 if (to_code != CODE_EUC) {
317 c1 = (unsigned char)name[i];
318 c2 = (unsigned char)name[i+1];
325 #endif /* MULTIBYTE_FILENAME */
329 /* transpose from_delim to to_delim */
331 if ((ptr = strchr(from_delim, name[i])) != NULL) {
332 name[i] = to_delim[ptr - from_delim];
337 if (case_to == TO_UPPER && islower(name[i])) {
338 name[i] = toupper(name[i]);
341 if (case_to == TO_LOWER && isupper(name[i])) {
342 name[i] = tolower(name[i]);
349 * Generic (MS-DOS style) time stamp format (localtime):
351 * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
352 * |<---- year-1980 --->|<- month ->|<--- day ---->|
354 * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
355 * |<--- hour --->|<---- minute --->|<- second/2 ->|
360 generic_to_unix_stamp(t)
365 #define subbits(n, off, len) (((n) >> (off)) & ((1 << (len))-1))
367 tm.tm_sec = subbits(t, 0, 5) * 2;
368 tm.tm_min = subbits(t, 5, 6);
369 tm.tm_hour = subbits(t, 11, 5);
370 tm.tm_mday = subbits(t, 16, 5);
371 tm.tm_mon = subbits(t, 21, 4) - 1;
372 tm.tm_year = subbits(t, 25, 7) + 80;
378 return timelocal(&tm);
383 unix_to_generic_stamp(t)
386 struct tm *tm = localtime(&t);
391 return ((long)(tm->tm_year << 25) +
393 (tm->tm_mday << 16) +
394 (tm->tm_hour << 11) +
400 wintime_to_unix_stamp()
404 uint64_t epoch = 0x019db1ded53e8000; /* 1970-01-01 00:00:00 (UTC) */
406 t = (unsigned long)get_longword();
407 t |= (uint64_t)(unsigned long)get_longword() << 32;
408 t = (t - epoch) / 10000000;
412 unsigned long t, q, x;
413 unsigned long wintime[8];
414 unsigned long epoch[8] = {0x01,0x9d,0xb1,0xde, 0xd5,0x3e,0x80,0x00};
415 /* 1970-01-01 00:00:00 (UTC) */
416 /* wintime -= epoch */
418 for (i = 7; i >= 0; i--) {
419 wintime[i] = (unsigned)get_byte() - epoch[i] - borrow;
420 borrow = (wintime[i] > 0xff) ? 1 : 0;
424 /* q = wintime / 10000000 */
426 x = 10000000; /* x: 24bit */
427 for (i = 0; i < 8; i++) {
428 t = (t << 8) + wintime[i]; /* 24bit + 8bit. t must be 32bit variable */
429 q <<= 8; /* q must be 32bit (time_t) */
441 * --------------------------------
443 * 2 or 4 next-header size [*1]
444 * --------------------------------------
445 * ext header: 1 ext-type ^
446 * ? contents | [*1] next-header size
447 * 2 or 4 next-header size v
448 * --------------------------------------
450 * on level 1, 2 header:
451 * size field is 2 bytes
453 * size field is 4 bytes
457 get_extended_header(fp, hdr, header_size, hcrc)
463 char data[LZHEADER_STORAGE];
465 char dirname[FILENAME_LENGTH];
468 ssize_t whole_size = header_size;
470 int n = 1 + hdr->size_field_length; /* `ext-type' + `next-header size' */
472 if (hdr->header_level == 0)
475 name_length = strlen(hdr->name);
477 while (header_size) {
479 if (sizeof(data) < header_size) {
480 error("header size (%ld) too large.", header_size);
484 if (fread(data, header_size, 1, fp) == 0) {
485 error("Invalid header (LHa file ?)");
489 ext_type = get_byte();
492 /* header crc (CRC-16) */
493 hdr->header_crc = get_word();
494 /* clear buffer for CRC calculation. */
495 data[1] = data[2] = 0;
496 skip_bytes(header_size - n - 2);
501 get_bytes(hdr->name, header_size-n, sizeof(hdr->name)-1);
502 hdr->name[name_length] = 0;
506 dir_length = get_bytes(dirname, header_size-n, sizeof(dirname)-1);
507 dirname[dir_length] = 0;
510 /* MS-DOS attribute */
511 hdr->attribute = get_word();
514 /* Windows time stamp (FILETIME structure) */
515 /* it is time in 100 nano seconds since 1601-01-01 00:00:00 */
517 skip_bytes(8); /* create time is ignored */
519 /* set last modified time */
520 if (hdr->header_level >= 2)
521 skip_bytes(8); /* time_t has been already set */
523 hdr->unix_last_modified_stamp = wintime_to_unix_stamp();
525 skip_bytes(8); /* last access time is ignored */
529 /* UNIX permission */
530 hdr->unix_mode = get_word();
533 /* UNIX gid and uid */
534 hdr->unix_gid = get_word();
535 hdr->unix_uid = get_word();
538 /* UNIX group name */
539 i = get_bytes(hdr->group, header_size-n, sizeof(hdr->group)-1);
540 hdr->group[i] = '\0';
544 i = get_bytes(hdr->user, header_size-n, sizeof(hdr->user)-1);
548 /* UNIX last modified time */
549 hdr->unix_last_modified_stamp = (time_t) get_longword();
553 /* 0x39: multi-disk header
554 0x3f: uncompressed comment
555 0x42: 64bit large file size
556 0x48-0x4f(?): reserved for authenticity verification
558 0x7e: extended attribute - platform information
559 0x7f: extended attribute - permission, owner-id and timestamp
561 0xc4: compressed comment (dict size: 4096)
562 0xc5: compressed comment (dict size: 8192)
563 0xc6: compressed comment (dict size: 16384)
564 0xc7: compressed comment (dict size: 32768)
565 0xc8: compressed comment (dict size: 65536)
566 0xd0-0xdf(?): operating systemm specific information
567 0xfc: encapsulation (another opinion)
568 0xfe: extended attribute - platform information(another opinion)
569 0xff: extended attribute - permission, owner-id and timestamp
570 (level 3 on UNLHA32) */
572 warning("unknown extended header 0x%02x", ext_type);
573 skip_bytes(header_size - n);
578 *hcrc = calccrc(*hcrc, data, header_size);
580 if (hdr->size_field_length == 2)
581 whole_size += header_size = get_word();
583 whole_size += header_size = get_longword();
586 /* concatenate dirname and filename */
588 if (name_length + dir_length >= sizeof(hdr->name)) {
589 warning("the length of pathname \"%s%s\" is too long.",
591 name_length = sizeof(hdr->name) - dir_length - 1;
592 hdr->name[name_length] = 0;
594 strcat(dirname, hdr->name);
595 strcpy(hdr->name, dirname);
596 name_length += dir_length;
602 #define I_HEADER_SIZE 0 /* level 0,1,2 */
603 #define I_HEADER_CHECKSUM 1 /* level 0,1 */
604 #define I_METHOD 2 /* level 0,1,2,3 */
605 #define I_PACKED_SIZE 7 /* level 0,1,2,3 */
606 #define I_ATTRIBUTE 19 /* level 0,1,2,3 */
607 #define I_HEADER_LEVEL 20 /* level 0,1,2,3 */
609 #define COMMON_HEADER_SIZE 21 /* size of common part */
611 #define I_GENERIC_HEADER_SIZE 24 /* + name_length */
612 #define I_LEVEL0_HEADER_SIZE 36 /* + name_length (unix extended) */
613 #define I_LEVEL1_HEADER_SIZE 27 /* + name_length */
614 #define I_LEVEL2_HEADER_SIZE 26 /* + padding */
615 #define I_LEVEL3_HEADER_SIZE 32
621 * offset size field name
622 * ----------------------------------
623 * 0 1 header size [*1]
625 * ---------------------------------------
627 * 7 4 packed size [*2] |
628 * 11 4 original size |
631 * 19 1 attribute | [*1] header size (X+Y+22)
632 * 20 1 level (0x00 fixed) |
635 * X +22 2 file crc (CRC-16) |
636 * X +24 Y ext-header(old style) v
637 * -------------------------------------------------
639 * : | [*2] packed size
641 * -------------------------------------------------
643 * ext-header(old style)
657 * bit6 archive bit (need to backup)
661 get_header_level0(fp, hdr, data)
672 hdr->size_field_length = 2; /* in bytes */
673 hdr->header_size = header_size = get_byte();
674 checksum = get_byte();
676 if (fread(data + COMMON_HEADER_SIZE,
677 header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
678 error("Invalid header (LHarc file ?)");
679 return FALSE; /* finish */
682 if (calc_sum(data + I_METHOD, header_size) != checksum) {
683 error("Checksum error (LHarc file?)");
687 get_bytes(hdr->method, 5, sizeof(hdr->method));
688 hdr->packed_size = get_longword();
689 hdr->original_size = get_longword();
690 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
691 hdr->attribute = get_byte(); /* MS-DOS attribute */
692 hdr->header_level = get_byte();
693 name_length = get_byte();
694 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
697 /* defaults for other type */
698 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
702 extend_size = header_size+2 - name_length - 24;
704 if (extend_size < 0) {
705 if (extend_size == -2) {
706 /* CRC field is not given */
707 hdr->extend_type = EXTEND_GENERIC;
708 hdr->has_crc = FALSE;
713 error("Unkonwn header (lha file?)");
718 hdr->crc = get_word();
720 if (extend_size == 0)
723 hdr->extend_type = get_byte();
726 if (hdr->extend_type == EXTEND_UNIX) {
727 if (extend_size >= 11) {
728 hdr->minor_version = get_byte();
729 hdr->unix_last_modified_stamp = (time_t) get_longword();
730 hdr->unix_mode = get_word();
731 hdr->unix_uid = get_word();
732 hdr->unix_gid = get_word();
735 hdr->extend_type = EXTEND_GENERIC;
739 skip_bytes(extend_size);
741 hdr->header_size += 2;
749 * offset size field name
750 * -----------------------------------
751 * 0 1 header size [*1]
753 * -------------------------------------
755 * 7 4 skip size [*2] |
756 * 11 4 original size |
759 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
760 * 20 1 level (0x01 fixed) |
763 * X+ 22 2 file crc (CRC-16) |
766 * X+Y+25 2 next-header size v
767 * -------------------------------------------------
768 * X+Y+27 Z ext-header ^
770 * ----------------------------------- | [*2] skip size
773 * -------------------------------------------------
777 get_header_level1(fp, hdr, data)
788 hdr->size_field_length = 2; /* in bytes */
789 hdr->header_size = header_size = get_byte();
790 checksum = get_byte();
792 if (fread(data + COMMON_HEADER_SIZE,
793 header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
794 error("Invalid header (LHarc file ?)");
795 return FALSE; /* finish */
798 if (calc_sum(data + I_METHOD, header_size) != checksum) {
799 error("Checksum error (LHarc file?)");
803 get_bytes(hdr->method, 5, sizeof(hdr->method));
804 hdr->packed_size = get_longword(); /* skip size */
805 hdr->original_size = get_longword();
806 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
807 hdr->attribute = get_byte(); /* 0x20 fixed */
808 hdr->header_level = get_byte();
810 name_length = get_byte();
811 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
814 /* defaults for other type */
815 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
820 hdr->crc = get_word();
821 hdr->extend_type = get_byte();
823 dummy = header_size+2 - name_length - I_LEVEL1_HEADER_SIZE;
825 skip_bytes(dummy); /* skip old style extend header */
827 extend_size = get_word();
828 extend_size = get_extended_header(fp, hdr, extend_size, 0);
829 if (extend_size == -1)
832 /* On level 1 header, size fields should be adjusted. */
833 /* the `packed_size' field contains the extended header size. */
834 /* the `header_size' field does not. */
835 hdr->packed_size -= extend_size;
836 hdr->header_size += extend_size + 2;
845 * offset size field name
846 * --------------------------------------------------
847 * 0 2 total header size [*1] ^
848 * ----------------------- |
850 * 7 4 packed size [*2] |
851 * 11 4 original size |
853 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
854 * 20 1 level (0x02 fixed) | (X+26+(1))
855 * 21 2 file crc (CRC-16) |
857 * 24 2 next-header size |
858 * ----------------------------------- |
861 * ----------------------------------- |
862 * X +26 (1) padding v
863 * -------------------------------------------------
865 * : | [*2] packed size
867 * -------------------------------------------------
871 get_header_level2(fp, hdr, data)
881 hdr->size_field_length = 2; /* in bytes */
882 hdr->header_size = header_size = get_word();
884 if (fread(data + COMMON_HEADER_SIZE,
885 I_LEVEL2_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
886 error("Invalid header (LHarc file ?)");
887 return FALSE; /* finish */
890 get_bytes(hdr->method, 5, sizeof(hdr->method));
891 hdr->packed_size = get_longword();
892 hdr->original_size = get_longword();
893 hdr->unix_last_modified_stamp = get_longword();
894 hdr->attribute = get_byte(); /* reserved */
895 hdr->header_level = get_byte();
897 /* defaults for other type */
898 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
903 hdr->crc = get_word();
904 hdr->extend_type = get_byte();
905 extend_size = get_word();
907 INITIALIZE_CRC(hcrc);
908 hcrc = calccrc(hcrc, data, get_ptr - data);
910 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
911 if (extend_size == -1)
914 padding = header_size - I_LEVEL2_HEADER_SIZE - extend_size;
915 while (padding--) /* padding should be 0 or 1 */
916 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
918 if (hdr->header_crc != hcrc)
919 error("header CRC error");
928 * offset size field name
929 * --------------------------------------------------
930 * 0 2 size field length (4 fixed) ^
932 * 7 4 packed size [*2] |
933 * 11 4 original size |
935 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
936 * 20 1 level (0x03 fixed) | (X+32)
937 * 21 2 file crc (CRC-16) |
939 * 24 4 total header size [*1] |
940 * 28 4 next-header size |
941 * ----------------------------------- |
944 * -------------------------------------------------
946 * : | [*2] packed size
948 * -------------------------------------------------
952 get_header_level3(fp, hdr, data)
962 hdr->size_field_length = get_word();
964 if (fread(data + COMMON_HEADER_SIZE,
965 I_LEVEL3_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
966 error("Invalid header (LHarc file ?)");
967 return FALSE; /* finish */
970 get_bytes(hdr->method, 5, sizeof(hdr->method));
971 hdr->packed_size = get_longword();
972 hdr->original_size = get_longword();
973 hdr->unix_last_modified_stamp = get_longword();
974 hdr->attribute = get_byte(); /* reserved */
975 hdr->header_level = get_byte();
977 /* defaults for other type */
978 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
983 hdr->crc = get_word();
984 hdr->extend_type = get_byte();
985 hdr->header_size = header_size = get_longword();
986 extend_size = get_longword();
988 INITIALIZE_CRC(hcrc);
989 hcrc = calccrc(hcrc, data, get_ptr - data);
991 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
992 if (extend_size == -1)
995 padding = header_size - I_LEVEL3_HEADER_SIZE - extend_size;
996 while (padding--) /* padding should be 0 */
997 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
999 if (hdr->header_crc != hcrc)
1000 error("header CRC error");
1010 char data[LZHEADER_STORAGE];
1012 int archive_kanji_code = CODE_SJIS;
1013 int system_kanji_code = default_system_kanji_code;
1014 char *archive_delim = "\377\\"; /* `\' is for level 0 header and
1016 char *system_delim = "//";
1017 int filename_case = NONE;
1020 memset(hdr, 0, sizeof(LzHeader));
1024 if ((end_mark = getc(fp)) == EOF || end_mark == 0) {
1025 return FALSE; /* finish */
1029 if (fread(data + 1, COMMON_HEADER_SIZE - 1, 1, fp) == 0) {
1030 error("Invalid header (LHarc file ?)");
1031 return FALSE; /* finish */
1034 switch (data[I_HEADER_LEVEL]) {
1036 if (get_header_level0(fp, hdr, data) == FALSE)
1040 if (get_header_level1(fp, hdr, data) == FALSE)
1044 if (get_header_level2(fp, hdr, data) == FALSE)
1048 if (get_header_level3(fp, hdr, data) == FALSE)
1052 error("Unknown level header (level %d)", data[I_HEADER_LEVEL]);
1056 /* filename conversion */
1057 switch (hdr->extend_type) {
1059 filename_case = noconvertcase ? NONE : TO_LOWER;
1066 filename_case = NONE;
1070 archive_delim = "\377/:\\";
1071 /* `\' is for level 0 header and broken archive. */
1072 system_delim = "/://";
1073 filename_case = NONE;
1077 filename_case = noconvertcase ? NONE : TO_LOWER;
1081 if (optional_archive_kanji_code)
1082 archive_kanji_code = optional_archive_kanji_code;
1083 if (optional_system_kanji_code)
1084 system_kanji_code = optional_system_kanji_code;
1085 if (optional_archive_delim)
1086 archive_delim = optional_archive_delim;
1087 if (optional_system_delim)
1088 system_delim = optional_system_delim;
1089 if (optional_filename_case)
1090 filename_case = optional_filename_case;
1092 /* kanji code and delimiter conversion */
1093 convert_filename(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1096 archive_delim, system_delim, filename_case);
1098 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1100 /* split symbolic link */
1101 p = strchr(hdr->name, '|');
1103 /* hdr->name is symbolic link name */
1104 /* hdr->realname is real name */
1106 strncpy(hdr->realname, p+1, sizeof(hdr->realname));
1109 error("unknown symlink name \"%s\"", hdr->name);
1115 /* skip SFX header */
1120 unsigned char buffer[64 * 1024]; /* max seek size */
1124 n = fread(buffer, 1, sizeof(buffer), fp);
1126 for (p = buffer; p < buffer + n; p++) {
1127 if (! (p[I_METHOD]=='-' && p[I_METHOD+1]=='l' && p[I_METHOD+4]=='-'))
1129 /* found "-l??-" keyword (as METHOD type string) */
1131 /* level 0 or 1 header */
1132 if ((p[I_HEADER_LEVEL] == 0 || p[I_HEADER_LEVEL] == 1)
1133 && p[I_HEADER_SIZE] > 20
1134 && p[I_HEADER_CHECKSUM] == calc_sum(p+2, p[I_HEADER_SIZE])) {
1135 if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
1136 fatal_error("cannot seek header");
1140 /* level 2 header */
1141 if (p[I_HEADER_LEVEL] == 2
1142 && p[I_HEADER_SIZE] >= 24
1143 && p[I_ATTRIBUTE] == 0x20) {
1144 if (fseek(fp, (p - buffer) - n, SEEK_CUR) == -1)
1145 fatal_error("cannot seek header");
1150 if (fseek(fp, -n, SEEK_CUR) == -1)
1151 fatal_error("cannot seek header");
1156 init_header(name, v_stat, hdr)
1158 struct stat *v_stat;
1163 memset(hdr, 0, sizeof(LzHeader));
1165 /* the `method' member is rewrote by the encoding function.
1166 but need set for empty files */
1167 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
1169 hdr->packed_size = 0;
1170 hdr->original_size = v_stat->st_size;
1171 hdr->attribute = GENERIC_ATTRIBUTE;
1172 hdr->header_level = header_level;
1173 strcpy(hdr->name, name);
1176 hdr->extend_type = EXTEND_UNIX;
1177 hdr->unix_last_modified_stamp = v_stat->st_mtime;
1178 /* since 00:00:00 JAN.1.1970 */
1179 #ifdef NOT_COMPATIBLE_MODE
1180 /* Please need your modification in this space. */
1182 hdr->unix_mode = v_stat->st_mode;
1185 hdr->unix_uid = v_stat->st_uid;
1186 hdr->unix_gid = v_stat->st_gid;
1188 #if INCLUDE_OWNER_NAME_IN_HEADER
1191 struct passwd *ent = getpwuid(hdr->unix_uid);
1194 strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
1195 if (hdr->user[sizeof(hdr->user)-1])
1196 hdr->user[sizeof(hdr->user)-1] = 0;
1202 struct group *ent = getgrgid(hdr->unix_gid);
1205 strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
1206 if (hdr->group[sizeof(hdr->group)-1])
1207 hdr->group[sizeof(hdr->group)-1] = 0;
1211 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
1212 if (is_directory(v_stat)) {
1213 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1214 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1215 hdr->original_size = 0;
1216 if (len > 0 && hdr->name[len - 1] != '/')
1217 strcpy(&hdr->name[len++], "/");
1221 if (is_symlink(v_stat)) {
1222 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1223 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1224 hdr->original_size = 0;
1225 readlink(name, hdr->realname, sizeof(hdr->realname));
1231 write_unix_info(hdr)
1234 /* UNIX specific informations */
1236 put_word(5); /* size */
1237 put_byte(0x50); /* permission */
1238 put_word(hdr->unix_mode);
1240 put_word(7); /* size */
1241 put_byte(0x51); /* gid and uid */
1242 put_word(hdr->unix_gid);
1243 put_word(hdr->unix_uid);
1245 if (hdr->group[0]) {
1246 int len = strlen(hdr->group);
1247 put_word(len + 3); /* size */
1248 put_byte(0x52); /* group name */
1249 put_bytes(hdr->group, len);
1253 int len = strlen(hdr->user);
1254 put_word(len + 3); /* size */
1255 put_byte(0x53); /* user name */
1256 put_bytes(hdr->user, len);
1259 if (hdr->header_level == 1) {
1260 put_word(7); /* size */
1261 put_byte(0x54); /* time stamp */
1262 put_longword(hdr->unix_last_modified_stamp);
1267 write_header_level0(data, hdr, pathname)
1269 char *data, *pathname;
1276 memset(data, 0, LZHEADER_STORAGE);
1278 put_byte(0x00); /* header size */
1279 put_byte(0x00); /* check sum */
1280 put_bytes(hdr->method, 5);
1281 put_longword(hdr->packed_size);
1282 put_longword(hdr->original_size);
1283 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1284 put_byte(hdr->attribute);
1285 put_byte(hdr->header_level); /* level 0 */
1287 /* write pathname (level 0 header contains the directory part) */
1288 name_length = strlen(pathname);
1290 limit = 255 - I_GENERIC_HEADER_SIZE + 2;
1292 limit = 255 - I_LEVEL0_HEADER_SIZE + 2;
1294 if (name_length > limit) {
1295 warning("the length of pathname \"%s\" is too long.", pathname);
1296 name_length = limit;
1298 put_byte(name_length);
1299 put_bytes(pathname, name_length);
1302 if (generic_format) {
1303 header_size = I_GENERIC_HEADER_SIZE + name_length - 2;
1304 data[I_HEADER_SIZE] = header_size;
1305 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1307 /* write old-style extend header */
1308 put_byte(EXTEND_UNIX);
1309 put_byte(CURRENT_UNIX_MINOR_VERSION);
1310 put_longword(hdr->unix_last_modified_stamp);
1311 put_word(hdr->unix_mode);
1312 put_word(hdr->unix_uid);
1313 put_word(hdr->unix_gid);
1315 /* size of extended header is 12 */
1316 header_size = I_LEVEL0_HEADER_SIZE + name_length - 2;
1317 data[I_HEADER_SIZE] = header_size;
1318 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1321 return header_size + 2;
1325 write_header_level1(data, hdr, pathname)
1327 char *data, *pathname;
1329 int name_length, dir_length, limit;
1330 char *basename, *dirname;
1332 char *extend_header_top;
1333 size_t extend_header_size;
1335 basename = strrchr(pathname, LHA_PATHSEP);
1338 name_length = strlen(basename);
1340 dir_length = basename - dirname;
1343 basename = pathname;
1344 name_length = strlen(basename);
1350 memset(data, 0, LZHEADER_STORAGE);
1352 put_byte(0x00); /* header size */
1353 put_byte(0x00); /* check sum */
1354 put_bytes(hdr->method, 5);
1355 put_longword(hdr->packed_size);
1356 put_longword(hdr->original_size);
1357 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1359 put_byte(hdr->header_level); /* level 1 */
1361 /* level 1 header: write filename (basename only) */
1362 limit = 255 - I_LEVEL1_HEADER_SIZE + 2;
1363 if (name_length > limit) {
1364 put_byte(0); /* name length */
1367 put_byte(name_length);
1368 put_bytes(basename, name_length);
1376 put_byte(EXTEND_UNIX);
1378 /* write extend header from here. */
1380 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1381 header_size = extend_header_top - data - 2;
1383 /* write filename and dirname */
1385 if (name_length > limit) {
1386 put_word(name_length + 3); /* size */
1387 put_byte(0x01); /* filename */
1388 put_bytes(basename, name_length);
1391 if (dir_length > 0) {
1392 put_word(dir_length + 3); /* size */
1393 put_byte(0x02); /* dirname */
1394 put_bytes(dirname, dir_length);
1397 if (!generic_format)
1398 write_unix_info(hdr);
1400 put_word(0x0000); /* next header size */
1402 extend_header_size = put_ptr - extend_header_top;
1403 /* On level 1 header, the packed size field is contains the ext-header */
1404 hdr->packed_size += put_ptr - extend_header_top;
1406 /* put `skip size' */
1407 setup_put(data + I_PACKED_SIZE);
1408 put_longword(hdr->packed_size);
1410 data[I_HEADER_SIZE] = header_size;
1411 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1413 return header_size + extend_header_size + 2;
1417 write_header_level2(data, hdr, pathname)
1419 char *data, *pathname;
1421 int name_length, dir_length;
1422 char *basename, *dirname;
1424 char *extend_header_top;
1425 char *headercrc_ptr;
1428 basename = strrchr(pathname, LHA_PATHSEP);
1431 name_length = strlen(basename);
1433 dir_length = basename - dirname;
1436 basename = pathname;
1437 name_length = strlen(basename);
1443 memset(data, 0, LZHEADER_STORAGE);
1445 put_word(0x0000); /* header size */
1446 put_bytes(hdr->method, 5);
1447 put_longword(hdr->packed_size);
1448 put_longword(hdr->original_size);
1449 put_longword(hdr->unix_last_modified_stamp);
1451 put_byte(hdr->header_level); /* level 2 */
1458 put_byte(EXTEND_UNIX);
1460 /* write extend header from here. */
1462 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1464 /* write common header */
1467 headercrc_ptr = put_ptr;
1468 put_word(0x0000); /* header CRC */
1470 /* write filename and dirname */
1471 /* must have this header, even if the name_length is 0. */
1472 put_word(name_length + 3); /* size */
1473 put_byte(0x01); /* filename */
1474 put_bytes(basename, name_length);
1476 if (dir_length > 0) {
1477 put_word(dir_length + 3); /* size */
1478 put_byte(0x02); /* dirname */
1479 put_bytes(dirname, dir_length);
1482 if (!generic_format)
1483 write_unix_info(hdr);
1485 put_word(0x0000); /* next header size */
1487 header_size = put_ptr - data;
1488 if ((header_size & 0xff) == 0) {
1489 /* cannot put zero at the first byte on level 2 header. */
1490 /* adjust header size. */
1491 put_byte(0); /* padding */
1495 /* put hader size */
1496 setup_put(data + I_HEADER_SIZE);
1497 put_word(header_size);
1499 /* put hader CRC in extended header */
1500 INITIALIZE_CRC(hcrc);
1501 hcrc = calccrc(hcrc, data, (unsigned int) header_size);
1502 setup_put(headercrc_ptr);
1509 write_header(fp, hdr)
1514 char data[LZHEADER_STORAGE];
1516 int archive_kanji_code = CODE_SJIS;
1517 int system_kanji_code = default_system_kanji_code;
1518 char *archive_delim = "\377";
1519 char *system_delim = "/";
1520 int filename_case = NONE;
1521 char pathname[FILENAME_LENGTH];
1523 if (optional_archive_kanji_code)
1524 archive_kanji_code = optional_archive_kanji_code;
1525 if (optional_system_kanji_code)
1526 system_kanji_code = optional_system_kanji_code;
1529 filename_case = TO_UPPER;
1531 if (hdr->header_level == 0) {
1532 archive_delim = "\\";
1535 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1537 p = strchr(hdr->name, '|');
1539 error("symlink name \"%s\" contains '|' char. change it into '_'",
1543 if (xsnprintf(pathname, sizeof(pathname),
1544 "%s|%s", hdr->name, hdr->realname) == -1)
1545 error("file name is too long (%s -> %s)", hdr->name, hdr->realname);
1548 strncpy(pathname, hdr->name, sizeof(pathname));
1549 pathname[sizeof(pathname)-1] = 0;
1552 convert_filename(pathname, strlen(pathname), sizeof(pathname),
1555 system_delim, archive_delim, filename_case);
1557 switch (hdr->header_level) {
1559 header_size = write_header_level0(data, hdr, pathname);
1562 header_size = write_header_level1(data, hdr, pathname);
1565 header_size = write_header_level2(data, hdr, pathname);
1568 error("Unknown level header (level %d)", hdr->header_level);
1572 if (fwrite(data, header_size, 1, fp) == 0)
1573 fatal_error("Cannot write to temporary file");
1576 #if MULTIBYTE_FILENAME
1578 #if defined(__APPLE__) /* Added by Hiroto Sakai */
1580 #include <CoreFoundation/CFString.h>
1581 #include <CoreFoundation/CFStringEncodingExt.h>
1583 /* this is not need for Mac OS X v 10.2 later */
1585 kCFStringEncodingAllowLossyConversion = 1,
1586 kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1587 kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1588 kCFStringEncodingSubstituteCombinings = (1 << 3),
1589 kCFStringEncodingComposeCombinings = (1 << 4),
1590 kCFStringEncodingIgnoreCombinings = (1 << 5),
1591 kCFStringEncodingUseCanonical = (1 << 6),
1592 kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1593 kCFStringEncodingPrependBOM = (1 << 8),
1594 kCFStringEncodingDisableCorporateArea = (1 << 9),
1595 kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1599 ConvertEncodingToUTF8(const char* inCStr,
1600 char* outUTF8Buffer,
1601 int outUTF8BufferLength,
1602 unsigned long scriptEncoding,
1603 unsigned long flags)
1605 unsigned long unicodeChars;
1606 unsigned long srcCharsUsed;
1607 unsigned long usedByteLen = 0;
1608 UniChar uniStr[512];
1609 unsigned long cfResult;
1611 cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1619 if (cfResult == 0) {
1620 cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1625 (char*)outUTF8Buffer,
1626 outUTF8BufferLength - 1,
1628 outUTF8Buffer[usedByteLen] = '\0';
1635 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1636 int inUTF8BufLength,
1637 char* outCStrBuffer,
1638 int outCStrBufferLength,
1639 unsigned long scriptEncoding,
1640 unsigned long flags)
1642 unsigned long unicodeChars;
1643 unsigned long srcCharsUsed;
1644 unsigned long usedByteLen = 0;
1645 UniChar uniStr[256];
1646 unsigned long cfResult;
1648 cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1656 if (cfResult == 0) {
1657 cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1662 (char*)outCStrBuffer,
1663 outCStrBufferLength - 1,
1665 outCStrBuffer[usedByteLen] = '\0';
1675 ConvertEncodingByIconv(const char *src, char *dst, int dstsize,
1676 const char *srcEnc, const char *dstEnc)
1679 static char szTmpBuf[2048];
1685 dst_p = &szTmpBuf[0];
1686 iLen = (size_t)sizeof(szTmpBuf)-1;
1687 src_p = (char *)src;
1688 sLen = (size_t)strlen(src);
1689 memset(szTmpBuf, 0, sizeof(szTmpBuf));
1690 memset(dst, 0, dstsize);
1692 ic = iconv_open(dstEnc, srcEnc);
1693 if (ic == (iconv_t)-1) {
1694 error("iconv_open() failure: %s", strerror(errno));
1698 if (iconv(ic, &src_p, &sLen, &dst_p, &iLen) == (size_t)-1) {
1699 error("iconv() failure: %s", strerror(errno));
1704 strncpy(dst, szTmpBuf, dstsize);
1710 #endif /* defined(__APPLE__) */
1713 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1715 #if defined(__APPLE__)
1717 if (ConvertEncodingToUTF8(src, dst, dstsize,
1718 kCFStringEncodingDOSJapanese,
1719 kCFStringEncodingUseHFSPlusCanonical) == 0)
1722 if (ConvertEncodingByIconv(src, dst, dstsize, "SJIS", "UTF-8") != -1)
1725 error("not support utf-8 conversion");
1728 if (dstsize < 1) return dst;
1730 return strncpy(dst, src, dstsize-1);
1734 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1736 #if defined(__APPLE__)
1740 srclen = strlen(src);
1741 if (ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1742 kCFStringEncodingDOSJapanese,
1743 kCFStringEncodingUseHFSPlusCanonical) == 0)
1746 if (ConvertEncodingByIconv(src, dst, dstsize, "UTF-8", "SJIS") != -1)
1749 error("not support utf-8 conversion");
1752 if (dstsize < 1) return dst;
1754 return strncpy(dst, src, dstsize-1);
1758 * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1759 * ¡ÖÆüËܸì¾ðÊó½èÍý¡× ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1760 * ¤è¤êÈ´¿è(by Koji Arai)
1763 euc2sjis(int *p1, int *p2)
1765 unsigned char c1 = *p1 & 0x7f;
1766 unsigned char c2 = *p2 & 0x7f;
1767 int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1768 int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1769 *p1 = ((c1 + 1) >> 1) + rowoff;
1770 *p2 += celoff - 0x80;
1774 sjis2euc(int *p1, int *p2)
1776 unsigned char c1 = *p1;
1777 unsigned char c2 = *p2;
1778 int adjust = c2 < 0x9f;
1779 int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1780 int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1781 *p1 = ((c1 - rowoff) << 1) - adjust;
1787 #endif /* MULTIBYTE_FILENAME */