utf16beの読み込み方法

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
駆け出し
記事: 25
登録日時: 7年前

utf16beの読み込み方法

#1

投稿記事 by 駆け出し » 7年前

こんにちは。テキストエディタを作成しているのですが、UTF-16BEのファイルを読み込めず右往左往しています。UTF-16LE、UTF-8は読み込めています。
_wfopen_sにはMSDNを見る限りutf16-beを読み込めないようなのです。

コード:

#include <Windows.h>
#include <stdio.h>
#include <Shlwapi.h>
#include <io.h>
#include <fcntl.h>  
#include <sys/stat.h>
#pragma comment(lib,"Shlwapi.lib")

//BOMを内部で識別するためのマクロ
#define BOM_UTF_8    (0x01)      //utf-8
#define BOM_UTF_16   (0x02)      //utf-16
#define BOM_UTF_32   (0x04)      //utf-32
#define BOM_UTF_7    (0x08) //utf-7

#define BOM_BE       (0x10)       //be
#define BOM_LE       (0x20)       //le

//BOM
//[0]...BOMのサイズ、[1]...BOM識別用のマクロ、[2]-[6]BOM
const unsigned char BOM[6][6] = {
	{ 3,BOM_UTF_8, 0xef,0xbb,0xbf },
	{ 2,BOM_UTF_16|BOM_BE, 0xfe,0xff },
	{ 2,BOM_UTF_16|BOM_LE, 0xff,0xfe },
	{ 4,BOM_UTF_32|BOM_BE, 0x00,0x00,0xfe,0xff },
	{ 4,BOM_UTF_32|BOM_LE,0xff, 0xfe, 0x00, 0x00 },
	{ 3,BOM_UTF_7, 0x2b,0x2f,0x76 }
};

int getBOM(LPCWSTR lpFile,int *bomsize)
{
	FILE *fp;
	char Buf[4];

	_wfopen_s(&fp, lpFile, L"rb");
	if (!fp)
		return 0;
	

	fread(Buf, 4, 1, fp);

	for (int i = 0; i < 6; i++)
	{
		if (!memcmp(BOM[i] + 2, Buf, BOM[i][0]))
		{
			*bomsize = BOM[i][0];
			return BOM[i][1];
		}
	}

	//BOMなし
	*bomsize = 0;
	return 0;
}

size_t GetFileSizeEx(LPCWSTR lpFileName)
{
	struct _stat stbuf;
	int fd;

	_wsopen_s(&fd, lpFileName, _O_BINARY,
		_SH_DENYWR, _S_IREAD);
	if (fd == -1) {
		return INVALID_VALUE; //0xfffffff...
	}


	if (_fstat(fd, &stbuf) == -1) {
		/* エラー処理 */
		return INVALID_VALUE;
	}

	_close(fd);

	return stbuf.st_size;
}

size_t EDMultiByteToWideChar(LPCSTR lpszMultiByte, LPWSTR *WideCharTemp)
{
	size_t len;
	WCHAR *Buffer;

	len = MultiByteToWideChar(
		CP_ACP,
		MB_PRECOMPOSED,
		lpszMultiByte,
		-1,
		NULL,
		0
	);

	Buffer = (WCHAR*)malloc(len * sizeof(WCHAR));
	if (!Buffer)
	{
		*WideCharTemp = NULL;
		return FALSE;
	}

	MultiByteToWideChar(
		CP_ACP,
		MB_PRECOMPOSED,
		lpszMultiByte,
		-1,
		Buffer,
		(int)(len)
	);

	*WideCharTemp = Buffer;

	return len;
}

