UTF-16 to UTF-8 example1
更新日2007年01月30日

UTF-16 to UTF-8 example1
UTF-16 to UTF-8 example1 への文字コード変換のサンプル実装。(Windows APIを使用)
MinGW + gcc 環境において動作確認してあります。

Example Code
以下の例は、Utf16ToUtf8()の実装の例です。 [utf16_to_utf8_1.zip]
/*
 * file:Utf16ToUtf8_1.c
 */
/** @file
 * @brief UTF-16 → UTF-8 への変換実装サンプルプログラム。
 * 
 * UTF-16 → UTF-8 への変換実装サンプルプログラムその1。(Windows APIを使用)
 * UTF-16にて用意された"data.txt"ファイルを読み込み、
 * UTF-8へと変換、
 * "out.txt"ファイルへと出力します。
 * 変換後の文字列にBOMが見つかれば、除去します。
 */
#define STRICT
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#define DEFAULT_BUFF_LEN 512

int Utf16ToUtf8(char *dest, size_t dest_size, wchar_t *src, size_t src_size);

int main(int argc, char *argv[])
{
    wchar_t     instr[DEFAULT_BUFF_LEN];
    char        outstr[DEFAULT_BUFF_LEN];
    FILE        *pFile;
    long        sizeFile = 0;
    size_t      countRead;
    int         instr_size = 0;
    int         iResult = 0;
    char        *pOutStr = NULL;
    
    /*
     * ファイルより文字列を読み込み
     */
    memset(instr, 0, sizeof(instr));
    pFile = fopen("data.txt", "rb");
    if (pFile == NULL)
    {
        perror("ファイルがひらけません: data.txt");
        return 1;
    }
    fseek(pFile, 0, SEEK_END);
    sizeFile = ftell(pFile);
    fseek(pFile, 0, SEEK_SET);
    countRead = fread(instr, min(sizeFile, DEFAULT_BUFF_LEN), 1, pFile);
    fclose(pFile);
    if (countRead == 0)
    {
        perror("ファイル読み込み失敗: data.txt");
        return 1;
    }
    
    instr_size = min(sizeFile, DEFAULT_BUFF_LEN) * countRead / sizeof(wchar_t);
    
    /*
     * utf16:instr -> utf8:outstr 変換。
     */
    memset(outstr, 0, sizeof(outstr));
    iResult = Utf16ToUtf8(outstr, sizeof(outstr), instr, instr_size);
    if (iResult == FALSE)
    {
        perror("Utf16ToUtf8() Failed.\n");
        return 1;
    }
    printf("%d バイト変換しました。\n", iResult);
    
    pOutStr = outstr;
    /*
     * BOMの除去
     */
    if ((*pOutStr == '\xef') && (*(pOutStr + 1) == '\xbb')
            && (*(pOutStr + 2) == '\xbf'))
    {
        /*
         * UTF-8のBOMはef bb bf
         * LE も BE も存在しないので、BOM付きの場合には除去。
         * BOMが無い場合はそのまま処理。
         */
        /* BOMがある場合にはBOMを無視する */
        pOutStr += 3;
        iResult -= 3;
    }
    
    /*
     * ファイルに文字列を書き込み。
     */
    pFile = fopen("out.txt", "wb");
    if (pFile == NULL)
    {
        perror("ファイルが開けません: out.txt");
        return 1;
    }
    fwrite(pOutStr, iResult, 1, pFile);
    fclose(pFile);
    
    return 0;
}

/**
 * 文字コードをUTF-16よりUTF-8へと変換。
 * 
 * @param[out] dest 出力文字列UTF-8
 * @param[in]  dest_size destのバイト数
 * @param[in]  src 入力文字列UTF-16
 * @param[in]  src_size 入力文字列の文字数
 * 
 * @return 成功時には出力文字列のバイト数を戻します。
 *         dest_size に0を指定し、こちらの関数を呼び出すと、変換された
 *         文字列を格納するのに必要なdestのバイト数を戻します。
 *         関数が失敗した場合には、FALSEを戻します。
 */
int Utf16ToUtf8(char *dest, size_t dest_size, wchar_t *src, size_t src_size)
{
    UINT    uCodePage;              /* コードページ */
    DWORD   dwFlags;                /* 処理性能とマッピングのフラグ */
    LPCWSTR lpWideCharStr;          /* ワイド文字の文字列のアドレス */
    int     cchWideChar;            /* 文字列の文字数 */
    LPSTR   lpMultiByteStr;         /* 新しい文字列のバッファのアドレス */
    int     cchMultiByte;           /* バッファのサイズ */
    LPCSTR  lpDefaultChar;          /* 文字をマップ不可能な場合のデフォルト文字のアドレス */
    LPBOOL  lpfUsedDefaultChar;     /* デフォルト文字が使われたときにセットされるフラグのアドレス */
    int     iResult;
    
    uCodePage           = CP_UTF8;
    dwFlags             = 0;
    lpWideCharStr       = src;
    cchWideChar         = src_size;
    lpMultiByteStr      = dest;
    cchMultiByte        = dest_size;
    lpDefaultChar       = NULL;
    lpfUsedDefaultChar  = NULL;
    iResult = WideCharToMultiByte(uCodePage, dwFlags, lpWideCharStr
            , cchWideChar, lpMultiByteStr, cchMultiByte, lpDefaultChar
            , lpfUsedDefaultChar);
    return iResult;
}