OSDN Git Service

[refactor] UTF-8 ↔ EUC-JPの変換処理を共通化
authorHabu <habu1010+github@gmail.com>
Thu, 25 Feb 2021 13:51:42 +0000 (22:51 +0900)
committerHabu <habu1010+github@gmail.com>
Thu, 25 Feb 2021 13:51:42 +0000 (22:51 +0900)
X11ドライバとGCUドライバでそれぞれ独自に行っている
UTF-8とEUC-JP間の変換処理をlocale/japanese.cにまとめ
共通化する。
Linux/UNIX(EUC-JP)環境では utf8_to_sys からも同じく
共通化した処理を使用する。

src/locale/japanese.c
src/locale/japanese.h
src/main-gcu.c
src/main-x11.c

index 6307237..a12a44a 100644 (file)
@@ -363,9 +363,21 @@ static const struct ms_to_jis_unicode_conv_t {
 };
 
 /*!
- * @brief EUCがシステムコードである環境下向けにUTF-8から変換処理を行うサブルーチン
- * @param str 変換する文字列のポインタ
- * @return なし
+ * @brief 受け取ったUTF-8文字列を調べ、特定のコードポイントの文字の置き換えを行う
+ *
+ * 受け取ったUTF-8の文字列に含まれる文字を1つ1つしらべて、ms_to_jis_unicode_conv で
+ * 定義されている特定のコードポイントの文字の変換を行う。
+ *
+ * '~'と'-'は、Windows環境(CP932)とLinux/UNIX環境(EUC-JP)でUTF-8に対応する
+ * 文字としてそれぞれ別のコードポイントが割り当てられており、別の環境の
+ * UTF-8からシステムの文字コードに変換した時に、これらの文字は変換できず
+ * 文字化けが起きてしまう。
+ *
+ * これを避けるため、Linux/UNIX環境(EUC-JP)ではUTF-8→EUC-JPの変換を行う前に
+ * 該当するコードポイントの文字をLinux/UNIX環境のものに置き換えてから
+ * 変換を行うようにするためのルーチン。
+ *
+ * @param str コードポイントの置き換えを行う文字列へのポインタ
  */
 static void ms_to_jis_unicode(char *str)
 {
@@ -397,6 +409,66 @@ static void ms_to_jis_unicode(char *str)
 #elif defined(SJIS) && defined(WINDOWS)
 #include <Windows.h>
 #endif
+
+#ifdef EUC
+/*!
+ * @brief 文字列の文字コードをUTF-8からEUC-JPに変換する
+ * @param utf8_str 変換元の文字列へのポインタ
+ * @param utf8_str_len 変換元の文字列の長さ(文字数ではなくバイト数)
+ * @param euc_buf 変換した文字列を格納するバッファへのポインタ
+ * @param euc_buf_len 変換した文字列を格納するバッファのサイズ
+ * @return 変換に成功した場合変換後の文字列の長さを返す
+ *         変換に失敗した場合-1を返す
+ */
+int utf8_to_euc(char *utf8_str, size_t utf8_str_len, char *euc_buf, size_t euc_buf_len)
+{
+    static iconv_t cd = NULL;
+    if (!cd)
+        cd = iconv_open("EUC-JP", "UTF-8");
+
+    ms_to_jis_unicode(utf8_str);
+
+    size_t inlen_left = utf8_str_len;
+    size_t outlen_left = euc_buf_len;
+    char *in = utf8_str;
+    char *out = euc_buf;
+
+    if (iconv(cd, &in, &inlen_left, &out, &outlen_left) == (size_t)-1) {
+        return -1;
+    }
+
+    return euc_buf_len - outlen_left;
+}
+
+/*!
+ * @brief 文字列の文字コードをEUC-JPからUTF-8に変換する
+ * @param euc_str 変換元の文字列へのポインタ
+ * @param euc_str_len 変換元の文字列の長さ(文字数ではなくバイト数)
+ * @param utf8_buf 変換した文字列を格納するバッファへのポインタ
+ * @param utf8_buf_len 変換した文字列を格納するバッファのサイズ
+ * @return 変換に成功した場合変換後の文字列の長さを返す
+ *         変換に失敗した場合-1を返す
+ */
+int euc_to_utf8(const char *euc_str, size_t euc_str_len, char *utf8_buf, size_t utf8_buf_len)
+{
+    static iconv_t cd = NULL;
+    if (!cd)
+        cd = iconv_open("UTF-8", "EUC-JP");
+
+    size_t inlen_left = euc_str_len;
+    size_t outlen_left = utf8_buf_len;
+    const char *in = euc_str;
+    char *out = utf8_buf;
+
+    // iconv は入力バッファを書き換えないのでキャストで const を外してよい
+    if (iconv(cd, (char **)&in, &inlen_left, &out, &outlen_left) == (size_t)-1) {
+        return -1;
+    }
+
+    return utf8_buf_len - outlen_left;
+}
+#endif
+
 /*!
  * @brief 文字コードがUTF-8の文字列をシステムの文字コードに変換する
  * @param utf8_str 変換するUTF-8の文字列へのポインタ
@@ -408,15 +480,8 @@ static bool utf8_to_sys(char *utf8_str, char *sys_str_buffer, size_t sys_str_buf
 {
 #if defined(EUC)
 
-    iconv_t cd = iconv_open("EUC-JP", "UTF-8");
-    size_t utf8_len = strlen(utf8_str) + 1; /* include termination character */
-    char *from = utf8_str;
-    int ret;
-
-    ms_to_jis_unicode(utf8_str);
-    ret = iconv(cd, &from, &utf8_len, &sys_str_buffer, &sys_str_buflen);
-    iconv_close(cd);
-    return (ret >= 0);
+    /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
+    return (utf8_to_euc(utf8_str, strlen(utf8_str) + 1, sys_str_buffer, sys_str_buflen) >= 0);
 
 #elif defined(SJIS) && defined(WINDOWS)
 
index 26d2b90..060e9cb 100644 (file)
@@ -14,4 +14,10 @@ void euc2sjis(char *str);
 byte codeconv(char *str);
 bool iskanji2(concptr s, int x);
 void guess_convert_to_system_encoding(char* strbuf, int buflen);
+
+#ifdef EUC
+int utf8_to_euc(char *utf8_str, size_t utf8_str_len, char *euc_buf, size_t euc_buf_len);
+int euc_to_utf8(const char *euc_str, size_t euc_str_len, char *utf8_buf, size_t utf8_buf_len);
+#endif
+
 #endif
index 2dd4019..de6fffd 100644 (file)
 #include "game-option/special-options.h"
 #include "io/exit-panic.h"
 #include "io/files-util.h"
+#include "locale/japanese.h"
 #include "main/sound-definitions-table.h"
 #include "main/sound-of-music.h"
 #include "system/angband.h"
  * Include the proper "header" file
  */
 #include <curses.h>
-#include <iconv.h>
 
 typedef struct term_data term_data;
 
@@ -193,8 +193,6 @@ struct term_data {
 #define MAX_TERM_DATA 4
 
 static term_data data[MAX_TERM_DATA];
-static iconv_t iconv_to_sys;
-static iconv_t iconv_to_gui;
 
 /*
  * Hack -- try to guess which systems use what commands
@@ -648,32 +646,6 @@ static void Term_nuke_gcu(term_type *t)
 }
 
 /*
- * Convert to EUC-JP
- */
-static void convert_to_sys(char *buf)
-{
-    size_t inlen = strlen(buf);
-    size_t outlen = inlen;
-    char tmp[outlen + 1];
-
-    char *inbuf = buf;
-    char *outbuf = tmp;
-    size_t res;
-    res = iconv(iconv_to_sys, 0, 0, 0, 0);
-    if (res == (size_t)-1)
-        return;
-    res = iconv(iconv_to_sys, &inbuf, &inlen, &outbuf, &outlen);
-    if (res == (size_t)-1)
-        return;
-    res = iconv(iconv_to_sys, 0, 0, &outbuf, &outlen);
-    if (res == (size_t)-1)
-        return;
-
-    outbuf[0] = '\0';
-    strcpy(buf, tmp);
-}
-
-/*
  * Push multiple keys reversal
  */
 static void term_string_push(char *buf)
@@ -726,8 +698,14 @@ static errr Term_xtra_gcu_event(int v)
         nodelay(stdscr, FALSE);
 
         *bp = '\0';
-        convert_to_sys(buf);
-        term_string_push(buf);
+#ifdef JP
+        char eucbuf[sizeof(buf)];
+        /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
+        if (utf8_to_euc(buf, strlen(buf) + 1, eucbuf, sizeof(eucbuf)) < 0) {
+            return (-1);
+        }
+#endif
+        term_string_push(_(eucbuf, buf));
     }
 
     /* Do not wait */
@@ -796,8 +774,14 @@ static errr Term_xtra_gcu_event(int v)
         }
 
         bp[0] = '\0';
