1 /* ------------------------------------------------------------------------ */
3 /* header.c -- header manipulate functions */
5 /* Modified Nobutaka Watazaki */
7 /* Original Y.Tagawa */
8 /* modified 1991.12.16 M.Oki */
9 /* Ver. 1.10 Symbolic Link added 1993.10.01 N.Watazaki */
10 /* Ver. 1.13b Symbolic Link Bug Fix 1994.08.22 N.Watazaki */
11 /* Ver. 1.14 Source All chagned 1995.01.14 N.Watazaki */
12 /* Ver. 1.14i bug fixed 2000.10.06 t.okamoto */
13 /* ------------------------------------------------------------------------ */
16 #define DUMP_HEADER 0 /* for debugging */
18 #if !STRCHR_8BIT_CLEAN
19 /* should use 8 bit clean version */
22 #define strchr xstrchr
23 #define strrchr xstrrchr
26 /* ------------------------------------------------------------------------ */
28 #define GET_BYTE() (*get_ptr++ & 0xff)
31 static char *start_ptr;
32 #define setup_get(PTR) (start_ptr = get_ptr = (PTR))
33 #define get_byte() dump_get_byte()
34 #define skip_bytes(len) dump_skip_bytes(len)
36 #define setup_get(PTR) (get_ptr = (PTR))
37 #define get_byte() GET_BYTE()
38 #define skip_bytes(len) (get_ptr += (len))
40 #define put_ptr get_ptr
41 #define setup_put(PTR) (put_ptr = (PTR))
42 #define put_byte(c) (*put_ptr++ = (char)(c))
44 int optional_archive_kanji_code = NONE;
45 int optional_system_kanji_code = NONE;
46 char *optional_archive_delim = NULL;
47 char *optional_system_delim = NULL;
48 int optional_filename_case = NONE;
50 #ifdef MULTIBYTE_FILENAME
51 int default_system_kanji_code = MULTIBYTE_FILENAME;
53 int default_system_kanji_code = NONE;
56 /* ------------------------------------------------------------------------ */
64 for (sum = 0; len; len--)
76 printf("%02d %2d: ", get_ptr - start_ptr, 1);
78 printf("%d(0x%02x)\n", i, i);
86 printf("%02d %2d:", get_ptr - start_ptr, len);
88 printf(" 0x%02x", GET_BYTE());
93 /* ------------------------------------------------------------------------ */
101 printf("%02d %2d: ", get_ptr - start_ptr, 2);
107 printf("%hd(0x%04hx)\n", w, w);
112 /* ------------------------------------------------------------------------ */
121 /* ------------------------------------------------------------------------ */
129 printf("%02d %2d: ", get_ptr - start_ptr, 4);
135 l = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
137 printf("%ld(0x%08lx)\n", l, l);
139 return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
142 /* ------------------------------------------------------------------------ */
154 get_bytes(buf, len, size)
161 printf("%02d %2d: ", get_ptr - start_ptr, len);
163 for (i = 0; i < len && i < size; i++)
167 printf("\"%s\"\n", buf);
178 for (i = 0; i < len; i++)
182 /* added by Koji Arai */
184 convert_filename(name, len, size,
186 from_delim, to_delim,
191 int from_code, to_code, case_to;
192 char *from_delim, *to_delim;
196 #ifdef MULTIBYTE_FILENAME
197 char tmp[FILENAME_LENGTH];
199 if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
200 for (i = 0; i < len; i++)
201 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
202 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
203 sjis_to_utf8(tmp, name, sizeof(tmp));
204 strncpy(name, tmp, size);
207 for (i = 0; i < len; i++)
208 if (name[i] == '/') name[i] = LHA_PATHSEP;
209 from_code = CODE_UTF8;
211 else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
212 for (i = 0; i < len; i++)
213 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
214 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
215 utf8_to_sjis(tmp, name, sizeof(tmp));
216 strncpy(name, tmp, size);
219 for (i = 0; i < len; i++)
220 if (name[i] == '/') name[i] = LHA_PATHSEP;
221 from_code = CODE_SJIS;
225 for (i = 0; i < len; i ++) {
226 #ifdef MULTIBYTE_FILENAME
227 if (from_code == CODE_EUC &&
228 (unsigned char)name[i] == 0x8e) {
229 if (to_code != CODE_SJIS) {
235 memmove(name + i, name + i + 1, len - i);
239 if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
240 if (to_code != CODE_EUC) {
244 if (len == size - 1) /* check overflow */
246 memmove(name+i+1, name+i, len-i);
252 if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
254 if (to_code != CODE_SJIS) {
259 c1 = (unsigned char)name[i];
260 c2 = (unsigned char)name[i+1];
267 if (from_code == CODE_SJIS &&
268 SJC_FIRST_P(name[i]) &&
269 SJC_SECOND_P(name[i+1])) {
272 if (to_code != CODE_EUC) {
277 c1 = (unsigned char)name[i];
278 c2 = (unsigned char)name[i+1];
285 #endif /* MULTIBYTE_FILENAME */
289 /* transpose from_delim to to_delim */
291 if ((ptr = strchr(from_delim, name[i])) != NULL) {
292 name[i] = to_delim[ptr - from_delim];
297 if (case_to == TO_UPPER && islower(name[i])) {
298 name[i] = toupper(name[i]);
301 if (case_to == TO_LOWER && isupper(name[i])) {
302 name[i] = tolower(name[i]);
308 /* ------------------------------------------------------------------------ */
310 /* Generic stamp format: */
312 /* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 */
313 /* |<-------- year ------->|<- month ->|<-- day -->| */
315 /* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */
316 /* |<--- hour --->|<---- minute --->|<- second*2 ->| */
318 /* ------------------------------------------------------------------------ */
321 * NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
322 * returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or TZSET.
326 #if defined(HAVE_MKTIME)
327 #ifdef HAVE_TIMELOCAL
328 #undef HAVE_TIMELOCAL
330 #endif /* defined(HAVE_MKTIME) */
332 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
336 #endif /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
338 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) || defined(HAVE_TZSET)
344 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) || defined(HAVE_TZSET) || defined(HAVE_FTIME)
345 #ifdef HAVE_GETTIMEOFDAY
346 #undef HAVE_GETTIMEOFDAY
349 #ifndef HAVE_GETTIMEOFDAY
350 #define HAVE_GETTIMEOFDAY /* use gettimeofday() */
355 #include <sys/timeb.h>
359 * You may define as : #define TIMEZONE_HOOK \ extern long
360 * timezone ; \ extern void tzset();
364 /* Which do you like better, `TIMEZONE_HOOK' or `TIMEZONE_HOOK;' ? */
367 #if defined(HAVE_TZSET) && defined(_MINIX)
368 extern long timezone; /* not defined in time.h */
371 /* ------------------------------------------------------------------------ */
372 #if defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY) || defined(HAVE_TZSET)
382 /* ------------------------------------------------------------------------ */
383 #if !defined(HAVE_TZSET) && defined(HAVE_FTIME)
388 return buf.timezone * 60L;
392 /* ------------------------------------------------------------------------ */
393 #if !defined(HAVE_TZSET) && !defined(HAVE_FTIME) /* maybe defined(HAVE_GETTIMEOFDAY) */
395 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
399 return -localtime(&tt)->tm_gmtoff;
400 #else /* HAVE_STRUCT_TM_TM_GMTOFF */
403 gettimeofday(&tp, &tzp);/* specific to 4.3BSD */
405 * return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L *
408 return (tzp.tz_minuteswest * 60L);
409 #endif /* HAVE_STRUCT_TM_TM_GMTOFF */
412 #endif /* defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY) ||
413 * defined(HAVE_TZSET) */
415 /* ------------------------------------------------------------------------ */
417 generic_to_unix_stamp(t)
419 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
424 * special case: if MSDOS format date and time were zero, then we
425 * set time to be zero here too.
430 dostm.tm_sec = (t & 0x1f) * 2;
431 dostm.tm_min = t >> 5 & 0x3f;
432 dostm.tm_hour = t >> 11 & 0x1f;
433 dostm.tm_mday = t >> 16 & 0x1f;
434 dostm.tm_mon = (t >> (16+5) & 0x0f) - 1; /* 0..11 */
435 dostm.tm_year = (t >> (16+9) & 0x7f) + 80;
437 dostm.tm_isdst = 0; /* correct? */
439 dostm.tm_isdst = -1; /* correct? */
441 return (time_t) mktime(&dostm);
442 #else /* maybe defined(HAVE_TIMELOCAL) */
443 return (time_t) timelocal(&dostm);
447 #else /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
449 int year, month, day, hour, min, sec;
451 static unsigned int dsboy[12] = {0, 31, 59, 90, 120, 151,
452 181, 212, 243, 273, 304, 334};
456 * special case: if MSDOS format date and time were zero, then we
457 * set time to be zero here too.
462 year = ((int) (t >> 16 + 9) & 0x7f) + 1980;
463 month = (int) (t >> 16 + 5) & 0x0f; /* 1..12 means Jan..Dec */
464 day = (int) (t >> 16) & 0x1f; /* 1..31 means 1st,...31st */
466 hour = ((int) t >> 11) & 0x1f;
467 min = ((int) t >> 5) & 0x3f;
468 sec = ((int) t & 0x1f) * 2;
470 /* Calculate days since 1970.01.01 */
471 days = (365 * (year - 1970) + /* days due to whole years */
472 (year - 1970 + 1) / 4 + /* days due to leap years */
473 dsboy[month - 1] + /* days since beginning of this year */
474 day - 1); /* days since beginning of month */
476 if ((year % 4 == 0) &&
477 (year % 100 != 0 || year % 400 == 0) && /* 1999.5.24 t.oka */
478 (month >= 3)) /* if this is a leap year and month */
479 days++; /* is March or later, add a day */
481 /* Knowing the days, we can find seconds */
482 longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
483 longtime += gettz(); /* adjust for timezone */
485 /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00. */
486 return (time_t) longtime;
488 #endif /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
490 /* ------------------------------------------------------------------------ */
492 unix_to_generic_stamp(t)
495 struct tm *tm = localtime(&t);
497 return ((((long) (tm->tm_year - 80)) << 25) +
498 (((long) (tm->tm_mon + 1)) << 21) +
499 (((long) tm->tm_mday) << 16) +
500 (long) ((tm->tm_hour << 11) +
505 /* ------------------------------------------------------------------------ */
506 /* build header functions */
507 /* ------------------------------------------------------------------------ */
513 * --------------------------------
515 * 2 or 4 next-header size [*1]
516 * --------------------------------------
517 * ext header: 1 ext-type ^
518 * ? contents | [*1] next-header size
519 * 2 or 4 next-header size v
520 * --------------------------------------
522 * on level 0, 1, 2 header:
523 * size field is 2 bytes
525 * size field is 4 bytes
528 get_extended_header(fp, hdr, header_size)
533 char data[LZHEADER_STORAGE];
535 char dirname[FILENAME_LENGTH];
538 long whole_size = header_size;
540 int n = 1 + hdr->size_field_length; /* `ext-type' + `next-header size' */
542 if (hdr->header_level == 0)
545 name_length = strlen(hdr->name);
547 while (header_size) {
549 if (sizeof(data) < header_size) {
550 error("header size (%ld) too large.", header_size);
554 if (fread(data, header_size, 1, fp) == 0) {
555 error("Invalid header (LHa file ?)");
558 ext_type = get_byte();
561 /* header crc (CRC-16) */
562 skip_bytes(header_size - n); /* FIXME: ignored? */
567 get_bytes(hdr->name, header_size-n, sizeof(hdr->name)-1);
568 hdr->name[name_length] = 0;
572 dir_length = get_bytes(dirname, header_size-n, sizeof(dirname)-1);
573 dirname[dir_length] = 0;
576 /* MS-DOS attribute */
577 if (hdr->extend_type == EXTEND_MSDOS ||
578 hdr->extend_type == EXTEND_HUMAN ||
579 hdr->extend_type == EXTEND_GENERIC)
580 hdr->attribute = get_word();
583 /* UNIX permission */
584 if (hdr->extend_type == EXTEND_UNIX)
585 hdr->unix_mode = get_word();
588 /* UNIX gid and uid */
589 if (hdr->extend_type == EXTEND_UNIX) {
590 hdr->unix_gid = get_word();
591 hdr->unix_uid = get_word();
595 /* UNIX group name */
596 if (hdr->extend_type == EXTEND_UNIX) {
597 i = get_bytes(hdr->group, header_size-n, sizeof(hdr->group)-1);
598 hdr->group[i] = '\0';
603 if (hdr->extend_type == EXTEND_UNIX) {
604 i = get_bytes(hdr->user, header_size-n, sizeof(hdr->user)-1);
609 /* UNIX last modified time */
610 if (hdr->extend_type == EXTEND_UNIX)
611 hdr->unix_last_modified_stamp = (time_t) get_longword();
616 warning("unknown extended header 0x%02x", ext_type);
617 skip_bytes(header_size - n);
622 if (hdr->size_field_length == 2)
623 whole_size += header_size = get_word();
625 whole_size += header_size = get_longword();
629 if (name_length + dir_length >= sizeof(hdr->name)) {
630 warning("the length of pathname \"%s%s\" is too long.",
632 name_length = sizeof(hdr->name) - dir_length - 1;
633 hdr->name[name_length] = 0;
635 strcat(dirname, hdr->name);
636 strcpy(hdr->name, dirname);
637 name_length += dir_length;
647 * offset size field name
648 * ----------------------------------
649 * 0 1 header size [*1]
651 * ---------------------------------------
653 * 7 4 packed size [*2] |
654 * 11 4 original size |
657 * 19 1 attribute | [*1] header size (X+Y+22)
658 * 20 1 level (0x00 fixed) |
661 * X +22 2 file crc (CRC-16) |
662 * X +24 Y ext-header(old style) v
663 * -------------------------------------------------
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+I_NAME_LENGTH, header_size+2-I_NAME_LENGTH, 1, fp) == 0) {
701 error("Invalid header (LHarc file ?)");
702 return FALSE; /* finish */
705 if (calc_sum(data + I_METHOD, header_size) != checksum) {
706 error("Checksum error (LHarc file?)");
710 get_bytes(hdr->method, 5, sizeof(hdr->method));
711 hdr->packed_size = get_longword();
712 hdr->original_size = get_longword();
713 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
714 hdr->attribute = get_byte(); /* MS-DOS attribute */
715 hdr->header_level = get_byte();
716 name_length = get_byte();
717 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
720 /* defaults for other type */
721 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
725 extend_size = header_size+2 - name_length - 24;
727 if (extend_size < 0) {
728 if (extend_size == -2) {
729 /* CRC field is not given */
730 hdr->extend_type = EXTEND_GENERIC;
731 hdr->has_crc = FALSE;
736 error("Unkonwn header (lha file?)");
741 hdr->crc = get_word();
743 if (extend_size == 0)
746 hdr->extend_type = get_byte();
749 if (hdr->extend_type == EXTEND_UNIX) {
750 if (extend_size >= 11) {
751 hdr->minor_version = get_byte();
752 hdr->unix_last_modified_stamp = (time_t) get_longword();
753 hdr->unix_mode = get_word();
754 hdr->unix_uid = get_word();
755 hdr->unix_gid = get_word();
758 hdr->extend_type = EXTEND_GENERIC;
762 skip_bytes(extend_size);
771 * offset size field name
772 * -----------------------------------
773 * 0 1 header size [*1]
775 * -------------------------------------
777 * 7 4 skip size [*2] |
778 * 11 4 original size |
781 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
782 * 20 1 level (0x01 fixed) |
785 * X+ 22 2 file crc (CRC-16) |
788 * X+Y+25 2 next-header size v
789 * -------------------------------------------------
790 * X+Y+27 Z ext-header ^
792 * ----------------------------------- | [*2] skip size
795 * -------------------------------------------------
799 get_header_level1(fp, hdr, data)
804 int header_size, extend_size;
809 hdr->size_field_length = 2; /* in bytes */
810 hdr->header_size = header_size = get_byte();
811 checksum = get_byte();
813 if (fread(data+I_NAME_LENGTH, header_size+2-I_NAME_LENGTH, 1, fp) == 0) {
814 error("Invalid header (LHarc file ?)");
815 return FALSE; /* finish */
818 if (calc_sum(data + I_METHOD, header_size) != checksum) {
819 error("Checksum error (LHarc file?)");
823 get_bytes(hdr->method, 5, sizeof(hdr->method));
824 hdr->packed_size = get_longword(); /* skip size */
825 hdr->original_size = get_longword();
826 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
827 hdr->attribute = get_byte(); /* 0x20 fixed */
828 hdr->header_level = get_byte();
830 name_length = get_byte();
831 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
834 /* defaults for other type */
835 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
840 hdr->crc = get_word();
841 hdr->extend_type = get_byte();
843 dummy = header_size+2 - name_length - 27;
845 skip_bytes(dummy); /* skip old style extend header */
847 extend_size = get_word();
848 extend_size = get_extended_header(fp, hdr, extend_size);
849 if (extend_size == -1)
852 /* On level 1 header, size fields should be adjusted. */
853 /* the `packed_size' field contains the extended header size. */
854 /* the `header_size' field does not. */
855 hdr->packed_size -= extend_size;
856 hdr->header_size += extend_size;
865 * offset size field name
866 * --------------------------------------------------
867 * 0 2 total header size [*1] ^
868 * ----------------------- |
870 * 7 4 packed size [*2] |
871 * 11 4 original size |
873 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
874 * 20 1 level (0x02 fixed) | (X+26+(1))
875 * 21 2 file crc (CRC-16) |
877 * 24 2 next-header size |
878 * ----------------------------------- |
881 * ----------------------------------- |
882 * X +26 (1) padding v
883 * -------------------------------------------------
885 * : | [*2] packed size
887 * -------------------------------------------------
891 get_header_level2(fp, hdr, data)
896 int header_size, extend_size;
899 hdr->size_field_length = 2; /* in bytes */
900 hdr->header_size = header_size = get_word();
902 if (fread(data + I_NAME_LENGTH, 26 - I_NAME_LENGTH, 1, fp) == 0) {
903 error("Invalid header (LHarc file ?)");
904 return FALSE; /* finish */
907 get_bytes(hdr->method, 5, sizeof(hdr->method));
908 hdr->packed_size = get_longword();
909 hdr->original_size = get_longword();
910 hdr->unix_last_modified_stamp = get_longword();
911 hdr->attribute = get_byte(); /* reserved */
912 hdr->header_level = get_byte();
914 /* defaults for other type */
915 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
920 hdr->crc = get_word();
921 hdr->extend_type = get_byte();
922 extend_size = get_word();
924 extend_size = get_extended_header(fp, hdr, extend_size);
925 if (extend_size == -1)
928 padding = header_size - 26 - extend_size;
929 while (padding--) /* padding should be 0 or 1 */
932 /* FIXME: no collate the header CRC */
941 * offset size field name
942 * --------------------------------------------------
943 * 0 2 size field length (4 fixed) ^
945 * 7 4 packed size [*2] |
946 * 11 4 original size |
948 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
949 * 20 1 level (0x03 fixed) | (X+32)
950 * 21 2 file crc (CRC-16) |
952 * 24 4 total header size [*1] |
953 * 28 4 next-header size |
954 * ----------------------------------- |
957 * -------------------------------------------------
959 * : | [*2] packed size
961 * -------------------------------------------------
965 get_header_level3(fp, hdr, data)
970 long header_size, extend_size;
973 hdr->size_field_length = get_word();
975 if (fread(data + I_NAME_LENGTH, 32 - I_NAME_LENGTH, 1, fp) == 0) {
976 error("Invalid header (LHarc file ?)");
977 return FALSE; /* finish */
980 get_bytes(hdr->method, 5, sizeof(hdr->method));
981 hdr->packed_size = get_longword();
982 hdr->original_size = get_longword();
983 hdr->unix_last_modified_stamp = get_longword();
984 hdr->attribute = get_byte(); /* reserved */
985 hdr->header_level = get_byte();
987 /* defaults for other type */
988 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
993 hdr->crc = get_word();
994 hdr->extend_type = get_byte();
995 hdr->header_size = header_size = get_longword();
996 extend_size = get_longword();
998 extend_size = get_extended_header(fp, hdr, extend_size);
999 if (extend_size == -1)
1002 padding = header_size - 32 - extend_size;
1003 while (padding--) /* padding should be 0 */
1006 /* FIXME: no collate the header CRC */
1016 char data[LZHEADER_STORAGE];
1018 int archive_kanji_code = CODE_SJIS;
1019 int system_kanji_code = default_system_kanji_code;
1020 char *archive_delim = "\377\\"; /* `\' is for level 0 header and
1022 char *system_delim = "//";
1023 int filename_case = NONE;
1026 memset(hdr, 0, sizeof(LzHeader));
1030 if ((end_mark = getc(fp)) == EOF || end_mark == 0) {
1031 return FALSE; /* finish */
1035 if (fread(data + 1, I_NAME_LENGTH - 1, 1, fp) == 0) {
1036 error("Invalid header (LHarc file ?)");
1037 return FALSE; /* finish */
1040 switch (data[I_HEADER_LEVEL]) {
1042 if (get_header_level0(fp, hdr, data) == FALSE)
1046 if (get_header_level1(fp, hdr, data) == FALSE)
1050 if (get_header_level2(fp, hdr, data) == FALSE)
1054 if (get_header_level3(fp, hdr, data) == FALSE)
1058 error("Unknown level header (level %d)", data[I_HEADER_LEVEL]);
1062 /* filename conversion */
1063 switch (hdr->extend_type) {
1065 filename_case = noconvertcase ? NONE : TO_LOWER;
1071 filename_case = NONE;
1075 archive_delim = "\377/:\\";
1076 /* `\' is for level 0 header and broken archive. */
1077 system_delim = "/://";
1078 filename_case = NONE;
1082 filename_case = noconvertcase ? NONE : TO_LOWER;
1083 /* FIXME: if small letter is included in filename,
1084 the generic_to_unix_filename() do not case conversion,
1085 but this code does not consider it. */
1089 if (optional_archive_kanji_code)
1090 archive_kanji_code = optional_archive_kanji_code;
1091 if (optional_system_kanji_code)
1092 system_kanji_code = optional_system_kanji_code;
1093 if (optional_archive_delim)
1094 archive_delim = optional_archive_delim;
1095 if (optional_system_delim)
1096 system_delim = optional_system_delim;
1097 if (optional_filename_case)
1098 filename_case = optional_filename_case;
1100 /* kanji code and delimiter conversion */
1101 convert_filename(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1104 archive_delim, system_delim, filename_case);
1109 /* ------------------------------------------------------------------------ */
1111 init_header(name, v_stat, hdr)
1113 struct stat *v_stat;
1118 memset(hdr, 0, sizeof(LzHeader));
1120 /* the `method' member is rewrote by the encoding function.
1121 but need set for empty files */
1122 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
1124 hdr->packed_size = 0;
1125 hdr->original_size = v_stat->st_size;
1126 hdr->attribute = GENERIC_ATTRIBUTE;
1127 hdr->header_level = header_level;
1128 strcpy(hdr->name, name);
1131 hdr->extend_type = EXTEND_UNIX;
1132 hdr->unix_last_modified_stamp = v_stat->st_mtime;
1133 /* since 00:00:00 JAN.1.1970 */
1134 #ifdef NOT_COMPATIBLE_MODE
1135 /* Please need your modification in this space. */
1137 hdr->unix_mode = v_stat->st_mode;
1140 hdr->unix_uid = v_stat->st_uid;
1141 hdr->unix_gid = v_stat->st_gid;
1143 #if INCLUDE_OWNER_NAME_IN_HEADER
1146 struct passwd *ent = getpwuid(hdr->unix_uid);
1149 strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
1150 if (hdr->user[sizeof(hdr->user)-1])
1151 hdr->user[sizeof(hdr->user)-1] = 0;
1157 struct group *ent = getgrgid(hdr->unix_gid);
1160 strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
1161 if (hdr->group[sizeof(hdr->group)-1])
1162 hdr->group[sizeof(hdr->group)-1] = 0;
1166 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
1167 if (is_directory(v_stat)) {
1168 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1169 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1170 hdr->original_size = 0;
1171 if (len > 0 && hdr->name[len - 1] != '/')
1172 strcpy(&hdr->name[len++], "/");
1176 if (is_symlink(v_stat)) {
1177 char lkname[FILENAME_LENGTH];
1179 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1180 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1181 hdr->original_size = 0;
1182 len = readlink(name, lkname, sizeof(lkname));
1183 if (xsnprintf(hdr->name, sizeof(hdr->name),
1184 "%s|%.*s", hdr->name, len, lkname) == -1)
1185 error("file name is too long (%s -> %.*s)", hdr->name, len, lkname);
1190 /* ------------------------------------------------------------------------ */
1191 /* Write unix extended header or generic header. */
1194 write_header_level0(data, hdr, pathname)
1196 char *data, *pathname;
1203 memset(data, 0, LZHEADER_STORAGE);
1205 put_byte(0x00); /* header size */
1206 put_byte(0x00); /* check sum */
1207 put_bytes(hdr->method, 5);
1208 put_longword(hdr->packed_size);
1209 put_longword(hdr->original_size);
1210 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1211 put_byte(hdr->attribute);
1212 put_byte(hdr->header_level); /* level 0 */
1214 /* write pathname (level 0 header contains the directory part) */
1215 name_length = strlen(pathname);
1217 limit = 255 - I_GENERIC_HEADER_BOTTOM + 2;
1219 limit = 255 - I_UNIX_EXTEND_BOTTOM + 2;
1221 if (name_length > limit) {
1222 warning("the length of pathname \"%s\" is too long.", pathname);
1223 name_length = limit;
1225 put_byte(name_length);
1226 put_bytes(pathname, name_length);
1229 if (generic_format) {
1230 header_size = I_GENERIC_HEADER_BOTTOM + name_length - 2;
1231 data[I_HEADER_SIZE] = header_size;
1232 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1234 /* write old-style extend header */
1235 put_byte(EXTEND_UNIX);
1236 put_byte(CURRENT_UNIX_MINOR_VERSION);
1237 put_longword(hdr->unix_last_modified_stamp);
1238 put_word(hdr->unix_mode);
1239 put_word(hdr->unix_uid);
1240 put_word(hdr->unix_gid);
1242 /* size of extended header is 12 */
1243 header_size = I_UNIX_EXTEND_BOTTOM + name_length - 2;
1244 data[I_HEADER_SIZE] = header_size;
1245 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1248 return header_size + 2;
1252 write_header_level1(data, hdr, pathname)
1254 char *data, *pathname;
1256 int name_length, dir_length, limit;
1257 char *basename, *dirname;
1259 char *extend_header_top;
1260 int extend_header_size;
1262 basename = strrchr(pathname, LHA_PATHSEP);
1265 name_length = strlen(basename);
1267 dir_length = basename - dirname;
1270 basename = pathname;
1271 name_length = strlen(basename);
1277 memset(data, 0, LZHEADER_STORAGE);
1279 put_byte(0x00); /* header size */
1280 put_byte(0x00); /* check sum */
1281 put_bytes(hdr->method, 5);
1282 put_longword(hdr->packed_size);
1283 put_longword(hdr->original_size);
1284 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1286 put_byte(hdr->header_level); /* level 1 */
1288 /* level 1 header: write filename (basename only) */
1289 limit = 255 - 27 + 2;
1290 if (name_length > limit) {
1291 put_byte(0); /* name length */
1294 put_byte(name_length);
1295 put_bytes(basename, name_length);
1303 put_byte(EXTEND_UNIX);
1305 /* write extend header from here. */
1307 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1308 header_size = extend_header_top - data - 2;
1310 /* write filename and dirname */
1312 if (name_length > limit) {
1313 put_word(name_length + 3); /* size */
1314 put_byte(0x01); /* filename */
1315 put_bytes(basename, name_length);
1318 if (dir_length > 0) {
1319 put_word(dir_length + 3); /* size */
1320 put_byte(0x02); /* dirname */
1321 put_bytes(dirname, dir_length);
1324 if (!generic_format) {
1325 /* UNIX specific informations */
1327 put_word(5); /* size */
1328 put_byte(0x50); /* permission */
1329 put_word(hdr->unix_mode);
1331 put_word(7); /* size */
1332 put_byte(0x51); /* gid and uid */
1333 put_word(hdr->unix_gid);
1334 put_word(hdr->unix_uid);
1336 if (hdr->group[0]) {
1337 int len = strlen(hdr->group);
1338 put_word(len + 3); /* size */
1339 put_byte(0x52); /* group name */
1340 put_bytes(hdr->group, len);
1344 int len = strlen(hdr->user);
1345 put_word(len + 3); /* size */
1346 put_byte(0x53); /* user name */
1347 put_bytes(hdr->user, len);
1350 if (hdr->header_level == 1) {
1351 put_word(7); /* size */
1352 put_byte(0x54); /* time stamp */
1353 put_longword(hdr->unix_last_modified_stamp);
1355 } /* if generic .. */
1357 put_word(0x0000); /* next header size */
1359 extend_header_size = put_ptr - extend_header_top;
1360 /* On level 1 header, the packed size field is contains the ext-header */
1361 hdr->packed_size += put_ptr - extend_header_top;
1363 /* put `skip size' */
1364 setup_put(data + I_PACKED_SIZE);
1365 put_longword(hdr->packed_size);
1367 data[I_HEADER_SIZE] = header_size;
1368 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1370 return header_size + extend_header_size + 2;
1374 write_header_level2(data, hdr, pathname)
1376 char *data, *pathname;
1378 int name_length, dir_length;
1379 char *basename, *dirname;
1381 char *extend_header_top;
1382 char *headercrc_ptr;
1383 unsigned short hcrc;
1385 basename = strrchr(pathname, LHA_PATHSEP);
1388 name_length = strlen(basename);
1390 dir_length = basename - dirname;
1393 basename = pathname;
1394 name_length = strlen(basename);
1400 memset(data, 0, LZHEADER_STORAGE);
1402 put_word(0x0000); /* header size */
1403 put_bytes(hdr->method, 5);
1404 put_longword(hdr->packed_size);
1405 put_longword(hdr->original_size);
1406 put_longword(hdr->unix_last_modified_stamp);
1408 put_byte(hdr->header_level); /* level 2 */
1415 put_byte(EXTEND_UNIX);
1417 /* write extend header from here. */
1419 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1421 /* write common header */
1424 headercrc_ptr = put_ptr;
1425 put_word(0x0000); /* header CRC */
1427 /* write filename and dirname */
1428 /* must have this header, even if the name_length is 0. */
1429 put_word(name_length + 3); /* size */
1430 put_byte(0x01); /* filename */
1431 put_bytes(basename, name_length);
1433 if (dir_length > 0) {
1434 put_word(dir_length + 3); /* size */
1435 put_byte(0x02); /* dirname */
1436 put_bytes(dirname, dir_length);
1439 if (!generic_format) {
1440 /* UNIX specific informations */
1442 put_word(5); /* size */
1443 put_byte(0x50); /* permission */
1444 put_word(hdr->unix_mode);
1446 put_word(7); /* size */
1447 put_byte(0x51); /* gid and uid */
1448 put_word(hdr->unix_gid);
1449 put_word(hdr->unix_uid);
1451 if (hdr->group[0]) {
1452 int len = strlen(hdr->group);
1453 put_word(len + 3); /* size */
1454 put_byte(0x52); /* group name */
1455 put_bytes(hdr->group, len);
1459 int len = strlen(hdr->user);
1460 put_word(len + 3); /* size */
1461 put_byte(0x53); /* user name */
1462 put_bytes(hdr->user, len);
1465 if (hdr->header_level == 1) {
1466 put_word(7); /* size */
1467 put_byte(0x54); /* time stamp */
1468 put_longword(hdr->unix_last_modified_stamp);
1470 } /* if generic .. */
1472 put_word(0x0000); /* next header size */
1474 header_size = put_ptr - data;
1475 if ((header_size & 0xff) == 0) {
1476 /* cannot put zero at the first byte on level 2 header. */
1477 /* adjust header size. */
1478 put_byte(0); /* padding */
1482 /* put hader size */
1483 setup_put(data + I_HEADER_SIZE);
1484 put_word(header_size);
1486 /* put hader CRC in extended header */
1487 hcrc = calc_header_crc(data, (unsigned int) header_size);
1488 setup_put(headercrc_ptr);
1495 write_header(fp, hdr)
1500 char data[LZHEADER_STORAGE];
1502 int archive_kanji_code = CODE_SJIS;
1503 int system_kanji_code = default_system_kanji_code;
1504 char *archive_delim = "\377";
1505 char *system_delim = "/";
1506 int filename_case = NONE;
1507 char pathname[FILENAME_LENGTH];
1509 if (optional_archive_kanji_code)
1510 archive_kanji_code = optional_archive_kanji_code;
1511 if (optional_system_kanji_code)
1512 system_kanji_code = optional_system_kanji_code;
1515 filename_case = TO_UPPER;
1517 if (hdr->header_level == HEADER_LEVEL0) {
1518 archive_delim = "\\";
1521 strncpy(pathname, hdr->name, sizeof(pathname));
1522 pathname[sizeof(pathname)-1] = 0;
1523 convert_filename(pathname, strlen(pathname), sizeof(pathname),
1526 system_delim, archive_delim, filename_case);
1528 switch (hdr->header_level) {
1530 header_size = write_header_level0(data, hdr, pathname);
1533 header_size = write_header_level1(data, hdr, pathname);
1536 header_size = write_header_level2(data, hdr, pathname);
1539 error("Unknown level header (level %d)", hdr->header_level);
1543 if (fwrite(data, header_size, 1, fp) == 0)
1544 fatal_error("Cannot write to temporary file");
1547 #if MULTIBYTE_FILENAME
1549 #if defined(__APPLE__)
1551 #include <CoreFoundation/CFString.h>
1552 #include <CoreFoundation/CFStringEncodingExt.h>
1554 /* this is not need for Mac OS X v 10.2 later */
1556 kCFStringEncodingAllowLossyConversion = 1,
1557 kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1558 kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1559 kCFStringEncodingSubstituteCombinings = (1 << 3),
1560 kCFStringEncodingComposeCombinings = (1 << 4),
1561 kCFStringEncodingIgnoreCombinings = (1 << 5),
1562 kCFStringEncodingUseCanonical = (1 << 6),
1563 kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1564 kCFStringEncodingPrependBOM = (1 << 8),
1565 kCFStringEncodingDisableCorporateArea = (1 << 9),
1566 kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1570 ConvertEncodingToUTF8(const char* inCStr,
1571 char* outUTF8Buffer,
1572 int outUTF8BufferLength,
1573 unsigned long scriptEncoding,
1574 unsigned long flags)
1576 unsigned long unicodeChars;
1577 unsigned long srcCharsUsed;
1578 unsigned long usedByteLen = 0;
1579 UniChar uniStr[512];
1580 unsigned long cfResult;
1582 cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1590 if (cfResult == 0) {
1591 cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1596 (char*)outUTF8Buffer,
1597 outUTF8BufferLength - 1,
1599 outUTF8Buffer[usedByteLen] = '\0';
1606 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1607 int inUTF8BufLength,
1608 char* outCStrBuffer,
1609 int outCStrBufferLength,
1610 unsigned long scriptEncoding,
1611 unsigned long flags)
1613 unsigned long unicodeChars;
1614 unsigned long srcCharsUsed;
1615 unsigned long usedByteLen = 0;
1616 UniChar uniStr[256];
1617 unsigned long cfResult;
1619 cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1627 if (cfResult == 0) {
1628 cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1633 (char*)outCStrBuffer,
1634 outCStrBufferLength - 1,
1636 outCStrBuffer[usedByteLen] = '\0';
1646 ConvertEncodingByIconv(const char *src, char *dst, int dstsize,
1647 const char *srcEnc, const char *dstEnc)
1650 static char szTmpBuf[2048];
1656 dst_p = &szTmpBuf[0];
1657 iLen = (size_t)sizeof(szTmpBuf)-1;
1658 src_p = (char *)src;
1659 sLen = (size_t)strlen(src);
1660 memset(szTmpBuf, 0, sizeof(szTmpBuf));
1661 memset(dst, 0, dstsize);
1663 ic = iconv_open(dstEnc, srcEnc);
1664 if (ic == (iconv_t)-1) {
1665 error("iconv_open() failure: %s", strerror(errno));
1669 if (iconv(ic, &src_p, &sLen, &dst_p, &iLen) == (size_t)-1) {
1670 error("iconv() failure: %s", strerror(errno));
1675 strncpy(dst, szTmpBuf, dstsize);
1681 #endif /* defined(__APPLE__) */
1684 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1686 #if defined(__APPLE__)
1688 if (ConvertEncodingToUTF8(src, dst, dstsize,
1689 kCFStringEncodingDOSJapanese,
1690 kCFStringEncodingUseHFSPlusCanonical) == 0)
1693 if (ConvertEncodingByIconv(src, dst, dstsize, "SJIS", "UTF-8") != -1)
1696 error("not support utf-8 conversion");
1699 if (dstsize < 1) return dst;
1701 return strncpy(dst, src, dstsize-1);
1705 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1707 #if defined(__APPLE__)
1711 srclen = strlen(src);
1712 if (ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1713 kCFStringEncodingDOSJapanese,
1714 kCFStringEncodingUseHFSPlusCanonical) == 0)
1717 if (ConvertEncodingByIconv(src, dst, dstsize, "UTF-8", "SJIS") != -1)
1720 error("not support utf-8 conversion");
1723 if (dstsize < 1) return dst;
1725 return strncpy(dst, src, dstsize-1);
1729 * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1730 * ¡ÖÆüËܸì¾ðÊó½èÍý¡× ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1731 * ¤è¤êÈ´¿è(by Koji Arai)
1734 euc2sjis(int *p1, int *p2)
1736 unsigned char c1 = *p1 & 0x7f;
1737 unsigned char c2 = *p2 & 0x7f;
1738 int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1739 int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1740 *p1 = ((c1 + 1) >> 1) + rowoff;
1741 *p2 += celoff - 0x80;
1745 sjis2euc(int *p1, int *p2)
1747 unsigned char c1 = *p1;
1748 unsigned char c2 = *p2;
1749 int adjust = c2 < 0x9f;
1750 int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1751 int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1752 *p1 = ((c1 - rowoff) << 1) - adjust;
1758 #endif /* MULTIBYTE_FILENAME */
1760 /* Local Variables: */
1763 /* compile-command:"gcc -c header.c" */
1765 /* vi: set tabstop=4: */