10

ゲームのリソースを1つのファイルにパックするためのシンプルなリソースパッカーを作成しました。私がアンパッカーを書き始めるまで、すべてが順調に進んでいました。パックした.txtファイル(26バイト)がリソースファイルから正常に出力され、問題なくすべてのデータが保持されていることに気付きました。ただし、リソースファイルにパックした.PNGファイルを読み取ると、最初の5バイトはそのままで、残りは完全に無効になりました。

これをパッキングプロセスまでたどると、freadが.PNGファイルの最初の5バイトしか読み取っていないことに気付き、その理由を一生理解できません。ファイルの長さがわずか5バイトであることを示す「EOF」もトリガーされますが、実際には、100ピクセル×100ピクセルの小さなポリゴンの787バイトのPNGです。

このPNGファイルをバッファに読み込むための別のアプリケーションを作成してこの問題をテストしたところ、同じ結果が得られ、5バイトしか読み取られませんでした。

その小さな個別のアプリケーションのコードは次のとおりです。

#include <cstdio>

int main(int argc, char** argv)
{
    char buffer[1024] = { 0 };
    FILE* f = fopen("test.png", "r");
    fread(buffer, 1, sizeof(buffer), f);
    fclose(f);        //<- I use a breakpoint here to verify the buffer contents
    return 0;
}

誰かが私の愚かな間違いを指摘してもらえますか?

4

2 に答える 2

21

誰かが私の愚かな間違いを指摘してもらえますか?

Windowsプラットフォームだと思いますか?

これを使って:

FILE* f = fopen("test.png", "rb");

これの代わりに:

FILE* f = fopen("test.png", "r");

説明については、 msdnを参照してください。

于 2010-08-22T19:47:38.727 に答える
8

SigTermからの正解を拡張して、テキストモードでPNGファイルを開くために行った効果が得られた理由の背景を次に示します。

PNG形式では、8バイトのファイルヘッダーを次のように説明しています。

PNGファイルの最初の8バイトには、常に次の値が含まれています。

   (10進数)137 80 78 71 13 10 26 10
   (16進数)89 50 4e 47 0d 0a 1a 0a
   (ASCII C表記)\ 211 PNG \ r \ n \ 032 \ n

この署名は、ファイルをPNGファイルとして識別し、一般的なファイル転送の問題を即座に検出します。最初の2バイトは、最初の2バイトがファイルタイプを一意に識別することを期待するシステム上のPNGファイルを区別します。テキストファイルがPNGファイルとして誤認識される可能性を減らすために、最初のバイトは非ASCII値として選択されます。また、ビット7をクリアする不正なファイル転送をキャッチします。バイト2から4は、フォーマットに名前を付けます。CR-LFシーケンスは、改行シーケンスを変更する不正なファイル転送をキャッチします。control-Z文字は、MS-DOSでのファイル表示を停止します。最後の改行は、CR-LF変換問題の逆をチェックします。

テキストモードでfread()は、Ctrl+Z文字を含む6番目のバイトを読み取ったときにtoの呼び出しが終了したと思います。Ctrl + Zは、これまでMSDOS(およびその前のCPM)でファイルの終わりを示すために使用されていました。これは、ファイルシステムがファイルのサイズをバイト数ではなくブロック数として保存するために必要でした。

バイナリモードではなくテキストモードでファイルを読み取ることにより、TYPEコマンドを誤って使用してPNGファイルを表示することに対する保護をトリガーしました。

このエラーの診断に役立つ可能性のあることの1つは、使用方法をfread()少し変えることです。からの戻り値をテストしていませんfread()。あなたがすべき。さらに、次のように呼び出す必要があります。

...
size_t nread;
...
nread = fread(buffer, sizeof(buffer), 1, f);

つまり、これnreadは実際にバッファに書き込まれたバイト数です。テキストモードのPNGファイルの場合、最初の読み取りで5バイトしか読み取らないことが通知されます。ファイルをそれほど小さくすることはできないので、何か他のことが起こっているという手がかりがあったでしょう。バッファの残りのバイトは、によって変更されることはありませんでしたfread()。これは、バッファを他の塗りつぶし値に初期化した場合に見られたはずです。

于 2010-08-23T02:07:02.867 に答える