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

  1. #include "packed_file.h"
  2. #include "string_btree.h"
  3. #include "fileid_btree.h"
  4. #include "fileinfo_btree.h"
  5. #include "volume.h"
  6. #include "crypt.h"
  7. #include "hash.h"
  8. #include "compression.h"
  9. #include "file.h"
  10. #include "memory_file.h"
  11. #include "path.h"
  12. #include "util.h"
  13.  
  14. PackedFile::PackedFile(const char* const file_path, const void* const data, const uint32_t data_size, const uint32_t segment_size)
  15.     : file_path_(nullptr)
  16.     , file_data_(nullptr)
  17.     , segment_size_(0)
  18.     , name_table_offset_(0)
  19.     , extension_table_offset_(0)
  20.     , file_info_table_offset_(0)
  21.     , num_file_id_trees_(0)
  22. {
  23.     const uint32_t magic = data_at<uint32_t>(data, 0x00);
  24.     if (magic == kMAGIC) {
  25.         file_path_ = file_path;
  26.         file_data_ = new char[data_size];
  27.         memcpy(file_data_, data, data_size);
  28.         segment_size_ = segment_size;
  29.         name_table_offset_ = data_at<uint32_t>(file_data_, 0x04);
  30.         extension_table_offset_ = data_at<uint32_t>(file_data_, 0x08);
  31.         file_info_table_offset_ = data_at<uint32_t>(file_data_, 0x0C);
  32.         num_file_id_trees_ = data_at<uint32_t>(file_data_, 0x10);
  33.     }
  34. }
  35.  
  36. PackedFile::~PackedFile()
  37. {
  38.     delete[] file_data_;
  39. }
  40.  
  41. bool PackedFile::get_file_info(const char* const file_path, FileInfo* const file_info) const
  42. {
  43.     StringBTree name_btree(advance_pointer(file_data_, name_table_offset_));
  44.     StringBTree extension_btree(advance_pointer(file_data_, extension_table_offset_));
  45.  
  46.     FileInfoBTree file_info_btree(advance_pointer(file_data_, file_info_table_offset_));
  47.     uint32_t file_info_id = BTreeBase::kINVALID_INDEX;
  48.  
  49.     const char* part = file_path;
  50.     uint32_t index = 0;
  51.     while (*part != '\0') {
  52.         const char* const delimeter = path_get_delimeter(part);
  53.         const char* extension = nullptr;
  54.         if (delimeter > part) {
  55.             if (*(delimeter - 1) != '.') {
  56.                 extension = delimeter - 1;
  57.                 do {
  58.                     extension--;
  59.                 } while (extension > part && *extension != '.');
  60.                 if (*extension != '.')
  61.                     extension = nullptr;
  62.             }
  63.         } else {
  64.             assert(0);
  65.         }
  66.         const size_t part_length = extension ? (extension - part) : (delimeter - part);
  67.  
  68.         const uint32_t name_index = name_btree.index_by_string(part, part_length);
  69.         const uint32_t extension_index = extension ? extension_btree.index_by_string(extension) : 0;
  70.  
  71.         if (name_index != BTreeBase::kINVALID_INDEX) {
  72.             FileIdBTree file_id_btree(advance_pointer(file_data_, file_id_table_offset(index)));
  73.             const void* const file_id_data = file_id_btree.search(name_index, extension_index);
  74.             if (file_id_data) {
  75.                 FileId file_id;
  76.                 if (file_id.parse(file_id_data)) {
  77.                     if ((file_id.flag & FileId::kDIRECTORY_FLAG) != 0)
  78.                         index = file_id.entry_index;
  79.                     else
  80.                         file_info_id = file_id.entry_index;
  81.                 } else {
  82.                     assert(0);
  83.                 }
  84.             }
  85.         }
  86.  
  87.         part = path_skip_delimeter(delimeter);
  88.     }
  89.  
  90.     if (file_info_id != BTreeBase::kINVALID_INDEX) {
  91.         const void* const data = file_info_btree.search(file_info_id);
  92.         if (data)
  93.             return file_info->parse(data) != nullptr;
  94.     }
  95.  
  96.     return false;
  97. }
  98.  
  99. uint32_t PackedFile::file_id_table_offset(const uint32_t index) const
  100. {
  101.     const uint32_t offset = data_at<uint32_t>(file_data_, kHEADER_SIZE + index * sizeof(uint32_t));
  102.     return offset;
  103. }
  104.  
  105. uint64_t PackedFile::data_offset() const
  106. {
  107.     const uint64_t offset = align_up(kSEGMENT_SIZE + segment_size_, kSEGMENT_SIZE);
  108.     return offset;
  109. }
  110.  
  111. struct TraverseEntryArgs
  112. {
  113.     const PackedFile* packed_file;
  114.     const char* output_dir;
  115.     unsigned int depth;
  116.     char prefix[256];
  117. };
  118.  
  119. bool build_entry_path(const PackedFile& packed_file, const FileId& file_id, const char* const prefix, const char** const path)
  120. {
  121.     StringBTree name_btree(advance_pointer(packed_file.file_data(), packed_file.name_table_offset()));
  122.     StringBTree extension_btree(advance_pointer(packed_file.file_data(), packed_file.extension_table_offset()));
  123.  
  124.     String name;
  125.     String extension;
  126.  
  127.     const bool has_name = name_btree.search_by_index(file_id.name_index, &name);
  128.     const bool has_extension = extension_btree.search_by_index(file_id.extension_index, &extension) && extension.length != 0;
  129.  
  130.     const unsigned int prefix_length = strlen(prefix);
  131.  
  132.     unsigned int path_length = prefix_length;
  133.     if (has_name) {
  134.         if (has_extension)
  135.             path_length += name.length + extension.length;
  136.         else
  137.             path_length += name.length;
  138.     } else if (has_extension) {
  139.         assert(0);
  140.     }
  141.  
  142.     char* path_buffer = new char[path_length + 1];
  143.     memset(path_buffer, 0, path_length + 1);
  144.     if (prefix_length != 0)
  145.         memcpy(path_buffer, prefix, prefix_length);
  146.     if (has_name) {
  147.         memcpy(path_buffer + prefix_length, name.data, name.length);
  148.         if (has_extension)
  149.             memcpy(path_buffer + prefix_length + name.length, extension.data, extension.length);
  150.     }
  151.     path_buffer[path_length] = '\0';
  152.  
  153.     *path = path_buffer;
  154.  
  155.     return true;
  156. }
  157.  
  158. int traverse_callback(const FileId* const file_id, void* const arg)
  159. {
  160.     TraverseEntryArgs* const args = static_cast<TraverseEntryArgs*>(arg);
  161.  
  162.     const bool is_directory = (file_id->flag & FileId::kDIRECTORY_FLAG) != 0;
  163.     const char* path;
  164.     if (!build_entry_path(*args->packed_file, *file_id, args->prefix, &path))
  165.         path = nullptr;
  166.  
  167.     if (is_directory) {
  168.         assert(path != nullptr);
  169.  
  170.         TraverseEntryArgs new_args = { args->packed_file, args->output_dir, args->depth + 2 };
  171.         strncpy(new_args.prefix, path, sizeof(new_args.prefix));
  172.         strcat(new_args.prefix, "/");
  173.  
  174.         FileIdBTree child_id_btree(advance_pointer(args->packed_file->file_data(), args->packed_file->file_id_table_offset(file_id->entry_index)));
  175.         child_id_btree.traverse(&traverse_callback, &new_args);
  176.     } else {
  177.         assert(path != nullptr);
  178.  
  179.         FileInfoBTree info_btree(advance_pointer(args->packed_file->file_data(), args->packed_file->file_info_table_offset()));
  180.         const void* const data = info_btree.search(file_id->entry_index);
  181.         FileInfo file_info;
  182.         if (file_info.parse(data)) {
  183.             char file_path[_MAX_PATH];
  184.             if (generate_file_path(file_info.entry_index, file_path, sizeof(file_path))) {
  185.                 char* data = nullptr;
  186.                 uint64_t data_offset = args->packed_file->data_offset() + file_info.segment_index * uint64_t(PackedFile::kSEGMENT_SIZE);
  187.                 uint32_t data_size = file_info.size1;
  188.  
  189.                 if (read_file(args->packed_file->file_path(), &data, &data_size, data_offset)) {
  190.                     crypt_segment(data, data_size, file_info.entry_index);
  191.  
  192.                     char full_file_path[_MAX_PATH];
  193.                     _snprintf(full_file_path, sizeof(full_file_path), "%s%s", args->output_dir, path);
  194.  
  195.                     char directory_path[_MAX_PATH];
  196.                     char* p = strrchr(full_file_path, '/');
  197.                     if (p) {
  198.                         const size_t length = p - full_file_path + 1;
  199.                         strncpy(directory_path, full_file_path, length);
  200.                         directory_path[length] = '\0';
  201.                         make_directories(directory_path);
  202.                     }
  203.  
  204.                     if (data_at<uint32_t>(data, 0) == 0xC5EEF7FFu) {
  205.                         const uint32_t decompressed_size = -little_to_host(*((int32_t*)data + 1));
  206.                         char* out_data = new char[decompressed_size];
  207.                         size_t out_size = decompressed_size;
  208.                         if (inflate(data + 8, data_size - 8, out_data, &out_size, -15) == 0)
  209.                             write_file(full_file_path, out_data, decompressed_size);
  210.                         delete[] out_data;
  211.                     } else {
  212.                         write_file(full_file_path, data, data_size);
  213.                     }
  214.                 }
  215.  
  216.                 delete[] data;
  217.             }
  218.         }
  219.     }
  220.  
  221.      delete[] path;
  222.  
  223.     return FileIdBTree::kTRAVERSE_CONTINUE;
  224. }
  225.  
  226. void PackedFile::extract_entries(const char* const output_dir)
  227. {
  228.     TraverseEntryArgs args = { this, output_dir, 0 };
  229.     memset(args.prefix, 0, sizeof(args.prefix));
  230.  
  231.     FileIdBTree id_btree(advance_pointer(file_data_, file_id_table_offset(0)));
  232.     id_btree.traverse(&traverse_callback, &args);
  233. }
  234.