source: trunk/sample/EncodeString.cpp @ 16

Last change on this file since 16 was 16, checked in by murachi, 6 years ago
  • EncodeString クラスは内部文字セットの型と形式を指定できるテンプレートクラスに変更した。
  • <regex> を使わないで文字列の置換を行うサンプルプログラムを作成。
File size: 3.3 KB
Line 
1#include <iconv.h>
2#include "EncodeString.hpp"
3
4using namespace std;
5
6EncodeStringImpl::cnmap_t const EncodeStringImpl::CharsetNames = {
7    { chset_Utf8, "UTF-8" }, { chset_C99, "C99" }, { chset_Java, "JAVA" },
8    { chset_Ucs2, "UCS-2" }, { chset_Ucs2Be, "UCS-2BE" }, { chset_Ucs2Le, "UCS-2LE" },
9    { chset_Ucs4, "UCS-4" }, { chset_Ucs4Be, "UCS-4BE" }, { chset_Ucs4Le, "UCS-4LE" },
10    { chset_Utf16, "UTF-16" }, { chset_Utf16Be, "UTF-16BE" }, { chset_Utf16Le, "UTF-16LE" },
11    { chset_Utf32, "UTF-32" }, { chset_Utf32Be, "UTF-32BE" }, { chset_Utf32Le, "UTF-32LE" },
12    { chset_Utf7, "UTF-7" },
13    { chset_EucJp, "EUC-JP" }, { chset_EucJis0213, "EUC-JISX0213" },
14    { chset_Iso2022Jp, "ISO-2022-JP" }, { chset_Iso2022Jp2, "ISO-2022-JP2" },
15    { chset_Iso2022Jp1, "ISO-2022-JP1" }, { chset_Iso2022Jp3, "ISO-2022-JP3" },
16    { chset_ShiftJis, "SHIFT_JIS" }, { chset_Cp932, "CP932" }, { chset_ShiftJisX0213, "SHIFT_JISX0213" },
17};
18
19EncodeStringImpl::EncodeStringImpl()
20{
21    result_length = 0;
22}
23
24void EncodeStringImpl::encode(void const *src, size_t src_length, size_t chr_size, charset_t from_charset,
25    charset_t to_charset)
26{
27    if (from_charset == to_charset) {
28        char const *p = reinterpret_cast<char const *>(src);
29        result.assign(p, &p[(src_length + 1) * chr_size]);
30        return;
31    }
32    class auto_iconv_t {
33        const iconv_t impl;
34    public:
35        auto_iconv_t(charset_t from_cs, charset_t to_cs) :
36            impl(iconv_open(CharsetNames.find(to_cs)->second, CharsetNames.find(from_cs)->second))
37        {
38            if (impl == reinterpret_cast<iconv_t>(-1)) {
39                throw EncodeStringException(string("LIBICONV initialize error: please check character set name \"") +
40                    CharsetNames.find(from_cs)->second + "\"(from) or \"" + CharsetNames.find(to_cs)->second +
41                    "\"(to)");
42            }
43        }
44        ~auto_iconv_t() { iconv_close(impl); }
45        iconv_t get() const { return impl; }
46    } iconv_handle(from_charset, to_charset);
47    size_t const src_size = src_length * chr_size;
48    result.resize(src_size + TerminateNullCharNum, '\0');   // ヌル文字分余裕を持って確保する。
49    char const *from_current = reinterpret_cast<char const *>(src);
50    char *to_current = &result[0];
51    size_t from_left = src_size, to_left = src_size;
52   
53#if defined(_ICONV_H)
54    while (iconv(iconv_handle.get(), const_cast<char **>(&from_current), &from_left, &to_current, &to_left) ==
55    static_cast<size_t>(-1)) {
56#elif defined(_LIBICONV_H)
57    while (iconv(iconv_handle.get(), &from_current, &from_left, &to_current, &to_left) == static_cast<size_t>(-1)) {
58#endif //_ICONV_H, _LIBICONV_H
59        // ループ内はエラー処理
60       
61        if (errno == EINVAL)    // マルチバイトの下位オクテットが欠けている?
62            break;
63       
64        switch (errno) {
65        case E2BIG:     // 出力先バッファが足りない
66            // バッファを拡張し、継続
67            {
68                size_t pre_size = result.size();
69                result.resize(pre_size + src_size, '\0');
70                to_current = &result[pre_size - TerminateNullCharNum - to_left];
71                to_left += src_size;
72            }
73            break;
74        case EILSEQ:    // あり得ないコードが出現
75            // エラー回避し、続きから変換を継続
76            from_current++;
77            from_left--;
78            break;
79        case EBADF:     // 変換に失敗 (原因不明)
80            throw EncodeStringException("LIBICONV bad conversion error (EBADF)");
81        default:        // 未定義のエラー
82            throw EncodeStringException("LIBICONV unknown error");
83        }
84    }
85    result_length = result.size() - to_left - TerminateNullCharNum;
86}
Note: See TracBrowser for help on using the repository browser.