Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 04.05.2012, 13:16   #1
Anton911
Форумчанин
 
Аватар для Anton911
 
Регистрация: 23.08.2011
Сообщений: 171
По умолчанию Хочу написать распаковщик формата

Всем привет!
Грубо говоря есть некая игра, у которой ресурсы хранятся в архивах, самые крупные это *.img
Нашел информацию об данном формате
Код:
Заголовок:
 4 байта	 - CHAR[4]	- сигнатура архива, всегда имеет значение "VER2"
 4 байта	 - DWORD	- общее количество элементов (файлов)
Элемент: (повторяется n-раз, где n - общее количество элементов):
 4 байта - DWORD     - смещение файла (в блоках) в архиве
 4 байта - DWORD     - размер файла (в блоках)
24 байта - CHAR[24]  - имя файла
Сначало сделал простенькую программу, где методом работы с файлами читал строку используя ReadLn. Действительно первые 4 символа "VER2".
А теперь вопрос, как лучше всего работать с байтами?
Код:
var s:string;
ch: array[0..4] of Char;
begin
if FileExists(Edit_PathToImg.Text) then
  Begin
  ImgArhStream:=TFileStream.Create(Edit_PathToImg.Text, fmOpenReadWrite);
  ImgArhStream.Read(ch,4);
  Memo_Console.Lines.Add(String(ch));
  ImgArhStream.Free;
  End;
Читаю 4 байта, а в мемо выводется "䕖㉒ꢧE". Что именно не так?
Каждый день узнаю новое...
Anton911 вне форума Ответить с цитированием
Старый 04.05.2012, 13:21   #2
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

не надо путать юникод и анси.
вам надо AnsiChar.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 04.05.2012, 14:10   #3
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
А теперь вопрос, как лучше всего работать с байтами?
имхо, идеально подходит TFileStream - и им можно читать так в массив байт, так и в строку или вообще в заданную структуру данных (если, конечно, структура файл позволяет - т.е. имеет фиксированный блок кода!).
Serge_Bliznykov вне форума Ответить с цитированием
Старый 04.05.2012, 14:45   #4
Anton911
Форумчанин
 
Аватар для Anton911
 
Регистрация: 23.08.2011
Сообщений: 171
По умолчанию Код программы

Так, ладно уже более менее разобрался, и получаю адекватную информацию)
Код:
var
  Form1: TForm1;
  Head:Ansichar;
  ElementCount:DWORD;
  ImgArhStream:TFileStream;

  const
  BlockCount=1024;  //Колличество байт в килобайте
  sBlockCount=2;    //Колличество килобайт в одном блоке
  FileExtr=300;     //Не важно

implementation

{$R *.dfm}

procedure TForm1.Button_OpenIMGClick(Sender: TObject);
begin
if FileExists(Edit_PathToImg.Text) then
  Begin
  ImgArhStream:=TFileStream.Create(Edit_PathToImg.Text, fmOpenReadWrite);
  ImgArhStream.Read(Head,4);  //Считываем 4 байта из заголовока
  ImgArhStream.Read(ElementCount,4);  //Считываем колличество элементов
  Memo_Console.Lines.Add('Заголовок '+String(Head)+' колличество файлов '+IntToStr(ElementCount));
  GetFilesInfoFromImg;
  ImgArhStream.Free;
  End;
end;

procedure TForm1.GetFilesInfoFromImg;
  var
  FileOffset:DWORD;
  FileStrange:DWORD;
  FileNameChr: array[0..23] of AnsiChar;
  FileIndex:LongInt;
begin
Process.Min:=0;
Process.Max:=FileExtr;
try
Begin
  for FileIndex := 0 to FileExtr-1 do
    Begin
    ImgArhStream.Seek(FileIndex*32+8,0);  //24 байта имя файла, 4 байта размер, 4 байта смещение и +8 байт заголовок
    ImgArhStream.Read(FileOffset,4);    //Считываем смещение
    ImgArhStream.Read(FileStrange,4);   //Считываем размер
    ImgArhStream.Read(FileNameChr,24);  //Считываем имя
    Memo_Console.Lines.Add('Файл: Номер '+IntToStr(FileIndex)
      +'; Название '+String(FileNameChr)
        +'; Размер байт'+IntToStr(FileStrange*BlockCount*sBlockCount)
          +'; Смещение байт '+IntToStr(FileOffset*BlockCount*sBlockCount));
    Process.Position:=FileIndex;
    Form1.Caption:=IntToStr(FileIndex);
    ExtractFile(FileStrange,FileOffset,FileNameChr);
    End;
End;
except
on E: Exception do
  begin
  showmessage('Ошибка, не важно');
  end;
end;

end;

procedure TForm1.ExtractFile(Strange,Offset:DWORD;FileName:Array of AnsiChar);
  var
  FileSymb:TStringList;
  BlockIndex:integer;
  TempChr:array[0..2047] of AnsiChar;
