ページ 11

FileRead_sizeがうまくいきません

Posted: 2012年11月07日(水) 18:41
by タケ
こんにちは
VisualStudio2010、DXライブラリ、C++でプログラミングしています。

外部ファイルから構造体に取得したデータの中の一つであるconst wchar_t* FilePathを、構造体のアドレスを関数に渡して、FileRead_sizeでサイズを調べるという処理をしようとしているのですが、どうにもうまくいきません。

コード:

typedef struct _FontData {
     const wchar_t* FontName;
     const wchar_t* FilePath;
   …
} FontData;

void SetFontTest(FontData* fontdata) {
     DrawFormatString(100, 50, White, L"%s", fontdata->FilePath); //①
     int filesize = FileRead_size(fontdata->FilePath);
     DrawFormatString(100,90, White, L"%s", fontdata->FilePath); //②
}

void WINAPI WinMain(略){
       …
     FontData fontdata;
     GetFontData(L"fontconf", &fontdata); // フォントデータ取得(正常)
     DrawFormatString(100, 250, White, L"%s", fontdata.FilePath); //③
     SetFontTest(&fontdata);
     DrawFormatString(100, 290, White, L"%s", fontdata.FilePath); //④
       …
}
試しにこのような関数を作ってみたところ、FileRead_size関数を呼び出す前の①、③は正しくパスが出力されてるのですが、この関数を使ったとたん(②、④での出力として)中身が正しく表示されなくなりました。
この点についても、なぜFileRead_size関数でFilePathの中身まで変わってしまうのか分かりません。

また、これで取得したファイルサイズを表示させると-1になっています。

もしかしたら、他の部分におかしなところがあるのかもしれませんが…、コメントアウトや出力を利用してここに絞り込みました。
実際に取得したフォントデータはFileRead_size関数がなければどこでも正しく出力されます。

色々と調べてみたのですが、どうにも自分では解決できそうにないので、知恵を貸していただければうれしいです。

Re: FileRead_sizeがうまくいきません

Posted: 2012年11月07日(水) 19:04
by softya(ソフト屋)
ほんとにこれだけの機能のプログラムでバグが再現するか別プロジェクトを作って最小限の形で実験してみてください。
それと、そのソースコードを動く形のままで貼り付けてみてください。
別に原因がある気がしてならないのです。

Re: FileRead_sizeがうまくいきません

Posted: 2012年11月07日(水) 19:24
by タケ
返信ありがとうございます。
今すぐにはできないのですが、後ほど実験してみます。

Re: FileRead_sizeがうまくいきません

Posted: 2012年11月09日(金) 22:41
by タケ
こんばんは、お世話になります。
アドバイスの通り、新規にプロジェクトを作成して最低限の構成で挑戦してみました。
試行錯誤の末、FileRead_size()を呼び出しても構造体の書き換えが行われなくなりました。
これに関しては、外部ファイルの最後に改行を入れていたために、読み込みの際のバッファが1行分足りておらず、不具合がおきていたようです。

しかし、新たな問題が発生しました。
直接ファイルのパスを打ち込まないとFileRead_sizeが-1を返してしまうのです。
比較として直接打ち込んだパスと変数の中身を並べて表示させましたが、見た目同じように思えます。

外部ファイルの内容は、
fontname=MigMix 2P
fontfilepath=font/migmix-2p-regular.ttf
[EOF]
になります。

以下コード、長くなりますがすいません。

コード:

// ヘッダファイルhoge.h
#include	<string.h>
#include	<stdlib.h>
#include	<locale.h>
#include	"DxLib.h"

typedef struct RndTxtConfTag {
	wchar_t	FontName[30];
	wchar_t	FontFilePath[30];
} RndTxtConf;

void SetRndTxtFont(RndTxtConf* rndtxtconf);
int LoadRndTxtConf(const wchar_t* filename, RndTxtConf* rndtxtconf);

//メイン関数のファイルhoge.cpp
#include	"hoge.h"

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

	RndTxtConf	rndtxtconf;
	setlocale(LC_ALL, "Japanese");
	SetGraphMode(1024, 576, 32);
	ChangeWindowMode(TRUE);

	if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_FRONT) != 0)	return -1;
	
	if(LoadRndTxtConf(L"conf/rendertext.conf", &rndtxtconf) != 0)	return -1;

	DrawFormatString(100, 100, GetColor(255, 255, 255), L"%s", rndtxtconf.FontName);
	DrawFormatString(100, 120, GetColor(255, 255, 255), L"%s", rndtxtconf.FontFilePath);

	SetRndTxtFont(&rndtxtconf);
	
	DrawFormatString(100, 140, GetColor(255, 0, 0),L"%s", rndtxtconf.FontName);
	DrawFormatString(100, 160, GetColor(255, 0, 0),L"%s", rndtxtconf.FontFilePath);

	WaitKey();

	DxLib_End();
	return 0;
}

