OSDN Git Service

* src/header.c (convert_filename): fixed bug on utf8 conversion,
[lha/lha.git] / src / header.c
index c778148..c327601 100644 (file)
 /* ------------------------------------------------------------------------ */
 #include "lha.h"
 
+#ifdef __APPLE__
+static int ConvertEncodingToUTF8(const char* inCStr, char* outUTF8Buffer, int outUTF8BufferLength, unsigned long scriptEncoding, unsigned long flags);
+static int ConvertUTF8ToEncoding(const char* inUTF8Buf, int inUTF8BufLength, char* outCStrBuffer, int outCStrBufferLength, unsigned long scriptEncoding, unsigned long flags);
+#endif /* __APPLE__ */
+
 /* ------------------------------------------------------------------------ */
 static char    *get_ptr;
 
@@ -191,10 +196,10 @@ unix_to_generic_filename(name, len)
 
 /* added by Koji Arai */
 static void
-filename_conv(name, len, size,
-              from_code, to_code,
-              from_delim, to_delim,
-              case_to)
+convert_filename(name, len, size,
+                 from_code, to_code,
+                 from_delim, to_delim,
+                 case_to)
        register char  *name;
        register int    len;
        register int    size;
@@ -203,6 +208,30 @@ filename_conv(name, len, size,
 
 {
        register int    i;
+#ifdef MULTIBYTE_FILENAME
+    char tmp[256];              /* 256 is sizeof(LzHeader.name) */
+
+    if (from_code == CODE_SJIS && to_code == CODE_UTF8) {
+        for (i = 0; i < len; i++)
+            if (name[i] == '\xff')  name[i] = '/';
+        sjis_to_utf8(tmp, name, sizeof(tmp));
+        strncpy(name, tmp, size);
+        name[size-1] = 0;
+        len = strlen(name);
+        for (i = 0; i < len; i++)
+            if (name[i] == '/')  name[i] = '\xff';
+    }
+    else if (from_code == CODE_UTF8 && to_code == CODE_SJIS) {
+        for (i = 0; i < len; i++)
+            if (name[i] == '\xff')  name[i] = '/';
+        utf8_to_sjis(tmp, name, sizeof(tmp));
+        strncpy(name, tmp, size);
+        name[size-1] = 0;
+        len = strlen(name);
+        for (i = 0; i < len; i++)
+            if (name[i] == '/')  name[i] = '\xff';
+    }
+#endif
 
        for (i = 0; i < len; i ++) {
 #ifdef MULTIBYTE_FILENAME
@@ -799,10 +828,10 @@ get_header(fp, hdr)
                name_length += dir_length;
        }
 
-    filename_conv(hdr->name, name_length, sizeof(hdr->name),
-                  archive_kanji_code,
-                  system_kanji_code,
-                  archive_delim, system_delim, filename_case);
+    convert_filename(hdr->name, name_length, sizeof(hdr->name),
+                     archive_kanji_code,
+                     system_kanji_code,
+                     archive_delim, system_delim, filename_case);
 
        return TRUE;
 }
@@ -904,10 +933,10 @@ init_header(name, v_stat, hdr)
         archive_delim = "\\";
     }
 
-    filename_conv(hdr->name, len, sizeof(hdr->name),
-                  system_kanji_code,
-                  system_kanji_code, /* no change code */
-                  system_delim, archive_delim, filename_case);
+    convert_filename(hdr->name, len, sizeof(hdr->name),
+                     system_kanji_code,
+                     system_kanji_code, /* no change code */
+                     system_delim, archive_delim, filename_case);
 }
 
 /* ------------------------------------------------------------------------ */
@@ -924,6 +953,7 @@ write_header(nafp, hdr)
        char           *headercrc_ptr;
     int archive_kanji_code = CODE_SJIS;
     int system_kanji_code = default_system_kanji_code;
+       char            lzname[256];
 
     if (optional_archive_kanji_code)
         archive_kanji_code = optional_archive_kanji_code;
@@ -953,18 +983,19 @@ write_header(nafp, hdr)
 
        put_byte(hdr->header_level);
 
-    filename_conv(hdr->name, strlen(hdr->name), sizeof(hdr->name),
-                  system_kanji_code,
-                  archive_kanji_code,
-                  "\xff\\/", "\xff\xff\xff", NONE);
+    strncpy(lzname, hdr->name, sizeof(lzname));
+    convert_filename(lzname, strlen(lzname), sizeof(lzname),
+                     system_kanji_code,
+                     archive_kanji_code,
+                     "\xff\\/", "\xff\xff\xff", NONE);
 
        if (hdr->header_level != HEADER_LEVEL2) {
-               if (p = (char *) strrchr(hdr->name, DELIM2))
+               if (p = (char *) strrchr(lzname, DELIM2))
                        name_length = strlen(++p);
                else
-                       name_length = strlen(hdr->name);
+                       name_length = strlen(lzname);
                put_byte(name_length);
-               memcpy(data + I_NAME, p ? p : hdr->name, name_length);
+               memcpy(data + I_NAME, p ? p : lzname, name_length);
                setup_put(data + I_NAME + name_length);
        }
 
@@ -1031,14 +1062,14 @@ write_header(nafp, hdr)
                     put_byte(hdr->user[i]);
             }
 
-                       if (p = (char *) strrchr(hdr->name, DELIM2)) {
+                       if (p = (char *) strrchr(lzname, DELIM2)) {
                                int             i;
 
-                               name_length = p - hdr->name + 1;
+                               name_length = p - lzname + 1;
                                put_word(name_length + 3);
                                put_byte(2);    /* dirname */
                                for (i = 0; i < name_length; i++)
-                                       put_byte(hdr->name[i]);
+                                       put_byte(lzname[i]);
                        }
                }               /* if generic .. */
 