begin
FileSymb:=TStringList.Create;
ImgArhStream.Seek(Offset*sBlockCount*BlockCount,0);
  for BlockIndex := 1 to Strange do    //1 до размера файла
    Begin
    ImgArhStream.Read(TempChr,sBlockCount*BlockCount);  //Считываем 2048 байт в TempChr
    FileSymb.Text:=FileSymb.Text+String(TempChr);  //Записывем 2048 байт
    Memo_Console.Lines.Add(String(TempChr));
    End;
FileSymb.SaveToFile(String(FileName));  //Сохраняем в файл
FileSymb.Free;
end;
Переделал код программы в более читабельный.
Весь архив разделен на блоки по 2 кб, 2*1024=2048 байт.
В размере файла указывается колличество блоков, также и в смещении. Поэтому мы умножаем их на 2*1024, чтобы получить число в байтах.
Размер и смещение находит правильно, вот только почемуто записывает файлы не полностью, из 10 кб только 2 кб, в чем дело?
Каждый день узнаю новое...

Последний раз редактировалось Anton911; 04.05.2012 в 17:29. Причина: Оптимизация и коментарии
Anton911 вне форума Ответить с цитированием
Старый 05.05.2012, 10:43   #5
Anton911
Форумчанин
 
Аватар для Anton911
 
Регистрация: 23.08.2011
Сообщений: 171
По умолчанию

Все разобрался, сделал, может комуто поможет:
Код:
var
  Form1: TForm1;
  Head:Ansichar;
  ElementCount:DWORD;
  ImgArhStream:TFileStream;

const
  ArhBlockCount=2048; //Размер одного архивного блока (байт)
  FileExtr=300;     //Читаем только 300 файлов из общего числа

implementation

{$R *.dfm}

procedure TForm1.Button_OpenIMGClick(Sender: TObject);
begin
if FileExists(Edit_PathToImg.Text) then
  Begin
  ImgArhStream:=TFileStream.Create(Edit_PathToImg.Text, fmOpenReadWrite);
  ImgArhStream.Read(Head,4);  //Считываем 4 байта из заголовока
  ImgArhStream.Read(ElementCount,4);  //Считываем колличество элементов
  Memo_Console.Lines.Add('Заголовок '+String(Head)+' колличество файлов '+IntToStr(ElementCount));
  GetFilesInfoFromImg;
  ImgArhStream.Free;
  End;
end;

procedure TForm1.GetFilesInfoFromImg;
  var
  FileOffset:DWORD;
  FileStrange:DWORD;
  FileNameChr: array[0..23] of AnsiChar;
  FileIndex:LongInt;
begin
Process.Min:=0;
Process.Max:=FileExtr;
try
Begin
 for FileIndex := 0 to FileExtr-1 do
    Begin
    ImgArhStream.Seek(FileIndex*32+8,0);  //24 байта имя файла, 4 байта размер, 4 байта смещение и +8 байт заголовок
    ImgArhStream.Read(FileOffset,4);    //Считываем смещение
    ImgArhStream.Read(FileStrange,4);   //Считываем размер
    ImgArhStream.Read(FileNameChr,24);  //Считываем имя
    Memo_Console.Lines.Add('Файл: Номер '+IntToStr(FileIndex)
      +'; Название '+String(FileNameChr)
        +'; Размер байт'+IntToStr(FileStrange*ArhBlockCount)
          +'; Смещение байт '+IntToStr(FileOffset*ArhBlockCount));
    Process.Position:=FileIndex;
    Form1.Caption:=IntToStr(FileIndex);
    ExtractFile(FileStrange,FileOffset,FileNameChr);
    End;
End;
except
on E: Exception do
  begin
  showmessage('Ошибка, не важно');
  end;
end;
end;


procedure ExtractFile(Strange,Offset:DWORD;FileName:Array of AnsiChar);
  var
  BlockIndex:integer;
  TempChr:array[1..2048] of AnsiChar;
  SaveFile:TFileStream;
  ByteStrange:integer;
  StrangeIndex:integer;
begin
SaveFile:=TFileStream.Create(String(FileName),fmCreate {fmOpenWrite});
ImgArhStream.Position:=ArhBlockCount*Offset;
ByteStrange:=Strange*ArhBlockCount;
  try
    for StrangeIndex := 1 to Strange do
      begin
      ImgArhStream.Read(TempChr,ArhBlockCount);
      SaveFile.Write(TempChr, ArhBlockCount);
      end;
  finally
    SaveFile.Free;
  end;
end;
Это был распаковщик формата img из GTA SAN ANDREAS
Каждый день узнаю новое...
Anton911 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
bash-распаковщик архивов SNake Ice Помощь студентам 0 02.04.2011 04:31
Хочу написать Программу Letnab Помощь студентам 2 16.12.2009 12:24
Нужен распаковщик .ехе файлов Veselyn Софт 3 03.05.2009 06:24