В ожидании задачника четвертого уровня я несколько дней просматривал фотографии, сохраненные моей цифровой камерой на карту памяти объемом 1 GB CompactFlash (CF). Фотки записаны в формате JPEG. Только не говорите мне, пожалуйста, что на самом деле я провел последние несколько дней на Facebook вместо этого. К сожалению, мои навыки владения компьютером оставляют желать лучшего, и я, сам того не ведая, случайно удалил мои драгоценные фоточки! К счастью, в цифровом мире «удален», как правило, не равняется «убит». Мой компьютер настаивает на том, что карта-памяти теперь пуста, но я-то знаю, что он лжёт.
Посему, вот ваше третье задание на эту неделю: Напишите в ~/workspace/pset4/jpg/recover.c
программу, которая восстановит мои фотографии.
Хммм… Сложно, да? Ладно, вот ещё кое-какое уточнение. Несмотря на то, что JPEG-формат сложнее, чем BMP, в него встроена полезная подсказка: JPEG имеет «подписи», шаблоны байтов, которые помогут отличить их от других форматов файлов. Большинство JPEG-файлов начинается со следующих трех байтов:
0xff 0xd8 0xff
От первого байта до третьего, слева направо. Четвертый байт, скорее всего, будет одной из следующих комбинаций: 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,0xe8, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef
. Иными словами, первые четыре бита четвертого байта JPEG-файла —1110.
Скорее всего, если вы найдете один из этих шаблонов на диске, на котором хранились фотографии (например, моя карта памяти), это и будет начало JPEG-файла. Конечно, вы можете столкнуться с такой комбинацией на диске случайно… Восстановление данных нельзя назвать точной наукой.
Как решать
- Открыть файл с содержимым карты памяти
- Найти начало JPEG-файла. Все файлы на этой карте являются картинками в JPEG-формате.
О маркерах JPEG вы уже знаете:
Важно (и приятно) осознавать, что каждый JPEG-файл сохраняется в памяти единым блоком, а сами файлы следуют один за другим. Изобразим схематическую карту памяти. Каждый прямоугольник — блок длиной 512 байт. Серые прямоугольники — области, где файлы JPEG отсутствуют, звездочками обозначено начало JPEG-файла. Полагаем, что серых блоков между файлами у нас нет.
Как нам прочитать эти данные, эти 512 байтов, чтобы сравнить их начало с заголовком JPEG? Можно воспользоваться уже знакомой нам функцией fread
, которая принимает указатель на структуру данных, куда будут записаны прочитанные байты, а также размер элемента, который прочитывается, количество таких элементов и указатель на файл, из которого мы читаем данные.
Мы хотим прочитать 512 байт и сохранить их в буфере. Им будет служить указатель &data
, а указатель inptr
будет указывать на открытый файл с содержимым карты памяти. Итак, вернемся к структуре нашего файла, в котором сохранено содержимое карты памяти. Мы собираемся читать блоки по 512 байт и сохранять их в буфер, пока не будем знать, что с этим буфером делать. Сначала буфер пуст. Мы читаем первый блок данных, сравниваем его с маркером JPEG и идем дальше.
sprint
, в которую передается шаблон и аргумент.fwrite
. fread
возвращает количество элементов размера size
, которые были успешно прочитаны. В идеале size
должно совпасть c number. Нам нужно организовать условный оператор, который позволит посчитать, сколько элементов на самом деле было прочитано.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