Формат war-файлаМатериал из Blitz Et CeteraКак уже было сказано ранее, в статье о формате pud-файла, Близзарды не горят желанием светить всю медиа-составляющую своих игр. А потому они тщательно ее скрывают. Нетрудно догадаться что один из самых больших файлов игры, как раз-таки содержит то, что от нас так поспешно хотели скрыть. Файл Maindat.war в папке Data из игры Вар2, наталкивает на мысль о том, что в нем находятся нужные нам вкусности, не только своим названием, но и своим размером. WAR - Warcraft ARchive. Сразу хочу оговориться, что я не считаю себя супер-хакером или кем-то в этом духе, но открыв файл в 16-ричном редакторе, сразу бросается в глаза стройность рядов 00 в определенных местах, а как говорят бывалые вскрыватели ресурсов игр, это ни что иное как FAT (или таблица расположения файлов - по нашему). Первые 4 байта как правило у Близзардов, да и не только у них - это заголовок. Дальше 2 байта(слово) с количеством файлов(секций или секторов) в этом файле, дальше 2 байта чепухи, и наконец начинаются смещения к началу секторов, друг за другом, количеством прочитанным ранее. До этого я докумекал сам, пока не нашел формат этого файла всрытый уже кем-то другим. Скачал с сайта wotsit.org - там много информации о файлах по их расширениям. Вот то, что было указано там: WAR File Format 00:0000-00:0003 L Id caption number $19000000 00:0004-00:0005 W Number of entries ( max enrty number +1 ) 00:0006-00:0007 W Archive Id ( used for entry determination) 1000=Maindat.war 2000=Snddat.war 3000=Rezdat.war 4000=Strdat.war 5000=Sfxdat.sud 6000=Muddat.cud 00:0008-XX:XXXX L Entry offsets in in file $FFFFFFFF=unavailable (used in demo version) XX:XXXX RXX Entries PseudoEntry=everything shorter than 4 bytes (counted by substracting offsets) UsefulEntry Index : Feature : 00 W Lower Entry Length word =entry datasize-4 02 B Higher Entry Length word 03 B LZSS Compression flag 00=uncompressed 20=compressed LZSS Compression scheme : 4096 Bytes buffering system 00 B Flags bits=bytes in next 8 records Bit set = any duplicity , use the same byte in buffer on current position record = byte Bit clear = duplicity on position in lower byte and lower nibble offset of length in higher byte higher nibble Информации скажу я вам немного, зато все по делу. Как видим мы были недалеко от истины в наших рассуждениях. Первые 4 байта и правда заголовок, потом количество секций и идентификатор архива, разный для разных файлов. Да, как видите архивы Варкрафта могут храниться в фалах не только с расширением war, но и sud, cud и наверняка других. Вслед за идентефикатором файла идут смещения (размер 4 байта каждое смещение) относительно начала файла до начала секции. Стоит остановиться. Почему я называю части этого архива секциями, а не файлами? Просто в моем понимании файл - это часть данных имеющих название, ведь у вас на диске каждый файл имеет название, а у секций названий нет, только порядковые номера. Так вот, а вначале каждой секции, если перейти на ее начало, есть тоже маленький заголовок в 4 байта: 1- байт это флаг обозначающий, заархивирована ли секция ( в этом случае байт = 0х20 ), либо не заархивирова( в этом случае этот байт = 0х00 ) и остальные 3 байта - это размер распакованной секции, если она конечно заархивирована. Отлично. Теперь мы знаем что:
Хорошо, уже можем написать немного кода: ' это тип для сектора, который описывает файл в архиве
Type _Sector Я уже использовал тип _Sector для примера с pud-файлом, и мне кажется что это наиболее удачное решение для организации одной секции такого вида информации. Для текущих целей я добавил еще парочку полей с данными необходимых нам для работы с war-архивами. Я сделал достаточно коментариев чтобы понять что творится в каждой строке программы. Можно было бы уже на этом этапе извлекать секции в отдельные файлы, но разве это имеет смысл, когда выяснилось что только 5 или 6 из них не заархивированны, а остальные содержат архивы. В небезызвестном документе, который я уже приводил как пример лаконичности и четкости рамок мысли, есть даже подсказка что это LZSS-архивация и даже, то как ее расшифровать. Честно скажу ниасилил, да и не пытался особо, я люблю когда описание эээ немного подлиннее и поконкретнее, поэтому я решил использовать для разархивирования наработки уже сделанные другими... Поиски мои привели меня даже на сайт Apple где лежала функция обрадовавшая меня своим названием (decompress_lzss) и ничего что на С, этот язык мне тоже знаком, тем более что я давно хотел проверить как подключать С-функции к БМаксу. Но как я не пытался, эта функция работать как надо не хотела. Она выдавала все что угодно, только не правильный результат. Тогда, слави Гугл-единый, откопал код такого же извиняюсь археолога Варкрафта как и я, в опен сорс. Оказывается не я один копаюсь в дерьме мамонтов (я думаю никто не посмеет оспорить, что это мамонты ). :) Так вот из кода была выдрана, самым наглым образом, функция разархивации, подрейхтована напильником и подключена к БМаксу. Надо бы по честному связаться с ним и сказать спасибо, правда в том месте стоит коммент // FIXME: If the decompression is too slow, optimise this loop :->
думаю это означает, что он и сам не очень доволен кодом, а значит не будет кричать о копирайтах и другой чуши. :) Так вот функция была внедрена и показала себя отлично. Все секции были извлечены. Да, но остался вопрос, что каждая секция означает, какую информацию она в себе несет? Эти вопросы не так сложны как кажутся, но и тут есть подвох. Мы привыкли (в виндовз) что расширение файла означает его принадлежность к какому-либо формату. А у секций, нет расширений, да что говорить у них и имен-то нет. (Эко их Близзарды уделали). Но не беда, открыв файлы 16-ричным редактором легко заметить по первым байтам, к каким категориям принадлежат эти файлы. Так например файл начинающийся символами FORM - означает звуковой файл XMI. RIFF - звуковой файл WAV , SMK2 - анимационный ролик и т.д. По размеру секции тоже можно кое-что догадаться, например размер 768- байт сразу наталкивает о мысли, что в нем хранится палитра. Так как игра старая, то она использовала только 256 цветов, которые брала из палитры. А палитра заполнялсь значениями RGB, три байта на 1 цвет палитры (3 * 256 = 768). В связи с этим рисунки имеют структуру простого массива, где в каждой ячейке лежит байт указывающий на цвет (индекс в таблице палитры), другими словами RAW-рисунок. Так, например, размер 64004 наталкивает на мысль, что это RAW-рисунок во весь экран режим VGA( 320x200 ) 320 х 200 = 64000 и еще 4 байта это наверняка его размеры в первых 4 байтах. Так и есть первые 4 байта 4001С800 - что значит 0х0140 = это 320 в десятичной и С8 - это 200. Обычно секции рисунков и палитр находятся рядом. Этим же образом смотрятся и другие файлы. С файлами анимации и стадий постройки сданий, несколько сложнее, там тоже свой формат. Но вас это пугать не должно, он тоже описан :) Спасибо за внимание, в аттаче исходник и файл распаковщик в ехе. Автор: Dimanche13 (e-mail: dimanche13 |

