Что у нас есть?

Это тоже интересно




Статьи и описания форматов игровых файлов

Brave Dwarves 2

Эта статья относится к играм:

Автор материала: Varg


Описание формата DAT из игры Brave Dwarves 2 (студия GameOverGame) и пример использования библиотеки Zlib для извлечения ресурсов.


Файлы формата DAT имеют следующее строение:
Заголовок.
Запакованные файлы.
(Запакованные файлы идут блоками и имеют свои заголовки, содержащие необходимую для распаковки информацию после которых идут данные запакованные Zlib`ом.)

Заголовок.

0x00000000 строка длинной 28 байт содержащая "GaveOverGames' Resource File" 
0x00000022 DWORD число указывает на первый запакованный файл 
0x00000026 DWORD количество файлов в архиве


На "С++" это выглядит следующим образом:

struct Header 
{ 
  char Id[0x1d]; //Начальная строка как индефикатор 

  DWORD start; //Начальная позиция 

  DWORD num; //Число файлов 

};


Пример чтения заголовка:

FILE *mfile; 
Header header; //Заголовок DAT файла 

.... 

BOOL ArcOpen(char *arc_name) 
{ 
  if(mfile!=0) 
    fclose(mfile); 
  mfile=fopen(arc_name,"rb"); 
  if(mfile==0) 
  { 
    sprintf(str_error,"Error! Can`t open arc file!"); 
    return FALSE; 
  }; 

  //****************************** 

  // Читаем заголовок 

  //****************************** 

  fread(header.Id,0x1c,1,mfile); 
  if(strcmp(header.Id,"GaveOverGames' Resource File")!=0) 
  { 
    sprintf(str_error,"Error! It`s not BD2 dat file!"); 
    return FALSE; 
  }; 
  fseek(mfile,0x22,0); 
  fread(&header.start,4,1,mfile); 
  fread(&header.num,4,1,mfile); 
  return TRUE; 
};


Запакованные файлы.
Заголовок запакованного файла:

offset+0 DWORD указатель на начало строки содержащей имя запакованного файла. 
offset+8 DWORD указатель на позицию следующего запакованного файла. 
offset+12 DWORD реальный размер запакованных данных. 
offset+16 DWORD размер запакованных данных. 
offset+22 строка содержащая имя запакованного файла.


Далее после строки имени идут сами запакованные данные.

На "C++" можно составить следующую структуру:

struct Arc_File 
{ 
  DWORD start_pos; //Указатель на имя файла 

  DWORD size; //Размер запакованных данных 

  DWORD r_size; //Реальный размер данных 

  DWORD data_pos; //Указатель на данные 

  DWORD next; //Указатель на следующий файл 

  char name[256]; //Имя запакованного файла 

};


Пример чтения информации из заголовков запакованных файлов:

FILE *mfile; 
Header header; //Заголовок 

Arc_File *afile; //Заголовки запакованных файлов 

... 

BOOL ArcScan() 
{ 
  afile=new Arc_File[header.num]; //Выделяем память под заголовки 

  if(!afile) 
  { 
    printf(str_error,"Error! Can`t Alloc Memory!"); 
    return FALSE; 
  }; 
  long off=0; 
  fseek(mfile,header.start,0); //Устанавливаем указатель на начало (заголовок) запакованного файла. 


  for(int i=0;i<header.num;i++) 
  { 
    fread(&afile[i].start_pos,4,1,mfile); //Читаем указатель на имя запакованного файла. 

    fseek(mfile,off+8,0); //Устанавливаем позицию ф-ла в off+8 

    fread(&afile[i].next,4,1,mfile); //Читаем смещение по которому расположен следующий запакованный файл.

    fseek(mfile,off+12,0); //Устанавливаем позицию ф-ла в off+12 

    fread(&afile[i].r_size,4,1,mfile); //Читаем реальный размер упакованных данных. 

    fseek(mfile,off+16,0); //Устанавливаем позицию ф-ла в off+16 

    fread(&afile[i].size,4,1,mfile); //Читаем размер упакованных данных. fseek(mfile,afile[i].start_pos,0); //Устанавливаем указатель на начало строки содержащей имя запакованного файла.

    fread(afile[i].name,afile[i].next-afile[i].start_pos-afile[i].size-1,1,mfile); //Читаем имя файла (обратить внимание на расчет длинны строки) 

    afile[i].data_pos=off=ftell(mfile); //Читаем позицию файла которая численно равна позиции с которой начинаются данные запакованные zlib. 


    fseek(mfile,afile[i].next,0); //Устанавливаем позицию на следующий запакованный файл. 

  }; 
  return TRUE; 
};