@@ -1057,11 +1088,11 @@ write_header(nafp, hdr)
                        data[I_HEADER_CHECKSUM] = calc_sum(data + I_METHOD, header_size);
                } else {                /* header level 2 */
                        int             i;
-                       if (p = (char *) strrchr(hdr->name, DELIM2))
+                       if (p = (char *) strrchr(lzname, DELIM2))
                                name_length = strlen(++p);
                        else {
-                               p = hdr->name;
-                               name_length = strlen(hdr->name);
+                               p = lzname;
+                               name_length = strlen(lzname);
                        }
                        put_word(name_length + 3);
                        put_byte(1);    /* filename */
@@ -1083,11 +1114,128 @@ write_header(nafp, hdr)
 
        if (fwrite(data, header_size + 2, 1, nafp) == 0)
                fatal_error("Cannot write to temporary file");
+}
 
-    filename_conv(hdr->name, strlen(hdr->name), sizeof(hdr->name),
-                  archive_kanji_code,
-                  system_kanji_code,
-                  "\xff\\/", "///", NONE);
+#ifdef __APPLE__
+/* this is not need for Mac OS X v 10.2 later */
+enum {
+  kCFStringEncodingAllowLossyConversion = 1,
+  kCFStringEncodingBasicDirectionLeftToRight = (1 << 1),
+  kCFStringEncodingBasicDirectionRightToLeft = (1 << 2),
+  kCFStringEncodingSubstituteCombinings = (1 << 3),
+  kCFStringEncodingComposeCombinings = (1 << 4),
+  kCFStringEncodingIgnoreCombinings = (1 << 5),
+  kCFStringEncodingUseCanonical = (1 << 6),
+  kCFStringEncodingUseHFSPlusCanonical = (1 << 7),
+  kCFStringEncodingPrependBOM = (1 << 8),
+  kCFStringEncodingDisableCorporateArea = (1 << 9),
+  kCFStringEncodingASCIICompatibleConversion = (1 << 10),
+};
+
+static int
+ConvertEncodingToUTF8(const char* inCStr,
+                      char* outUTF8Buffer,
+                      int outUTF8BufferLength,
+                      unsigned long scriptEncoding,
+                      unsigned long flags)
+{
+    unsigned long unicodeChars;
+    unsigned long srcCharsUsed;
+    unsigned long usedByteLen = 0;
+    UniChar uniStr[512];
+    unsigned long cfResult;
+
+    cfResult = CFStringEncodingBytesToUnicode(scriptEncoding,
+                                              flags,
+                                              (char *)inCStr,
+                                              strlen(inCStr),
+                                              &srcCharsUsed,
+                                              uniStr,
+                                              512,
+                                              &unicodeChars);
+    if (cfResult == 0) {
+        cfResult = CFStringEncodingUnicodeToBytes(kCFStringEncodingUTF8,
+                                                  flags,
+                                                  uniStr,
+                                                  unicodeChars,
+                                                  &srcCharsUsed,
+                                                  (char*)outUTF8Buffer,
+                                                  outUTF8BufferLength - 1,
+                                                  &usedByteLen);
+        outUTF8Buffer[usedByteLen] = '\0';
+    }
+
+    return cfResult;
+}
+
+static int
+ConvertUTF8ToEncoding(const char* inUTF8Buf,
+                      int inUTF8BufLength,
+                      char* outCStrBuffer,
+                      int outCStrBufferLength,
+                      unsigned long scriptEncoding,
+                      unsigned long flags)
+{
+    unsigned long unicodeChars;
+    unsigned long srcCharsUsed;
+    unsigned long usedByteLen = 0;
+    UniChar uniStr[256];
+    unsigned long cfResult;
+
+    cfResult = CFStringEncodingBytesToUnicode(kCFStringEncodingUTF8,
+                                              flags,
+                                              (char*)inUTF8Buf,
+                                              inUTF8BufLength,
+                                              &srcCharsUsed,
+                                              uniStr,
+                                              255,
+                                              &unicodeChars);
+    if (cfResult == 0) {
+        cfResult = CFStringEncodingUnicodeToBytes(scriptEncoding,
+                                                  flags,
+                                                  uniStr,
+                                                  unicodeChars,
+                                                  &srcCharsUsed,
+                                                  (char*)outCStrBuffer,
+                                                  outCStrBufferLength - 1,
+                                                  &usedByteLen);
+        outCStrBuffer[usedByteLen] = '\0';
+    }
+
+    return cfResult;
+}
+#endif /* __APPLE__ */
+
+char *
+sjis_to_utf8(char *dst, const char *src, size_t dstsize)
+{
+#ifdef __APPLE__
+  dst[0] = '\0';
+  ConvertEncodingToUTF8(src, dst, dstsize,
+                        kCFStringEncodingDOSJapanese,
+                        kCFStringEncodingUseHFSPlusCanonical);
+
+#else
+  /* not supported */
+#endif
+  return dst;
+}
+
+char *
+utf8_to_sjis(char *dst, const char *src, size_t dstsize)
+{
+#ifdef __APPLE__
+  int srclen;
+
+  dst[0] = '\0';
+  srclen = strlen(src);
+  ConvertUTF8ToEncoding(src, srclen, dst, dstsize,
+                        kCFStringEncodingDOSJapanese,
+                        kCFStringEncodingUseHFSPlusCanonical);
+#else
+  /* not supported */
+#endif
+  return dst;
 }
 
 /*