• R/O
  • SSH
  • HTTPS

ttssh2: Commit


Commit MetaInfo

Revision7462 (tree)
Time2019-03-10 02:32:42
Authorzmatsuo

Log Message

unicode関連をcodeconv.cに集めた
CP932へ/からの変換を関数に分離(UTF32ToCP932(), UTF32ToCP932())
unicodeからDEC特殊文字変換を関数に分離(UTF32ToDecSp())
SJIS2UTF8() (内部コードからUTF-8へ出力)を language.c から ttcmn.c に移動
_WideCharToMultiByte(), _MultiByteToWideChar() の変換した文字数の戻り値修正
UTF32ToMBCP()追加
UTF32_CP932()追加
MBCPToUTF32()追加
WideCharToUTF8(), WideCharToCP932() の仕様を変更
変換テーブルとWindows APIをつかったコード変換の優先順位を変更できるようにした

Change Summary

Incremental Difference

--- trunk/teraterm/common/codeconv.cpp (revision 7461)
+++ trunk/teraterm/common/codeconv.cpp (revision 7462)
@@ -26,14 +26,21 @@
2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2727 */
2828
29+/* unicode関連の文字コード変換 */
30+
2931 #include <windows.h>
3032 #include <string.h>
33+#include <assert.h>
3134 #include <crtdbg.h>
3235 #if (defined(_MSC_VER) && (_MSC_VER >= 1600)) || !defined(_MSC_VER)
3336 #include <stdint.h>
3437 #endif
38+#include "codemap.h"
3539 #include "codeconv.h"
3640
41+// cp932変換時、Windows API より Tera Term の変換テーブルを優先する
42+//#define PRIORITY_CP932_TABLE
43+
3744 #if defined(_MSC_VER) && (_MSC_VER < 1600)
3845 typedef unsigned char uint8_t;
3946 typedef unsigned short uint16_t;
@@ -47,12 +54,158 @@
4754 #define _wcsdup(s) _wcsdup_dbg((s), _NORMAL_BLOCK, __FILE__, __LINE__)
4855 #endif
4956
57+/*
58+ * 見つからない場合は 0 を返す
59+ */
60+static unsigned short _ConvertUnicode(unsigned short code, const codemap_t *table, int tmax)
61+{
62+ int low, mid, high;
63+ unsigned short result;
64+
65+ low = 0;
66+ high = tmax - 1;
67+ result = 0; // convert error
68+
69+ // binary search
70+ while (low < high) {
71+ mid = (low + high) / 2;
72+ if (table[mid].from_code < code) {
73+ low = mid + 1;
74+ } else {
75+ high = mid;
76+ }
77+ }
78+
79+ if (table[low].from_code == code) {
80+ result = table[low].to_code;
81+ }
82+
83+ return (result);
84+}
85+
86+static int IsHighSurrogate(wchar_t u16)
87+{
88+ return 0xd800 <= u16 && u16 < 0xdc00;
89+}
90+
91+static int IsLowSurrogate(wchar_t u16)
92+{
93+ return 0xdc00 <= u16 && u16 < 0xe000;
94+}
95+
5096 /**
51- * UTF-32 から UTF-8 へ変換する
97+ * 1文字として扱うために、必要なキャラクタ数を得る
98+ * @retval 0 文字として扱えない(文字コードがおかしい)
99+ * @retval 1 1キャラクタで1文字として扱える
100+ * @retval 2 2キャラクタで1文字として扱える
101+ */
102+#if 0
103+static size_t UTF16GetCharCount(const wchar_t *wstr_ptr, size_t wstr_len)
104+{
105+ wchar_t u16;
106+ assert(wstr_ptr != NULL);
107+ if (wstr_len == 0) {
108+ return 0;
109+ }
110+ u16 = *wstr_ptr++;
111+ if (IsHighSurrogate(u16)) {
112+ if (wstr_len >= 2) {
113+ const wchar_t u16_lo = *wstr_ptr++;
114+ if (IsLowSurrogate(u16_lo)) {
115+ return 2;
116+ } else {
117+ return 0;
118+ }
119+ } else {
120+ return 0;
121+ }
122+ } else if (IsLowSurrogate(u16)) {
123+ return 0;
124+ }
125+ return 1;
126+}
127+#endif
128+
129+/**
130+ * code page の mulit byte 文字を UTF-32へ変換する
131+ * @param KCode マルチバイトの文字コード(0x0000-0xffff)
132+ * @param CoePage マルチバイトのコードページ
133+ * @retval unicode(UTF-32文字コード)
134+ */
135+unsigned int MBCPToUTF32(unsigned short KCode, int CodePage)
136+{
137+ unsigned int c;
138+
139+ if (CodePage == 932) {
140+ c = CP932ToUTF32(KCode);
141+ } else {
142+ char buf[3];
143+ wchar_t wchar;
144+ int ret;
145+ int len = 0;
146+ if (KCode < 0x100) {
147+ buf[0] = KCode & 0xff;
148+ len = 1;
149+ } else {
150+ buf[0] = KCode >> 8;
151+ buf[1] = KCode & 0xff;
152+ len = 2;
153+ }
154+ ret = MultiByteToWideChar(CodePage, MB_ERR_INVALID_CHARS, buf, len, &wchar, 1);
155+ if (ret <= 0) {
156+ c = 0;
157+ } else {
158+ c = (unsigned int)wchar;
159+ }
160+ }
161+ return c;
162+}
163+
164+/**
165+ * wchar_t文字列からunicode(UTF-32)を1文字取り出す
166+ * @retval 0 文字として扱えない(文字コードがおかしい)
167+ * @retval 1 1キャラクタで1文字として扱える
168+ * @retval 2 2キャラクタで1文字として扱える
169+ */
170+size_t UTF16ToUTF32(const wchar_t *wstr_ptr, size_t wstr_len, unsigned int *u32)
171+{
172+ assert(wstr_ptr != NULL);
173+ if (wstr_len == 0) {
174+ *u32 = 0;
175+ return 0;
176+ }
177+ const wchar_t u16 = *wstr_ptr++;
178+ // サロゲート high?
179+ if (IsHighSurrogate(u16)) {
180+ if (wstr_len >= 2) {
181+ const wchar_t u16_lo = *wstr_ptr++;
182+ if (IsLowSurrogate(u16_lo)) {
183+ // サロゲートペア デコード
184+ *u32 = 0x10000 + (u16 - 0xd800) * 0x400 + (u16_lo - 0xdc00);
185+ return 2;
186+ } else {
187+ *u32 = 0;
188+ return 0;
189+ }
190+ } else {
191+ *u32 = 0;
192+ return 0;
193+ }
194+ } else if (IsLowSurrogate(u16)) {
195+ *u32 = 0;
196+ return 0;
197+ } else {
198+ *u32 = u16;
199+ return 1;
200+ }
201+}
202+
203+/**
204+ * UTF-32文字 から UTF-8 へ変換する
52205 * @param[in] u32 変換するUTF-32
53206 * @param[in,out] u8_ptr 変換後UTF-8文字列出力先(NULLのとき出力しない)
54207 * @param[in] u8_len UTF-8出力先文字数(バッファ長,byte数)
55- * @retval 使用したutf8文字数(byte数)
208+ * @retval 出力したutf8文字数(byte数)
56209 * 0=エラー
57210 */
58211 size_t UTF32ToUTF8(uint32_t u32, char *u8_ptr_, size_t u8_len)
@@ -113,7 +266,7 @@
113266 * @param[in] u8_len UTF-8文字列長さ
114267 * @param[out] u32 変換したUTF-32文字
115268 * @retval 使用したUTF-8文字数(byte数)
116- * 0=エラー
269+ * 0=エラー(変換できなかった)
117270 */
118271 size_t UTF8ToUTF32(const char *u8_ptr_, size_t u8_len, uint32_t *u32_)
119272 {
@@ -191,33 +344,286 @@
191344 return u8_in;
192345 }
193346
194-// WideCharToMultiByteのUTF8特化版
195-int WideCharToUTF8(const wchar_t *wstr_ptr, int wstr_len, char *u8_ptr, int u8_len)
347+/**
348+ * UTF-32 から UTF-16 へ変換する
349+ * @param[in] u32 変換するUTF-32
350+ * @param[in,out] wstr_ptr 変換後UTF-16文字列出力先(NULLのとき出力しない)
351+ * @param[in] wstr_len UTF-16出力先文字数(文字数,sizeof(wchar_t)*wstr_len bytes)
352+ * @retval 出力したUTF-16文字数(sizeof(wchar_t)倍するとbyte数)
353+ * 0=エラー(変換できなかった)
354+ */
355+size_t UTF32ToUTF16(uint32_t u32, wchar_t *wstr_ptr, size_t wstr_len)
196356 {
197- int u8_out_sum = 0;
198- if (u8_ptr == NULL) {
199- u8_len = 4;
357+ size_t u16_out;
358+ if (u32 < 0x10000) {
359+ if (wstr_len >= 1) {
360+ if (wstr_ptr != NULL) {
361+ *wstr_ptr++ = (uint16_t)u32;
362+ }
363+ u16_out = 1;
364+ } else {
365+ u16_out = 0;
366+ }
367+ } else if (u32 <= 0x10ffff) {
368+ if (wstr_len >= 2) {
369+ if (wstr_ptr != NULL) {
370+ // サロゲート エンコード
371+ *wstr_ptr++ = uint16_t((u32 - 0x10000) / 0x400) + 0xd800;
372+ *wstr_ptr++ = uint16_t((u32 - 0x10000) % 0x400) + 0xdc00;
373+ }
374+ u16_out = 2;
375+ } else {
376+ u16_out = 0;
377+ }
200378 } else {
201- if (u8_len == 0) {
202- return 0;
379+ u16_out = 0;
380+ }
381+ return u16_out;
382+}
383+
384+/**
385+ * UTF-32文字をCP932文字(Shift_JIS) 1文字へ変換する
386+ * @retval 使用したCP932文字
387+ * 0=エラー(変換できなかった)
388+ */
389+unsigned short UTF32_CP932(unsigned int u32)
390+{
391+#include "../teraterm/uni2sjis.map" // mapUnicodeToSJIS[]
392+ char mbstr[2];
393+ unsigned short mb;
394+ DWORD mblen;
395+ wchar_t u16_str[2];
396+ size_t u16_len;
397+
398+ if (u32 < 0x80) {
399+ return (unsigned short)u32;
400+ }
401+
402+#if defined(PRIORITY_CP932_TABLE)
403+ if (u32 < 0x10000) {
404+ wchar_t u16 = (wchar_t)u32;
405+ // Tera Termの変換テーブルで Unicode -> Shift_JISへ変換
406+ mb = _ConvertUnicode(u16, mapUnicodeToSJIS, _countof(mapUnicodeToSJIS));
407+ if (mb != 0) {
408+ // 変換できた
409+ return mb;
203410 }
204411 }
205- if (wstr_len < 0) {
412+#endif
413+ u16_len = UTF32ToUTF16(u32, u16_str, 2);
414+ if (u16_len == 0) {
415+ return 0;
416+ }
417+ mblen = WideCharToMultiByte(932, 0, u16_str, (int)u16_len, mbstr, 2, NULL, NULL);
418+ switch (mblen) {
419+ case 0:
420+ case 1:
421+ default:
422+ if (mblen == 0 || mbstr[0] == '?') {
423+ goto next_convert;
424+ } else {
425+ mb = (unsigned char)mbstr[0];
426+ return mb;
427+ }
428+ case 2:
429+ if (mbstr[0] == '?' && mbstr[1] == '?') {
430+ // 2byte出力 && "??" の場合は変換できなかった
431+ goto next_convert;
432+ }
433+ mb = (((unsigned char)mbstr[0]) << 8) | (unsigned char)mbstr[1];
434+ return mb;
435+ }
436+
437+next_convert:
438+#if !defined(PRIORITY_CP932_TABLE)
439+ if (u32 < 0x10000) {
440+ wchar_t u16 = (wchar_t)u32;
441+ // Tera Termの変換テーブルで Unicode -> Shift_JISへ変換
442+ mb = _ConvertUnicode(u16, mapUnicodeToSJIS, _countof(mapUnicodeToSJIS));
443+ if (mb != 0) {
444+ // 変換できた
445+ return mb;
446+ }
447+ }
448+#endif
449+ return 0;
450+}
451+
452+/**
453+ * CP932文字(Shift_JIS) 1文字からUTF-32へ変換する
454+ * @param[in] cp932 CP932文字
455+ * @retval 変換したUTF-32文字数
456+ * 0=エラー(変換できなかった)
457+ */
458+unsigned int CP932ToUTF32(unsigned short cp932)
459+{
460+#include "../ttpcmn/sjis2uni.map" // mapSJISToUnicode[]
461+ wchar_t wchar;
462+ int ret;
463+ unsigned int u32;
464+ unsigned char buf[2];
465+ int len = 0;
466+
467+#if defined(PRIORITY_CP932_TABLE)
468+ u32 = _ConvertUnicode(cp932, mapSJISToUnicode, sizeof(mapSJISToUnicode)/sizeof(mapSJISToUnicode[0]));
469+ if (u32 != 0) {
470+ return u32;
471+ }
472+#endif
473+ if (cp932 < 0x100) {
474+ buf[0] = cp932 & 0xff;
475+ len = 1;
476+ } else {
477+ buf[0] = cp932 >> 8;
478+ buf[1] = cp932 & 0xff;
479+ len = 2;
480+ }
481+ ret = MultiByteToWideChar(932, MB_ERR_INVALID_CHARS, (char *)buf, len, &wchar, 1);
482+ if (ret <= 0) {
483+ // MultiByteToWideChar()が変換失敗
484+#if !defined(PRIORITY_CP932_TABLE)
485+ u32 = _ConvertUnicode(cp932, mapSJISToUnicode, sizeof(mapSJISToUnicode)/sizeof(mapSJISToUnicode[0]));
486+ // テーブルにもなかった場合 c = 0(変換失敗時)
487+#else
488+ u32 = 0;
489+#endif
490+ } else {
491+ u32 = (unsigned int)wchar;
492+ }
493+
494+ return u32;
495+}
496+
497+/**
498+ * UnicodeからDEC特殊文字へ変換
499+ * @param u32 UTF-32文字コード
500+ * @return 下位8bit DEC特殊文字コード
501+ * 上位8bit 文字コード種別 (1,2,4)
502+ * file://../../doc/ja/html/setup/teraterm-term.html 参照
503+ * 0 変換できなかった
504+ */
505+unsigned short UTF32ToDecSp(unsigned int u32)
506+{
507+#include "../teraterm/unisym2decsp.map" // mapUnicodeSymbolToDecSp[]
508+ unsigned short cset;
509+ if (u32 > 0x10000) {
510+ cset = 0;
511+ } else {
512+ const unsigned short u16 = (unsigned short)u32;
513+ cset = _ConvertUnicode(u16, mapUnicodeSymbolToDecSp, _countof(mapUnicodeSymbolToDecSp));
514+ }
515+ return cset;
516+}
517+
518+/**
519+ * UTF-32 から CP932 へ変換する
520+ * @param[in] u32 変換するUTF-32
521+ * @param[in,out] mb_ptr 変換後CP932文字列出力先(NULLのとき出力しない)
522+ * @param[in] mb_len CP932出力先文字数(文字数,sizeof(wchar_t)*wstr_len bytes)
523+ * @retval 出力したCP932文字数(byte数)
524+ * 0=エラー(変換できなかった)
525+ */
526+size_t UTF32ToCP932(uint32_t u32, char *mb_ptr, size_t mb_len)
527+{
528+ size_t cp932_out;
529+ const uint16_t cp932 = UTF32_CP932(u32);
530+ if (cp932 == 0 && u32 != 0) {
531+ return 0;
532+ }
533+ if (mb_ptr == NULL) {
534+ mb_len = 2;
535+ }
536+ if (cp932 < 0x100) {
537+ if (mb_len >= 1) {
538+ if (mb_ptr != NULL) {
539+ *mb_ptr = cp932 & 0xff;
540+ }
541+ cp932_out = 1;
542+ } else {
543+ cp932_out = 0;
544+ }
545+ } else {
546+ if (mb_len >= 2) {
547+ if (mb_ptr != NULL) {
548+ mb_ptr[0] = (cp932 >> 8) & 0xff;
549+ mb_ptr[1] = cp932 & 0xff;
550+ }
551+ cp932_out = 2;
552+ } else {
553+ cp932_out = 0;
554+ }
555+ }
556+ return cp932_out;
557+}
558+
559+size_t UTF32ToMBCP(unsigned int u32, int code_page, char *mb_ptr, size_t mb_len)
560+{
561+ wchar_t u16_str[2];
562+ size_t u16_len;
563+ u16_len = UTF32ToUTF16(u32, u16_str, 2);
564+ if (u16_len == 0) {
565+ return 0;
566+ }
567+ mb_len = WideCharToMultiByte(code_page, 0, u16_str, u16_len, mb_ptr, mb_len, NULL, NULL);
568+ if (mb_len == 1 && mb_ptr[0] == '?' && u32 != '?') {
569+ // 変換できなかったとき、戻り値=1, 文字[0]='?' を返してくる
570+ mb_len = 0;
571+ }
572+ return mb_len;
573+}
574+
575+/**
576+ * wchar_t(UTF-16)文字列をマルチバイトに変換する
577+ *
578+ * @param[in] *wstr_ptr wchar_t文字列
579+ * @param[in,out] *wstr_len wchar_t文字列長
580+ * NULLまたは0のとき自動、L'\0'でターミネートすること)
581+ * NULL以外のとき入力した文字数を返す
582+ * @param[in] *mb_ptr 変換した文字列を収納するポインタ
583+ * (NULLのとき変換せずに文字数をカウントする)
584+ * @param[in,out] *mb_len 変換した文字列を収納できるサイズ,byte数,
585+ * mb_ptrがNULLのとき出力可能サイズは不要
586+ * 変換したマルチバイト文字列の長さを返す
587+ * L'\0'を変換したら'\0'も含む
588+ * mb_ptrがNULLのときでも長さは返す
589+ * @param[in] UTF32ToMB UTF32をマルチバイトに変換する関数へのポインタ
590+ */
591+static void WideCharToMB(const wchar_t *wstr_ptr, size_t *wstr_len_,
592+ char *mb_ptr, size_t *mb_len_,
593+ size_t (*UTF32ToMB)(uint32_t u32, char *mb_ptr, size_t mb_len))
594+{
595+ size_t wstr_len;
596+ size_t mb_len;
597+ size_t mb_out_sum = 0;
598+ size_t wstr_in = 0;
599+
600+ assert(wstr_ptr != NULL);
601+ if (mb_ptr == NULL) {
602+ // 変換文字列を書き出さない
603+ mb_len = 4; // 1文字4byteには収まるはず
604+ } else {
605+ mb_len = *mb_len_;
606+ }
607+ if (wstr_len_ == NULL || *wstr_len_ == 0) {
206608 wstr_len = (int)wcslen(wstr_ptr) + 1;
609+ } else {
610+ wstr_len = *wstr_len_;
207611 }
208612
209- while(u8_len > 0 && wstr_len > 0) {
613+ while(mb_len > 0 && wstr_len > 0) {
210614 const wchar_t u16 = *wstr_ptr++;
211615 uint32_t u32 = u16;
212- size_t u8_out;
616+ size_t mb_out;
213617 wstr_len--;
618+ wstr_in++;
214619 // サロゲート high?
215- if (0xd800 <= u16 && u16 < 0xdc00) {
620+ if (IsHighSurrogate(u16)) {
216621 if (wstr_len >= 1) {
217622 const wchar_t u16_lo = *wstr_ptr++;
218623 wstr_len--;
624+ wstr_in++;
219625 // サロゲート low?
220- if (0xdc00 <= u16_lo && u16_lo < 0xe000) {
626+ if (IsLowSurrogate(u16_lo)) {
221627 // サロゲートペア デコード
222628 u32 = 0x10000 + (u16 - 0xd800) * 0x400 + (u16_lo - 0xdc00);
223629 } else {
@@ -224,34 +630,75 @@
224630 goto unknown_code;
225631 }
226632 } else {
227- unknown_code:
228- if (u8_ptr != NULL) {
229- *u8_ptr++ = '?';
230- }
231- u8_out = 1;
232- goto loop_next;
633+ goto unknown_code;
233634 }
234635 }
235- u8_out = UTF32ToUTF8(u32, u8_ptr, u8_len);
236- if (u8_out == 0) {
237- goto unknown_code;
636+ mb_out = UTF32ToMB(u32, mb_ptr, mb_len);
637+ if (mb_out == 0) {
638+ unknown_code:
639+ if (mb_ptr != NULL) {
640+ // 変換できなかった場合
641+ *mb_ptr++ = '?';
642+ }
643+ mb_out = 1;
238644 }
239- loop_next:
240- u8_out_sum += u8_out;
241- if (u8_ptr != NULL) {
242- u8_ptr += u8_out;
243- u8_len -= u8_out;
645+ mb_out_sum += mb_out;
646+ if (mb_ptr != NULL) {
647+ mb_ptr += mb_out;
648+ mb_len -= mb_out;
244649 }
245650 }
246- return u8_out_sum;
651+
652+ if (wstr_len_ != NULL) {
653+ *wstr_len_ = wstr_in;
654+ }
655+ *mb_len_ = mb_out_sum;
247656 }
248657
658+// WideCharToMultiByteのUTF8特化版
659+void WideCharToUTF8(const wchar_t *wstr_ptr, size_t *wstr_len, char *u8_ptr, size_t *u8_len)
660+{
661+ WideCharToMB(wstr_ptr, wstr_len, u8_ptr, u8_len, UTF32ToUTF8);
662+}
663+
664+void WideCharToCP932(const wchar_t *wstr_ptr, size_t *wstr_len, char *cp932_ptr, size_t *cp932_len)
665+{
666+ WideCharToMB(wstr_ptr, wstr_len,
667+ cp932_ptr, cp932_len,
668+ UTF32ToCP932);
669+}
670+
671+void WideCharToMBCP(const wchar_t *wstr_ptr, size_t *wstr_len, char *mb_ptr, size_t *mb_len,
672+ int code_page)
673+{
674+ size_t (*utf32_to_mb)(uint32_t u32, char *mb_ptr, size_t mb_len);
675+ switch (code_page) {
676+ case CP_UTF8:
677+ utf32_to_mb = UTF32ToUTF8;
678+ break;
679+ case 932:
680+ utf32_to_mb = UTF32ToCP932;
681+ break;
682+ default:
683+ *mb_len = 0;
684+ return;
685+ }
686+
687+ WideCharToMB(wstr_ptr, wstr_len,
688+ mb_ptr, mb_len,
689+ utf32_to_mb);
690+}
691+
249692 // MultiByteToWideCharのUTF8特化版
250-int UTF8ToWideChar(const char *u8_ptr, int u8_len, wchar_t *wstr_ptr, int wstr_len)
693+int UTF8ToWideChar(const char *u8_ptr, int u8_len_, wchar_t *wstr_ptr, int wstr_len_)
251694 {
695+ size_t u8_len;
696+ size_t wstr_len = wstr_len_;
252697 size_t u16_out_sum = 0;
253- if (u8_len < 0) {
698+ if (u8_len_ < 0) {
254699 u8_len = strlen(u8_ptr) + 1;
700+ } else {
701+ u8_len = u8_len_;
255702 }
256703 if (wstr_ptr == NULL) {
257704 wstr_len = 1;
@@ -295,16 +742,18 @@
295742 }
296743 u16_out_sum += u16_out;
297744 }
298- return u16_out_sum;
745+ return (int)u16_out_sum;
299746 }
300747
301748 /**
302749 * wchar_t文字列をマルチバイト文字列へ変換
303750 * @param[in] *wstr_ptr wchar_t文字列
304- * @param[in] wstr_len wchar_t文字列長(0のとき自動)
751+ * @param[in] wstr_len wchar_t文字列長(0のとき自動、自動のときはL'\0'でターミネートすること)
305752 * @param[in] code_page 変換先コードページ
306- * @param[out] *mb_len_ mb文字列長(NULLのとき内部エラー)
753+ * @param[out] *mb_len_ 変換した文字列長,byte数,L'\0'を変換したら'\0'も含む
754+ * (NULLのとき文字列長を返さない)
307755 * @retval mb文字列へのポインタ(NULLの時変換エラー)
756+ * 使用後 free() すること
308757 */
309758 char *_WideCharToMultiByte(const wchar_t *wstr_ptr, size_t wstr_len, int code_page, size_t *mb_len_)
310759 {
@@ -317,9 +766,11 @@
317766 wstr_len = wcslen(wstr_ptr) + 1;
318767 }
319768 int len;
320- if (code_page == CP_UTF8) {
321- len = WideCharToUTF8(wstr_ptr, (DWORD)wstr_len,
322- NULL, 0);
769+ if (code_page == CP_UTF8 || code_page == 932) {
770+ size_t wl = wstr_len;
771+ size_t ml;
772+ WideCharToMBCP(wstr_ptr, &wl, NULL, &ml, code_page);
773+ len = ml;
323774 } else {
324775 len = ::WideCharToMultiByte(code_page, flags,
325776 wstr_ptr, (DWORD)wstr_len,
@@ -333,9 +784,11 @@
333784 if (mb_ptr == NULL) {
334785 return NULL;
335786 }
336- if (code_page == CP_UTF8) {
337- len = WideCharToUTF8(wstr_ptr, (DWORD)wstr_len,
338- mb_ptr, len);
787+ if (code_page == CP_UTF8 || code_page == 932) {
788+ size_t wl = wstr_len;
789+ size_t ml = len;
790+ WideCharToMBCP(wstr_ptr, &wl, mb_ptr, &ml, code_page);
791+ len = ml;
339792 } else {
340793 len = ::WideCharToMultiByte(code_page, flags,
341794 wstr_ptr, (DWORD)wstr_len,
@@ -347,7 +800,8 @@
347800 return NULL;
348801 }
349802 if (mb_len_ != NULL) {
350- *mb_len_ = len - 1;
803+ // 変換した文字列数(byte数)を返す
804+ *mb_len_ = len;
351805 }
352806 return mb_ptr;
353807 }
@@ -355,10 +809,12 @@
355809 /**
356810 * マルチバイト文字列をwchar_t文字列へ変換
357811 * @param[in] *str_ptr mb(char)文字列
358- * @param[in] str_len mb(char)文字列長(0のとき自動)
812+ * @param[in] str_len mb(char)文字列長(0のとき自動、自動のときは'\0'でターミネートすること)
359813 * @param[in] code_page 変換元コードページ
360- * @param[out] *w_len_ wchar_t文字列長
361- * @retval mb文字列へのポインタ(NULLの時変換エラー)
814+ * @param[out] *w_len_ wchar_t文字列長,wchar_t数,'\0'を変換したらL'\0'も含む
815+ * (NULLのとき文字列長を返さない)
816+ * @retval wchar_t文字列へのポインタ(NULLの時変換エラー)
817+ * 使用後 free() すること
362818 */
363819 wchar_t *_MultiByteToWideChar(const char *str_ptr, size_t str_len, int code_page, size_t *w_len_)
364820 {
@@ -402,7 +858,8 @@
402858 return NULL;
403859 }
404860 if (w_len_ != NULL) {
405- *w_len_ = len - 1;
861+ // 変換した文字列数(wchar_t数)を返す
862+ *w_len_ = len;
406863 }
407864 return wstr_ptr;
408865 }
--- trunk/teraterm/common/codeconv.h (revision 7461)
+++ trunk/teraterm/common/codeconv.h (revision 7462)
@@ -35,12 +35,24 @@
3535 #endif
3636
3737
38-// 1char
38+// simple code convert
39+unsigned int CP932ToUTF32(unsigned short cp932);
40+unsigned short UTF32ToDecSp(unsigned int u32);
41+unsigned int MBCPToUTF32(unsigned short KCode, int CodePage);
42+unsigned short UTF32_CP932(unsigned int u32);
43+
44+// 1char ToUTF32
45+size_t UTF8ToUTF32(const char *u8_ptr_, size_t u8_len, unsigned int *u32_);
46+size_t UTF16ToUTF32(const wchar_t *wstr_ptr, size_t wstr_len, unsigned int *u32);
47+// 1char UTF32To
48+size_t UTF32ToUTF16(unsigned int u32, wchar_t *wstr_ptr, size_t wstr_len);
3949 size_t UTF32ToUTF8(unsigned int u32, char *u8_ptr, size_t u8_len);
40-size_t UTF8ToUTF32(const char *u8_ptr_, size_t u8_len, unsigned int *u32_);
50+size_t UTF32ToCP932(unsigned int u32, char *mb_ptr, size_t mb_len);
51+size_t UTF32ToMBCP(unsigned int u32, int code_page, char *mb_ptr, size_t mb_len);
4152
4253 // MultiByteToWideChar() wrappers
43-int WideCharToUTF8(const wchar_t *wstr_ptr, int wstr_len, char *u8_ptr, int u8_len);
54+void WideCharToUTF8(const wchar_t *wstr_ptr, size_t *wstr_len, char *u8_ptr, size_t *u8_len);
55+void WideCharToCP932(const wchar_t *wstr_ptr, size_t *wstr_len, char *cp932_ptr, size_t *cp932_len);
4456 int UTF8ToWideChar(const char *u8_ptr, int u8_len, wchar_t *wstr_ptr, int wstr_len);
4557
4658 // API wrappers
--- trunk/teraterm/teraterm/CMakeLists.txt (revision 7461)
+++ trunk/teraterm/teraterm/CMakeLists.txt (revision 7462)
@@ -31,7 +31,12 @@
3131 ../common/i18n.h
3232 ../common/dllutil.cpp
3333 ../common/dllutil.h
34- ../ttpcmn/language.h
34+ ../common/codeconv.h
35+ ../common/codeconv.cpp
36+ #
37+ ../teraterm/unisym2decsp.map
38+ ../teraterm/uni2sjis.map
39+ ../ttpcmn/sjis2uni.map
3540 )
3641
3742 source_group(
@@ -102,8 +107,6 @@
102107 WSAAsyncGetAddrInfo.c
103108 WSAAsyncGetAddrInfo.h
104109 #
105- uni2sjis.map
106- unisym2decsp.map
107110 uni_combining.map
108111 #
109112 teraterm.manifest
--- trunk/teraterm/teraterm/vtterm.c (revision 7461)
+++ trunk/teraterm/teraterm/vtterm.c (revision 7462)
@@ -52,7 +52,8 @@
5252 #include "telnet.h"
5353 #include "ttime.h"
5454 #include "clipboar.h"
55-#include "../ttpcmn/language.h"
55+#include "codeconv.h"
56+#include "codeconv.h"
5657
5758 #include "vtterm.h"
5859
@@ -5408,13 +5409,6 @@
54085409 }
54095410
54105411 //
5411-// UTF-8
5412-//
5413-#include "uni2sjis.map"
5414-#include "unisym2decsp.map"
5415-
5416-
5417-//
54185412 // Unicode Combining Character Support
54195413 //
54205414 #include "uni_combining.map"
@@ -5467,17 +5461,22 @@
54675461 return (index);
54685462 }
54695463
5470-// unicode(UTF-16,wchar_t)をバッファへ書き込む
5464+// unicode(UTF-32,wchar_t)をバッファへ書き込む
54715465 static void UnicodeToCP932(unsigned int code)
54725466 {
5473- wchar_t wchar = (wchar_t)code;
5467+ wchar_t wchar;
54745468 int ret;
54755469 char mbchar[2];
54765470 unsigned short cset;
54775471
5472+ if (code >= 0x10000) {
5473+ goto unknown;
5474+ }
5475+ wchar = (wchar_t)code;
5476+
54785477 // UnicodeからDEC特殊文字へのマッピング
54795478 if (ts.UnicodeDecSpMapping) {
5480- cset = ConvertUnicode(wchar, mapUnicodeSymbolToDecSp, MAPSIZE(mapUnicodeSymbolToDecSp));
5479+ cset = UTF32ToDecSp(wchar);
54815480 if (((cset >> 8) & ts.UnicodeDecSpMapping) != 0) {
54825481 PutDecSp(cset & 0xff);
54835482 return;
@@ -5485,7 +5484,24 @@
54855484 }
54865485
54875486 // Unicode -> 内部コード(ts.CodePage)へ変換して出力
5488- ret = WideCharToMultiByte(ts.CodePage, 0, &wchar, 1, mbchar, 2, NULL, NULL);
5487+ if (ts.CodePage == 932) {
5488+ ret = (int)UTF16ToCP932(&wchar, 1, &cset);
5489+ if (ret == 0) {
5490+ // 変換できなかった
5491+ ;
5492+ } else if (cset < 0x100) {
5493+ // 1byte文字
5494+ mbchar[0] = (char)cset;
5495+ ret = 1;
5496+ } else {
5497+ // 2byte文字
5498+ mbchar[0] = (char)(cset >> 8);
5499+ mbchar[1] = (char)(cset & 0xff);
5500+ ret = 2;
5501+ }
5502+ } else {
5503+ ret = WideCharToMultiByte(ts.CodePage, 0, &wchar, 1, mbchar, 2, NULL, NULL);
5504+ }
54895505 if (ret == 1 && mbchar[0] == '?' && code != '?') {
54905506 // 変換できなかったとき、ret=1, '?' を返してくる
54915507 ret = 0;
@@ -5492,17 +5508,7 @@
54925508 }
54935509 switch (ret) {
54945510 case 0:
5495- if (ts.CodePage == 932) {
5496- // CP932
5497- // U+301Cなどは変換できない。Unicode -> Shift_JISへ変換してみる。
5498- cset = ConvertUnicode(code, mapUnicodeToSJIS, MAPSIZE(mapUnicodeToSJIS));
5499- if (cset != 0) {
5500- Kanji = cset & 0xff00;
5501- PutKanji(cset & 0x00ff);
5502- return;
5503- }
5504- }
5505-
5511+ unknown:
55065512 PutChar('?');
55075513 if (ts.UnknownUnicodeCharaAsWide) {
55085514 PutChar('?');
--- trunk/teraterm/ttpcmn/language.c (revision 7461)
+++ trunk/teraterm/ttpcmn/language.c (revision 7462)
@@ -35,9 +35,8 @@
3535 #include <locale.h>
3636
3737 #include "language.h"
38-#include "codeconv.h"
39-#include "sjis2uni.map"
4038
39+// exportされている
4140 unsigned short ConvertUnicode(unsigned short code, const codemap_t *table, int tmax)
4241 {
4342 int low, mid, high;
@@ -64,69 +63,6 @@
6463 return (result);
6564 }
6665
67-// 内部コード(CodePage)をUTF8へ変換する
68-unsigned int PASCAL SJIS2UTF8(WORD KCode, int *byte, int CodePage)
69-{
70- wchar_t wchar;
71- int ret;
72- unsigned int code;
73- unsigned int c, c1, c2, c3;
74- unsigned char buf[3];
75- unsigned char KCode_h;
76- int len = 0;
77-
78- // 内部コード(CodePage)からUTF-16LEへ変換する
79- KCode_h = (unsigned char)(KCode >> 8);
80- if (KCode_h != 0) {
81- buf[len++] = KCode_h;
82- }
83- buf[len++] = KCode & 0xff;
84- ret = MultiByteToWideChar(CodePage, MB_ERR_INVALID_CHARS, buf, len, &wchar, 1);
85- if (ret <= 0) {
86- // 変換失敗
87- unsigned short cset = 0;
88- if (CodePage == 932) {
89- // CP932
90- cset = ConvertUnicode(KCode, mapSJISToUnicode, sizeof(mapSJISToUnicode)/sizeof(mapSJISToUnicode[0]));
91- }
92- if (cset == 0) {
93- c = 0xfffd; // U+FFFD: Replacement Character
94- } else {
95- c = cset;
96- }
97- } else {
98- c = (unsigned int)wchar;
99- }
100-
101- // UTF-16LEからUTF-8へ変換する
102- if (c <= 0x0000007f) {
103- // 0x00000000 <= c <= 0x0000007f
104- code = (c & 0xff);
105- *byte = 1;
106-
107- } else if (c <= 0x000007ff) {
108- // 0x00000080 <= c <= 0x000007ff
109- c1 = ((c >> 6) & 0x1f) | 0xc0;
110- c2 = (c & 0x3f) | 0x80;
111- code = (c1 << 8) | c2;
112- *byte = 2;
113-
114- } else if (c <= 0x0000ffff) {
115- // 0x00000800 <= c <= 0x0000ffff
116- c1 = ((c >> 12) & 0xf) | 0xe0;
117- c2 = ((c >> 6) & 0x3f) | 0x80;
118- c3 = ((c) & 0x3f) | 0x80;
119- code = (c1 << 16) | (c2 << 8) | c3;
120- *byte = 3;
121- } else {
122- code = KCode;
123- *byte = 2;
124- }
125-
126- return (code);
127-}
128-
129-
13066 // Japanese SJIS -> JIS
13167 WORD PASCAL SJIS2JIS(WORD KCode)
13268 {
--- trunk/teraterm/ttpcmn/language.h (revision 7461)
+++ trunk/teraterm/ttpcmn/language.h (revision 7462)
@@ -35,13 +35,11 @@
3535 #endif
3636
3737 /* proto types */
38-unsigned int PASCAL SJIS2UTF8(WORD KCode, int *byte, int CodePage);
3938 WORD PASCAL SJIS2JIS(WORD KCode);
4039 WORD PASCAL SJIS2EUC(WORD KCode);
4140 WORD PASCAL JIS2SJIS(WORD KCode);
4241 BYTE PASCAL RussConv(int cin, int cout, BYTE b);
4342 void PASCAL RussConvStr(int cin, int cout, PCHAR Str, int count);
44-unsigned short ConvertUnicode(unsigned short code, const codemap_t *table, int tmax);
4543
4644 #ifdef __cplusplus
4745 }
--- trunk/teraterm/ttpcmn/ttcmn.c (revision 7461)
+++ trunk/teraterm/ttpcmn/ttcmn.c (revision 7462)
@@ -1582,25 +1582,52 @@
15821582 return i;
15831583 }
15841584
1585+// 内部コード(CodePage)をUTF-32(UTF-16LE)へ変換する
1586+static unsigned int SJIS2UTF32(WORD KCode, int CodePage)
1587+{
1588+ unsigned int c;
1589+
1590+ // 内部コード(CodePage)からUTF-16LEへ変換する
1591+ if (CodePage == 932) {
1592+ c = CP932ToUTF32(KCode);
1593+ } else {
1594+ unsigned char buf[3];
1595+ wchar_t wchar;
1596+ int ret;
1597+ int len = 0;
1598+ if (KCode < 0x100) {
1599+ buf[0] = KCode & 0xff;
1600+ len = 1;
1601+ } else {
1602+ buf[0] = KCode >> 8;
1603+ buf[1] = KCode & 0xff;
1604+ len = 2;
1605+ }
1606+ ret = MultiByteToWideChar(CodePage, MB_ERR_INVALID_CHARS, buf, len, &wchar, 1);
1607+ if (ret <= 0) {
1608+ c = 0;
1609+ } else {
1610+ c = (unsigned int)wchar;
1611+ }
1612+ }
1613+ if (c <= 0) {
1614+ // 変換失敗
1615+ c = 0xfffd; // U+FFFD: Replacement Character
1616+ }
1617+
1618+ return c;
1619+}
1620+
1621+// 内部コード(CodePage)をUTF-8へ出力する
15851622 static int OutputTextUTF8(WORD K, char *TempStr, PComVar cv)
15861623 {
1624+ int CodePage = *cv->CodePage;
15871625 unsigned int code;
15881626 int outlen;
1589- int TempLen = 0;
15901627
1591- code = SJIS2UTF8(K, &outlen, *cv->CodePage);
1592- switch (outlen) {
1593- case 4:
1594- TempStr[TempLen++] = (code >> 24) & 0xff;
1595- case 3:
1596- TempStr[TempLen++] = (code >> 16) & 0xff;
1597- case 2:
1598- TempStr[TempLen++] = (code >> 8) & 0xff;
1599- case 1:
1600- TempStr[TempLen++] = code & 0xff;
1601- }
1602-
1603- return TempLen;
1628+ code = SJIS2UTF32(K, CodePage);
1629+ outlen = UTF32ToUTF8(code, TempStr, 4);
1630+ return outlen;
16041631 }
16051632
16061633 //
Show on old repository browser