Только первые 5 байтов файла .PNG - PullRequest
9 голосов
/ 22 августа 2010

Я сделал простой упаковщик ресурсов для упаковки ресурсов для моей игры в один файл. Все шло хорошо, пока я не начал писать распаковщик. Я заметил, что файл .txt - 26 байт - который я упаковал, вышел из файла ресурсов нормально, без каких-либо проблем, все данные сохранились. Однако при чтении файла .PNG, который я упаковал в файл ресурсов, первые 5 байтов были целы, а остальные полностью аннулированы.

Я проследил это до процесса упаковки и заметил, что fread читает только первые 5 байтов файла .PNG, и я не могу понять, почему. Он даже запускает 'EOF', указывая, что файл имеет длину всего 5 байтов, тогда как на самом деле это PNG размером 787 байтов маленького многоугольника, 100 на 100 пикселей.

Я даже протестировал эту проблему, создав отдельное приложение для простого чтения этого 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;
}

Может кто-нибудь указать на мою глупую ошибку?

Ответы [ 2 ]

21 голосов
/ 22 августа 2010

Может кто-нибудь указать на мою глупую ошибку?

Платформа Windows, наверное?

Используйте это:

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

вместо этого:

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

См. msdn для объяснения.

8 голосов
/ 23 августа 2010

Расширение правильного ответа от SigTerm , вот некоторый фон , почему вы получили эффект от открытия файла PNG в текстовом режиме:

Формат PNG объясняет свой 8-байтовый заголовок файла следующим образом:

Первые восемь байтов файла PNG всегда содержат следующие значения:

   (decimal)              137  80  78  71  13  10  26  10
   (hexadecimal)           89  50  4e  47  0d  0a  1a  0a
   (ASCII C notation)    \211   P   N   G  \r  \n \032 \n

Эта подпись идентифицирует файл как файл PNG и обеспечивает немедленное обнаружение распространенных проблем с передачей файлов. Первые два байта различают файлы PNG в системах, которые ожидают, что первые два байта будут однозначно идентифицировать тип файла. Первый байт выбирается как не-ASCII-значение, чтобы уменьшить вероятность того, что текстовый файл может быть неправильно распознан как файл PNG; Кроме того, он перехватывает неверные передачи файлов, которые сбрасывают бит 7. Байты со второго по четвертый называют формат. Последовательность CR-LF ловит неверные передачи файлов, которые изменяют последовательности новой строки. Символ control-Z останавливает отображение файла под MS-DOS. Последний перевод строки проверяет наличие обратной задачи перевода CR-LF.

Я полагаю, что в текстовом режиме вызов fread() был прерван, когда он прочитал шестой байт, содержащий символ Ctrl + Z. Ctrl + Z исторически использовался в MSDOS (и в CPM до него) для указания конца файла, что было необходимо, поскольку файловая система сохраняла размер файла в виде количества блоков, а не количества байтов.

Считывая файл в текстовом режиме вместо двоичного, вы включили защиту от случайного использования команды TYPE для отображения файла PNG.

Единственное, что вы могли бы сделать, чтобы помочь диагностировать эту ошибку, это использовать fread() немного по-другому. Вы не проверяли возвращаемое значение из fread(). Вам следует. Далее, вы должны назвать это так:

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

, так что nread - это число байтов, фактически записанных в буфер. Для файла PNG в текстовом режиме он сказал бы вам при первом чтении, что он читает только 5 байтов. Поскольку файл не может быть таким маленьким, вы бы знали, что происходит что-то еще. Оставшиеся байты буфера никогда не изменялись с помощью fread(), что было бы замечено, если бы вы инициализировали буфер каким-либо другим значением заполнения.

...