Если нравится наш проект, пожалуйста, поддержите любой приемлимой суммой чтобы помочь оплачивать хостинг. Спасибо!
Навигация  [ RU | EN ]

Новые комментарии

Последние файлы

Пожертвования
[ Через QIWI ]
+77785298462

[ Через Яндекс.Деньги ]
410011494554572

[ Через WebMoney ]
WMR R849059014348
WMZ Z157557603481

Наши друзья

Статьи

Распакуй файло


В данной статье будут рассматриваться архивы от игр, т. н. "без сжатия", где куча файлов просто сливается в один (в играх Doom эти архивы остроумно назвали WAD - т.е. "комок").


Общие положения

Если у Вас есть архив, то распаковать его обычно не сложно. Почти все архивы устроены одинаково:

1) Сначала идёт сигнатура архива: "BIGF", "IWAD", "PACK"... (иногда, конечно, может и не быть).

2) Количество файлов в архиве (в Doom для этих целей используется файл "F_END" - последний файл, дальше не распаковывать).

3) Размер заголовка (редко).

4) Описание файлов. Обычно состоит из имени файла (нередко с путём), размера и смещения (либо от начала файла-архива, либо от конца заголовка-описания). Есть правда "долбанутые" архивы (например из игры Syberia II), где хранится только размер и имя файла - тогда приходится высчитывать смещение вручную. Имя файла обычно заканчивается символом $00 или оно фиксировано, скажем, 8 символов как в .WAD (что не используется - забивается тем же нулём). Смещение и размер бычно 4 (dword) байта.

Важно: "FAT архива" или, проще говоря, заголовки файлов, могут шифровать (в играх Max Payne .RAS архивы), чтобы кто-нибудь умный не вытащил. Но если не шифровали сами файлы, то их нетрудно достать. Например, .WAV, .BMP, .AVI - содержат в начале описания свой размер.

В архивах Quake-подобных игр (.PAK, .WAD) раздел-описание файлов находится не в начале, а в конце архива. В начале стоит ссылка (4 байта) на место в файле, с которого начинается раздел-описание файлов.


Пример

Рассмотрим формат архива от игры C&C: Generals. Возьмём файл MUSIC.BIG и будем тащить оттуда музыку (заодно и послушаем в удовольствие). Раскройте файл каким-нибудь HEX редактором. Смотрим:

1) Первые 4 байта сигнатура - "BIGF".

2) Вторые 4 байта - размер файла-архива.

3) Опять 4 байта - количество файлов в архиве (ВНИМАНИЕ! Эти и ВСЕ последующие 4 байта перед использованием нужно РАЗВЕРНУТЬ ЗАДОМ НАПЕРЁД!!!).

4) 4 байта - размер всего заголовка-описания в файле-архиве (развернуть!).

5) Смещение файла от начала файла-архива - 4 байта (развернуть!).

6) Размер файла - 4 байта (развернуть!).

7) Имя файла (вместе с путём). Заканчивается символом $00.


Пункты 5-7 повторить пока не пройдёте все файлы в архиве (generals.asc, который распакуется, можете переименовать в .TGA и полюбоваться на него).



--- Листинг программы для вытаскивания музыки из MUSIC.BIG файла ---

(можете скачать эту программу из раздела "Файловый архив")


{ Распаковщик BIGF файлов из игр от Electronic Arts }

{ Написана на Delphi }

Program EAUnpack;


{$APPTYPE CONSOLE} { консольное приложение }


Uses SysUtils;

Var

TF, FPos, Sz, FSz, FOffs, I: LongInt;

S, St, Sd: String;

P: Pointer;

Fl, F: File;

B: Byte;

SChar: Char; { Slash char - for NFSU2 }


{ прочедура для "разворота" типа LongInt }

Function ReadLong(Var F: File; VIV: Boolean): LongInt;

Var K, Bl: Byte;

L: LongInt;

Begin

L:=0;

If VIV=False Then BlockRead(F, L, 4)

Else

For K:=3 DownTo 0 Do

Begin

BlockRead(F, Bl, 1);

L:=L+(Bl Shl (8*K));

End;

ReadLong:=L;

End;


Begin

WriteLn('EA Unpacker (for BIGF)');