-        convert_to_sys(buf);
-        term_string_push(buf);
+#ifdef JP
+        char eucbuf[sizeof(buf)];
+        /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
+        if (utf8_to_euc(buf, strlen(buf) + 1, eucbuf, sizeof(eucbuf)) < 0) {
+            return (-1);
+        }
+#endif
+        term_string_push(_(eucbuf, buf));
     }
 
     /* Do not wait */
@@ -1029,14 +1013,6 @@ static errr Term_text_gcu(int x, int y, int n, byte a, concptr s)
 {
     term_data *td = (term_data *)(Term->data);
 
-    char intext[n];
-    char text[80 * 3 + 1];
-    size_t inlen = n;
-    size_t outlen = sizeof(text);
-    char *inbuf = intext;
-    char *outbuf = text;
-    size_t res;
-
 #ifdef USE_NCURSES_ACS
     /* do we have colors + 16 ? */
     /* then call special routine for drawing special characters */
@@ -1046,24 +1022,6 @@ static errr Term_text_gcu(int x, int y, int n, byte a, concptr s)
     }
 #endif
 
-    /* Copy to char array because of iconv's warning by const char pointer */
-    memcpy(intext, s, (size_t)n);
-
-    /* Obtain a copy of the text */
-    res = iconv(iconv_to_gui, 0, 0, 0, 0);
-    if (res == (size_t)-1)
-        return (-1);
-    res = iconv(iconv_to_gui, &inbuf, &inlen, &outbuf, &outlen);
-    if (res == (size_t)-1)
-        return (-1);
-    res = iconv(iconv_to_gui, 0, 0, &outbuf, &outlen);
-    if (res == (size_t)-1)
-        return (-1);
-
-    if (outlen == 0)
-        return (-1);
-    *outbuf = '\0';
-
     /* Move the cursor and dump the string */
     wmove(td->win, y, x);
 