int edLoadPlainText(LPCWSTR lpFile,WCHAR **loadedText,const int forceBOM = 0)
{
	FILE *fp;
	int bomsize;
	size_t size;
	void *loaded;
	int filebom;
	WCHAR mode[32] = { 0 };

	wcscpy_s(mode, L"rb");

	filebom = getBOM(lpFile, &bomsize);
	if(forceBOM)
		filebom = forceBOM;

	if ((size = GetFileSizeEx(lpFile)) == INVALID_VALUE)
		return FALSE;

	if ((filebom & BOM_UTF_8))
		wcscat_s(mode, L", ccs=UTF-8");
	else if ((filebom & BOM_UTF_16) && (filebom & BOM_LE))
		wcscat_s(mode, L", ccs=UTF-16LE");
/*	else if ((filebom & BOM_UTF_16) && (filebom & BOM_BE))
		wcscat_s(mode, L", ccs=UNICODE");*/

	_wfopen_s(&fp, lpFile, mode);

	if (!fp)
		return FALSE;

	if ((loaded = calloc(1,size + 2/*NULL*/)) == NULL)
	{
		fclose(fp);
		return FALSE;
	}

	fread(loaded, size, 1, fp);

	//もしBOMがUTF-16を指している場合は
	if ((filebom & BOM_UTF_16))
	{
		*loadedText = (WCHAR*)loaded + bomsize / sizeof(WCHAR);
		fclose(fp);

		return TRUE;
	}

	//utf-8なら変換して返す
	EDMultiByteToWideChar((LPCSTR)loaded + bomsize, loadedText);

	fclose(fp);

	return TRUE;
}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
       //テスト
	WCHAR *t1, *t2, *t3, *t4;
	edLoadPlainText(L"test-utf-8.txt", &t1);
	edLoadPlainText(L"test-utf16le.txt", &t2);
	edLoadPlainText(L"test-.txt", &t3);
	edLoadPlainText(L"test-utf16be.txt", &t4);
}

添付ファイル
test-utf16be.zip
メモ帳で作成したものになります
(523 バイト) ダウンロード数: 130 回

アバター
keito94
記事: 264
登録日時: 7年前
連絡を取る:

Re: utf16beの読み込み方法

#2

投稿記事 by keito94 » 7年前

どうやら、C言語の標準機能で、UTF-16BEを読み込もうと努力しているわけですね。
何かのライブラリが必要だと思いますよ。
デバッグは投げ捨てるものではない。
今までの質問でこれは学んだこと。
質問する時は、必ずちゃんと調べた上に問題をもとにした仕様書を作ってから質問すること。
仕様書の大切さを改めて思い知った…。

inemaru
記事: 108
登録日時: 7年前

Re: utf16beの読み込み方法

#3

投稿記事 by inemaru » 7年前

標準ライブラリのcodecvt_utf16を使用する方法がありますが、どうですか?
下記の実装は、BOM付utf16BEを表示するサンプルです。

環境:VS2013/Unicodeプロジェクト

コード:

#include <windows.h>
#include <locale>
#include <fstream>
#include <string>
#include <codecvt>

using namespace std;

std::wstring GetString_UTF16BE(const char* filePath)
{
	wifstream ifs(filePath);
	if (!ifs) {
		// 読み込み失敗
		return L"";
	}
	ifs.imbue(locale(locale::empty(), new codecvt_utf16<wchar_t, 0x10ffff, consume_header>));
	return wstring(istreambuf_iterator<wchar_t>(ifs), istreambuf_iterator<wchar_t>());
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	// ロケールをデフォルトに設定
	locale::global(locale(""));
	setlocale(LC_ALL, locale().c_str());

	// utf16be表示
	MessageBoxW(nullptr, GetString_UTF16BE("test-utf16be.txt").c_str(), L"", MB_OK);

	return 0;
}

駆け出し
記事: 25
登録日時: 7年前

Re: utf16beの読み込み方法

#4

投稿記事 by 駆け出し » 7年前

ありがとうございます。C++ほとんど触ってないので、試行錯誤しながらやっていきたいと思います!

駆け出し
記事: 25
登録日時: 7年前

Re: utf16beの読み込み方法

#5

投稿記事 by 駆け出し » 7年前

解決つけ忘れてました。

返信

“C言語何でも質問掲示板” へ戻る