Собственно распаковка всех файлов:

... 
#include "direct.h" 
#include "zlib.h" 
... 
#pragma comment (lib, "zlib.lib") //Подключаем zlib.dll 

... 
FILE *mfile; 
Header header; 
Arc_File *afile; 
... 

void ExtractAll() 
{ 
  FILE *o; //Указатель на файл вывода данных 

  Bytef *cdata; //Упакованные данные 

  Bytef *data; //Распакованные данные 

  uLongf sz=0; //Реальный размер 

  //********************************** 

  //Главный цикл извлечения данных 

  //********************************** 

  for(int i=0;i<header.num;i++) 
  { 
    o=CreateFileName(i); //Создаем файл для вывода данных 

    if(o!=0) 
    { 
      fseek(mfile,afile[i].data_pos,0); //Начало запакованных данных 

      cdata=new Bytef[afile[i].size+1]; //Выделяем память под запакованные данные 

      if(cdata) 
      { 
        data=new Bytef[afile[i].r_size]; //Выделяем память под незапакованные данные 

        if(data) 
        { 
          sz=afile[i].r_size; //Реальный размер 

          fread(cdata,afile[i].size+1,1,mfile); //Читаем запакованные данные из файла DAT 


          //Распаковываем данные из cdata в data с размером r_size используя 

          //функцию из библиотеки ZLib 

          //где &sz реальный размер распакованного файла 

          //afile[i].size+1 размер запакованных данных 

          //если функция uncompress возвращает 0 (Z_OK) значит все рулеzzz 

          //если же нет, то номера ошибок можно найти в zlib.h 

          if(uncompress(data,&sz,cdata,afile[i].size+1)==0) 
          { 
            //Записываем данные data в файл// 

            fwrite(data,afile[i].r_size,1,o); 

          }; 
          delete data; //new data 

        }; 
        delete cdata; //new cdata 

      } 
      fclose(o); //fopen 

    } 
    else 
    { 
      printf("Error"); 
    } 
  }; 

}; 

//************** CreateFileName()*****************// 

//************************************ 

// Функция создающая файл для вывода 

// распакованных данных 

//************************************ 

FILE * CreateFileName(int n) 
{ 
  FILE *out; 
  char str[256]; 
  char sstr[256]; 
  BYTE ch=0; 
  int len=0; 
  strcpy(sstr,afile[n].name); 
  len=strlen(sstr); 
  for(int a=0;a<len;a++) 
  { 
    ch=sstr[a]; 
    if(ch==0x5c) 
    { 
      str[a]=0; 
      mkdir(str); 
    }; 
    str[a]=ch; 
  }; 

  out=fopen(afile[n].name,"wb"); 
  return out; 
};


Вот и все что нужно знать, чтобы распаковать файлы с такой структурой. Причем навык пользования ZLib можно использовать и при написании программ к другим форматам использующим ZLib для компрессии.
По всем вопросам мылить на: [email protected]


 
©2000—2010 Михаил Бесчетнов aka Terminus
«EXTRACTOR.ru» — игровые ресурсы: распаковка музыки и графики, конверторы форматов и многое другое…
Ссылка на «EXTRACTOR.ru» при перепечатывании оригинальных материалов крайне желательна

Rambler's Top100