@@ -1073,8 +1031,15 @@ static errr Term_text_gcu(int x, int y, int n, byte a, concptr s)
         wattrset(td->win, colortable[a & 0x0F]);
 #endif
 
+#ifdef JP
+    char text[1024];
+    int text_len = euc_to_utf8(s, n, text, sizeof(text));
+    if (text_len < 0) {
+        return (-1);
+    }
+#endif
     /* Add the text */
-    waddstr(td->win, text);
+    waddnstr(td->win, _(text, s), _(text_len, n));
 
     /* Success */
     return (0);
@@ -1134,9 +1099,6 @@ static void hook_quit(concptr str)
 
     /* Exit curses */
     endwin();
-
-    iconv_close(iconv_to_sys);
-    iconv_close(iconv_to_gui);
 }
 
 /*
@@ -1159,12 +1121,6 @@ errr init_gcu(int argc, char *argv[])
     (void)argv;
 
     setlocale(LC_ALL, "");
-    iconv_to_sys = iconv_open("EUC-JP", "");
-    if (iconv_to_sys == (iconv_t)-1)
-        return (-1);
-    iconv_to_gui = iconv_open("", "EUC-JP");
-    if (iconv_to_gui == (iconv_t)-1)
-        return (-1);
 
     /* Build the "sound" path */
     path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound");
index a3de23a..d4f8058 100644 (file)
@@ -95,6 +95,7 @@
 #include "game-option/runtime-arguments.h"
 #include "game-option/special-options.h"
 #include "io/files-util.h"
+#include "locale/japanese.h"
 #include "locale/utf-8.h"
 #include "main/sound-definitions-table.h"
 #include "main/sound-of-music.h"
 #include <X11/Xatom.h>
 #endif /* __MAKEDEPEND__ */
 
-#include <iconv.h>
 #ifdef USE_XFT
 #include <X11/Xft/Xft.h>
 #endif
