DIFAT – Double Indirection File Access Table. Это массив 4х байтных номеров секторов, в которых находится FAT. Первые 109 записей хранятся в первом секторе файла (пять из них выделены жёлтым внизу КДПВ). Если файл больше 6.8 Мбайт (436 Мбайт для v4), то следующие сектора DIFAT хранятся как односвязный список. Номер первого сектора из этого списка хранится в заголовке. В кажом из этих секторов хранится 127 (1023) указателей на сектора с FAT, а в последних 4х байтах — номер следующего сектора DIFAT.
FAT – File Access Table. Это массив из 4х байтных значений. Работает так же, как в одноимённой файловой системе. Каждому сектору в файле (кроме заголовочного) соответствует 4х байтное значение в FAT.
Для чтения потока данных (STREAM) нужно знать длину потока (в байтах) и номер первого сектора этого потока. Номер следующего сектора всегда записан в элементе FAT, соответствующем текущему сектору. В элементе FAT, соответствующем последнему сектору в потоке, будет записано значение 0xFFFFFFFE (EndOfChain).
Это структура, которая хранит информацию обо всех остальных объектах в файле, аналог структуры каталогов. Сама она хранится в виде потока данных, длина и первый сектор которого записаны в заголовке файла. Представляет из себя массив 128 байтных записей. Каждая запись соответствует хранимому объекту. Объекты в directory имеют имя и бывают 4х видов:
У каждого объекта есть временные метки: время создания и время модификации, правда часто они просто заполнены 0.
Пример дерева директорий небольшого doc файла:Root_storage:Root Entry 06090200-0000-0000-c000-000000000046
- Stream:x01CompObj[106]
- Stream:x01Ole[20]
- Stream:1Table[4640]
- Stream:Data[374]
- Stream:x05SummaryInformation[172]
- Stream:WordDocument[198510]
- Storage:ObjectPool 00000000-0000-0000-0000-000000000000
- Stream:x05DocumentSummaryInformation[116]
В принципе описанного выше достаточно для хранения данных, но в CFB предусмотрена ещё оптимизация для хранения коротких потоков данных — меньше 4096 байт.
При хранении потока данных, длина которого не кратна длине сектора, в последнем секторе остаётся некоторое количество неиспользуемых байт. Чем больше сектор — тем больше таких байт в среднем остаётся. Для борьбы с этой проблемой все небольшие (меньше 4096 байт) потоки данных хранятся не в обычных секторах по 512 (4096) байт и FAT, а в отдельном потоке, разбитом на сектора по 64 байта. Этот поток называется MiniStream, а информация для сцепления его секторов в потоки хранится в MiniFAT. Работает это всё совершенно аналогично основной FAT.
И MiniFAT, и MiniStream хранятся как обычные (не Mini) потоки данных. Номер первого сектора и длина MiniFAT хранятся в заголовке, а информация о MiniStream — в объекте «Root Entry» (логической причины хранить именно там не вижу).
Получается такая «матрёшка»: файл разделён на 512 (4096) байтные сектора, а один из потоков, состоящих из этих секторов, рассматривается как последовательность 64 байтных секторов, и в нём уже хранятся «мини» потоки данных.
Откуда читать поток данных: из «большой» FAT или из MiniStream, определяется только по его размеру (меньше 4096 — из MiniStream, иначе — как обычный поток).
CFB используется как хранилище, позволяющее сохранить данные разных приложений в одном файле. Если вы хотите докопаться до человекочитаемых данных, то надо парсить потоки данных, извлечённые из CFB, в соответствии с форматом данных приложения. Эта тема выходит за пределы данной статьи (но см. ссылки).
По идее такая структура файла была разработана для ускорения внесения отдельных изменений в файл без его полной перезаписи. Не думаю, что это свойство ценно сейчас для обычных офисных документов размером несколько мегабайт.
В общем структура файла CFB — просто кладезь для стеганографии, основанной на формате файла. Т. е. сделать совершенно корректный файл, который при открытии в ворде покажет «Hello world», а внутри будет ещё много, которые «правильный» парсер будет считать просто мусором — вообще не проблема.
С другой стороны — огромный простор для ошибок, путаницы и т. п., огромное количество избыточных записей. Например, можно «зациклить» цепочку секторов, образующую поток. «Наивный» парсер при чтении такого файла зависнет.
P.S. Файлы MS Office 2007 и старше (docx, xlsx, pptx, docm,…) имеют совершенно другой формат. Внутри там тоже дерево директорий, только вместо CFB там используется ZIP (да, их можно прям раззиповать). Однако макросы, например, хранятся внутри документа в файле vbaProject.bin, который является Compound файлом.
VK объявляет о приобретении 40% компании Intickets.ru (Интикетс). Это облачный сервис для контроля и управления продажей билетов на мероприятия. Сумма…
OpenAI готовится запустить собственную поисковую систему на базе ChatGPT. Информацию об этом публикуют западные издания. Ожидается, что новый поисковик может…
Центр управления связью общего пользования (ЦМУ ССОП) Роскомнадзора рекомендовал компаниям из реестра провайдеров ограничить доступ поисковых ботов к информации на российских сайтах.…
Apple возобновила переговоры с OpenAI о возможности внедрения ИИ-технологий в iOS 18, на основе данной операционной системы будут работать новые…
Конкурсный управляющий российской «дочки» Google подготовил 23 иска к участникам рекламного рынка. Общая сумма исков составляет 16 млрд рублей –…
Google завершил обновление основного алгоритма March 2024 Core Update. Раскатка обновлений была завершена 19 апреля, но сообщил об этом поисковик…