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 static char *start_ptr;
31 static off_t storage_size;
32 #define setup_get(PTR, SIZE) (start_ptr = get_ptr = (PTR), storage_size = (SIZE))
35 #define get_byte() dump_get_byte()
36 #define skip_bytes(len) dump_skip_bytes(len)
38 #define get_byte() _get_byte()
39 #define skip_bytes(len) _skip_bytes(len)
41 #define put_ptr get_ptr
42 #define setup_put(PTR) (put_ptr = (PTR))
43 #define put_byte(c) (*put_ptr++ = (char)(c))
45 int optional_archive_kanji_code = NONE;
46 int optional_system_kanji_code = NONE;
47 char *optional_archive_delim = NULL;
48 char *optional_system_delim = NULL;
49 int optional_filename_case = NONE;
51 #ifdef MULTIBYTE_FILENAME
52 int default_system_kanji_code = MULTIBYTE_FILENAME;
54 int default_system_kanji_code = NONE;
63 unsigned char *pc = (unsigned char*)p;
65 while (len--) sum += *pc++;
74 error("Invalid header: %d", len);
83 if (get_ptr < start_ptr || get_ptr - start_ptr >= storage_size) {
84 error("Invalid header");
88 return (*get_ptr++ & 0xff);
97 if (verbose_listing && verbose > 1)
98 printf("%02d %2d: ", get_ptr - start_ptr, 1);
100 if (verbose_listing && verbose > 1) {
102 printf("%d(0x%02x) '%c'\n", c, c, c);
104 printf("%d(0x%02x)\n", c, c);
113 if (len == 0) return;
114 if (verbose_listing && verbose > 1) {
115 printf("%02d %2d: ", get_ptr - start_ptr, len);
117 error("Invalid header: %d", len);
121 printf("0x%02x ", _get_byte());
122 printf("... ignored\n");
136 if (verbose_listing && verbose > 1)
137 printf("%02d %2d: ", get_ptr - start_ptr, 2);
143 if (verbose_listing && verbose > 1)
144 printf("%d(0x%04x)\n", w, w);
164 if (verbose_listing && verbose > 1)
165 printf("%02d %2d: ", get_ptr - start_ptr, 4);
171 l = (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
173 if (verbose_listing && verbose > 1)
174 printf("%ld(0x%08lx)\n", l, l);
192 uint64_t b0, b1, b2, b3, b4, b5, b6, b7;
196 if (verbose_listing && verbose > 1)
197 printf("%02d %2d: ", get_ptr - start_ptr, 4);
208 l = (b7 << 24) + (b6 << 16) + (b5 << 8) + b4;
210 l |= (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
212 if (verbose_listing && verbose > 1)
213 printf("%lld(%#016llx)\n", l, l);
219 put_longlongword(uint64_t v)
233 get_bytes(buf, len, size)
240 if (verbose_listing && verbose > 1)
241 printf("%02d %2d: \"", get_ptr - start_ptr, len);
243 error("Invalid header: %d", len);
247 for (i = 0; i < len; i++) {
248 if (i < size) buf[i] = get_ptr[i];
250 if (verbose_listing && verbose > 1) {
252 printf("%c", buf[i]);
254 printf("\\x%02x", (unsigned char)buf[i]);
258 if (verbose_listing && verbose > 1)
262 error("Invalid header: %d", len);
265 for (i = 0; i < len && i < size; i++)
279 for (i = 0; i < len; i++)
283 /* added by Koji Arai */
285 convert_filename(name, len, size,
287 from_delim, to_delim,
290 int len; /* length of name */
291 int size; /* size of name buffer */
292 int from_code, to_code, case_to;
293 char *from_delim, *to_delim;
297 #ifdef MULTIBYTE_FILENAME
298 char tmp[FILENAME_LENGTH];
299 int to_code_save = NONE;
301 if (from_code == CODE_CAP) {
302 len = cap_to_sjis(tmp, name, sizeof(tmp));
303 strncpy(name, tmp, size);
306 from_code = CODE_SJIS;
309 if (to_code == CODE_CAP) {
310 to_code_save = CODE_CAP;
315 /* special case: if `name' has small lettter, not convert case. */
316 if (from_code == CODE_SJIS && case_to == TO_LOWER) {
317 for (i = 0; i < len; i++) {
318 #ifdef MULTIBYTE_FILENAME
319 if (SJIS_FIRST_P(name[i]) && SJIS_SECOND_P(name[i+1]))
323 if (islower(name[i])) {
330 #ifdef MULTIBYTE_FILENAME
331 if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
332 for (i = 0; i < len; i++) {
333 if (SJIS_FIRST_P(name[i]) && SJIS_SECOND_P(name[i+1]))
336 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
337 if (strchr(from_delim, name[i]))
341 sjis_to_utf8(tmp, name, sizeof(tmp));
342 strncpy(name, tmp, size);
345 for (i = 0; i < len; i++)
346 if (name[i] == '/') name[i] = LHA_PATHSEP;
347 from_code = CODE_UTF8;
349 else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
350 for (i = 0; i < len; i++)
351 /* FIXME: provisionally fix for the Mac OS CoreFoundation */
352 if ((unsigned char)name[i] == LHA_PATHSEP) name[i] = '/';
353 utf8_to_sjis(tmp, name, sizeof(tmp));
354 strncpy(name, tmp, size);
357 for (i = 0; i < len; i++)
358 if (name[i] == '/') name[i] = LHA_PATHSEP;
359 from_code = CODE_SJIS;
363 for (i = 0; i < len; i ++) {
364 #ifdef MULTIBYTE_FILENAME
365 if (from_code == CODE_EUC &&
366 (unsigned char)name[i] == 0x8e) {
367 if (to_code != CODE_SJIS) {
373 memmove(name + i, name + i + 1, len - i);
377 if (from_code == CODE_SJIS && X0201_KANA_P(name[i])) {
378 if (to_code != CODE_EUC) {
382 if (len == size - 1) /* check overflow */
384 memmove(name+i+1, name+i, len-i);
390 if (from_code == CODE_EUC && (name[i] & 0x80) && (name[i+1] & 0x80)) {
392 if (to_code != CODE_SJIS) {
397 c1 = (unsigned char)name[i];
398 c2 = (unsigned char)name[i+1];
405 if (from_code == CODE_SJIS &&
406 SJIS_FIRST_P(name[i]) &&
407 SJIS_SECOND_P(name[i+1])) {
410 if (to_code != CODE_EUC) {
415 c1 = (unsigned char)name[i];
416 c2 = (unsigned char)name[i+1];
423 #endif /* MULTIBYTE_FILENAME */
427 /* transpose from_delim to to_delim */
429 if ((ptr = strchr(from_delim, name[i])) != NULL) {
430 name[i] = to_delim[ptr - from_delim];
435 if (case_to == TO_UPPER && islower(name[i])) {
436 name[i] = toupper(name[i]);
439 if (case_to == TO_LOWER && isupper(name[i])) {
440 name[i] = tolower(name[i]);
445 #ifdef MULTIBYTE_FILENAME
446 if (to_code_save == CODE_CAP) {
447 len = sjis_to_cap(tmp, name, sizeof(tmp));
448 strncpy(name, tmp, size);
452 #endif /* MULTIBYTE_FILENAME */
456 * Generic (MS-DOS style) time stamp format (localtime):
458 * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
459 * |<---- year-1980 --->|<- month ->|<--- day ---->|
461 * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
462 * |<--- hour --->|<---- minute --->|<- second/2 ->|
467 generic_to_unix_stamp(t)
472 #define subbits(n, off, len) (((n) >> (off)) & ((1 << (len))-1))
474 tm.tm_sec = subbits(t, 0, 5) * 2;
475 tm.tm_min = subbits(t, 5, 6);
476 tm.tm_hour = subbits(t, 11, 5);
477 tm.tm_mday = subbits(t, 16, 5);
478 tm.tm_mon = subbits(t, 21, 4) - 1;
479 tm.tm_year = subbits(t, 25, 7) + 80;
485 return timelocal(&tm);
490 unix_to_generic_stamp(t)
493 struct tm *tm = localtime(&t);
498 return ((long)(tm->tm_year << 25) +
500 (tm->tm_mday << 16) +
501 (tm->tm_hour << 11) +
507 wintime_to_unix_stamp()
511 uint64_t epoch = ((uint64_t)0x019db1de << 32) + 0xd53e8000;
512 /* 0x019db1ded53e8000ULL: 1970-01-01 00:00:00 (UTC) */
514 t = (unsigned long)get_longword();
515 t |= (uint64_t)(unsigned long)get_longword() << 32;
516 t = (t - epoch) / 10000000;
520 unsigned long t, q, x;
521 unsigned long wintime[8];
522 unsigned long epoch[8] = {0x01,0x9d,0xb1,0xde, 0xd5,0x3e,0x80,0x00};
523 /* 1970-01-01 00:00:00 (UTC) */
524 /* wintime -= epoch */
526 for (i = 7; i >= 0; i--) {
527 wintime[i] = (unsigned)get_byte() - epoch[i] - borrow;
528 borrow = (wintime[i] > 0xff) ? 1 : 0;
532 /* q = wintime / 10000000 */
534 x = 10000000; /* x: 24bit */
535 for (i = 0; i < 8; i++) {
536 t = (t << 8) + wintime[i]; /* 24bit + 8bit. t must be 32bit variable */
537 q <<= 8; /* q must be 32bit (time_t) */
549 * --------------------------------
551 * 2 or 4 next-header size [*1]
552 * --------------------------------------
553 * ext header: 1 ext-type ^
554 * ? contents | [*1] next-header size
555 * 2 or 4 next-header size v
556 * --------------------------------------
558 * on level 1, 2 header:
559 * size field is 2 bytes
561 * size field is 4 bytes
565 get_extended_header(fp, hdr, header_size, hcrc)
571 char data[LZHEADER_STORAGE];
573 char dirname[FILENAME_LENGTH];
576 ssize_t whole_size = header_size;
578 int n = 1 + hdr->size_field_length; /* `ext-type' + `next-header size' */
580 if (hdr->header_level == 0)
583 name_length = strlen(hdr->name);
585 while (header_size) {
587 if (verbose_listing && verbose > 1)
590 setup_get(data, sizeof(data));
591 if (sizeof(data) < header_size) {
592 error("header size (%ld) too large.", header_size);
596 if (fread(data, header_size, 1, fp) == 0) {
597 error("Invalid header (LHa file ?)");
601 ext_type = get_byte();
605 if (verbose_listing && verbose > 1) printf(" < header crc >\n");
607 /* header crc (CRC-16) */
608 hdr->header_crc = get_word();
609 /* clear buffer for CRC calculation. */
610 data[1] = data[2] = 0;
611 skip_bytes(header_size - n - 2);
615 if (verbose_listing && verbose > 1) printf(" < filename >\n");
619 get_bytes(hdr->name, header_size-n, sizeof(hdr->name)-1);
620 hdr->name[name_length] = 0;
624 if (verbose_listing && verbose > 1) printf(" < directory >\n");
627 dir_length = get_bytes(dirname, header_size-n, sizeof(dirname)-1);
628 dirname[dir_length] = 0;
632 if (verbose_listing && verbose > 1) printf(" < MS-DOS attribute >\n");
634 /* MS-DOS attribute */
635 hdr->attribute = get_word();
639 if (verbose_listing && verbose > 1) printf(" < Windows time stamp (FILETIME) >\n");
641 /* Windows time stamp (FILETIME structure) */
642 /* it is time in 100 nano seconds since 1601-01-01 00:00:00 */
644 skip_bytes(8); /* create time is ignored */
646 /* set last modified time */
647 if (hdr->header_level >= 2)
648 skip_bytes(8); /* time_t has been already set */
650 hdr->unix_last_modified_stamp = wintime_to_unix_stamp();
652 skip_bytes(8); /* last access time is ignored */
657 if (verbose_listing && verbose > 1) printf(" < 64bits file size header >\n");
660 /* 64bits file size header (UNLHA32 extension) */
661 hdr->packed_size = get_longlongword();
662 hdr->original_size = get_longlongword();
671 if (verbose_listing && verbose > 1) printf(" < UNIX permission >\n");
673 /* UNIX permission */
674 hdr->unix_mode = get_word();
678 if (verbose_listing && verbose > 1) printf(" < UNIX gid and uid >\n");
680 /* UNIX gid and uid */
681 hdr->unix_gid = get_word();
682 hdr->unix_uid = get_word();
686 if (verbose_listing && verbose > 1) printf(" < UNIX group name >\n");
688 /* UNIX group name */
689 i = get_bytes(hdr->group, header_size-n, sizeof(hdr->group)-1);
690 hdr->group[i] = '\0';
694 if (verbose_listing && verbose > 1) printf(" < UNIX user name >\n");
697 i = get_bytes(hdr->user, header_size-n, sizeof(hdr->user)-1);
702 if (verbose_listing && verbose > 1) printf(" < UNIX last modifed time (time_t) >\n");
704 /* UNIX last modified time */
705 hdr->unix_last_modified_stamp = (time_t) get_longword();
709 /* 0x39: multi-disk header
710 0x3f: uncompressed comment
711 0x42: 64bit large file size
712 0x48-0x4f(?): reserved for authenticity verification
714 0x7e: extended attribute - platform information
715 0x7f: extended attribute - permission, owner-id and timestamp
717 0xc4: compressed comment (dict size: 4096)
718 0xc5: compressed comment (dict size: 8192)
719 0xc6: compressed comment (dict size: 16384)
720 0xc7: compressed comment (dict size: 32768)
721 0xc8: compressed comment (dict size: 65536)
722 0xd0-0xdf(?): operating systemm specific information
723 0xfc: encapsulation (another opinion)
724 0xfe: extended attribute - platform information(another opinion)
725 0xff: extended attribute - permission, owner-id and timestamp
726 (level 3 on UNLHA32) */
728 warning("unknown extended header 0x%02x", ext_type);
729 skip_bytes(header_size - n);
734 *hcrc = calccrc(*hcrc, data, header_size);
736 if (hdr->size_field_length == 2)
737 whole_size += header_size = get_word();
739 whole_size += header_size = get_longword();
742 /* concatenate dirname and filename */
744 if (name_length + dir_length >= sizeof(hdr->name)) {
745 warning("the length of pathname \"%s%s\" is too long.",
747 name_length = sizeof(hdr->name) - dir_length - 1;
748 hdr->name[name_length] = 0;
750 strcat(dirname, hdr->name); /* ok */
751 strcpy(hdr->name, dirname); /* ok */
752 name_length += dir_length;
758 #define I_HEADER_SIZE 0 /* level 0,1,2 */
759 #define I_HEADER_CHECKSUM 1 /* level 0,1 */
760 #define I_METHOD 2 /* level 0,1,2,3 */
761 #define I_PACKED_SIZE 7 /* level 0,1,2,3 */
762 #define I_ATTRIBUTE 19 /* level 0,1,2,3 */
763 #define I_HEADER_LEVEL 20 /* level 0,1,2,3 */
765 #define COMMON_HEADER_SIZE 21 /* size of common part */
767 #define I_GENERIC_HEADER_SIZE 24 /* + name_length */
768 #define I_LEVEL0_HEADER_SIZE 36 /* + name_length (unix extended) */
769 #define I_LEVEL1_HEADER_SIZE 27 /* + name_length */
770 #define I_LEVEL2_HEADER_SIZE 26 /* + padding */
771 #define I_LEVEL3_HEADER_SIZE 32
777 * offset size field name
778 * ----------------------------------
779 * 0 1 header size [*1]
781 * ---------------------------------------
783 * 7 4 packed size [*2] |
784 * 11 4 original size |
787 * 19 1 attribute | [*1] header size (X+Y+22)
788 * 20 1 level (0x00 fixed) |
791 * X +22 2 file crc (CRC-16) |
792 * X +24 Y ext-header(old style) v
793 * -------------------------------------------------
795 * : | [*2] packed size
797 * -------------------------------------------------
799 * ext-header(old style)
813 * bit6 archive bit (need to backup)
817 get_header_level0(fp, hdr, data)
829 hdr->size_field_length = 2; /* in bytes */
830 hdr->header_size = header_size = get_byte();
831 checksum = get_byte();
833 /* The data variable has been already read as COMMON_HEADER_SIZE bytes.
834 So we must read the remaining header size by the header_size. */
835 remain_size = header_size + 2 - COMMON_HEADER_SIZE;
836 if (remain_size <= 0) {
837 error("Invalid header size (LHarc file ?)");
840 if (fread(data + COMMON_HEADER_SIZE, remain_size, 1, fp) == 0) {
841 error("Invalid header (LHarc file ?)");
842 return FALSE; /* finish */
845 if (calc_sum(data + I_METHOD, header_size) != checksum) {
846 error("Checksum error (LHarc file?)");
850 get_bytes(hdr->method, 5, sizeof(hdr->method));
851 hdr->packed_size = (unsigned long)get_longword();
852 hdr->original_size = (unsigned long)get_longword();
853 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
854 hdr->attribute = get_byte(); /* MS-DOS attribute */
855 hdr->header_level = get_byte();
856 name_length = get_byte();
857 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
860 /* defaults for other type */
861 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
865 extend_size = header_size+2 - name_length - 24;
867 if (extend_size < 0) {
868 if (extend_size == -2) {
869 /* CRC field is not given */
870 hdr->extend_type = EXTEND_GENERIC;
871 hdr->has_crc = FALSE;
876 error("Unkonwn header (lha file?)");
881 hdr->crc = get_word();
883 if (extend_size == 0)
886 hdr->extend_type = get_byte();
889 if (hdr->extend_type == EXTEND_UNIX) {
890 if (extend_size >= 11) {
891 hdr->minor_version = get_byte();
892 hdr->unix_last_modified_stamp = (time_t) get_longword();
893 hdr->unix_mode = get_word();
894 hdr->unix_uid = get_word();
895 hdr->unix_gid = get_word();
898 hdr->extend_type = EXTEND_GENERIC;
902 skip_bytes(extend_size);
904 hdr->header_size += 2;
912 * offset size field name
913 * -----------------------------------
914 * 0 1 header size [*1]
916 * -------------------------------------
918 * 7 4 skip size [*2] |
919 * 11 4 original size |
922 * 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
923 * 20 1 level (0x01 fixed) |
926 * X+ 22 2 file crc (CRC-16) |
929 * X+Y+25 2 next-header size v
930 * -------------------------------------------------
931 * X+Y+27 Z ext-header ^
933 * ----------------------------------- | [*2] skip size
936 * -------------------------------------------------
940 get_header_level1(fp, hdr, data)
952 hdr->size_field_length = 2; /* in bytes */
953 hdr->header_size = header_size = get_byte();
954 checksum = get_byte();
956 /* The data variable has been already read as COMMON_HEADER_SIZE bytes.
957 So we must read the remaining header size by the header_size. */
958 remain_size = header_size + 2 - COMMON_HEADER_SIZE;
959 if (remain_size <= 0) {
960 error("Invalid header size (LHarc file ?)");
963 if (fread(data + COMMON_HEADER_SIZE, remain_size, 1, fp) == 0) {
964 error("Invalid header (LHarc file ?)");
965 return FALSE; /* finish */
968 if (calc_sum(data + I_METHOD, header_size) != checksum) {
969 error("Checksum error (LHarc file?)");
973 get_bytes(hdr->method, 5, sizeof(hdr->method));
974 hdr->packed_size = (unsigned long)get_longword(); /* skip size */
975 hdr->original_size = (unsigned long)get_longword();
976 hdr->unix_last_modified_stamp = generic_to_unix_stamp(get_longword());
977 hdr->attribute = get_byte(); /* 0x20 fixed */
978 hdr->header_level = get_byte();
980 name_length = get_byte();
981 i = get_bytes(hdr->name, name_length, sizeof(hdr->name)-1);
984 /* defaults for other type */
985 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
990 hdr->crc = get_word();
991 hdr->extend_type = get_byte();
993 dummy = header_size+2 - name_length - I_LEVEL1_HEADER_SIZE;
995 skip_bytes(dummy); /* skip old style extend header */
997 extend_size = get_word();
998 extend_size = get_extended_header(fp, hdr, extend_size, 0);
999 if (extend_size == -1)
1002 /* On level 1 header, size fields should be adjusted. */
1003 /* the `packed_size' field contains the extended header size. */
1004 /* the `header_size' field does not. */
1005 hdr->packed_size -= extend_size;
1006 hdr->header_size += extend_size + 2;
1015 * offset size field name
1016 * --------------------------------------------------
1017 * 0 2 total header size [*1] ^
1018 * ----------------------- |
1020 * 7 4 packed size [*2] |
1021 * 11 4 original size |
1023 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
1024 * 20 1 level (0x02 fixed) | (X+26+(1))
1025 * 21 2 file crc (CRC-16) |
1027 * 24 2 next-header size |
1028 * ----------------------------------- |
1031 * ----------------------------------- |
1032 * X +26 (1) padding v
1033 * -------------------------------------------------
1035 * : | [*2] packed size
1037 * -------------------------------------------------
1041 get_header_level2(fp, hdr, data)
1047 ssize_t remain_size;
1048 ssize_t extend_size;
1052 hdr->size_field_length = 2; /* in bytes */
1053 hdr->header_size = header_size = get_word();
1055 /* The data variable has been already read as COMMON_HEADER_SIZE bytes.
1056 So we must read the remaining header size without ext-header. */
1057 remain_size = header_size - I_LEVEL2_HEADER_SIZE;
1058 if (remain_size < 0) {
1059 error("Invalid header size (LHarc file ?)");
1062 if (fread(data + COMMON_HEADER_SIZE,
1063 I_LEVEL2_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
1064 error("Invalid header (LHarc file ?)");
1065 return FALSE; /* finish */
1068 get_bytes(hdr->method, 5, sizeof(hdr->method));
1069 hdr->packed_size = (unsigned long)get_longword();
1070 hdr->original_size = (unsigned long)get_longword();
1071 hdr->unix_last_modified_stamp = get_longword();
1072 hdr->attribute = get_byte(); /* reserved */
1073 hdr->header_level = get_byte();
1075 /* defaults for other type */
1076 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
1080 hdr->has_crc = TRUE;
1081 hdr->crc = get_word();
1082 hdr->extend_type = get_byte();
1083 extend_size = get_word();
1085 INITIALIZE_CRC(hcrc);
1086 hcrc = calccrc(hcrc, data, get_ptr - data);
1088 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
1089 if (extend_size == -1)
1092 padding = header_size - I_LEVEL2_HEADER_SIZE - extend_size;
1093 /* padding should be 0 or 1 */
1094 if (padding != 0 && padding != 1) {
1095 error("Invalid header size (padding: %d)", padding);
1099 hcrc = UPDATE_CRC(hcrc, fgetc(fp));
1101 if (hdr->header_crc != hcrc)
1102 error("header CRC error");
1111 * offset size field name
1112 * --------------------------------------------------
1113 * 0 2 size field length (4 fixed) ^
1115 * 7 4 packed size [*2] |
1116 * 11 4 original size |
1118 * 19 1 RESERVED (0x20 fixed) | [*1] total header size
1119 * 20 1 level (0x03 fixed) | (X+32)
1120 * 21 2 file crc (CRC-16) |
1122 * 24 4 total header size [*1] |
1123 * 28 4 next-header size |
1124 * ----------------------------------- |
1127 * -------------------------------------------------
1129 * : | [*2] packed size
1131 * -------------------------------------------------
1135 get_header_level3(fp, hdr, data)
1141 ssize_t remain_size;
1142 ssize_t extend_size;
1146 hdr->size_field_length = get_word();
1148 if (fread(data + COMMON_HEADER_SIZE,
1149 I_LEVEL3_HEADER_SIZE - COMMON_HEADER_SIZE, 1, fp) == 0) {
1150 error("Invalid header (LHarc file ?)");
1151 return FALSE; /* finish */
1154 get_bytes(hdr->method, 5, sizeof(hdr->method));
1155 hdr->packed_size = (unsigned long)get_longword();
1156 hdr->original_size = (unsigned long)get_longword();
1157 hdr->unix_last_modified_stamp = get_longword();
1158 hdr->attribute = get_byte(); /* reserved */
1159 hdr->header_level = get_byte();
1161 /* defaults for other type */
1162 hdr->unix_mode = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;
1166 hdr->has_crc = TRUE;
1167 hdr->crc = get_word();
1168 hdr->extend_type = get_byte();
1169 hdr->header_size = header_size = get_longword();
1170 remain_size = header_size - I_LEVEL3_HEADER_SIZE;
1171 if (remain_size < 0) {
1172 error("Invalid header size (LHarc file ?)");
1175 extend_size = get_longword();
1177 INITIALIZE_CRC(hcrc);
1178 hcrc = calccrc(hcrc, data, get_ptr - data);
1180 extend_size = get_extended_header(fp, hdr, extend_size, &hcrc);
1181 if (extend_size == -1)
1184 padding = remain_size - extend_size;
1185 /* padding should be 0 */
1187 error("Invalid header size (padding: %d)", padding);
1191 if (hdr->header_crc != hcrc)
1192 error("header CRC error");
1202 char data[LZHEADER_STORAGE];
1204 int archive_kanji_code = CODE_SJIS;
1205 int system_kanji_code = default_system_kanji_code;
1206 char *archive_delim = "\377\\"; /* `\' is for level 0 header and
1208 char *system_delim = "//";
1209 int filename_case = NONE;
1212 memset(hdr, 0, sizeof(LzHeader));
1214 setup_get(data, sizeof(data));
1216 if ((end_mark = getc(fp)) == EOF || end_mark == 0) {
1217 return FALSE; /* finish */
1221 if (fread(data + 1, COMMON_HEADER_SIZE - 1, 1, fp) == 0) {
1222 error("Invalid header (LHarc file ?)");
1223 return FALSE; /* finish */
1226 switch (data[I_HEADER_LEVEL]) {
1228 if (get_header_level0(fp, hdr, data) == FALSE)
1232 if (get_header_level1(fp, hdr, data) == FALSE)
1236 if (get_header_level2(fp, hdr, data) == FALSE)
1240 if (get_header_level3(fp, hdr, data) == FALSE)
1244 error("Unknown level header (level %d)", data[I_HEADER_LEVEL]);
1248 /* filename conversion */
1249 switch (hdr->extend_type) {
1251 filename_case = convertcase ? TO_LOWER : NONE;
1258 filename_case = NONE;
1262 archive_delim = "\377/:\\";
1263 /* `\' is for level 0 header and broken archive. */
1264 system_delim = "/://";
1265 filename_case = NONE;
1269 filename_case = convertcase ? TO_LOWER : NONE;
1273 if (optional_archive_kanji_code)
1274 archive_kanji_code = optional_archive_kanji_code;
1275 if (optional_system_kanji_code)
1276 system_kanji_code = optional_system_kanji_code;
1277 if (optional_archive_delim)
1278 archive_delim = optional_archive_delim;
1279 if (optional_system_delim)
1280 system_delim = optional_system_delim;
1281 if (optional_filename_case)
1282 filename_case = optional_filename_case;
1284 /* kanji code and delimiter conversion */
1285 convert_filename(hdr->name, strlen(hdr->name), sizeof(hdr->name),
1288 archive_delim, system_delim, filename_case);
1290 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1292 /* split symbolic link */
1293 p = strchr(hdr->name, '|');
1295 /* hdr->name is symbolic link name */
1296 /* hdr->realname is real name */
1298 strcpy(hdr->realname, p+1); /* ok */
1301 error("unknown symlink name \"%s\"", hdr->name);
1307 /* skip SFX header */
1312 unsigned char buffer[64 * 1024]; /* max seek size */
1316 n = fread(buffer, 1, sizeof(buffer), fp);
1318 for (p = buffer; p < buffer + n; p++) {
1319 if (! (p[I_METHOD]=='-' &&
1320 (p[I_METHOD+1]=='l' || p[I_METHOD+1]=='p') &&
1321 p[I_METHOD+4]=='-'))
1323 /* found "-[lp]??-" keyword (as METHOD type string) */
1325 /* level 0 or 1 header */
1326 if ((p[I_HEADER_LEVEL] == 0 || p[I_HEADER_LEVEL] == 1)
1327 && p[I_HEADER_SIZE] > 20
1328 && p[I_HEADER_CHECKSUM] == calc_sum(p+2, p[I_HEADER_SIZE])) {
1329 if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
1330 fatal_error("cannot seek header");
1334 /* level 2 header */
1335 if (p[I_HEADER_LEVEL] == 2
1336 && p[I_HEADER_SIZE] >= 24
1337 && p[I_ATTRIBUTE] == 0x20) {
1338 if (fseeko(fp, (p - buffer) - n, SEEK_CUR) == -1)
1339 fatal_error("cannot seek header");
1344 if (fseeko(fp, -n, SEEK_CUR) == -1)
1345 fatal_error("cannot seek header");
1350 /* remove leading `xxxx/..' */
1352 remove_leading_dots(char *path)
1357 if (strcmp(first, "..") == 0) {
1358 warning("Removing leading `..' from member name.");
1359 return first+1; /* change to "." */
1362 if (strstr(first, "..") == 0)
1365 while (path && *path) {
1367 if (strcmp(path, "..") == 0)
1368 ptr = path = path+2;
1369 else if (strncmp(path, "../", 3) == 0)
1370 ptr = path = path+3;
1372 path = strchr(path, '/');
1374 if (path && *path == '/') {
1380 warning("Removing leading `%.*s' from member name.", ptr-first, first);
1388 copy_path_element(char *dst, const char *src, int size)
1392 if (size < 1) return 0;
1394 for (i = 0; i < size; i++) {
1398 if (dst[i] == '/') {
1412 remove leading "xxx/../"
1413 remove "./", "././", "././ ... ./"
1414 remove duplicated "/"
1417 canon_path(char *newpath, char *path, size_t size)
1421 path = remove_leading_dots(path);
1424 if (path[0] == '.' && path[1] == '/')
1428 len = copy_path_element(newpath, path, size);
1437 /* remove duplicated '/' */
1438 while (*path == '/') path++;
1441 /* When newpath is empty, set "." */
1443 strcpy(newpath, ".");
1447 return newpath - p; /* string length */
1451 init_header(name, v_stat, hdr)
1453 struct stat *v_stat;
1458 memset(hdr, 0, sizeof(LzHeader));
1460 /* the `method' member is rewrote by the encoding function.
1461 but need set for empty files */
1462 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
1464 hdr->packed_size = 0;
1465 hdr->original_size = v_stat->st_size;
1466 hdr->attribute = GENERIC_ATTRIBUTE;
1467 hdr->header_level = header_level;
1469 len = canon_path(hdr->name, name, sizeof(hdr->name));
1472 hdr->extend_type = EXTEND_UNIX;
1473 hdr->unix_last_modified_stamp = v_stat->st_mtime;
1474 /* since 00:00:00 JAN.1.1970 */
1475 #ifdef NOT_COMPATIBLE_MODE
1476 /* Please need your modification in this space. */
1479 if (S_ISREG(v_stat->st_mode))
1480 hdr->unix_mode = hdr->unix_mode | UNIX_FILE_REGULAR;
1481 if (S_ISDIR(v_stat->st_mode))
1482 hdr->unix_mode = hdr->unix_mode | UNIX_FILE_DIRECTORY;
1483 if (S_ISLNK(v_stat->st_mode))
1484 hdr->unix_mode = hdr->unix_mode | UNIX_FILE_SYMLINK;
1485 if (v_stat->st_mode & S_IRUSR)
1486 hdr->unix_mode = hdr->unix_mode | UNIX_OWNER_READ_PERM;
1487 if (v_stat->st_mode & S_IRGRP)
1488 hdr->unix_mode = hdr->unix_mode | UNIX_GROUP_READ_PERM;
1489 if (v_stat->st_mode & S_IROTH)
1490 hdr->unix_mode = hdr->unix_mode | UNIX_OTHER_READ_PERM;
1491 if (v_stat->st_mode & S_IWUSR)
1492 hdr->unix_mode = hdr->unix_mode | UNIX_OWNER_WRITE_PERM;
1493 if (v_stat->st_mode & S_IWGRP)
1494 hdr->unix_mode = hdr->unix_mode | UNIX_GROUP_WRITE_PERM;
1495 if (v_stat->st_mode & S_IWOTH)
1496 hdr->unix_mode = hdr->unix_mode | UNIX_OTHER_WRITE_PERM;
1497 if (v_stat->st_mode & S_IXUSR)
1498 hdr->unix_mode = hdr->unix_mode | UNIX_OWNER_EXEC_PERM;
1499 if (v_stat->st_mode & S_IXGRP)
1500 hdr->unix_mode = hdr->unix_mode | UNIX_GROUP_EXEC_PERM;
1501 if (v_stat->st_mode & S_IXOTH)
1502 hdr->unix_mode = hdr->unix_mode | UNIX_OTHER_EXEC_PERM;
1503 if (v_stat->st_mode & S_ISUID)
1504 hdr->unix_mode = hdr->unix_mode | UNIX_SETUID;
1505 if (v_stat->st_mode & S_ISGID)
1506 hdr->unix_mode = hdr->unix_mode | UNIX_SETGID;
1507 #endif /* __DJGPP__ */
1509 hdr->unix_mode = v_stat->st_mode;
1512 hdr->unix_uid = v_stat->st_uid;
1513 hdr->unix_gid = v_stat->st_gid;
1515 #if INCLUDE_OWNER_NAME_IN_HEADER
1518 struct passwd *ent = getpwuid(hdr->unix_uid);
1521 strncpy(hdr->user, ent->pw_name, sizeof(hdr->user));
1522 if (hdr->user[sizeof(hdr->user)-1])
1523 hdr->user[sizeof(hdr->user)-1] = 0;
1529 struct group *ent = getgrgid(hdr->unix_gid);
1532 strncpy(hdr->group, ent->gr_name, sizeof(hdr->group));
1533 if (hdr->group[sizeof(hdr->group)-1])
1534 hdr->group[sizeof(hdr->group)-1] = 0;
1538 #endif /* INCLUDE_OWNER_NAME_IN_HEADER */
1539 if (is_directory(v_stat)) {
1540 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1541 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1542 hdr->original_size = 0;
1543 if (len > 0 && hdr->name[len - 1] != '/') {
1544 if (len < sizeof(hdr->name)-1)
1545 strcpy(&hdr->name[len++], "/"); /* ok */
1547 warning("the length of dirname \"%s\" is too long.",
1553 if (is_symlink(v_stat)) {
1554 memcpy(hdr->method, LZHDIRS_METHOD, METHOD_TYPE_STORAGE);
1555 hdr->attribute = GENERIC_DIRECTORY_ATTRIBUTE;
1556 hdr->original_size = 0;
1557 readlink(name, hdr->realname, sizeof(hdr->realname));
1563 write_unix_info(hdr)
1566 /* UNIX specific informations */
1568 put_word(5); /* size */
1569 put_byte(0x50); /* permission */
1570 put_word(hdr->unix_mode);
1572 put_word(7); /* size */
1573 put_byte(0x51); /* gid and uid */
1574 put_word(hdr->unix_gid);
1575 put_word(hdr->unix_uid);
1577 if (hdr->group[0]) {
1578 int len = strlen(hdr->group);
1579 put_word(len + 3); /* size */
1580 put_byte(0x52); /* group name */
1581 put_bytes(hdr->group, len);
1585 int len = strlen(hdr->user);
1586 put_word(len + 3); /* size */
1587 put_byte(0x53); /* user name */
1588 put_bytes(hdr->user, len);
1591 if (hdr->header_level == 1) {
1592 put_word(7); /* size */
1593 put_byte(0x54); /* time stamp */
1594 put_longword(hdr->unix_last_modified_stamp);
1599 write_header_level0(data, hdr, pathname)
1601 char *data, *pathname;
1608 memset(data, 0, LZHEADER_STORAGE);
1610 put_byte(0x00); /* header size */
1611 put_byte(0x00); /* check sum */
1612 put_bytes(hdr->method, 5);
1613 put_longword(hdr->packed_size);
1614 put_longword(hdr->original_size);
1615 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1616 put_byte(hdr->attribute);
1617 put_byte(hdr->header_level); /* level 0 */
1619 /* write pathname (level 0 header contains the directory part) */
1620 name_length = strlen(pathname);
1622 limit = 255 - I_GENERIC_HEADER_SIZE + 2;
1624 limit = 255 - I_LEVEL0_HEADER_SIZE + 2;
1626 if (name_length > limit) {
1627 warning("the length of pathname \"%s\" is too long.", pathname);
1628 name_length = limit;
1630 put_byte(name_length);
1631 put_bytes(pathname, name_length);
1634 if (generic_format) {
1635 header_size = I_GENERIC_HEADER_SIZE + name_length - 2;
1636 data[I_HEADER_SIZE] = header_size;
1637 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1639 /* write old-style extend header */
1640 put_byte(EXTEND_UNIX);
1641 put_byte(CURRENT_UNIX_MINOR_VERSION);
1642 put_longword(hdr->unix_last_modified_stamp);
1643 put_word(hdr->unix_mode);
1644 put_word(hdr->unix_uid);
1645 put_word(hdr->unix_gid);
1647 /* size of extended header is 12 */
1648 header_size = I_LEVEL0_HEADER_SIZE + name_length - 2;
1649 data[I_HEADER_SIZE] = header_size;
1650 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1653 return header_size + 2;
1657 write_header_level1(data, hdr, pathname)
1659 char *data, *pathname;
1661 int name_length, dir_length, limit;
1662 char *basename, *dirname;
1664 char *extend_header_top;
1665 size_t extend_header_size;
1667 basename = strrchr(pathname, LHA_PATHSEP);
1670 name_length = strlen(basename);
1672 dir_length = basename - dirname;
1675 basename = pathname;
1676 name_length = strlen(basename);
1682 memset(data, 0, LZHEADER_STORAGE);
1684 put_byte(0x00); /* header size */
1685 put_byte(0x00); /* check sum */
1686 put_bytes(hdr->method, 5);
1687 put_longword(hdr->packed_size);
1688 put_longword(hdr->original_size);
1689 put_longword(unix_to_generic_stamp(hdr->unix_last_modified_stamp));
1691 put_byte(hdr->header_level); /* level 1 */
1693 /* level 1 header: write filename (basename only) */
1694 limit = 255 - I_LEVEL1_HEADER_SIZE + 2;
1695 if (name_length > limit) {
1696 put_byte(0); /* name length */
1699 put_byte(name_length);
1700 put_bytes(basename, name_length);
1708 put_byte(EXTEND_UNIX);
1710 /* write extend header from here. */
1712 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1713 header_size = extend_header_top - data - 2;
1715 /* write filename and dirname */
1717 if (name_length > limit) {
1718 put_word(name_length + 3); /* size */
1719 put_byte(0x01); /* filename */
1720 put_bytes(basename, name_length);
1723 if (dir_length > 0) {
1724 put_word(dir_length + 3); /* size */
1725 put_byte(0x02); /* dirname */
1726 put_bytes(dirname, dir_length);
1729 if (!generic_format)
1730 write_unix_info(hdr);
1732 put_word(0x0000); /* next header size */
1734 extend_header_size = put_ptr - extend_header_top;
1735 /* On level 1 header, the packed size field is contains the ext-header */
1736 hdr->packed_size += put_ptr - extend_header_top;
1738 /* put `skip size' */
1739 setup_put(data + I_PACKED_SIZE);
1740 put_longword(hdr->packed_size);
1742 data[I_HEADER_SIZE] = header_size;
1743 data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
1745 return header_size + extend_header_size + 2;
1749 write_header_level2(data, hdr, pathname)
1751 char *data, *pathname;
1753 int name_length, dir_length;
1754 char *basename, *dirname;
1756 char *extend_header_top;
1757 char *headercrc_ptr;
1760 basename = strrchr(pathname, LHA_PATHSEP);
1763 name_length = strlen(basename);
1765 dir_length = basename - dirname;
1768 basename = pathname;
1769 name_length = strlen(basename);
1775 memset(data, 0, LZHEADER_STORAGE);
1777 put_word(0x0000); /* header size */
1778 put_bytes(hdr->method, 5);
1779 put_longword(hdr->packed_size);
1780 put_longword(hdr->original_size);
1781 put_longword(hdr->unix_last_modified_stamp);
1783 put_byte(hdr->header_level); /* level 2 */
1790 put_byte(EXTEND_UNIX);
1792 /* write extend header from here. */
1794 extend_header_top = put_ptr+2; /* +2 for the field `next header size' */
1796 /* write common header */
1799 headercrc_ptr = put_ptr;
1800 put_word(0x0000); /* header CRC */
1802 /* write filename and dirname */
1803 /* must have this header, even if the name_length is 0. */
1804 put_word(name_length + 3); /* size */
1805 put_byte(0x01); /* filename */
1806 put_bytes(basename, name_length);
1808 if (dir_length > 0) {
1809 put_word(dir_length + 3); /* size */
1810 put_byte(0x02); /* dirname */
1811 put_bytes(dirname, dir_length);
1814 if (!generic_format)
1815 write_unix_info(hdr);
1817 put_word(0x0000); /* next header size */
1819 header_size = put_ptr - data;
1820 if ((header_size & 0xff) == 0) {
1821 /* cannot put zero at the first byte on level 2 header. */
1822 /* adjust header size. */
1823 put_byte(0); /* padding */
1827 /* put header size */
1828 setup_put(data + I_HEADER_SIZE);
1829 put_word(header_size);
1831 /* put header CRC in extended header */
1832 INITIALIZE_CRC(hcrc);
1833 hcrc = calccrc(hcrc, data, (unsigned int) header_size);
1834 setup_put(headercrc_ptr);
1841 write_header(fp, hdr)
1846 char data[LZHEADER_STORAGE];
1848 int archive_kanji_code = CODE_SJIS;
1849 int system_kanji_code = default_system_kanji_code;
1850 char *archive_delim = "\377";
1851 char *system_delim = "/";
1852 int filename_case = NONE;
1853 char pathname[FILENAME_LENGTH];
1855 if (optional_archive_kanji_code)
1856 archive_kanji_code = optional_archive_kanji_code;
1857 if (optional_system_kanji_code)
1858 system_kanji_code = optional_system_kanji_code;
1860 if (generic_format && convertcase)
1861 filename_case = TO_UPPER;
1863 if (hdr->header_level == 0) {
1864 archive_delim = "\\";
1867 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
1869 p = strchr(hdr->name, '|');
1871 error("symlink name \"%s\" contains '|' char. change it into '_'",
1875 if (xsnprintf(pathname, sizeof(pathname),
1876 "%s|%s", hdr->name, hdr->realname) == -1)
1877 error("file name is too long (%s -> %s)", hdr->name, hdr->realname);
1880 strncpy(pathname, hdr->name, sizeof(pathname));
1881 pathname[sizeof(pathname)-1] = 0;
1884 convert_filename(pathname, strlen(pathname), sizeof(pathname),
1887 system_delim, archive_delim, filename_case);
1889 switch (hdr->header_level) {
1891 header_size = write_header_level0(data, hdr, pathname);
1894 header_size = write_header_level1(data, hdr, pathname);
1897 header_size = write_header_level2(data, hdr, pathname);
1900 error("Unknown level header (level %d)", hdr->header_level);
1904 if (fwrite(data, header_size, 1, fp) == 0)
1905 fatal_error("Cannot write to temporary file");
1908 #if MULTIBYTE_FILENAME
1910 #if defined(__APPLE__) /* Added by Hiroto Sakai */
1912 #include <CoreFoundation/CFString.h>
1913 #include <CoreFoundation/CFStringEncodingExt.h>
1915 /* this is not need for Mac OS X v 10.2 later */
1917 kCFStringEncodingAllowLossyConversion = 1,
1918 kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
1919 kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
1920 kCFStringEncodingSubstituteCombinings = (1 << 3),
1921 kCFStringEncodingComposeCombinings = (1 << 4),
1922 kCFStringEncodingIgnoreCombinings = (1 << 5),
1923 kCFStringEncodingUseCanonical = (1 << 6),
1924 kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
1925 kCFStringEncodingPrependBOM = (1 << 8),
1926 kCFStringEncodingDisableCorporateArea = (1 << 9),
1927 kCFStringEncodingASCIICompatibleConversion = (1 << 10),
1931 ConvertEncodingToUTF8(const char* inCStr,
1932 char* outUTF8Buffer,
1933 int outUTF8BufferLength,
1934 unsigned long scriptEncoding,
1935 unsigned long flags)
1937 unsigned long unicodeChars;
1938 unsigned long srcCharsUsed;
1939 unsigned long usedByteLen = 0;
1940 UniChar uniStr[512];
1941 unsigned long cfResult;
1943 cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
1951 if (cfResult == 0) {
1952 cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
1957 (char*)outUTF8Buffer,
1958 outUTF8BufferLength - 1,
1960 outUTF8Buffer[usedByteLen] = '\0';
1967 ConvertUTF8ToEncoding(const char* inUTF8Buf,
1968 int inUTF8BufLength,
1969 char* outCStrBuffer,
1970 int outCStrBufferLength,
1971 unsigned long scriptEncoding,
1972 unsigned long flags)
1974 unsigned long unicodeChars;
1975 unsigned long srcCharsUsed;
1976 unsigned long usedByteLen = 0;
1977 UniChar uniStr[256];
1978 unsigned long cfResult;
1980 cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
1988 if (cfResult == 0) {
1989 cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
1994 (char*)outCStrBuffer,
1995 outCStrBufferLength - 1,
1997 outCStrBuffer[usedByteLen] = '\0';
2007 ConvertEncodingByIconv(const char *src, char *dst, int dstsize,
2008 const char *srcEnc, const char *dstEnc)
2011 static char szTmpBuf[2048];
2017 dst_p = &szTmpBuf[0];
2018 iLen = (size_t)sizeof(szTmpBuf)-1;
2019 src_p = (char *)src;
2020 sLen = (size_t)strlen(src);
2021 memset(szTmpBuf, 0, sizeof(szTmpBuf));
2022 memset(dst, 0, dstsize);
2024 ic = iconv_open(dstEnc, srcEnc);
2025 if (ic == (iconv_t)-1) {
2026 error("iconv_open() failure: %s", strerror(errno));
2030 if (iconv(ic, &src_p, &sLen, &dst_p, &iLen) == (size_t)-1) {
2031 error("iconv() failure: %s", strerror(errno));
2036 strncpy(dst, szTmpBuf, dstsize);
2042 #endif /* defined(__APPLE__) */
2045 sjis_to_utf8(char *dst, const char *src, size_t dstsize)
2047 #if defined(__APPLE__)
2049 if (ConvertEncodingToUTF8(src, dst, dstsize,
2050 kCFStringEncodingDOSJapanese,
2051 kCFStringEncodingUseHFSPlusCanonical) == 0)
2054 if (ConvertEncodingByIconv(src, dst, dstsize, "SJIS", "UTF-8") != -1)
2057 error("not support utf-8 conversion");
2060 if (dstsize < 1) return dst;
2062 return strncpy(dst, src, dstsize-1);
2066 utf8_to_sjis(char *dst, const char *src, size_t dstsize)
2068 #if defined(__APPLE__)
2072 srclen = strlen(src);
2073 if (ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
2074 kCFStringEncodingDOSJapanese,
2075 kCFStringEncodingUseHFSPlusCanonical) == 0)
2078 if (ConvertEncodingByIconv(src, dst, dstsize, "UTF-8", "SJIS") != -1)
2081 error("not support utf-8 conversion");
2084 if (dstsize < 1) return dst;
2086 return strncpy(dst, src, dstsize-1);
2091 * 「日本語情報処理」 ソフトバンク(株)
2092 * より抜粋(by Koji Arai)
2095 euc2sjis(int *p1, int *p2)
2097 unsigned char c1 = *p1 & 0x7f;
2098 unsigned char c2 = *p2 & 0x7f;
2099 int rowoff = c1 < 0x5f ? 0x70 : 0xb0;
2100 int celoff = c1 % 2 ? (c2 > 0x5f ? 0x20 : 0x1f) : 0x7e;
2101 *p1 = ((c1 + 1) >> 1) + rowoff;
2102 *p2 += celoff - 0x80;
2106 sjis2euc(int *p1, int *p2)
2108 unsigned char c1 = *p1;
2109 unsigned char c2 = *p2;
2110 int adjust = c2 < 0x9f;
2111 int rowoff = c1 < 0xa0 ? 0x70 : 0xb0;
2112 int celoff = adjust ? (c2 > 0x7f ? 0x20 : 0x1f) : 0x7e;
2113 *p1 = ((c1 - rowoff) << 1) - adjust;
2124 case '0': case '1': case '2': case '3': case '4':
2125 case '5': case '6': case '7': case '8': case '9':
2128 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
2129 return c - 'a' + 10;
2131 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
2132 return c - 'A' + 10;
2142 case 0: case 1: case 2: case 3: case 4:
2143 case 5: case 6: case 7: case 8: case 9:
2146 case 10: case 11: case 12: case 13: case 14: case 15:
2147 return c + 'a' - 10;
2155 cap_to_sjis(char *dst, const char *src, size_t dstsize)
2158 size_t len = strlen(src);
2161 for (i = j = 0; i < len && i < dstsize; i++) {
2162 if (src[i] != ':') {
2168 a = hex2int((unsigned char)src[i]);
2169 b = hex2int((unsigned char)src[i+1]);
2171 if (a == -1 || b == -1) {
2174 strncpy(dst+j, src+i, dstsize-j);
2181 dst[j++] = a * 16 + b;
2188 sjis_to_cap(char *dst, const char *src, size_t dstsize)
2191 size_t len = strlen(src);
2194 for (i = j = 0; i < len && i < dstsize; i++) {
2195 if (src[i] == ':') {
2196 strncpy(dst+j, ":3a", dstsize-j);
2201 if (isprint(src[i])) {
2206 if (j + 3 >= dstsize) {
2211 a = int2hex((unsigned char)src[i] / 16);
2212 b = int2hex((unsigned char)src[i] % 16);
2221 #endif /* MULTIBYTE_FILENAME */