CでのSJISとUTF8の変換
■サンプルダウンロード(BorlandC++Builder6用プロジェクト)

utf8.lzh(18,997 バイト)

  • 使い方はフォームに書いてあります。
  • UTF-8へのコンバートが成功しているかどうかは、実行すると 出来るtempというファイルを、サクラエディタなどのUTF-8に対応した エディタで読み込んで、それがUTF-8と認識されることで確認出来ます。
■導入

J-PHONE携帯用のJAVAアプリを作成する際に、MANIFESTファイルと JADファイルというのを作成しないといけないが、日本語を利用する にはUTF-8Nというフォーマットにしないといけない。UTF-8に対応している テキストエディタで変換していたが何かと煩わしいので 自前のツール( jadman)にUTF-8Nへの変換機能をつけることとする。

■解決方法

手っ取り早く実装できる手段を調べてたら、 WindowsのAPIでコンバート用の命令があることが判明 (林道の鬼のページの以下の場所を参照させていただきました。 http://www.geocities.co.jp/SilkRoad/4511/vb/utf8.htm
VBのソースが掲載されています)。

命令はMultiByteCharをWideCharに変換する MultiByteToWideChar()と、WideCharをMultiByteCharに変換する WideCharToMultiByte() の2つ。因みにMultiByteとWideCharとは以下のことである。

MultiByteCharS-JISやUTF-8などの様々な文字コード
WideCharUnicode

つまり、S-JISをUTF-8に変換するには、

S-JIS
-------------------->
MultiByteToWideChar()
Unicode
-------------------->
WideCharToMultiByte()
UTF-8

というステップを踏めばよい。因みに、ここで変換されるUTF-8には先頭 3バイトのBOM(Byte Order Mark)はつかない(UTF-8Nと呼ばれることも ある)。よって、そのままJADやMANIFESTに利用可能 (UTF-8とUTF-8Nの違いについては こちら を参照下さい[2002/10/29])

■変換関数例

最初にコンバートしたデータを格納するのに必要な 容量を調べて、その分の容量を確保してコンバートし、そのデータを 引数で与えた領域に収まる分だけコピーしている。S-JISもUTF-8もNULL 終端。

//---------------------------------------------------------------------------
// doconv()
//! 実際の変換処理。
/*!
\param	ssrc	[i]		変換元の文字列ポインタ
\param	sdst	[i/o]	変換後の文字列を返す先のポインタ
\param	idstsz	[i]		wdstの上限サイズ。この値-1byteまで記録できる
\retval	0		エラー
\retval	1以上	変換後のバイト数
\retval	-1		作業メモリの確保失敗
*/
//---------------------------------------------------------------------------
int doconv(const char * ssrc,char * sdst,int idstsz,int istoutf)
{
    int i;
    int ires;
    LPWSTR wbuf;
    LPSTR  putf;

    // unicodeへ変換
    //// 事前チェック
    ires = MultiByteToWideChar(
        (istoutf!=0) ? CP_ACP : CP_UTF8,
                        // 文字コード
        0,              // フラグなし
        ssrc,           // 変換元文字列
        -1,             // 変換文字列バイト数
        NULL,           // 変換後格納先
        0               // 格納領域取得
        );
    if (ires == 0)
    {
        return 0;
    }
    //// ワーク取得
    wbuf = new WCHAR[ires+1];
    if (wbuf == NULL)
    {
        return -1;
    }
    //// 実変換
    ires = MultiByteToWideChar(
        (istoutf!=0) ? CP_ACP : CP_UTF8,
                        // 文字コード
        0,              // フラグなし
        ssrc,           // 変換元文字列
        -1,             // 変換文字列バイト数
        wbuf,           // 変換後格納先
        ires            // 格納領域取得
        );
    wbuf[ires]  = 0;
    if (ires == 0)
    {
        return 0;
    }

    // UTF8への変換
    //// 事前チェック
    ires = WideCharToMultiByte(
        (istoutf==0) ? CP_ACP : CP_UTF8,
                        // UTF8
        0,              // フラグなし
        wbuf,           // 変換元文字列
        -1,             // 変換文字列バイト数
        NULL,           // 変換後格納先
        0,              // 格納領域
        NULL,NULL
        );
    if (ires == 0)
    {
        delete [] wbuf;
        return 0;
    }
    // 容量チェック
    if (idstsz == 0)
    {
        delete [] wbuf;
        return ires+1;
    }

    //// 領域確保
    putf = new char[ires+1];
    if (putf == NULL)
    {
        delete [] wbuf;
        return -1;
    }
    //// 実変換
    ires = WideCharToMultiByte(
        (istoutf==0) ? CP_ACP : CP_UTF8,
                        // UTF8
        0,              // フラグなし
        wbuf,           // 変換元文字列
        -1,             // 変換文字列バイト数
        putf,           // 変換後格納先
        ires,           // 格納領域
        NULL,NULL
        );
    if (ires == 0)
    {
        delete [] wbuf;
        delete [] putf;
        return 0;
    }

    // コピー
    ires = ((idstsz-1) > ires) ? ires : idstsz-1;
    for (i=0 ; i < ires ; i++)
    {
        sdst[i] = putf[i];
    }
    sdst[i] = 0;

    delete [] wbuf;
   	delete [] putf;
    return i;
}

