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,
214 int len; /* length of name */
215 int size; /* size of name buffer */
216 int from_code, to_code, case_to;
217 char *from_delim, *to_delim;
221 #ifdef MULTIBYTE_FILENAME
222 char tmp[FILENAME_LENGTH];
223 int to_code_save = NONE;
225 if (from_code == CODE_CAP) {
226 len = cap_to_sjis(tmp, name, sizeof(tmp));
227 strncpy(name, tmp, size);
230 from_code = CODE_SJIS;
233 if (to_code == CODE_CAP) {
234 to_code_save = CODE_CAP;
238 if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
239 for (i = 0; i < len; i++)
240 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
241 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
242 sjis_to_utf8(tmp, name, sizeof(tmp));
243 strncpy(name, tmp, size);
246 for (i = 0; i < len; i++)
247 if (name[i] == '/') name[i] = LHA_PATHSEP;
248 from_code = CODE_UTF8;
250 else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
251 for (i = 0; i < len; i++)
252 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
253 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
254 utf8_to_sjis(tmp, name, sizeof(tmp));
255 strncpy(name, tmp, size);
258 for (i = 0; i < len; i++)
259 if (name[i] == '/') name[i] = LHA_PATHSEP;
260 from_code = CODE_SJIS;
264 /* special case: if `name' has small lettter, not convert case. */
265 if (from_code == CODE_SJIS && case_to == TO_LOWER) {
266 for (i = 0; i < len; i++) {
267 #ifdef MULTIBYTE_FILENAME
268 if (SJIS_FIRST_P(name[i]) && SJIS_SECOND_P(name[i+1]))
272 if (islower(name[i])) {
279 for (i = 0; i < len; i ++) {
280 #ifdef MULTIBYTE_FILENAME
281 if (from_code == CODE_EUC &&
282 (unsigned char)name[i] == 0x8e) {
283 if (to_code != CODE_SJIS) {
289 memmove(name + i, name + i + 1, len - i);
293 if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
294 if (to_code != CODE_EUC) {
298 if (len == size - 1) /* check overflow */
300 memmove(name+i+1, name+i, len-i);
306 if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
308 if (to_code != CODE_SJIS) {
313 c1 = (unsigned char)name[i];
314 c2 = (unsigned char)name[i+1];
321 if (from_code == CODE_SJIS &&
322 SJIS_FIRST_P(name[i]) &&
323 SJIS_SECOND_P(name[i+1])) {
326 if (to_code != CODE_EUC) {
331 c1 = (unsigned char)name[i];
332 c2 = (unsigned char)name[i+1];
339 #endif /* MULTIBYTE_FILENAME */
343 /* transpose from_delim to to_delim */
345 if ((ptr = strchr(from_delim, name[i])) != NULL) {
346 name[i] = to_delim[ptr - from_delim];
351 if (case_to == TO_UPPER && islower(name[i])) {
352 name[i] = toupper(name[i]);
355 if (case_to == TO_LOWER && isupper(name[i])) {
356 name[i] = tolower(name[i]);
361 #ifdef MULTIBYTE_FILENAME
362 if (to_code_save == CODE_CAP) {
363 len = sjis_to_cap(tmp, name, sizeof(tmp));
364 strncpy(name, tmp, size);
368 #endif /* MULTIBYTE_FILENAME */
372 * Generic (MS-DOS style) time stamp format (localtime):
374 * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
375 * |<---- year-1980 --->|<- month ->|<--- day ---->|
377 * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
378 * |<--- hour --->|<---- minute --->|<- second/2 ->|
383 generic_to_unix_stamp(t)
388 #define subbits(n, off, len) (((n) >> (off)) & ((1 << (len))-1))
390 tm.tm_sec = subbits(t, 0, 5) * 2;
391 tm.tm_min = subbits(t, 5, 6);
392 tm.tm_hour = subbits(t, 11, 5);
393 tm.tm_mday = subbits(t, 16, 5);
394 tm.tm_mon = subbits(t, 21, 4) - 1;
395 tm.tm_year = subbits(t, 25, 7) + 80;
401 return timelocal(&tm);
406 unix_to_generic_stamp(t)
409 struct tm *tm = localtime(&t);
414 return ((long)(tm->tm_year << 25) +
416 (tm->tm_mday << 16) +
417 (tm->tm_hour << 11) +
423 wintime_to_unix_stamp()
427 uint64_t epoch = ((uint64_t)0x019db1de << 32) + 0xd53e8000;
428 /* 0x019db1ded53e8000ULL: 1970-01-01 00:00:00 (UTC) */
430 t = (unsigned long)get_longword();
431 t |= (uint64_t)(unsigned long)get_longword() << 32;
432 t = (t - epoch) / 10000000;
436 unsigned long t, q, x;
437 unsigned long wintime[8];
438 unsigned long epoch[8] = {0x01,0x9d,0xb1,0xde, 0xd5,0x3e,0x80,0x00};
439 /* 1970-01-01 00:00:00 (UTC) */
440 /* wintime -= epoch */
442 for (i = 7; i >= 0; i--) {
443 wintime[i] = (unsigned)get_byte() - epoch[i] - borrow;
444 borrow = (wintime[i] > 0xff) ? 1 : 0;
448 /* q = wintime / 10000000 */
450 x = 10000000; /* x: 24bit */
451 for (i = 0; i < 8; i++) {
452 t = (t << 8) + wintime[i]; /* 24bit + 8bit. t must be 32bit variable */
453 q <<= 8; /* q must be 32bit (time_t) */
465 * --------------------------------
467 * 2 or 4 next-header size [*1]
468 * --------------------------------------
469 * ext header: 1 ext-type ^
470 * ? contents | [*1] next-header size
471 * 2 or 4 next-header size v
472 * --------------------------------------
474 * on level 1, 2 header:
475 * size field is 2 bytes
477 * size field is 4 bytes
481 get_extended_header(fp, hdr, header_size, hcrc)
487 char data[LZHEADER_STORAGE];
489 char dirname[FILENAME_LENGTH];
492 ssize_t whole_size = header_size;
494 int n = 1 + hdr->size_field_length; /* `ext-type' + `next-header size' */
496 if (hdr->header_level == 0)
499 name_length = strlen(hdr->name);
501 while (header_size) {
503 if (sizeof(data) < header_size) {
504 error("header size (%ld) too large.", header_size);
508 if (fread(data, header_size, 1, fp) == 0) {
509 error("Invalid header (LHa file ?)");
513 ext_type = get_byte();
516 /* header crc (CRC-16) */
517 hdr->header_crc = get_word();
518 /* clear buffer for CRC calculation. */
519 data[1] = data[2] = 0;
520 skip_bytes(header_size - n - 2);
525 get_bytes(hdr->name, header_size-n, sizeof(hdr->name)-1);
526 hdr->name[name_length] = 0;
530 dir_length = get_bytes(dirname, header_size-n, sizeof(dirname)-1);
531 dirname[dir_length] = 0;
534 /* MS-DOS attribute */
535 hdr->attribute = get_word();
538 /* Windows time stamp (FILETIME structure) */
539 /* it is time in 100 nano seconds since 1601-01-01 00:00:00 */
541 skip_bytes(8); /* create time is ignored */
543 /* set last modified time */
544 if (hdr->header_level >= 2)
545 skip_bytes(8); /* time_t has been already set */
547 hdr->unix_last_modified_stamp = wintime_to_unix_stamp();
549 skip_bytes(8); /* last access time is ignored */
553 /* UNIX permission */
554 hdr->unix_mode = get_word();
557 /* UNIX gid and uid */
558 hdr->unix_gid = get_word();
559 hdr->unix_uid = get_word();
562 /* UNIX group name */
563 i = get_bytes(hdr->group, header_size-n, sizeof(hdr->group)-1);
564 hdr->group[i] = '\0';
568 i = get_bytes(hdr->user, header_size-n, sizeof(hdr->user)-1);
572 /* UNIX last modified time */
573 hdr->unix_last_modified_stamp = (time_t) get_longword();
577 /* 0x39: multi-disk header
578 0x3f: uncompressed comment
579 0x42: 64bit large file size
580 0x48-0x4f(?): reserved for authenticity verification
582 0x7e: extended attribute - platform information
583 0x7f: extended attribute - permission, owner-id and timestamp
585 0xc4: compressed comment (dict size: 4096)
586 0xc5: compressed comment (dict size: 8192)
587 0xc6: compressed comment (dict size: 16384)
588 0xc7: compressed comment (dict size: 32768)
589 0xc8: compressed comment (dict size: 65536)
590 0xd0-0xdf(?): operating systemm specific information
591 0xfc: encapsulation (another opinion)
592 0xfe: extended attribute - platform information(another opinion)
593 0xff: extended attribute - permission, owner-id and timestamp
594 (level 3 on UNLHA32) */
596 warning("unknown extended header 0x%02x", ext_type);
597 skip_bytes(header_size - n);
602 *hcrc = calccrc(*hcrc, data, header_size);
604 if (hdr->size_field_length == 2)
605 whole_size += header_size = get_word();
607 whole_size += header_size = get_longword();
610 /* concatenate dirname and filename */
612 if (name_length + dir_length >= sizeof(hdr->name)) {
613 warning("the length of pathname \"%s%s\" is too long.",
615 name_length = sizeof(hdr->name) - dir_length - 1;
616 hdr->name[name_length] = 0;
618 strcat(dirname, hdr->name); /* ok */
619 strcpy(hdr->name, dirname); /* ok */
620 name_length += dir_length;
626 #define I_HEADER_SIZE 0 /* level 0,1,2 */
627 #define I_HEADER_CHECKSUM 1 /* level 0,1 */
628 #define I_METHOD 2 /* level 0,1,2,3 */
629 #define I_PACKED_SIZE 7 /* level 0,1,2,3 */
630 #define I_ATTRIBUTE 19 /* level 0,1,2,3 */
631 #define I_HEADER_LEVEL 20 /* level 0,1,2,3 */
633 #define COMMON_HEADER_SIZE 21 /* size of common part */
635 #define I_GENERIC_HEADER_SIZE 24 /* + name_length */
636 #define I_LEVEL0_HEADER_SIZE 36 /* + name_length (unix extended) */
637 #define I_LEVEL1_HEADER_SIZE 27 /* + name_length */
638 #define I_LEVEL2_HEADER_SIZE 26 /* + padding */
639 #define I_LEVEL3_HEADER_SIZE 32
645 * offset size field name
646 * ----------------------------------
647 * 0 1 header size [*1]
649 * ---------------------------------------
651 * 7 4 packed size [*2] |
652 * 11 4 original size |
655 * 19 1 attribute | [*1] header size (X+Y+22)
656 * 20 1 level (0x00 fixed) |
659 * X +22 2 file crc (CRC-16) |
660 * X +24 Y ext-header(old style) v
661 * -------------------------------------------------
663 * : | [*2] packed size
665 * -------------------------------------------------
667 * ext-header(old style)
681 * bit6 archive bit (need to backup)
685 get_header_level0(fp, hdr, data)
696 hdr->size_field_length = 2; /* in bytes */
697 hdr->header_size = header_size = get_byte();
698 checksum = get_byte();
700 if (fread(data + COMMON_HEADER_SIZE,
701 header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
702 error("Invalid header (LHarc file ?)");
703 return FALSE; /* finish */
706 if (calc_sum(data + I_METHOD, header_size) != checksum) {
707 error("Checksum error (LHarc file?)");
711 get_bytes(hdr->method, 5, sizeof(hdr->method));
712 hdr->packed_size = get_longword();
713 hdr->original_size = get_longword();
714 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
715 hdr->attribute = get_byte(); /* MS-DOS attribute */
716 hdr->header_level = get_byte();
717 name_length = get_byte();
718 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
721 /* defaults for other type */
722 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
726 extend_size = header_size+2 - name_length - 24;
728 if (extend_size < 0) {
729 if (extend_size == -2) {
730 /* CRC field is not given */
731 hdr->extend_type = EXTEND_GENERIC;
732 hdr->has_crc = FALSE;
737 error("Unkonwn header (lha file?)");
742 hdr->crc = get_word();
744 if (extend_size == 0)
747 hdr->extend_type = get_byte();
750 if (hdr->extend_type == EXTEND_UNIX) {
751 if (extend_size >= 11) {
752 hdr->minor_version = get_byte();
753 hdr->unix_last_modified_stamp = (time_t) get_longword();
754 hdr->unix_mode = get_word();
755 hdr->unix_uid = get_word();
756 hdr->unix_gid = get_word();
759 hdr->extend_type = EXTEND_GENERIC;
763 skip_bytes(extend_size);
765 hdr->header_size += 2;
773 * offset size field name
774 * -----------------------------------
775 * 0 1 header size [*1]
777 * -------------------------------------
779 * 7 4 skip size [*2] |
780 * 11 4 original size |
783 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
784 * 20 1 level (0x01 fixed) |
787 * X+ 22 2 file crc (CRC-16) |
790 * X+Y+25 2 next-header size v
791 * -------------------------------------------------
792 * X+Y+27 Z ext-header ^
794 * ----------------------------------- | [*2] skip size
797 * -------------------------------------------------
801 get_header_level1(fp, hdr, data)
812 hdr->size_field_length = 2; /* in bytes */
813 hdr->header_size = header_size = get_byte();
814 checksum = get_byte();
816 if (fread(data + COMMON_HEADER_SIZE,
817 header_size + 2 - COMMON_HEADER_SIZE, 1, fp) == 0) {
818 error("Invalid header (LHarc file ?)");
819 return FALSE; /* finish */
822 if (calc_sum(data + I_METHOD, header_size) != checksum) {
823 error("Checksum error (LHarc file?)");
827 get_bytes(hdr->method, 5, sizeof(hdr->method));
828 hdr->packed_size = get_longword(); /* skip size */
829 hdr->original_size = get_longword();
830 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
831 hdr->attribute = get_byte(); /* 0x20 fixed */
832 hdr->header_level = get_byte();
834 name_length = get_byte();
835 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
838 /* defaults for other type */
839 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
844 hdr->crc = get_word();
845 hdr->extend_type = get_byte();
847 dummy = header_size+2 - name_length - I_LEVEL1_HEADER_SIZE;
849 skip_bytes(dummy); /* skip old style extend header */
851 extend_size = get_word();
852 extend_size = get_extended_header(fp, hdr, extend_size, 0);
853 if (extend_size == -1)
856 /* On level 1 header, size fields should be adjusted. */
857 /* the `packed_size' field contains the extended header size. */
858 /* the `header_size' field does not. */
859 hdr->packed_size -= extend_size;
860 hdr->header_size += extend_size + 2;
869 * offset size field name
870 * --------------------------------------------------
871 * 0 2 total header size [*1] ^
872 * ----------------------- |
874 * 7 4 packed size [*2] |
875 * 11 4 original size |
877 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
878 * 20 1 level (0x02 fixed) | (X+26+(1))
879 * 21 2 file crc (CRC-16) |
881 * 24 2 next-header size |
882 * ----------------------------------- |
885 * ----------------------------------- |
886 * X +26 (1) padding v
887 * -------------------------------------------------
889 * : | [*2] packed size
891 * -------------------------------------------------
895 get_header_level2(fp, hdr, data)
905 hdr->size_field_length = 2; /* in bytes */
906 hdr->header_size = header_size = get_word();
908 if (fread(data + COMMON_HEADER_SIZE,
909 I_LEVEL2_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
910 error("Invalid header (LHarc file ?)");
911 return FALSE; /* finish */
914 get_bytes(hdr->method, 5, sizeof(hdr->method));
915 hdr->packed_size = get_longword();
916 hdr->original_size = get_longword();
917 hdr->unix_last_modified_stamp = get_longword();
918 hdr->attribute = get_byte(); /* reserved */
919 hdr->header_level = get_byte();
921 /* defaults for other type */
922 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
927 hdr->crc = get_word();
928 hdr->extend_type = get_byte();
929 extend_size = get_word();
931 INITIALIZE_CRC(hcrc);
932 hcrc = calccrc(hcrc, data, get_ptr - data);
934 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
935 if (extend_size == -1)
938 padding = header_size - I_LEVEL2_HEADER_SIZE - extend_size;
939 while (padding--) /* padding should be 0 or 1 */
940 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
942 if (hdr->header_crc != hcrc)
943 error("header CRC error");
952 * offset size field name
953 * --------------------------------------------------
954 * 0 2 size field length (4 fixed) ^
956 * 7 4 packed size [*2] |
957 * 11 4 original size |
959 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
960 * 20 1 level (0x03 fixed) | (X+32)
961 * 21 2 file crc (CRC-16) |
963 * 24 4 total header size [*1] |
964 * 28 4 next-header size |
965 * ----------------------------------- |
968 * -------------------------------------------------
970 * : | [*2] packed size
972 * -------------------------------------------------
976 get_header_level3(fp, hdr, data)
986 hdr->size_field_length = get_word();
988 if (fread(data + COMMON_HEADER_SIZE,
989 I_LEVEL3_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
990 error("Invalid header (LHarc file ?)");
991 return FALSE; /* finish */
994 get_bytes(hdr->method, 5, sizeof(hdr->method));
995 hdr->packed_size = get_longword();
996 hdr->original_size = get_longword();
997 hdr->unix_last_modified_stamp = get_longword();
998 hdr->attribute = get_byte(); /* reserved */
999 hdr->header_level = get_byte();
1001 /* defaults for other type */
1002 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
1006 hdr->has_crc = TRUE;
1007 hdr->crc = get_word();
1008 hdr->extend_type = get_byte();
1009 hdr->header_size = header_size = get_longword();
1010 extend_size = get_longword();
1012 INITIALIZE_CRC(hcrc);
1013 hcrc = calccrc(hcrc, data, get_ptr - data);
1015 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
1016 if (extend_size == -1)
1019 padding = header_size - I_LEVEL3_HEADER_SIZE - extend_size;
1020 while (padding--) /* padding should be 0 */
1021 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
1023 if (hdr->header_crc != hcrc)
1024 error("header CRC error");
1034 char data[LZHEADER_STORAGE];
1036 int archive_kanji_code = CODE_SJIS;
1037 int system_kanji_code = default_system_kanji_code;
1038 char *archive_delim = "\377\\"; /* `\' is for level 0 header and
1040 char *system_delim = "//";
1041 int filename_case = NONE;
1044 memset(hdr, 0, sizeof(LzHeader));
1048 if ((end_mark = getc(fp)) == EOF || end_mark == 0) {
1049 return FALSE; /* finish */
1053 if (fread(data + 1, COMMON_HEADER_SIZE - 1, 1, fp) == 0) {
1054 error("Invalid header (LHarc file ?)");
1055 return FALSE; /* finish */
1058 switch (data[I_HEADER_LEVEL]) {
1060 if (get_header_level0(fp, hdr, data) == FALSE)
1064 if (get_header_level1(fp, hdr, data) == FALSE)
1068 if (get_header_level2(fp, hdr, data) == FALSE)
1072 if (get_header_level3(fp, hdr, data) == FALSE)
1076 error("Unknown level header (level %d)", data[I_HEADER_LEVEL]);
1080 /* filename conversion */
1081 switch (hdr->extend_type) {
1083 filename_case = noconvertcase ? NONE : TO_LOWER;
1090 filename_case = NONE;
1094 archive_delim = "\377/:\\";
1095 /* `\' is for level 0 header and broken archive. */
1096 system_delim = "/://";
1097 filename_case = NONE;
1101 filename_case = noconvertcase ? NONE : TO_LOWER;
1105 if (optional_archive_kanji_code)
1106 archive_kanji_code = optional_archive_kanji_code;
1107 if (optional_system_kanji_code)
1108 system_kanji_code = optional_system_kanji_code;
1109 if (optional_archive_delim)
1110 archive_delim = optional_archive_delim;
1111 if (optional_system_delim)
1112 system_delim = optional_system_delim;
1113 if (optional_filename_case)
1114 filename_case = optional_filename_case;
1116 /* kanji code and delimiter conversion */
1117 convert_filename(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1120 archive_delim, system_delim, filename_case);
1122 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1124 /* split symbolic link */
1125 p = strchr(hdr->name, '|');
1127 /* hdr->name is symbolic link name */
1128 /* hdr->realname is real name */
1130 strcpy(hdr->realname, p+1); /* ok */
1133 error("unknown symlink name \"%s\"", hdr->name);
1139 /* skip SFX header */
1144 unsigned char buffer[64 * 1024]; /* max seek size */
1148 n = fread(buffer, 1, sizeof(buffer), fp);
1150 for (p = buffer; p < buffer + n; p++) {
1151 if (! (p[I_METHOD]=='-' && p[I_METHOD+1]=='l' && p[I_METHOD+4]=='-'))
1153 /* found "-l??-" keyword (as METHOD type string) */
1155 /* level 0 or 1 header */
1156 if ((p[I_HEADER_LEVEL] == 0 || p[I_HEADER_LEVEL] == 1)
1157 && p[I_HEADER_SIZE] > 20
1158 && p[I_HEADER_CHECKSUM] == calc_sum(p+2, p[I_HEADER_SIZE])) {
1159 if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
1160 fatal_error("cannot seek header");
1164 /* level 2 header */
1165 if (p[I_HEADER_LEVEL] == 2
1166 && p[I_HEADER_SIZE] >= 24
1167 && p[I_ATTRIBUTE] == 0x20) {
1168 if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
1169 fatal_error("cannot seek header");
1174 if (fseeko(fp, -n, SEEK_CUR) == -1)
1175 fatal_error("cannot seek header");
1180 /* remove leading `xxxx/..' */
1182 remove_leading_dots(char *path)
1187 if (strcmp(first, "..") == 0) {
1188 warning("Removing leading `..' from member name.");
1189 return first+1; /* change to "." */
1192 if (strstr(first, "..") == 0)
1195 while (path && *path) {
1197 if (strcmp(path, "..") == 0)
1198 ptr = path = path+2;
1199 else if (strncmp(path, "../", 3) == 0)
1200 ptr = path = path+3;
1202 path = strchr(path, '/');
1204 if (path && *path == '/') {
1210 warning("Removing leading `%.*s' from member name.", ptr-first, first);
1218 init_header(name, v_stat, hdr)
1220 struct stat *v_stat;
1225 memset(hdr, 0, sizeof(LzHeader));
1227 /* the `method' member is rewrote by the encoding function.
1228 but need set for empty files */
1229 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
1231 hdr->packed_size = 0;
1232 hdr->original_size = v_stat->st_size;
1233 hdr->attribute = GENERIC_ATTRIBUTE;
1234 hdr->header_level = header_level;
1235 len = str_safe_copy(hdr->name,
1236 remove_leading_dots(name),
1239 hdr->extend_type = EXTEND_UNIX;
1240 hdr->unix_last_modified_stamp = v_stat->st_mtime;
1241 /* since 00:00:00 JAN.1.1970 */
1242 #ifdef NOT_COMPATIBLE_MODE
1243 /* Please need your modification in this space. */
1245 hdr->unix_mode = v_stat->st_mode;
1248 hdr->unix_uid = v_stat->st_uid;
1249 hdr->unix_gid = v_stat->st_gid;
1251 #if INCLUDE_OWNER_NAME_IN_HEADER
1254 struct passwd *ent = getpwuid(hdr->unix_uid);
1257 strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
1258 if (hdr->user[sizeof(hdr->user)-1])
1259 hdr->user[sizeof(hdr->user)-1] = 0;
1265 struct group *ent = getgrgid(hdr->unix_gid);
1268 strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
1269 if (hdr->group[sizeof(hdr->group)-1])
1270 hdr->group[sizeof(hdr->group)-1] = 0;
1274 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
1275 if (is_directory(v_stat)) {
1276 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1277 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1278 hdr->original_size = 0;
1279 if (len > 0 && hdr->name[len - 1] != '/') {
1280 if (len < sizeof(hdr->name)-1)
1281 strcpy(&hdr->name[len++], "/"); /* ok */
1283 warning("the length of dirname \"%s\" is too long.",
1289 if (is_symlink(v_stat)) {
1290 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1291 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1292 hdr->original_size = 0;
1293 readlink(name, hdr->realname, sizeof(hdr->realname));
1299 write_unix_info(hdr)
1302 /* UNIX specific informations */
1304 put_word(5); /* size */
1305 put_byte(0x50); /* permission */
1306 put_word(hdr->unix_mode);
1308 put_word(7); /* size */
1309 put_byte(0x51); /* gid and uid */
1310 put_word(hdr->unix_gid);
1311 put_word(hdr->unix_uid);
1313 if (hdr->group[0]) {
1314 int len = strlen(hdr->group);
1315 put_word(len + 3); /* size */
1316 put_byte(0x52); /* group name */
1317 put_bytes(hdr->group, len);
1321 int len = strlen(hdr->user);
1322 put_word(len + 3); /* size */
1323 put_byte(0x53); /* user name */
1324 put_bytes(hdr->user, len);
1327 if (hdr->header_level == 1) {
1328 put_word(7); /* size */
1329 put_byte(0x54); /* time stamp */
1330 put_longword(hdr->unix_last_modified_stamp);
1335 write_header_level0(data, hdr, pathname)
1337 char *data, *pathname;
1344 memset(data, 0, LZHEADER_STORAGE);
1346 put_byte(0x00); /* header size */
1347 put_byte(0x00); /* check sum */
1348 put_bytes(hdr->method, 5);
1349 put_longword(hdr->packed_size);
1350 put_longword(hdr->original_size);
1351 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1352 put_byte(hdr->attribute);
1353 put_byte(hdr->header_level); /* level 0 */
1355 /* write pathname (level 0 header contains the directory part) */
1356 name_length = strlen(pathname);
1358 limit = 255 - I_GENERIC_HEADER_SIZE + 2;
1360 limit = 255 - I_LEVEL0_HEADER_SIZE + 2;
1362 if (name_length > limit) {
1363 warning("the length of pathname \"%s\" is too long.", pathname);
1364 name_length = limit;
1366 put_byte(name_length);
1367 put_bytes(pathname, name_length);
1370 if (generic_format) {
1371 header_size = I_GENERIC_HEADER_SIZE + name_length - 2;
1372 data[I_HEADER_SIZE] = header_size;
1373 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1375 /* write old-style extend header */
1376 put_byte(EXTEND_UNIX);
1377 put_byte(CURRENT_UNIX_MINOR_VERSION);
1378 put_longword(hdr->unix_last_modified_stamp);
1379 put_word(hdr->unix_mode);
1380 put_word(hdr->unix_uid);
1381 put_word(hdr->unix_gid);
1383 /* size of extended header is 12 */
1384 header_size = I_LEVEL0_HEADER_SIZE + name_length - 2;
1385 data[I_HEADER_SIZE] = header_size;
1386 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1389 return header_size + 2;
1393 write_header_level1(data, hdr, pathname)
1395 char *data, *pathname;
1397 int name_length, dir_length, limit;
1398 char *basename, *dirname;
1400 char *extend_header_top;
1401 size_t extend_header_size;
1403 basename = strrchr(pathname, LHA_PATHSEP);
1406 name_length = strlen(basename);
1408 dir_length = basename - dirname;
1411 basename = pathname;
1412 name_length = strlen(basename);
1418 memset(data, 0, LZHEADER_STORAGE);
1420 put_byte(0x00); /* header size */
1421 put_byte(0x00); /* check sum */
1422 put_bytes(hdr->method, 5);
1423 put_longword(hdr->packed_size);
1424 put_longword(hdr->original_size);
1425 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1427 put_byte(hdr->header_level); /* level 1 */
1429 /* level 1 header: write filename (basename only) */
1430 limit = 255 - I_LEVEL1_HEADER_SIZE + 2;
1431 if (name_length > limit) {
1432 put_byte(0); /* name length */
1435 put_byte(name_length);
1436 put_bytes(basename, name_length);
1444 put_byte(EXTEND_UNIX);
1446 /* write extend header from here. */
1448 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1449 header_size = extend_header_top - data - 2;
1451 /* write filename and dirname */
1453 if (name_length > limit) {
1454 put_word(name_length + 3); /* size */
1455 put_byte(0x01); /* filename */
1456 put_bytes(basename, name_length);
1459 if (dir_length > 0) {
1460 put_word(dir_length + 3); /* size */
1461 put_byte(0x02); /* dirname */
1462 put_bytes(dirname, dir_length);
1465 if (!generic_format)
1466 write_unix_info(hdr);
1468 put_word(0x0000); /* next header size */
1470 extend_header_size = put_ptr - extend_header_top;
1471 /* On level 1 header, the packed size field is contains the ext-header */
1472 hdr->packed_size += put_ptr - extend_header_top;
1474 /* put `skip size' */
1475 setup_put(data + I_PACKED_SIZE);
1476 put_longword(hdr->packed_size);
1478 data[I_HEADER_SIZE] = header_size;
1479 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1481 return header_size + extend_header_size + 2;
1485 write_header_level2(data, hdr, pathname)
1487 char *data, *pathname;
1489 int name_length, dir_length;
1490 char *basename, *dirname;
1492 char *extend_header_top;
1493 char *headercrc_ptr;
1496 basename = strrchr(pathname, LHA_PATHSEP);
1499 name_length = strlen(basename);
1501 dir_length = basename - dirname;
1504 basename = pathname;
1505 name_length = strlen(basename);
1511 memset(data, 0, LZHEADER_STORAGE);
1513 put_word(0x0000); /* header size */
1514 put_bytes(hdr->method, 5);
1515 put_longword(hdr->packed_size);
1516 put_longword(hdr->original_size);
1517 put_longword(hdr->unix_last_modified_stamp);
1519 put_byte(hdr->header_level); /* level 2 */
1526 put_byte(EXTEND_UNIX);
1528 /* write extend header from here. */
1530 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1532 /* write common header */
1535 headercrc_ptr = put_ptr;
1536 put_word(0x0000); /* header CRC */
1538 /* write filename and dirname */
1539 /* must have this header, even if the name_length is 0. */
1540 put_word(name_length + 3); /* size */
1541 put_byte(0x01); /* filename */
1542 put_bytes(basename, name_length);
1544 if (dir_length > 0) {
1545 put_word(dir_length + 3); /* size */
1546 put_byte(0x02); /* dirname */
1547 put_bytes(dirname, dir_length);
1550 if (!generic_format)
1551 write_unix_info(hdr);
1553 put_word(0x0000); /* next header size */
1555 header_size = put_ptr - data;
1556 if ((header_size & 0xff) == 0) {
1557 /* cannot put zero at the first byte on level 2 header. */
1558 /* adjust header size. */
1559 put_byte(0); /* padding */
1563 /* put header size */
1564 setup_put(data + I_HEADER_SIZE);
1565 put_word(header_size);
1567 /* put header CRC in extended header */
1568 INITIALIZE_CRC(hcrc);
1569 hcrc = calccrc(hcrc, data, (unsigned int) header_size);
1570 setup_put(headercrc_ptr);
1577 write_header(fp, hdr)
1582 char data[LZHEADER_STORAGE];
1584 int archive_kanji_code = CODE_SJIS;
1585 int system_kanji_code = default_system_kanji_code;
1586 char *archive_delim = "\377";
1587 char *system_delim = "/";
1588 int filename_case = NONE;
1589 char pathname[FILENAME_LENGTH];
1591 if (optional_archive_kanji_code)
1592 archive_kanji_code = optional_archive_kanji_code;
1593 if (optional_system_kanji_code)
1594 system_kanji_code = optional_system_kanji_code;
1597 filename_case = TO_UPPER;
1599 if (hdr->header_level == 0) {
1600 archive_delim = "\\";
1603 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1605 p = strchr(hdr->name, '|');
1607 error("symlink name \"%s\" contains '|' char. change it into '_'",
1611 if (xsnprintf(pathname, sizeof(pathname),
1612 "%s|%s", hdr->name, hdr->realname) == -1)
1613 error("file name is too long (%s -> %s)", hdr->name, hdr->realname);
1616 strncpy(pathname, hdr->name, sizeof(pathname));
1617 pathname[sizeof(pathname)-1] = 0;
1620 convert_filename(pathname, strlen(pathname), sizeof(pathname),
1623 system_delim, archive_delim, filename_case);
1625 switch (hdr->header_level) {
1627 header_size = write_header_level0(data, hdr, pathname);
1630 header_size = write_header_level1(data, hdr, pathname);
1633 header_size = write_header_level2(data, hdr, pathname);
1636 error("Unknown level header (level %d)", hdr->header_level);
1640 if (fwrite(data, header_size, 1, fp) == 0)
1641 fatal_error("Cannot write to temporary file");
1644 #if MULTIBYTE_FILENAME
1646 #if defined(__APPLE__) /* Added by Hiroto Sakai */
1648 #include <CoreFoundation/CFString.h>
1649 #include <CoreFoundation/CFStringEncodingExt.h>
1651 /* this is not need for Mac OS X v 10.2 later */
1653 kCFStringEncodingAllowLossyConversion = 1,
1654 kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1655 kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1656 kCFStringEncodingSubstituteCombinings = (1 << 3),
1657 kCFStringEncodingComposeCombinings = (1 << 4),
1658 kCFStringEncodingIgnoreCombinings = (1 << 5),
1659 kCFStringEncodingUseCanonical = (1 << 6),
1660 kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1661 kCFStringEncodingPrependBOM = (1 << 8),
1662 kCFStringEncodingDisableCorporateArea = (1 << 9),
1663 kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1667 ConvertEncodingToUTF8(const char* inCStr,
1668 char* outUTF8Buffer,
1669 int outUTF8BufferLength,
1670 unsigned long scriptEncoding,
1671 unsigned long flags)
1673 unsigned long unicodeChars;
1674 unsigned long srcCharsUsed;
1675 unsigned long usedByteLen = 0;
1676 UniChar uniStr[512];
1677 unsigned long cfResult;
1679 cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1687 if (cfResult == 0) {
1688 cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1693 (char*)outUTF8Buffer,
1694 outUTF8BufferLength - 1,
1696 outUTF8Buffer[usedByteLen] = '\0';
1703 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1704 int inUTF8BufLength,
1705 char* outCStrBuffer,
1706 int outCStrBufferLength,
1707 unsigned long scriptEncoding,
1708 unsigned long flags)
1710 unsigned long unicodeChars;
1711 unsigned long srcCharsUsed;
1712 unsigned long usedByteLen = 0;
1713 UniChar uniStr[256];
1714 unsigned long cfResult;
1716 cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1724 if (cfResult == 0) {
1725 cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1730 (char*)outCStrBuffer,
1731 outCStrBufferLength - 1,
1733 outCStrBuffer[usedByteLen] = '\0';
1743 ConvertEncodingByIconv(const char *src, char *dst, int dstsize,
1744 const char *srcEnc, const char *dstEnc)
1747 static char szTmpBuf[2048];
1753 dst_p = &szTmpBuf[0];
1754 iLen = (size_t)sizeof(szTmpBuf)-1;
1755 src_p = (char *)src;
1756 sLen = (size_t)strlen(src);
1757 memset(szTmpBuf, 0, sizeof(szTmpBuf));
1758 memset(dst, 0, dstsize);
1760 ic = iconv_open(dstEnc, srcEnc);
1761 if (ic == (iconv_t)-1) {
1762 error("iconv_open() failure: %s", strerror(errno));
1766 if (iconv(ic, &src_p, &sLen, &dst_p, &iLen) == (size_t)-1) {
1767 error("iconv() failure: %s", strerror(errno));
1772 strncpy(dst, szTmpBuf, dstsize);
1778 #endif /* defined(__APPLE__) */
1781 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1783 #if defined(__APPLE__)
1785 if (ConvertEncodingToUTF8(src, dst, dstsize,
1786 kCFStringEncodingDOSJapanese,
1787 kCFStringEncodingUseHFSPlusCanonical) == 0)
1790 if (ConvertEncodingByIconv(src, dst, dstsize, "SJIS", "UTF-8") != -1)
1793 error("not support utf-8 conversion");
1796 if (dstsize < 1) return dst;
1798 return strncpy(dst, src, dstsize-1);
1802 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1804 #if defined(__APPLE__)
1808 srclen = strlen(src);
1809 if (ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1810 kCFStringEncodingDOSJapanese,
1811 kCFStringEncodingUseHFSPlusCanonical) == 0)
1814 if (ConvertEncodingByIconv(src, dst, dstsize, "UTF-8", "SJIS") != -1)
1817 error("not support utf-8 conversion");
1820 if (dstsize < 1) return dst;
1822 return strncpy(dst, src, dstsize-1);
1826 * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1827 * ¡ÖÆüËܸì¾ðÊó½èÍý¡× ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1828 * ¤è¤êÈ´¿è(by Koji Arai)
1831 euc2sjis(int *p1, int *p2)
1833 unsigned char c1 = *p1 & 0x7f;
1834 unsigned char c2 = *p2 & 0x7f;
1835 int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1836 int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1837 *p1 = ((c1 + 1) >> 1) + rowoff;
1838 *p2 += celoff - 0x80;
1842 sjis2euc(int *p1, int *p2)
1844 unsigned char c1 = *p1;
1845 unsigned char c2 = *p2;
1846 int adjust = c2 < 0x9f;
1847 int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1848 int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1849 *p1 = ((c1 - rowoff) << 1) - adjust;
1860 case '0': case '1': case '2': case '3': case '4':
1861 case '5': case '6': case '7': case '8': case '9':
1864 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1865 return c - 'a' + 10;
1867 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1868 return c - 'A' + 10;
1878 case 0: case 1: case 2: case 3: case 4:
1879 case 5: case 6: case 7: case 8: case 9:
1882 case 10: case 11: case 12: case 13: case 14: case 15:
1883 return c + 'a' - 10;
1891 cap_to_sjis(char *dst, const char *src, size_t dstsize)
1894 size_t len = strlen(src);
1897 for (i = j = 0; i < len && i < dstsize; i++) {
1898 if (src[i] != ':') {
1904 a = hex2int((unsigned char)src[i]);
1905 b = hex2int((unsigned char)src[i+1]);
1907 if (a == -1 || b == -1) {
1910 strncpy(dst+j, src+i, dstsize-j);
1917 dst[j++] = a * 16 + b;
1924 sjis_to_cap(char *dst, const char *src, size_t dstsize)
1927 size_t len = strlen(src);
1930 for (i = j = 0; i < len && i < dstsize; i++) {
1931 if (src[i] == ':') {
1932 strncpy(dst+j, ":3a", dstsize-j);
1937 if (isprint(src[i])) {
1942 if (j + 3 >= dstsize) {
1947 a = int2hex((unsigned char)src[i] / 16);
1948 b = int2hex((unsigned char)src[i] % 16);
1957 #endif /* MULTIBYTE_FILENAME */