//外部ファイル関連関数のファイルhogehoge.cpp
#include	"hoge.h"

void SetRndTxtFont(RndTxtConf* rndtxtconf) {
/*
問題のFileRead_sizeの箇所
構造体から直接取得① 一時的に変数に入れてみる(やけくそ)② 直接入力③
①、②ともにファイルのパスは出力されますがサイズは正常に取得できず。
③は取得できます。
また、①、②、③を並べて表示させてみたところ、ファイルパスとして同じ文字列が出力されます。
*/	
	DrawFormatString(600, 430,GetColor(255,255,255),L"%s",rndtxtconf->FontFilePath);

	wchar_t* fontfilepath = (wchar_t *)malloc(50);
	wcscpy(fontfilepath, rndtxtconf->FontFilePath);

	int	filesize = FileRead_size(rndtxtconf->FontFilePath);      //①
	//int	filesize = FileRead_size(fontfilepath);                         //②
	//int	filesize = FileRead_size(L"font/migmix-2p-regular.ttf"); //③

	DrawFormatString(600, 430,GetColor(255,255,255),L"%s", rndtxtconf->FontFilePath);
	DrawFormatString(600, 450,GetColor(255,255,255),L"%s", fontfilepath);
	DrawFormatString(600, 470,GetColor(255,255,255),L"font/migmix-2p-regular.ttf");
	DrawFormatString(600, 490,GetColor(255,255,255),L"%d", filesize);
}

int LoadRndTxtConf(const wchar_t* filename, RndTxtConf* rndtxtconf) {
	int	fh;
	int	lflg = 0;
	int	i = 0, j = 0;
	wchar_t cbuf;
	wchar_t	wstrbuf[3][30];

	if((fh = FileRead_open(filename)) == 0) return -1;

	while(FileRead_eof(fh) == 0) {
		cbuf = FileRead_getc(fh);
		if(cbuf == L'\n') {
			wstrbuf[i][j] = L'\0';
			i++;
			j = 0;
			lflg = 0;
		}
		if(lflg == 1) {
			wstrbuf[i][j] = cbuf;
			j++;
		}
		if(cbuf == L'=')	lflg = 1;
	}
	FileRead_close(fh);

	wcscpy(rndtxtconf->FontName, wstrbuf[0]);
	wcscpy(rndtxtconf->FontFilePath, wstrbuf[1]);
	
	DrawFormatString(500, 340, GetColor(0, 255, 255), L"%s", rndtxtconf->FontName);
	DrawFormatString(500, 360, GetColor(0, 255, 255), L"%s", rndtxtconf->FontFilePath);

	return 0;
}
外部ファイルを読み込ませる箇所は、自分なりに実装してみたのですが、もしも良い例や改善箇所があったら併せてアドバイス頂けると嬉しいです。
宜しくお願いします。

Re: FileRead_sizeがうまくいきません

Posted: 2012年11月09日(金) 23:28
by softya(ソフト屋)
結論から言うと復帰改行コードの改行コードしか処理していなかったため復帰コードが文字列末端に残っています(これは表示されません)。
こう直せば、表示されるようになります。
※ 分かりづらかったので変数名だけ直してありますが、本当はもっと直したほうが良いでしょう。

コード:

// ヘッダファイルhoge.h
#include    <string.h>
#include    <stdlib.h>
#include    <locale.h>
#include    "DxLib.h"
 
typedef struct RndTxtConfTag {
    wchar_t FontName[30];
    wchar_t FontFilePath[30];
} RndTxtConf;
 
void SetRndTxtFont(RndTxtConf* rndtxtconf);
int LoadRndTxtConf(const wchar_t* filename, RndTxtConf* rndtxtconf);
 
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
 
    RndTxtConf  rndtxtconf;
    setlocale(LC_ALL, "Japanese");
    SetGraphMode(1024, 576, 32);
    ChangeWindowMode(TRUE);
 
    if(DxLib_Init() == -1 || SetDrawScreen(DX_SCREEN_FRONT) != 0)   return -1;
    
    if(LoadRndTxtConf(L"conf/rendertext.conf", &rndtxtconf) != 0)   return -1;
 
    DrawFormatString(100, 100, GetColor(255, 255, 255), L"%s", rndtxtconf.FontName);
    DrawFormatString(100, 120, GetColor(255, 255, 255), L"%s", rndtxtconf.FontFilePath);
 
    SetRndTxtFont(&rndtxtconf);
    
    DrawFormatString(100, 140, GetColor(255, 0, 0),L"%s", rndtxtconf.FontName);
    DrawFormatString(100, 160, GetColor(255, 0, 0),L"%s", rndtxtconf.FontFilePath);
 
    WaitKey();
 
    DxLib_End();
    return 0;
}
 
//外部ファイル関連関数のファイルhogehoge.cpp
//#include    "hoge.h"
 