■utf8cv.cpp/.hの使い方

サンプルに含まれるutf8cv.cppとutf8.cv.hというファイルに 変換用の関数を実装している。Windows98SE/2000/ME/XPのC++ プロジェクトで利用出来ると思うので自由に使って下さい。 メモリ周りと拡張子を書き換えればCでもいけるはず。WindowsのAPIに 依存しているのでLinuxなどでは利用不可。

  1. プロジェクトにutf8cv.cppを加え、インクルードパスの通っている場所にutf8cv.hを置く
  2. 利用したいソースにutf8cv.hをインクルードする
  3. SJISからUTF-8Nへ変換したい場合は以下の命令を実行
    SJIS2UTF8N(const char * ssrc,char * sdst,int idstsz)
     ssrc : 変換元文字列へのポインタ(NULL終端)
     sdst : 変換後のUTF-8Nを格納する先のポインタ
     idstsz : UTF-8N格納領域バッファサイズ);
     戻り値 : 1以上の時、変換後のバイト数
    : 0以下の時、エラー
  4. UTF-8NからSJISへの変換
    UTF8N2SJIS(const char * ssrc,char * sdst,int idstsz)
     ssrc : UTF-8Nの文字列のポインタ(NULL終端)
     sdst : 変換後のS-JISを格納する先のポインタ
     idstsz : 格納領域バッファサイズ
     戻り値 : 1以上の時、変換後のバイト数
    : 0以下の時、エラー
■UTF-8について
プログラマー's研究所(渡辺 義則氏)
http://www.hcn.zaq.ne.jp/no-ji/reseach/990303.htm
UTF-8を分かりやすく解説してくれてます。Unicodeにちょっと手を入 れたものということが判明。ASCIIだけならコードはそのままだし1byteで済 むので、多分殆どASCIIで書かれることが前提のデータ向けに作った フォーマットと推測。JADやMANIFESTにはうってつけ(Descriptが長いと あまり効率的ではないかも)。 因みにこの研究所ページのTipsは大変充実してて参考になります。

林道の鬼アイコン 林道の鬼
UTF-8の変換のVBのコードが紹介されてます。ここで命令の存在を知りました。

鈴木朝子と高橋誠の部屋
http://homepage2.nifty.com/hobbit/html/utf8.html
「Windows 98/2000上でのUTF-8のページの作り方」というページで、 UTF-8とUTF-8Nの何が違うのかが記載されています。UTF-8についての 知識を得るのに助かりました。

プログラムTipsインデックスへ