home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 7662 / gttool_src_bin.7z / gttool / src / volume.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2014-08-01  |  5.4 KB  |  233 lines

  1. #include "volume.h"
  2. #include "crypt.h"
  3. #include "compression.h"
  4. #include "hash.h"
  5. #include "path.h"
  6. #include "file.h"
  7. #include "memory_file.h"
  8. #include "util.h"
  9.  
  10. const uint32_t kGT5_VOLUME_KEY[4] = { 0x2DEE26A7, 0x412D99F5, 0x883C94E9, 0x0F1A7069 };
  11. const uint32_t kGT6_VOLUME_KEY[4] = { 0xAA1B6A59, 0xE70B6FB3, 0x62DC6095, 0x6A594A25 };
  12.  
  13. const char kGT5_VOLUME_SEED[] = { "KALAHARI-37863889" };
  14. const char kGT6_VOLUME_SEED[] = { "PISCINAS-323419048" };
  15.  
  16. namespace
  17. {
  18.     const uint32_t kVOLUME_HEADER_MAGIC = 0x5B745162u;
  19.     const uint32_t kVOLUME_HEADER_SIZE = 0xA0;
  20.  
  21.     const uint32_t kVOLUME_SEGMENT_MAGIC = 0x5B74516Eu;
  22.     const uint32_t kVOLUME_SEGMENT_HEADER_SIZE = 0x08;
  23.     const uint32_t kVOLUME_SEGMENT_SIZE = 0x800;
  24.  
  25.     static KeyContext s_key_context;
  26.  
  27.     struct VolumeHeader
  28.     {
  29.         uint32_t magic;
  30.         uint32_t segment_index;
  31.         uint32_t size;
  32.         uint32_t real_size;
  33.         uint64_t unk4;
  34.         uint64_t file_size;
  35.         char title_id[128];
  36.  
  37.         bool load(IStream* stream)
  38.         {
  39.             if (!stream->read_be(magic) || magic != kVOLUME_HEADER_MAGIC)
  40.                 return false;
  41.             if (!stream->read_be(segment_index))
  42.                 return false;
  43.             if (!stream->read_be(size))
  44.                 return false;
  45.             if (!stream->read_be(real_size))
  46.                 return false;
  47.             if (!stream->read_be(unk4))
  48.                 return false;
  49.             if (!stream->read_be(file_size))
  50.                 return false;
  51.             if (!stream->read(title_id, sizeof(title_id)))
  52.                 return false;
  53.             return true;
  54.         }
  55.  
  56.         bool save(IStream* stream)
  57.         {
  58.             if (!stream->write_be(magic))
  59.                 return false;
  60.             if (!stream->write_be(segment_index))
  61.                 return false;
  62.             if (!stream->write_be(size))
  63.                 return false;
  64.             if (!stream->write_be(real_size))
  65.                 return false;
  66.             if (!stream->write_be(unk4))
  67.                 return false;
  68.             if (!stream->write_be(file_size))
  69.                 return false;
  70.             if (!stream->write(title_id, sizeof(title_id)))
  71.                 return false;
  72.             return true;
  73.         }
  74.     };
  75.  
  76.     struct VolumeSegment
  77.     {
  78.         uint32_t segment_index;
  79.         uint32_t size;
  80.         uint32_t real_size;
  81.  
  82.         uint32_t unk1;
  83.         uint32_t data_size;
  84.         char* data;
  85.  
  86.         VolumeSegment(const uint32_t segment_index, const uint32_t size, const uint32_t real_size)
  87.             : segment_index(segment_index)
  88.             , size(size)
  89.             , real_size(real_size)
  90.             , data(nullptr)
  91.         {
  92.         }
  93.  
  94.         ~VolumeSegment()
  95.         {
  96.             delete[] data;
  97.         }
  98.  
  99.         bool load(IStream* stream)
  100.         {
  101.             if (!stream->read_le(unk1))
  102.                 return false;
  103.             if (!stream->read_le(data_size))
  104.                 return false;
  105.  
  106.             size -= kVOLUME_SEGMENT_HEADER_SIZE;
  107.             char* buffer = new char[size];
  108.             if (!stream->read(buffer, size))
  109.                 return false;
  110.  
  111.             data_size = -static_cast<int32_t>(data_size);
  112.             assert(data_size == real_size);
  113.             data = new char[data_size];
  114.             memset(data, 0, data_size);
  115.  
  116.             uint32_t real_data_size = data_size;
  117.             if (inflate(buffer, size, data, &real_data_size, -15) != 0) {
  118.                 delete[] buffer;
  119.                 return false;
  120.             }
  121.             assert(data_size == real_data_size);
  122.  
  123.             delete[] buffer;
  124.  
  125.             return true;
  126.         }
  127.     };
  128. }
  129.  
  130. Volume::Volume()
  131.     : game_id_(GameID::UNKNOWN)
  132. {
  133. }
  134.  
  135. void crypt_header(void* const data, const uint32_t size)
  136. {
  137.     uint32_t key[4];
  138.     data_keygen(s_key_context.seed, s_key_context.key, 1, key);
  139.     data_crypt(key, data, data, size);
  140.     block_crypt(data, data, size);
  141. }
  142.  
  143. void crypt_segment(void* const data, const uint32_t size, const uint32_t index)
  144. {
  145.     uint32_t key[4];
  146.     data_keygen(s_key_context.seed, s_key_context.key, index, key);
  147.     data_crypt(key, data, data, size);
  148. }
  149.  
  150. Volume::Volume(const char* const path, const GameID game_id)
  151.     : game_id_(GameID::UNKNOWN)
  152. {
  153.     open(path, game_id);
  154. }
  155.  
  156. Volume::~Volume()
  157. {
  158.     close();
  159. }
  160.  
  161. bool Volume::open(const char* const path, const GameID game_id)
  162. {
  163.     game_id_ = game_id;
  164.  
  165.     const char* seed = nullptr;
  166.     const uint32_t* key = nullptr;
  167.     switch (game_id) {
  168.         case GameID::GT5:
  169.             seed = kGT5_VOLUME_SEED, key = kGT5_VOLUME_KEY;
  170.             break;
  171.         case GameID::GT6:
  172.             seed = kGT6_VOLUME_SEED, key = kGT6_VOLUME_KEY;
  173.             break;
  174.     }
  175.     if (!seed || !key)
  176.         return false;
  177.  
  178.     memset(&s_key_context, 0, sizeof(s_key_context));
  179.     strncpy(s_key_context.seed, seed, sizeof(s_key_context.seed));
  180.     memcpy(s_key_context.key, key, sizeof(s_key_context.key));
  181.  
  182.     File volume_file;
  183.     if (!volume_file.open(path, OpenMode::kREAD | OpenMode::kSHARE))
  184.         return false;
  185.  
  186.     VolumeHeader header;
  187.     {
  188.         char* data = static_cast<char*>(_alloca(kVOLUME_HEADER_SIZE));
  189.         memset(data, 0, kVOLUME_HEADER_SIZE);
  190.         if (!volume_file.read(data, kVOLUME_HEADER_SIZE))
  191.             return false;
  192.         crypt_header(data, kVOLUME_HEADER_SIZE);
  193.         MemoryFile memory_file(data, kVOLUME_HEADER_SIZE);
  194.         if (!header.load(&memory_file))
  195.             return false;
  196.     }
  197.  
  198.     volume_file.seek(kVOLUME_SEGMENT_SIZE);
  199.  
  200.     std::unique_ptr<char[]> data(new char[header.size]);
  201.     if (!volume_file.read(data.get(), header.size))
  202.         return false;
  203.     crypt_segment(data.get(), header.size, header.segment_index);
  204.  
  205.     VolumeSegment segment(header.segment_index, header.size, header.real_size);
  206.     {
  207.         MemoryFile memory_file(data.get(), header.size);
  208.         if (!segment.load(&memory_file))
  209.             return false;
  210.     }
  211.  
  212.     data.reset();
  213.  
  214.     packed_file_.reset(new PackedFile(path, segment.data, segment.data_size, segment.size));
  215.  
  216.     return true;
  217. }
  218.  
  219. void Volume::close()
  220. {
  221.     packed_file_.reset();
  222.  
  223.     game_id_ = GameID::UNKNOWN;
  224. }
  225.  
  226. bool Volume::extract(const char* const output_dir) {
  227.     if (!packed_file_)
  228.         return false;
  229.  
  230.     packed_file_->extract_entries(output_dir);
  231.  
  232.     return true;
  233. }