void SetRndTxtFont(RndTxtConf* rndtxtconf) {
/*
問題のFileRead_sizeの箇所
構造体から直接取得① 一時的に変数に入れてみる(やけくそ)② 直接入力③
①、②ともにファイルのパスは出力されますがサイズは正常に取得できず。
③は取得できます。
また、①、②、③を並べて表示させてみたところ、ファイルパスとして同じ文字列が出力されます。
*/  
    DrawFormatString(600, 430,GetColor(255,255,255),L"%s",rndtxtconf->FontFilePath);
 
    wchar_t* fontfilepath = (wchar_t *)malloc(50);
    wcscpy(fontfilepath, rndtxtconf->FontFilePath);
 
    int filesize1 = FileRead_size(rndtxtconf->FontFilePath);     //①
    int filesize2 = FileRead_size(fontfilepath);                         //②
    int filesize3 = FileRead_size(L"font/migmix-2p-regular.ttf"); //③
 
    DrawFormatString(600, 430,GetColor(255,255,255),L"%s", rndtxtconf->FontFilePath);
    DrawFormatString(600, 450,GetColor(255,255,255),L"%s", fontfilepath);
    DrawFormatString(600, 470,GetColor(255,255,255),L"font/migmix-2p-regular.ttf");
    DrawFormatString(400, 490,GetColor(255,255,255),L"%d", filesize1);
    DrawFormatString(500, 490,GetColor(255,255,255),L"%d", filesize2);
    DrawFormatString(600, 490,GetColor(255,255,255),L"%d", filesize3);
}
 
int LoadRndTxtConf(const wchar_t* filename, RndTxtConf* rndtxtconf) {
    int fh;
    int lflg = 0;
    int line = 0, col = 0;
    wchar_t cbuf;
    wchar_t wstrbuf[3][30];
 
    if((fh = FileRead_open(filename)) == 0) return -1;
 
    while(FileRead_eof(fh) == 0) {
        cbuf = FileRead_getc(fh);
        if(cbuf == L'\n') {
            wstrbuf[line][col] = L'\0';
            line++;
            col = 0;
            lflg = 0;
        }
        if(cbuf == L'\r') {
			//skip
		} else
        if(lflg == 1) {
            wstrbuf[line][col] = cbuf;
            col++;
        }
        if(cbuf == L'=')    lflg = 1;
    }
    FileRead_close(fh);
 
    wcscpy(rndtxtconf->FontName, wstrbuf[0]);
    wcscpy(rndtxtconf->FontFilePath, wstrbuf[1]);
    
    DrawFormatString(500, 340, GetColor(0, 255, 255), L"%s", rndtxtconf->FontName);
    DrawFormatString(500, 360, GetColor(0, 255, 255), L"%s", rndtxtconf->FontFilePath);
 
    return 0;
}
素直に読みやすくしてみました。

コード:

	while(FileRead_eof(fh) == 0) {
		cbuf = FileRead_getc(fh);
		if(cbuf == L'\n') {
			//	改行
			wstrbuf[line][col] = L'\0';
			line++;
			col = 0;
			lflg = 0;
		} else if(cbuf == L'\r') {
			//	復帰	skip
		} else if(cbuf == L'=') {
			//	=で切り替え
			lflg = 1;
		} else if(lflg == 1) {
			//	=以降の文字
			wstrbuf[line][col] = cbuf;
			col++;
		}
	}

Re: FileRead_sizeがうまくいきません

Posted: 2012年11月09日(金) 23:43
by タケ
本当にありがとうございます。
2日悩み続けてしましましたが…、おかげでスッキリ解決することができました。

一つだけ確認させて欲しいのですが、
fontname=hoge
fontfilepath=font/hoge.tff
[EOF]
は、
fontname=hoge\r\nfontfilepath=font/hoge.tff\r\n[EOF]
と解釈されてしまい、上のコードによると
wstrbuf[0]の中身: h o g e \r \0
wstrbuf[1]の中身: f o n t / h o g e h o g e \r \0
になってしまっていた、という認識で良いでしょうか?

質問ばかりで申し訳ありません。

Re: FileRead_sizeがうまくいきません

Posted: 2012年11月10日(土) 00:32
by softya(ソフト屋)
その通りです。
Windowsの改行は\r\nであり実際には復帰改行なのです。
※ MacとLinuxは違います。
この問題を見つけるには、もう一度ファイルに書き出してみてバイナリエディタで見てみるとか、VC++のデバッグ→ウィンドウ→メモリでアドレスを入力してメモリダンプを見るしか無いです。あと自分でメモリダンプ関数を作るとか。

Re: FileRead_sizeがうまくいきません

Posted: 2012年11月10日(土) 02:53
by タケ
なるほど、とても参考になりました。
詳しく調べておこうとおもいます!

ありがとうございました。