WriteLn('For .BIG (C&C: Generals) / .VIV (Need For Speed (includes Underground 2!))');

WriteLn('T#i$ PR0GR@M bY -=CHE@TER=-');

WriteLn('http://CTPAX-CHEATER.losthost.org');

WriteLn;

If ParamCount<>1 Then

Begin

WriteLn('Usage: eaunpack filename.ext');

Exit;

End;

If FileExists(ParamStr(1))=False Then

Begin

WriteLn('Input file not found!');

Exit;

End;

AssignFile(Fl, ParamStr(1));

Reset(Fl, 1);

SetLength(S, 4);

BlockRead(Fl, S[1], 4);

If (S<>'BIGF') And (S<>'BIG4') Then { 'BIG4' for NFSU2 } { читаем сигнатуру }

Begin

CloseFile(Fl);

WriteLn('This is not BIG/VIV archive!'); { Упс! Это - не BIGF! }

Exit;

End;

Sz:=ReadLong(Fl, False); { Читаем нормальные 4 байта }

If Sz<>FileSize(Fl) Then { Если не равны размеру файла, то пытаемся }

Begin { прочитать как "развёрнутые" }

Seek(Fl, 4);

Sz:=ReadLong(Fl, True);

End;

If Sz<>FileSize(Fl) Then { если и после этого не совпало - то это не BIGF }

Begin

CloseFile(Fl);

WriteLn('This is not BIG/VIV archive!');

Exit;

End;

TF:=ReadLong(Fl, True); { Total Files - количество файлов в архиве }

Seek(Fl, FilePos(Fl)+4);{ Пропускаем развёрнутые 4 байта - размер заголовка }

For I:=1 To TF Do { от 1 до количества_файлов_в_архиве делать: }

Begin

FOffs:=ReadLong(Fl, True); { читаем смещение файла }

FSz:=ReadLong(Fl, True); { читаем размер файла }

S:=''; { чистим строчку }

Repeat

BlockRead(Fl, B, 1); { читаем байты из файла, пока не встретится символ 0 }

If B<>0 Then S:=S+Chr(B); { и добавляем их в строку - формируем имя }

Until B=0;

FPos:=FilePos(Fl); { запоминаем текущую позицию в заголовке, чтобы вернуться позже }

St:=S;

If Pos('/', St)<>0 Then SChar:='/' { <- данная примочка, для файлов из NFSU2 - }

Else SChar:='\'; { определяет символ-разделитель для каталогов }

While (Length(St)>0) And (St[Length(St)]<>SChar) Do

Delete(St, Length(St), 1); { вычленяем путь, без имени файла }

If Length(St)>0 Then

Begin

Sd:='.';

While Length(St)<>0 Do

Begin

{ по очереди удлинняем имя пути ... }

Sd:=Sd+'\'+Copy(St, 1, Pos(SChar,St));

Delete(Sd, Length(Sd), 1);

{ ... и создаём его, если его нет }

If DirectoryExists(Sd)=False Then CreateDir(Sd);

St:=Copy(St, Pos(SChar, St)+1, Length(St));

End;

End;

Seek(Fl, FOffs); { смещаемся в файле-архиве в то место, где начинается файл }

GetMem(P, FSz); { выделяем кусок памяти под его размер }

BlockRead(Fl, P^, FSz); { читаем его в память }

AssignFile(F, S); { создаём новый файл }

ReWrite(F, 1);

BlockWrite(F, P^, FSz); { и засовываем туда содержимое буфера }

CloseFile(F);

FreeMem(P, FSz); { чистим память }

Seek(Fl, FPos); { перемещаемся обратно к заголовку, где остановились }

WriteLn(S); { для отчётности выводим имя файла, который распаковали }

End;

CloseFile(Fl);

WriteLn;

WriteLn('Total files: ', TF); { выводим количество распакованных файлов }

End. { всё... }


2006-04-15 11:43
-=CHE@TER=-

© CTPAX-X 2006-2019 | engine version 2.4
Based on original site design by Blade




При копировании материалов ссылка на сайт WWW.CTPAX-X.ORG обязательна!
Использование материалов влечёт безоговорочное принятие правил сайта.
Количество запросов к БД: 7 | Страница сгенерирована за 0.004781 сек.