1 /* ------------------------------------------------------------------------ */
3 /* header.c -- header manipulate functions */
5 /* Modified Nobutaka Watazaki */
7 /* Original Y.Tagawa */
8 /* modified 1991.12.16 M.Oki */
9 /* Ver. 1.10 Symbolic Link added 1993.10.01 N.Watazaki */
10 /* Ver. 1.13b Symbolic Link Bug Fix 1994.08.22 N.Watazaki */
11 /* Ver. 1.14 Source All chagned 1995.01.14 N.Watazaki */
12 /* Ver. 1.14i bug fixed 2000.10.06 t.okamoto */
13 /* ------------------------------------------------------------------------ */
16 #define DUMP_HEADER 1 /* for debugging */
18 #if !STRCHR_8BIT_CLEAN
19 /* should use 8 bit clean version */
22 #define strchr xstrchr
23 #define strrchr xstrrchr
26 /* ------------------------------------------------------------------------ */
28 #define GET_BYTE() (*get_ptr++ & 0xff)
31 static char *start_ptr;
32 #define setup_get(PTR) (start_ptr = get_ptr = (PTR))
33 #define get_byte() dump_get_byte()
34 #define skip_bytes(len) dump_skip_bytes(len)
36 #define setup_get(PTR) (get_ptr = (PTR))
37 #define get_byte() GET_BYTE()
38 #define skip_bytes(len) (get_ptr += (len))
40 #define put_ptr get_ptr
41 #define setup_put(PTR) (put_ptr = (PTR))
42 #define put_byte(c) (*put_ptr++ = (char)(c))
44 int optional_archive_kanji_code = NONE;
45 int optional_system_kanji_code = NONE;
46 char *optional_archive_delim = NULL;
47 char *optional_system_delim = NULL;
48 int optional_filename_case = NONE;
50 #ifdef MULTIBYTE_FILENAME
51 int default_system_kanji_code = MULTIBYTE_FILENAME;
53 int default_system_kanji_code = NONE;
56 /* ------------------------------------------------------------------------ */
64 for (sum = 0; len; len--)
76 if (verbose_listing && verbose > 1)
77 printf("%02d %2d: ", get_ptr - start_ptr, 1);
79 if (verbose_listing && verbose > 1) {
81 printf("%d(0x%02x) '%c'\n", c, c, c);
83 printf("%d(0x%02x)\n", c, c);
92 if (verbose_listing && verbose > 1) {
93 printf("%02d %2d:", get_ptr - start_ptr, len);
95 printf(" 0x%02x", GET_BYTE());
103 /* ------------------------------------------------------------------------ */
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);
124 /* ------------------------------------------------------------------------ */
133 /* ------------------------------------------------------------------------ */
141 if (verbose_listing && verbose > 1)
142 printf("%02d %2d: ", get_ptr - start_ptr, 4);
148 l = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
150 if (verbose_listing && verbose > 1)
151 printf("%ld(0x%08lx)\n", l, l);
153 return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
156 /* ------------------------------------------------------------------------ */
168 get_bytes(buf, len, size)
175 if (verbose_listing && verbose > 1)
176 printf("%02d %2d: ", get_ptr - start_ptr, len);
178 for (i = 0; i < len && i < size; i++)
182 if (verbose_listing && verbose > 1)
183 printf("\"%*.*s\"\n", i, i, buf);
194 for (i = 0; i < len; i++)
198 /* added by Koji Arai */
200 convert_filename(name, len, size,
202 from_delim, to_delim,
207 int from_code, to_code, case_to;
208 char *from_delim, *to_delim;
212 #ifdef MULTIBYTE_FILENAME
213 char tmp[FILENAME_LENGTH];
215 if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
216 for (i = 0; i < len; i++)
217 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
218 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
219 sjis_to_utf8(tmp, name, sizeof(tmp));
220 strncpy(name, tmp, size);
223 for (i = 0; i < len; i++)
224 if (name[i] == '/') name[i] = LHA_PATHSEP;
225 from_code = CODE_UTF8;
227 else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
228 for (i = 0; i < len; i++)
229 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
230 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
231 utf8_to_sjis(tmp, name, sizeof(tmp));
232 strncpy(name, tmp, size);
235 for (i = 0; i < len; i++)
236 if (name[i] == '/') name[i] = LHA_PATHSEP;
237 from_code = CODE_SJIS;
241 for (i = 0; i < len; i ++) {
242 #ifdef MULTIBYTE_FILENAME
243 if (from_code == CODE_EUC &&
244 (unsigned char)name[i] == 0x8e) {
245 if (to_code != CODE_SJIS) {
251 memmove(name + i, name + i + 1, len - i);
255 if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
256 if (to_code != CODE_EUC) {
260 if (len == size - 1) /* check overflow */
262 memmove(name+i+1, name+i, len-i);
268 if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
270 if (to_code != CODE_SJIS) {
275 c1 = (unsigned char)name[i];
276 c2 = (unsigned char)name[i+1];
283 if (from_code == CODE_SJIS &&
284 SJC_FIRST_P(name[i]) &&
285 SJC_SECOND_P(name[i+1])) {
288 if (to_code != CODE_EUC) {
293 c1 = (unsigned char)name[i];
294 c2 = (unsigned char)name[i+1];
301 #endif /* MULTIBYTE_FILENAME */
305 /* transpose from_delim to to_delim */
307 if ((ptr = strchr(from_delim, name[i])) != NULL) {
308 name[i] = to_delim[ptr - from_delim];
313 if (case_to == TO_UPPER && islower(name[i])) {
314 name[i] = toupper(name[i]);
317 if (case_to == TO_LOWER && isupper(name[i])) {
318 name[i] = tolower(name[i]);
324 /* ------------------------------------------------------------------------ */
326 /* Generic stamp format: */
328 /* 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 */
329 /* |<-------- year ------->|<- month ->|<-- day -->| */
331 /* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 */
332 /* |<--- hour --->|<---- minute --->|<- second*2 ->| */
334 /* ------------------------------------------------------------------------ */
337 * NOTE : If you don't have `gettimeofday(2)', or your gettimeofday(2)
338 * returns bogus timezone information, try FTIME, MKTIME, TIMELOCAL or TZSET.
342 #if defined(HAVE_MKTIME)
343 #ifdef HAVE_TIMELOCAL
344 #undef HAVE_TIMELOCAL
346 #endif /* defined(HAVE_MKTIME) */
348 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
352 #endif /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
354 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) || defined(HAVE_TZSET)
360 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) || defined(HAVE_TZSET) || defined(HAVE_FTIME)
361 #ifdef HAVE_GETTIMEOFDAY
362 #undef HAVE_GETTIMEOFDAY
365 #ifndef HAVE_GETTIMEOFDAY
366 #define HAVE_GETTIMEOFDAY /* use gettimeofday() */
371 #include <sys/timeb.h>
375 * You may define as : #define TIMEZONE_HOOK \ extern long
376 * timezone ; \ extern void tzset();
380 /* Which do you like better, `TIMEZONE_HOOK' or `TIMEZONE_HOOK;' ? */
383 #if defined(HAVE_TZSET) && defined(_MINIX)
384 extern long timezone; /* not defined in time.h */
387 /* ------------------------------------------------------------------------ */
388 #if defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY) || defined(HAVE_TZSET)
398 /* ------------------------------------------------------------------------ */
399 #if !defined(HAVE_TZSET) && defined(HAVE_FTIME)
404 return buf.timezone * 60L;
408 /* ------------------------------------------------------------------------ */
409 #if !defined(HAVE_TZSET) && !defined(HAVE_FTIME) /* maybe defined(HAVE_GETTIMEOFDAY) */
411 #ifdef HAVE_STRUCT_TM_TM_GMTOFF
415 return -localtime(&tt)->tm_gmtoff;
416 #else /* HAVE_STRUCT_TM_TM_GMTOFF */
419 gettimeofday(&tp, &tzp);/* specific to 4.3BSD */
421 * return (tzp.tz_minuteswest * 60L + (tzp.tz_dsttime != 0 ? 60L *
424 return (tzp.tz_minuteswest * 60L);
425 #endif /* HAVE_STRUCT_TM_TM_GMTOFF */
428 #endif /* defined(HAVE_FTIME) || defined(HAVE_GETTIMEOFDAY) ||
429 * defined(HAVE_TZSET) */
431 /* ------------------------------------------------------------------------ */
433 generic_to_unix_stamp(t)
435 #if defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL)
440 * special case: if MSDOS format date and time were zero, then we
441 * set time to be zero here too.
446 dostm.tm_sec = (t & 0x1f) * 2;
447 dostm.tm_min = t >> 5 & 0x3f;
448 dostm.tm_hour = t >> 11 & 0x1f;
449 dostm.tm_mday = t >> 16 & 0x1f;
450 dostm.tm_mon = (t >> (16+5) & 0x0f) - 1; /* 0..11 */
451 dostm.tm_year = (t >> (16+9) & 0x7f) + 80;
453 dostm.tm_isdst = 0; /* correct? */
455 dostm.tm_isdst = -1; /* correct? */
457 return (time_t) mktime(&dostm);
458 #else /* maybe defined(HAVE_TIMELOCAL) */
459 return (time_t) timelocal(&dostm);
463 #else /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
465 int year, month, day, hour, min, sec;
467 static unsigned int dsboy[12] = {0, 31, 59, 90, 120, 151,
468 181, 212, 243, 273, 304, 334};
472 * special case: if MSDOS format date and time were zero, then we
473 * set time to be zero here too.
478 year = ((int) (t >> 16 + 9) & 0x7f) + 1980;
479 month = (int) (t >> 16 + 5) & 0x0f; /* 1..12 means Jan..Dec */
480 day = (int) (t >> 16) & 0x1f; /* 1..31 means 1st,...31st */
482 hour = ((int) t >> 11) & 0x1f;
483 min = ((int) t >> 5) & 0x3f;
484 sec = ((int) t & 0x1f) * 2;
486 /* Calculate days since 1970.01.01 */
487 days = (365 * (year - 1970) + /* days due to whole years */
488 (year - 1970 + 1) / 4 + /* days due to leap years */
489 dsboy[month - 1] + /* days since beginning of this year */
490 day - 1); /* days since beginning of month */
492 if ((year % 4 == 0) &&
493 (year % 100 != 0 || year % 400 == 0) && /* 1999.5.24 t.oka */
494 (month >= 3)) /* if this is a leap year and month */
495 days++; /* is March or later, add a day */
497 /* Knowing the days, we can find seconds */
498 longtime = (((days * 24) + hour) * 60 + min) * 60 + sec;
499 longtime += gettz(); /* adjust for timezone */
501 /* LONGTIME is now the time in seconds, since 1970/01/01 00:00:00. */
502 return (time_t) longtime;
504 #endif /* defined(HAVE_MKTIME) || defined(HAVE_TIMELOCAL) */
506 /* ------------------------------------------------------------------------ */
508 unix_to_generic_stamp(t)
511 struct tm *tm = localtime(&t);
513 return ((((long) (tm->tm_year - 80)) << 25) +
514 (((long) (tm->tm_mon + 1)) << 21) +
515 (((long) tm->tm_mday) << 16) +
516 (long) ((tm->tm_hour << 11) +
521 /* ------------------------------------------------------------------------ */
522 /* build header functions */
523 /* ------------------------------------------------------------------------ */
529 * --------------------------------
531 * 2 or 4 next-header size [*1]
532 * --------------------------------------
533 * ext header: 1 ext-type ^
534 * ? contents | [*1] next-header size
535 * 2 or 4 next-header size v
536 * --------------------------------------
538 * on level 0, 1, 2 header:
539 * size field is 2 bytes
541 * size field is 4 bytes
544 get_extended_header(fp, hdr, header_size, hcrc)
550 char data[LZHEADER_STORAGE];
552 char dirname[FILENAME_LENGTH];
555 long whole_size = header_size;
557 int n = 1 + hdr->size_field_length; /* `ext-type' + `next-header size' */
559 if (hdr->header_level == 0)
562 name_length = strlen(hdr->name);
564 while (header_size) {
566 if (sizeof(data) < header_size) {
567 error("header size (%ld) too large.", header_size);
571 if (fread(data, header_size, 1, fp) == 0) {
572 error("Invalid header (LHa file ?)");
576 ext_type = get_byte();
579 /* header crc (CRC-16) */
580 hdr->header_crc = get_word();
581 *--get_ptr = 0; /* clear buffer for CRC calculation. */
583 skip_bytes(header_size - n);
588 get_bytes(hdr->name, header_size-n, sizeof(hdr->name)-1);
589 hdr->name[name_length] = 0;
593 dir_length = get_bytes(dirname, header_size-n, sizeof(dirname)-1);
594 dirname[dir_length] = 0;
597 /* MS-DOS attribute */
598 if (hdr->extend_type == EXTEND_MSDOS ||
599 hdr->extend_type == EXTEND_HUMAN ||
600 hdr->extend_type == EXTEND_GENERIC)
601 hdr->attribute = get_word();
604 /* UNIX permission */
605 if (hdr->extend_type == EXTEND_UNIX)
606 hdr->unix_mode = get_word();
609 /* UNIX gid and uid */
610 if (hdr->extend_type == EXTEND_UNIX) {
611 hdr->unix_gid = get_word();
612 hdr->unix_uid = get_word();
616 /* UNIX group name */
617 if (hdr->extend_type == EXTEND_UNIX) {
618 i = get_bytes(hdr->group, header_size-n, sizeof(hdr->group)-1);
619 hdr->group[i] = '\0';
624 if (hdr->extend_type == EXTEND_UNIX) {
625 i = get_bytes(hdr->user, header_size-n, sizeof(hdr->user)-1);
630 /* UNIX last modified time */
631 if (hdr->extend_type == EXTEND_UNIX)
632 hdr->unix_last_modified_stamp = (time_t) get_longword();
637 warning("unknown extended header 0x%02x", ext_type);
638 skip_bytes(header_size - n);
644 *hcrc = calccrc(*hcrc, data, header_size);
646 if (hdr->size_field_length == 2)
647 whole_size += header_size = get_word();
649 whole_size += header_size = get_longword();
653 if (name_length + dir_length >= sizeof(hdr->name)) {
654 warning("the length of pathname \"%s%s\" is too long.",
656 name_length = sizeof(hdr->name) - dir_length - 1;
657 hdr->name[name_length] = 0;
659 strcat(dirname, hdr->name);
660 strcpy(hdr->name, dirname);
661 name_length += dir_length;
671 * offset size field name
672 * ----------------------------------
673 * 0 1 header size [*1]
675 * ---------------------------------------
677 * 7 4 packed size [*2] |
678 * 11 4 original size |
681 * 19 1 attribute | [*1] header size (X+Y+22)
682 * 20 1 level (0x00 fixed) |
685 * X +22 2 file crc (CRC-16) |
686 * X +24 Y ext-header(old style) v
687 * -------------------------------------------------
691 * ext-header(old style)
705 * bit6 archive bit (need to backup)
709 get_header_level0(fp, hdr, data)
720 hdr->size_field_length = 2; /* in bytes */
721 hdr->header_size = header_size = get_byte();
722 checksum = get_byte();
724 if (fread(data+I_NAME_LENGTH, header_size+2-I_NAME_LENGTH, 1, fp) == 0) {
725 error("Invalid header (LHarc file ?)");
726 return FALSE; /* finish */
729 if (calc_sum(data + I_METHOD, header_size) != checksum) {
730 error("Checksum error (LHarc file?)");
734 get_bytes(hdr->method, 5, sizeof(hdr->method));
735 hdr->packed_size = get_longword();
736 hdr->original_size = get_longword();
737 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
738 hdr->attribute = get_byte(); /* MS-DOS attribute */
739 hdr->header_level = get_byte();
740 name_length = get_byte();
741 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
744 /* defaults for other type */
745 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
749 extend_size = header_size+2 - name_length - 24;
751 if (extend_size < 0) {
752 if (extend_size == -2) {
753 /* CRC field is not given */
754 hdr->extend_type = EXTEND_GENERIC;
755 hdr->has_crc = FALSE;
760 error("Unkonwn header (lha file?)");
765 hdr->crc = get_word();
767 if (extend_size == 0)
770 hdr->extend_type = get_byte();
773 if (hdr->extend_type == EXTEND_UNIX) {
774 if (extend_size >= 11) {
775 hdr->minor_version = get_byte();
776 hdr->unix_last_modified_stamp = (time_t) get_longword();
777 hdr->unix_mode = get_word();
778 hdr->unix_uid = get_word();
779 hdr->unix_gid = get_word();
782 hdr->extend_type = EXTEND_GENERIC;
786 skip_bytes(extend_size);
788 hdr->header_size += 2;
796 * offset size field name
797 * -----------------------------------
798 * 0 1 header size [*1]
800 * -------------------------------------
802 * 7 4 skip size [*2] |
803 * 11 4 original size |
806 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
807 * 20 1 level (0x01 fixed) |
810 * X+ 22 2 file crc (CRC-16) |
813 * X+Y+25 2 next-header size v
814 * -------------------------------------------------
815 * X+Y+27 Z ext-header ^
817 * ----------------------------------- | [*2] skip size
820 * -------------------------------------------------
824 get_header_level1(fp, hdr, data)
829 int header_size, extend_size;
834 hdr->size_field_length = 2; /* in bytes */
835 hdr->header_size = header_size = get_byte();
836 checksum = get_byte();
838 if (fread(data+I_NAME_LENGTH, header_size+2-I_NAME_LENGTH, 1, fp) == 0) {
839 error("Invalid header (LHarc file ?)");
840 return FALSE; /* finish */
843 if (calc_sum(data + I_METHOD, header_size) != checksum) {
844 error("Checksum error (LHarc file?)");
848 get_bytes(hdr->method, 5, sizeof(hdr->method));
849 hdr->packed_size = get_longword(); /* skip size */
850 hdr->original_size = get_longword();
851 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
852 hdr->attribute = get_byte(); /* 0x20 fixed */
853 hdr->header_level = get_byte();
855 name_length = get_byte();
856 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
859 /* defaults for other type */
860 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
865 hdr->crc = get_word();
866 hdr->extend_type = get_byte();
868 dummy = header_size+2 - name_length - 27;
870 skip_bytes(dummy); /* skip old style extend header */
872 extend_size = get_word();
873 extend_size = get_extended_header(fp, hdr, extend_size, 0);
874 if (extend_size == -1)
877 /* On level 1 header, size fields should be adjusted. */
878 /* the `packed_size' field contains the extended header size. */
879 /* the `header_size' field does not. */
880 hdr->packed_size -= extend_size;
881 hdr->header_size += extend_size + 2;
890 * offset size field name
891 * --------------------------------------------------
892 * 0 2 total header size [*1] ^
893 * ----------------------- |
895 * 7 4 packed size [*2] |
896 * 11 4 original size |
898 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
899 * 20 1 level (0x02 fixed) | (X+26+(1))
900 * 21 2 file crc (CRC-16) |
902 * 24 2 next-header size |
903 * ----------------------------------- |
906 * ----------------------------------- |
907 * X +26 (1) padding v
908 * -------------------------------------------------
910 * : | [*2] packed size
912 * -------------------------------------------------
916 get_header_level2(fp, hdr, data)
921 int header_size, extend_size;
925 hdr->size_field_length = 2; /* in bytes */
926 hdr->header_size = header_size = get_word();
928 if (fread(data + I_NAME_LENGTH, 26 - I_NAME_LENGTH, 1, fp) == 0) {
929 error("Invalid header (LHarc file ?)");
930 return FALSE; /* finish */
933 get_bytes(hdr->method, 5, sizeof(hdr->method));
934 hdr->packed_size = get_longword();
935 hdr->original_size = get_longword();
936 hdr->unix_last_modified_stamp = get_longword();
937 hdr->attribute = get_byte(); /* reserved */
938 hdr->header_level = get_byte();
940 /* defaults for other type */
941 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
946 hdr->crc = get_word();
947 hdr->extend_type = get_byte();
948 extend_size = get_word();
950 INITIALIZE_CRC(hcrc);
951 hcrc = calccrc(hcrc, data, get_ptr - data);
953 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
954 if (extend_size == -1)
957 padding = header_size - 26 - extend_size;
958 while (padding--) /* padding should be 0 or 1 */
959 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
961 if (hdr->header_crc != hcrc)
962 error("header CRC error");
971 * offset size field name
972 * --------------------------------------------------
973 * 0 2 size field length (4 fixed) ^
975 * 7 4 packed size [*2] |
976 * 11 4 original size |
978 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
979 * 20 1 level (0x03 fixed) | (X+32)
980 * 21 2 file crc (CRC-16) |
982 * 24 4 total header size [*1] |
983 * 28 4 next-header size |
984 * ----------------------------------- |
987 * -------------------------------------------------
989 * : | [*2] packed size
991 * -------------------------------------------------
995 get_header_level3(fp, hdr, data)
1000 long header_size, extend_size;
1004 hdr->size_field_length = get_word();
1006 if (fread(data + I_NAME_LENGTH, 32 - I_NAME_LENGTH, 1, fp) == 0) {
1007 error("Invalid header (LHarc file ?)");
1008 return FALSE; /* finish */
1011 get_bytes(hdr->method, 5, sizeof(hdr->method));
1012 hdr->packed_size = get_longword();
1013 hdr->original_size = get_longword();
1014 hdr->unix_last_modified_stamp = get_longword();
1015 hdr->attribute = get_byte(); /* reserved */
1016 hdr->header_level = get_byte();
1018 /* defaults for other type */
1019 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
1023 hdr->has_crc = TRUE;
1024 hdr->crc = get_word();
1025 hdr->extend_type = get_byte();
1026 hdr->header_size = header_size = get_longword();
1027 extend_size = get_longword();
1029 INITIALIZE_CRC(hcrc);
1030 hcrc = calccrc(hcrc, data, get_ptr - data);
1032 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
1033 if (extend_size == -1)
1036 padding = header_size - 32 - extend_size;
1037 while (padding--) /* padding should be 0 */
1038 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
1040 if (hdr->header_crc != hcrc)
1041 error("header CRC error");
1051 char data[LZHEADER_STORAGE];
1053 int archive_kanji_code = CODE_SJIS;
1054 int system_kanji_code = default_system_kanji_code;
1055 char *archive_delim = "\377\\"; /* `\' is for level 0 header and
1057 char *system_delim = "//";
1058 int filename_case = NONE;
1061 memset(hdr, 0, sizeof(LzHeader));
1065 if ((end_mark = getc(fp)) == EOF || end_mark == 0) {
1066 return FALSE; /* finish */
1070 if (fread(data + 1, I_NAME_LENGTH - 1, 1, fp) == 0) {
1071 error("Invalid header (LHarc file ?)");
1072 return FALSE; /* finish */
1075 switch (data[I_HEADER_LEVEL]) {
1077 if (get_header_level0(fp, hdr, data) == FALSE)
1081 if (get_header_level1(fp, hdr, data) == FALSE)
1085 if (get_header_level2(fp, hdr, data) == FALSE)
1089 if (get_header_level3(fp, hdr, data) == FALSE)
1093 error("Unknown level header (level %d)", data[I_HEADER_LEVEL]);
1097 /* filename conversion */
1098 switch (hdr->extend_type) {
1100 filename_case = noconvertcase ? NONE : TO_LOWER;
1107 filename_case = NONE;
1111 archive_delim = "\377/:\\";
1112 /* `\' is for level 0 header and broken archive. */
1113 system_delim = "/://";
1114 filename_case = NONE;
1118 filename_case = noconvertcase ? NONE : TO_LOWER;
1119 /* FIXME: if small letter is included in filename,
1120 the generic_to_unix_filename() do not case conversion,
1121 but this code does not consider it. */
1125 if (optional_archive_kanji_code)
1126 archive_kanji_code = optional_archive_kanji_code;
1127 if (optional_system_kanji_code)
1128 system_kanji_code = optional_system_kanji_code;
1129 if (optional_archive_delim)
1130 archive_delim = optional_archive_delim;
1131 if (optional_system_delim)
1132 system_delim = optional_system_delim;
1133 if (optional_filename_case)
1134 filename_case = optional_filename_case;
1136 /* kanji code and delimiter conversion */
1137 convert_filename(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1140 archive_delim, system_delim, filename_case);
1145 /* ------------------------------------------------------------------------ */
1147 init_header(name, v_stat, hdr)
1149 struct stat *v_stat;
1154 memset(hdr, 0, sizeof(LzHeader));
1156 /* the `method' member is rewrote by the encoding function.
1157 but need set for empty files */
1158 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
1160 hdr->packed_size = 0;
1161 hdr->original_size = v_stat->st_size;
1162 hdr->attribute = GENERIC_ATTRIBUTE;
1163 hdr->header_level = header_level;
1164 strcpy(hdr->name, name);
1167 hdr->extend_type = EXTEND_UNIX;
1168 hdr->unix_last_modified_stamp = v_stat->st_mtime;
1169 /* since 00:00:00 JAN.1.1970 */
1170 #ifdef NOT_COMPATIBLE_MODE
1171 /* Please need your modification in this space. */
1173 hdr->unix_mode = v_stat->st_mode;
1176 hdr->unix_uid = v_stat->st_uid;
1177 hdr->unix_gid = v_stat->st_gid;
1179 #if INCLUDE_OWNER_NAME_IN_HEADER
1182 struct passwd *ent = getpwuid(hdr->unix_uid);
1185 strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
1186 if (hdr->user[sizeof(hdr->user)-1])
1187 hdr->user[sizeof(hdr->user)-1] = 0;
1193 struct group *ent = getgrgid(hdr->unix_gid);
1196 strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
1197 if (hdr->group[sizeof(hdr->group)-1])
1198 hdr->group[sizeof(hdr->group)-1] = 0;
1202 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
1203 if (is_directory(v_stat)) {
1204 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1205 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1206 hdr->original_size = 0;
1207 if (len > 0 && hdr->name[len - 1] != '/')
1208 strcpy(&hdr->name[len++], "/");
1212 if (is_symlink(v_stat)) {
1213 char lkname[FILENAME_LENGTH];
1215 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1216 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1217 hdr->original_size = 0;
1218 len = readlink(name, lkname, sizeof(lkname));
1219 if (xsnprintf(hdr->name, sizeof(hdr->name),
1220 "%s|%.*s", hdr->name, len, lkname) == -1)
1221 error("file name is too long (%s -> %.*s)", hdr->name, len, lkname);
1226 /* ------------------------------------------------------------------------ */
1227 /* Write unix extended header or generic header. */
1230 write_header_level0(data, hdr, pathname)
1232 char *data, *pathname;
1239 memset(data, 0, LZHEADER_STORAGE);
1241 put_byte(0x00); /* header size */
1242 put_byte(0x00); /* check sum */
1243 put_bytes(hdr->method, 5);
1244 put_longword(hdr->packed_size);
1245 put_longword(hdr->original_size);
1246 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1247 put_byte(hdr->attribute);
1248 put_byte(hdr->header_level); /* level 0 */
1250 /* write pathname (level 0 header contains the directory part) */
1251 name_length = strlen(pathname);
1253 limit = 255 - I_GENERIC_HEADER_BOTTOM + 2;
1255 limit = 255 - I_UNIX_EXTEND_BOTTOM + 2;
1257 if (name_length > limit) {
1258 warning("the length of pathname \"%s\" is too long.", pathname);
1259 name_length = limit;
1261 put_byte(name_length);
1262 put_bytes(pathname, name_length);
1265 if (generic_format) {
1266 header_size = I_GENERIC_HEADER_BOTTOM + name_length - 2;
1267 data[I_HEADER_SIZE] = header_size;
1268 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1270 /* write old-style extend header */
1271 put_byte(EXTEND_UNIX);
1272 put_byte(CURRENT_UNIX_MINOR_VERSION);
1273 put_longword(hdr->unix_last_modified_stamp);
1274 put_word(hdr->unix_mode);
1275 put_word(hdr->unix_uid);
1276 put_word(hdr->unix_gid);
1278 /* size of extended header is 12 */
1279 header_size = I_UNIX_EXTEND_BOTTOM + name_length - 2;
1280 data[I_HEADER_SIZE] = header_size;
1281 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1284 return header_size + 2;
1288 write_header_level1(data, hdr, pathname)
1290 char *data, *pathname;
1292 int name_length, dir_length, limit;
1293 char *basename, *dirname;
1295 char *extend_header_top;
1296 int extend_header_size;
1298 basename = strrchr(pathname, LHA_PATHSEP);
1301 name_length = strlen(basename);
1303 dir_length = basename - dirname;
1306 basename = pathname;
1307 name_length = strlen(basename);
1313 memset(data, 0, LZHEADER_STORAGE);
1315 put_byte(0x00); /* header size */
1316 put_byte(0x00); /* check sum */
1317 put_bytes(hdr->method, 5);
1318 put_longword(hdr->packed_size);
1319 put_longword(hdr->original_size);
1320 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1322 put_byte(hdr->header_level); /* level 1 */
1324 /* level 1 header: write filename (basename only) */
1325 limit = 255 - 27 + 2;
1326 if (name_length > limit) {
1327 put_byte(0); /* name length */
1330 put_byte(name_length);
1331 put_bytes(basename, name_length);
1339 put_byte(EXTEND_UNIX);
1341 /* write extend header from here. */
1343 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1344 header_size = extend_header_top - data - 2;
1346 /* write filename and dirname */
1348 if (name_length > limit) {
1349 put_word(name_length + 3); /* size */
1350 put_byte(0x01); /* filename */
1351 put_bytes(basename, name_length);
1354 if (dir_length > 0) {
1355 put_word(dir_length + 3); /* size */
1356 put_byte(0x02); /* dirname */
1357 put_bytes(dirname, dir_length);
1360 if (!generic_format) {
1361 /* UNIX specific informations */
1363 put_word(5); /* size */
1364 put_byte(0x50); /* permission */
1365 put_word(hdr->unix_mode);
1367 put_word(7); /* size */
1368 put_byte(0x51); /* gid and uid */
1369 put_word(hdr->unix_gid);
1370 put_word(hdr->unix_uid);
1372 if (hdr->group[0]) {
1373 int len = strlen(hdr->group);
1374 put_word(len + 3); /* size */
1375 put_byte(0x52); /* group name */
1376 put_bytes(hdr->group, len);
1380 int len = strlen(hdr->user);
1381 put_word(len + 3); /* size */
1382 put_byte(0x53); /* user name */
1383 put_bytes(hdr->user, len);
1386 if (hdr->header_level == 1) {
1387 put_word(7); /* size */
1388 put_byte(0x54); /* time stamp */
1389 put_longword(hdr->unix_last_modified_stamp);
1391 } /* if generic .. */
1393 put_word(0x0000); /* next header size */
1395 extend_header_size = put_ptr - extend_header_top;
1396 /* On level 1 header, the packed size field is contains the ext-header */
1397 hdr->packed_size += put_ptr - extend_header_top;
1399 /* put `skip size' */
1400 setup_put(data + I_PACKED_SIZE);
1401 put_longword(hdr->packed_size);
1403 data[I_HEADER_SIZE] = header_size;
1404 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1406 return header_size + extend_header_size + 2;
1410 write_header_level2(data, hdr, pathname)
1412 char *data, *pathname;
1414 int name_length, dir_length;
1415 char *basename, *dirname;
1417 char *extend_header_top;
1418 char *headercrc_ptr;
1421 basename = strrchr(pathname, LHA_PATHSEP);
1424 name_length = strlen(basename);
1426 dir_length = basename - dirname;
1429 basename = pathname;
1430 name_length = strlen(basename);
1436 memset(data, 0, LZHEADER_STORAGE);
1438 put_word(0x0000); /* header size */
1439 put_bytes(hdr->method, 5);
1440 put_longword(hdr->packed_size);
1441 put_longword(hdr->original_size);
1442 put_longword(hdr->unix_last_modified_stamp);
1444 put_byte(hdr->header_level); /* level 2 */
1451 put_byte(EXTEND_UNIX);
1453 /* write extend header from here. */
1455 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1457 /* write common header */
1460 headercrc_ptr = put_ptr;
1461 put_word(0x0000); /* header CRC */
1463 /* write filename and dirname */
1464 /* must have this header, even if the name_length is 0. */
1465 put_word(name_length + 3); /* size */
1466 put_byte(0x01); /* filename */
1467 put_bytes(basename, name_length);
1469 if (dir_length > 0) {
1470 put_word(dir_length + 3); /* size */
1471 put_byte(0x02); /* dirname */
1472 put_bytes(dirname, dir_length);
1475 if (!generic_format) {
1476 /* UNIX specific informations */
1478 put_word(5); /* size */
1479 put_byte(0x50); /* permission */
1480 put_word(hdr->unix_mode);
1482 put_word(7); /* size */
1483 put_byte(0x51); /* gid and uid */
1484 put_word(hdr->unix_gid);
1485 put_word(hdr->unix_uid);
1487 if (hdr->group[0]) {
1488 int len = strlen(hdr->group);
1489 put_word(len + 3); /* size */
1490 put_byte(0x52); /* group name */
1491 put_bytes(hdr->group, len);
1495 int len = strlen(hdr->user);
1496 put_word(len + 3); /* size */
1497 put_byte(0x53); /* user name */
1498 put_bytes(hdr->user, len);
1501 if (hdr->header_level == 1) {
1502 put_word(7); /* size */
1503 put_byte(0x54); /* time stamp */
1504 put_longword(hdr->unix_last_modified_stamp);
1506 } /* if generic .. */
1508 put_word(0x0000); /* next header size */
1510 header_size = put_ptr - data;
1511 if ((header_size & 0xff) == 0) {
1512 /* cannot put zero at the first byte on level 2 header. */
1513 /* adjust header size. */
1514 put_byte(0); /* padding */
1518 /* put hader size */
1519 setup_put(data + I_HEADER_SIZE);
1520 put_word(header_size);
1522 /* put hader CRC in extended header */
1523 INITIALIZE_CRC(hcrc);
1524 hcrc = calccrc(hcrc, data, (unsigned int) header_size);
1525 setup_put(headercrc_ptr);
1532 write_header(fp, hdr)
1537 char data[LZHEADER_STORAGE];
1539 int archive_kanji_code = CODE_SJIS;
1540 int system_kanji_code = default_system_kanji_code;
1541 char *archive_delim = "\377";
1542 char *system_delim = "/";
1543 int filename_case = NONE;
1544 char pathname[FILENAME_LENGTH];
1546 if (optional_archive_kanji_code)
1547 archive_kanji_code = optional_archive_kanji_code;
1548 if (optional_system_kanji_code)
1549 system_kanji_code = optional_system_kanji_code;
1552 filename_case = TO_UPPER;
1554 if (hdr->header_level == HEADER_LEVEL0) {
1555 archive_delim = "\\";
1558 strncpy(pathname, hdr->name, sizeof(pathname));
1559 pathname[sizeof(pathname)-1] = 0;
1560 convert_filename(pathname, strlen(pathname), sizeof(pathname),
1563 system_delim, archive_delim, filename_case);
1565 switch (hdr->header_level) {
1567 header_size = write_header_level0(data, hdr, pathname);
1570 header_size = write_header_level1(data, hdr, pathname);
1573 header_size = write_header_level2(data, hdr, pathname);
1576 error("Unknown level header (level %d)", hdr->header_level);
1580 if (fwrite(data, header_size, 1, fp) == 0)
1581 fatal_error("Cannot write to temporary file");
1584 #if MULTIBYTE_FILENAME
1586 #if defined(__APPLE__)
1588 #include <CoreFoundation/CFString.h>
1589 #include <CoreFoundation/CFStringEncodingExt.h>
1591 /* this is not need for Mac OS X v 10.2 later */
1593 kCFStringEncodingAllowLossyConversion = 1,
1594 kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1595 kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1596 kCFStringEncodingSubstituteCombinings = (1 << 3),
1597 kCFStringEncodingComposeCombinings = (1 << 4),
1598 kCFStringEncodingIgnoreCombinings = (1 << 5),
1599 kCFStringEncodingUseCanonical = (1 << 6),
1600 kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1601 kCFStringEncodingPrependBOM = (1 << 8),
1602 kCFStringEncodingDisableCorporateArea = (1 << 9),
1603 kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1607 ConvertEncodingToUTF8(const char* inCStr,
1608 char* outUTF8Buffer,
1609 int outUTF8BufferLength,
1610 unsigned long scriptEncoding,
1611 unsigned long flags)
1613 unsigned long unicodeChars;
1614 unsigned long srcCharsUsed;
1615 unsigned long usedByteLen = 0;
1616 UniChar uniStr[512];
1617 unsigned long cfResult;
1619 cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1627 if (cfResult == 0) {
1628 cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1633 (char*)outUTF8Buffer,
1634 outUTF8BufferLength - 1,
1636 outUTF8Buffer[usedByteLen] = '\0';
1643 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1644 int inUTF8BufLength,
1645 char* outCStrBuffer,
1646 int outCStrBufferLength,
1647 unsigned long scriptEncoding,
1648 unsigned long flags)
1650 unsigned long unicodeChars;
1651 unsigned long srcCharsUsed;
1652 unsigned long usedByteLen = 0;
1653 UniChar uniStr[256];
1654 unsigned long cfResult;
1656 cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1664 if (cfResult == 0) {
1665 cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1670 (char*)outCStrBuffer,
1671 outCStrBufferLength - 1,
1673 outCStrBuffer[usedByteLen] = '\0';
1683 ConvertEncodingByIconv(const char *src, char *dst, int dstsize,
1684 const char *srcEnc, const char *dstEnc)
1687 static char szTmpBuf[2048];
1693 dst_p = &szTmpBuf[0];
1694 iLen = (size_t)sizeof(szTmpBuf)-1;
1695 src_p = (char *)src;
1696 sLen = (size_t)strlen(src);
1697 memset(szTmpBuf, 0, sizeof(szTmpBuf));
1698 memset(dst, 0, dstsize);
1700 ic = iconv_open(dstEnc, srcEnc);
1701 if (ic == (iconv_t)-1) {
1702 error("iconv_open() failure: %s", strerror(errno));
1706 if (iconv(ic, &src_p, &sLen, &dst_p, &iLen) == (size_t)-1) {
1707 error("iconv() failure: %s", strerror(errno));
1712 strncpy(dst, szTmpBuf, dstsize);
1718 #endif /* defined(__APPLE__) */
1721 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
1723 #if defined(__APPLE__)
1725 if (ConvertEncodingToUTF8(src, dst, dstsize,
1726 kCFStringEncodingDOSJapanese,
1727 kCFStringEncodingUseHFSPlusCanonical) == 0)
1730 if (ConvertEncodingByIconv(src, dst, dstsize, "SJIS", "UTF-8") != -1)
1733 error("not support utf-8 conversion");
1736 if (dstsize < 1) return dst;
1738 return strncpy(dst, src, dstsize-1);
1742 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
1744 #if defined(__APPLE__)
1748 srclen = strlen(src);
1749 if (ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
1750 kCFStringEncodingDOSJapanese,
1751 kCFStringEncodingUseHFSPlusCanonical) == 0)
1754 if (ConvertEncodingByIconv(src, dst, dstsize, "UTF-8", "SJIS") != -1)
1757 error("not support utf-8 conversion");
1760 if (dstsize < 1) return dst;
1762 return strncpy(dst, src, dstsize-1);
1766 * SJIS <-> EUC ÊÑ´¹´Ø¿ô
1767 * ¡ÖÆüËܸì¾ðÊó½èÍý¡× ¥½¥Õ¥È¥Ð¥ó¥¯(³ô)
1768 * ¤è¤êÈ´¿è(by Koji Arai)
1771 euc2sjis(int *p1, int *p2)
1773 unsigned char c1 = *p1 & 0x7f;
1774 unsigned char c2 = *p2 & 0x7f;
1775 int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
1776 int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
1777 *p1 = ((c1 + 1) >> 1) + rowoff;
1778 *p2 += celoff - 0x80;
1782 sjis2euc(int *p1, int *p2)
1784 unsigned char c1 = *p1;
1785 unsigned char c2 = *p2;
1786 int adjust = c2 < 0x9f;
1787 int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
1788 int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
1789 *p1 = ((c1 - rowoff) << 1) - adjust;
1795 #endif /* MULTIBYTE_FILENAME */
1797 /* Local Variables: */
1800 /* compile-command:"gcc -c header.c" */
1802 /* vi: set tabstop=4: */