@@ -912,17 +912,13 @@ static errr Infofnt_text_std(int x, int y, concptr str, int len)
         }
 #endif
     } else {
-        iconv_t cd = iconv_open("UTF-8", "EUC-JP");
-        size_t inlen = len;
-        size_t outlen = len * 2;
-        char *kanji = malloc(outlen);
-        char *sp;
-        char *kp = kanji;
-        char sbuf[1024];
-        memcpy(sbuf, str, (size_t)len);
-        sp = sbuf;
-        iconv(cd, &sp, &inlen, &kp, &outlen);
-        iconv_close(cd);
+#ifdef JP
+        char utf8_buf[1024];
+        int utf8_len = euc_to_utf8(str, len, utf8_buf, sizeof(utf8_buf));
+        if (utf8_len < 0) {
+            return (-1);
+        }
+#endif
 
 #ifdef USE_XFT
         XftDraw *draw = Infowin->draw;
@@ -934,12 +930,11 @@ static errr Infofnt_text_std(int x, int y, concptr str, int len)
         r.height = Infofnt->hgt;
         XftDrawSetClipRectangles(draw, x, y - Infofnt->asc, &r, 1);
         XftDrawRect(draw, &Infoclr->bg, x, y - Infofnt->asc, Infofnt->wid * len, Infofnt->hgt);
-        Infofnt_text_std_xft_draw_str(x, y, kanji, kp);
+        Infofnt_text_std_xft_draw_str(x, y, _(utf8_buf, str), _(utf8_buf + utf8_len, str + len));
         XftDrawSetClip(draw, 0);
 #else
-        XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info, Infoclr->gc, x, y, kanji, kp - kanji);
+        XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info, Infoclr->gc, x, y, _(utf8_buf, str), _(utf8_len, len));
 #endif
-        free(kanji);
     }
 
     return (0);
@@ -1043,49 +1038,6 @@ struct x11_selection_type {
 
 static x11_selection_type s_ptr[1];
 
-// EUC-JP -> UTF-8 変換。
-// utf8_buf には十分なサイズがあると仮定している。
-// 出力文字列は0終端される。
-static void euc_to_utf8(const char *const euc, char *const utf8_buf, const size_t utf8_buf_len)
-{
-    static iconv_t cd = NULL;
-    if (!cd)
-        cd = iconv_open("UTF-8", "EUC-JP");
-
-    size_t inlen = strlen(euc);
-    size_t outlen = utf8_buf_len;
-    const char *in = euc;
-    char *out = utf8_buf;
-    // iconv は入力バッファを書き換えないのでキャストで const を外してよい
-    iconv(cd, (char **)&in, &inlen, &out, &outlen);
-
-    const size_t n = utf8_buf_len - outlen;
-    utf8_buf[n] = '\0';
-}
-
-/*
- * Convert to EUC-JP
- */
-#ifdef USE_XIM
-static void convert_to_euc(char *buf)
-{
-    size_t inlen = strlen(buf);
-    size_t outlen_orig = inlen + 1;
-    size_t outlen = outlen_orig;
-    char tmp[outlen];
-
-    iconv_t iconvd = iconv_open("EUC-JP", "UTF-8");
-    char *inbuf = buf;
-    char *outbuf = tmp;
-    iconv(iconvd, &inbuf, &inlen, &outbuf, &outlen);
-    iconv_close(iconvd);
-
-    size_t n = outlen_orig - outlen;
-    memcpy(buf, tmp, n);
-    buf[n] = '\0';
-}
-#endif
-
 // ゲーム側へキーを送る
 static void send_key(const char key)
 {
@@ -1151,8 +1103,14 @@ static void react_keypress(XKeyEvent *xev)
 
 #ifdef USE_XIM
     if (!valid_keysym) { /* XIMからの入力時のみ FALSE になる */
-        convert_to_euc(buf);
-        send_keys(buf);
+#ifdef JP
+        char euc_buf[sizeof(buf)];
+        /* strlen + 1 を渡して文字列終端('\0')を含めて変換する */
+        if (utf8_to_euc(buf, strlen(buf) + 1, euc_buf, sizeof(euc_buf)) < 0) {
+            return;
+        }
+#endif
+        send_keys(_(euc_buf, buf));
         return;
     }
 #endif
@@ -1526,10 +1484,13 @@ static bool paste_x11_send_text(XSelectionRequestEvent *rq)
 
         buf[l] = '\0';
 
+#ifdef JP
         char utf8_buf[2048];
-        euc_to_utf8(buf, utf8_buf, sizeof(utf8_buf));
-
-        XChangeProperty(DPY, rq->requestor, rq->property, xa_utf8, 8, PropModeAppend, (unsigned char *)utf8_buf, (int)strlen(utf8_buf));
+        const int len = euc_to_utf8(buf, l, utf8_buf, sizeof(utf8_buf));
+#endif
+        if (_(len, l) > 0) {
+            XChangeProperty(DPY, rq->requestor, rq->property, xa_utf8, 8, PropModeAppend, (unsigned char *)_(utf8_buf, buf), _(len, l));
+        }
     }
 
     return TRUE;