home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 5257 / source.7z / ps3_one_piece.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2012-03-05  |  29.1 KB  |  885 lines

  1. #include "xentax.h"
  2. #include "x_file.h"
  3. #include "x_findfile.h"
  4. #include "x_stream.h"
  5. #include "x_dds.h"
  6. #include "x_smc.h"
  7. #include "ps3_one_piece.h"
  8.  
  9. #define X_SYSTEM PS3
  10. #define X_GAME   OnePiece
  11.  
  12. namespace X_SYSTEM { namespace X_GAME {
  13.  
  14. #define GUSELESS 0
  15. #define GARCHIVE 1
  16. #define G1TG0050 2
  17. #define G1TG0060 3
  18. #define G1CT0001 4
  19. #define G1M_0034 5
  20.  
  21. class extractor {
  22.  private :
  23.   std::string pathname;
  24.  private :
  25.   bool debug;
  26.   std::ofstream dfile;
  27.  private :
  28.   bool unpack(const std::string& filename)const;
  29.   char getFileType(std::ifstream& ifile)const;
  30.   bool processBIN(const std::string& filename);
  31.   bool processG1T(binary_stream& bs, const std::string& filepath);
  32.   bool processG1M(binary_stream& bs, const std::string& filepath);
  33.  private :
  34.   bool processG1MG0044(const binary_stream& bs, SIMPLEMODELCONTAINER& smc);
  35.  public :
  36.   bool extract(void);
  37.  public :
  38.   extractor(const char* pn) : pathname(pn) {}
  39.  ~extractor() {}
  40. };
  41.  
  42. };};
  43.  
  44. namespace X_SYSTEM { namespace X_GAME {
  45.  
  46. bool extractor::unpack(const std::string& filename)const
  47. {
  48.  // open file
  49.  using namespace std;
  50.  ifstream ifile;
  51.  ifile.open(filename.c_str(), ios::binary);
  52.  if(!ifile) return error("Could not open file.");
  53.  
  54.  // read header
  55.  uint32 headMagic = BE_read_uint32(ifile); if(ifile.fail()) return error("Read failure.");
  56.  uint32 headFiles = BE_read_uint32(ifile); if(ifile.fail()) return error("Read failure.");
  57.  uint32 headScale = BE_read_uint32(ifile); if(ifile.fail()) return error("Read failure.");
  58.  uint32 headUnk01 = BE_read_uint32(ifile); if(ifile.fail()) return error("Read failure.");
  59.  
  60.  // validate header
  61.  if(headMagic != 0x077DF9) return error("Invalid header signature.");
  62.  if(headFiles >= 0xFFFF) return error("No dynasty warriors game contains this many files.");
  63.  if(headScale != 0x0800) return error("File assets should occur on 0x800 boundaries.");
  64.  
  65.  // read file table
  66.  deque<pair<uint32, uint32>> filetable;
  67.  for(size_t i = 0; i < headFiles; i++) {
  68.      uint32 param1 = BE_read_uint32(ifile); // 0x00
  69.      uint32 param2 = BE_read_uint32(ifile); // scaled offset
  70.      uint32 param3 = BE_read_uint32(ifile); // filesize
  71.      uint32 param4 = BE_read_uint32(ifile); // 0x00
  72.      pair<uint32, uint32> p;
  73.      p.first  = param2; if(ifile.fail()) return error("Read failure.");
  74.      p.second = param3; if(ifile.fail()) return error("Read failure.");
  75.      filetable.push_back(p);
  76.     }
  77.  
  78.  // create subdirectory string
  79.  string subdpath = GetShortFilename(filename);
  80.  for(size_t i = 0; i < subdpath.length(); i++) if(subdpath[i] == '.') subdpath[i] = '_';
  81.  
  82.  // create save path
  83.  string savepath = GetPathnameFromFilename(filename);
  84.  savepath += subdpath;
  85.  savepath += "\\";
  86.  CreateDirectoryA(savepath.c_str(), NULL);
  87.  
  88.  // for each item in the file table
  89.  for(size_t i = 0; i < filetable.size(); i++)
  90.     {
  91.      // move to file position
  92.      size_t position = filetable[i].first*headScale;
  93.      size_t filesize = filetable[i].second;
  94.      ifile.seekg(position);
  95.      if(ifile.fail()) return error("Failed to seek file position.");
  96.  
  97.      // create file
  98.      cout << "Reading file " << (i + 1) << " of " << filetable.size() << "." << endl;
  99.      stringstream name;
  100.      name << savepath << setfill('0') << setw(4) << i << ".bin";
  101.      ofstream ofile(name.str().c_str(), ios::binary);
  102.      if(!ofile) return error("Failed to create bin file.");
  103.  
  104.      // small files
  105.      if(filesize < 0x2000000) // 32 MB
  106.        {
  107.         // read data
  108.         boost::shared_array<char> data(new char[filesize]);
  109.         ifile.read(data.get(), filesize);
  110.         if(ifile.fail()) return error("Read failure.");
  111.         
  112.         // save data
  113.         ofile.write(data.get(), filesize);
  114.         if(ofile.fail()) return error("Failed to write to bin file.");
  115.        }
  116.      // large files
  117.      else
  118.        {
  119.         // create buffer
  120.         cout << " NOTE: This is a large file and might take a while to save." << endl;
  121.         uint32 buffersize = 0x1000000; // 16 MB
  122.         boost::shared_array<char> data(new char[buffersize]);
  123.  
  124.         // read and copy data
  125.         uint32 bytes_left = filesize;
  126.         while(bytes_left)
  127.              {
  128.               // specify how much to read
  129.               uint32 datasize = buffersize;
  130.               if(bytes_left < buffersize) datasize = bytes_left;
  131.  
  132.               // read data
  133.               ifile.read(data.get(), datasize);
  134.               if(ifile.fail()) return error("Read failure.");
  135.               
  136.               // save data
  137.               ofile.write(data.get(), datasize);
  138.               if(ofile.fail()) return error("Failed to write to bin file.");
  139.  
  140.               // update
  141.               bytes_left -= datasize;
  142.              }
  143.        }
  144.     }
  145.  
  146.  cout << endl;
  147.  return true;
  148. }
  149.  
  150. char extractor::getFileType(std::ifstream& ifile)const
  151. {
  152.  // get filesize
  153.  using namespace std;
  154.  ifile.seekg(0, ios::end);
  155.  uint32 filesize = (uint32)ifile.tellg();
  156.  ifile.seekg(0, ios::beg);
  157.  
  158.  // read first uint32
  159.  uint32 head01 = BE_read_uint32(ifile);
  160.  if(ifile.fail()) {
  161.     error("getFileType(): Read failure.");
  162.     return GUSELESS;
  163.    }
  164.  
  165.  // G1M_0034?
  166.  if(head01 == 0x47314D5F) {
  167.     uint32 head02 = BE_read_uint32(ifile);
  168.     if(ifile.fail()) {
  169.        error("getFileType(): Read failure.");
  170.        return GUSELESS;
  171.       }
  172.     if(head02 == 0x30303334) return G1M_0034;
  173.     return GUSELESS;
  174.    }
  175.  
  176.  // G1TG0050 or G1TG0060?
  177.  if(head01 == 0x47315447) {
  178.     uint32 head02 = BE_read_uint32(ifile);
  179.     if(ifile.fail()) {
  180.        error("getFileType(): Read failure.");
  181.        return GUSELESS;
  182.       }
  183.     if(head02 == 0x30303530) return G1TG0050;
  184.     if(head02 == 0x30303630) return G1TG0060;
  185.     return GUSELESS;
  186.    }
  187.  
  188.  // G1CT0001?
  189.  if(head01 == 0x47314354) {
  190.     uint32 head02 = BE_read_uint32(ifile);
  191.     if(ifile.fail()) {
  192.        error("getFileType(): Read failure.");
  193.        return GUSELESS;
  194.       }
  195.     if(head02 == 0x30303031) return G1CT0001;
  196.     return GUSELESS;
  197.    }
  198.  
  199.  // archive?
  200.  if((head01 == 0) || !(head01 < 0x2FF)) return GUSELESS; // largest is 0x2D1
  201.  
  202.  // can we read all offsets?
  203.  if(filesize < head01*sizeof(uint32)) return GUSELESS;
  204.  
  205.  // read offsets
  206.  boost::shared_array<uint32> offsets(new uint32[head01]);
  207.  BE_read_array(ifile, offsets.get(), head01);
  208.  if(ifile.fail()) {
  209.     error("getFileType(): Read failure.");
  210.     return GUSELESS;
  211.    }
  212.  
  213.  // check first offset
  214.  uint32 prev = offsets[0];
  215.  if((prev == 0) || !(prev < filesize)) return GUSELESS;
  216.  
  217.  // check other offsets
  218.  for(uint32 i = 1; i < head01; i++) {
  219.      if(offsets[i] == 0) return false;
  220.      if(offsets[i] < offsets[i - 1]) return GUSELESS;
  221.      if(!(offsets[i] < filesize)) return GUSELESS;
  222.     }
  223.  
  224.  // move back to the beginning if it is!
  225.  ifile.seekg(0, ios::beg);
  226.  return GARCHIVE;
  227. }
  228.  
  229. bool extractor::processBIN(const std::string& filename)
  230. {
  231.  // open file
  232.  using namespace std;
  233.  ifstream ifile;
  234.  ifile.open(filename.c_str(), ios::binary);
  235.  if(!ifile) return error("processBIN: Could not open file.");
  236.  
  237.  // is this an archive?
  238.  char ftype = getFileType(ifile);
  239.  if(ifile.fail()) return error("processBIN: Seek failure.");
  240.  
  241.  // compute filesize
  242.  ifile.seekg(0, ios::end);
  243.  if(ifile.fail()) return error("processBIN: Seek failure.");
  244.  uint32 filesize = (uint32)ifile.tellg();
  245.  ifile.seekg(0, ios::beg);
  246.  if(ifile.fail()) return error("processBIN: Seek failure.");
  247.  
  248.  // depending on file type
  249.  switch(ftype) {
  250.    case(GUSELESS) : break;
  251.    case(GARCHIVE) : break;
  252.    case(G1TG0050) : {
  253.         string filepath = GetPathnameFromFilename(filename);
  254.         filepath += GetShortFilenameWithoutExtension(filename);
  255.         boost::shared_array<char> data(new char[filesize]);
  256.         ifile.read(data.get(), filesize);
  257.         if(ifile.fail()) return error("processBin: Read failure.");
  258.         binary_stream bs(data, filesize);
  259.         //processG1T(bs, filepath);
  260.         break;
  261.        }
  262.    case(G1TG0060) : {
  263.         string filepath = GetPathnameFromFilename(filename);
  264.         filepath += GetShortFilenameWithoutExtension(filename);
  265.         boost::shared_array<char> data(new char[filesize]);
  266.         ifile.read(data.get(), filesize);
  267.         if(ifile.fail()) return error("processBin: Read failure.");
  268.         binary_stream bs(data, filesize);
  269.         //processG1T(bs, filepath);
  270.         break;
  271.        }
  272.    case(G1CT0001) : {
  273.         break;
  274.        }
  275.    case(G1M_0034) : {
  276.         string filepath = GetPathnameFromFilename(filename);
  277.         filepath += GetShortFilenameWithoutExtension(filename);
  278.         boost::shared_array<char> data(new char[filesize]);
  279.         ifile.read(data.get(), filesize);
  280.         if(ifile.fail()) return error("processBin: Read failure.");
  281.         binary_stream bs(data, filesize);
  282.         if(!processG1M(bs, filepath)) return false;
  283.         break;
  284.        }
  285.   }
  286.  
  287. /*
  288.  // create buffer
  289.  uint32 buffersize = 0x1000000; // 16 MB
  290.  boost::shared_array<char> data(new char[buffersize]);
  291.  
  292.  uint32 foundModel = 0;
  293.  uint32 foundG1TG5 = 0;
  294.  uint32 foundG1TG6 = 0;
  295.  
  296.  // read and copy data
  297.  uint32 bytes_left = filesize;
  298.  while(bytes_left)
  299.       {
  300.        // specify how much to read
  301.        uint32 datasize = buffersize;
  302.        if(bytes_left < buffersize) datasize = bytes_left;
  303.  
  304.        // read data
  305.        ifile.read(data.get(), datasize);
  306.        if(ifile.fail()) {
  307.           cout << "filesize, datasize = " << filesize << ", " << datasize << endl;
  308.           return error("Read failure.");
  309.          }
  310.        
  311.        // find data
  312.        binary_stream bs(data, datasize);
  313.        if(bs.search("G1M_0034", 8) != binary_stream::npos) foundModel++;
  314.        if(bs.search("G1TG0050", 8) != binary_stream::npos) foundG1TG5++;
  315.        if(bs.search("G1TG0060", 8) != binary_stream::npos) foundG1TG6++;
  316.  
  317.        // update
  318.        bytes_left -= datasize;
  319.       }
  320.  
  321.  if(debug && (foundModel || foundG1TG5 || foundG1TG6)) {
  322.     dfile << filename << endl;
  323.     if(ftype == GARCHIVE) dfile << "GARCHIVE" << endl;
  324.     if(ftype == GUSELESS) dfile << "GUSELESS" << endl;
  325.     if(ftype == G1M_0034) dfile << "G1M_0034" << endl;
  326.     if(ftype == G1CT0001) dfile << "G1CT0001" << endl;
  327.     if(ftype == G1TG0050) dfile << "G1TG0050" << endl;
  328.     if(ftype == G1TG0060) dfile << "G1TG0060" << endl;
  329.     if(foundModel) dfile << "Models: YES" << endl;
  330.     if(foundG1TG5) dfile << "G1TG5s: YES" << endl;
  331.     if(foundG1TG6) dfile << "G1TG6s: YES" << endl;
  332.    }
  333. */
  334.  
  335.  return true;
  336. }
  337.  
  338. bool extractor::processG1T(binary_stream& bs, const std::string& filepath)
  339. {
  340.  using namespace std;
  341.  
  342.  // create folder to save files
  343.  CreateDirectoryA(filepath.c_str(), NULL);
  344.  
  345.  // read header
  346.  uint32 magic = bs.BE_read_uint32();
  347.  uint32 version = bs.BE_read_uint32();
  348.  uint32 section_size = bs.BE_read_uint32();
  349.  uint32 table_offset = bs.BE_read_uint32();
  350.  uint32 n_textures = bs.BE_read_uint32();
  351.  
  352.  // validate header
  353.  if(magic != 0x47315447) return error("Expecting G1TG section.");
  354.  if(!(version == 0x30303530 || version == 0x30303630)) return error("Invalid G1TG version.");
  355.  if(n_textures == 0) return error("Invalid number of textures.");
  356.  
  357.  // move to table
  358.  bs.seek(table_offset);
  359.  if(bs.fail()) return error("Stream seek failure.");
  360.  
  361.  // read offset table
  362.  deque<size_t> offset_list;
  363.  for(size_t i = 0; i < n_textures; i++) {
  364.      offset_list.push_back(bs.BE_read_uint32());
  365.      if(bs.fail()) return error("Stream read failure.");
  366.     }
  367.  
  368.  // process textures
  369.  for(size_t i = 0; i < offset_list.size(); i++)
  370.     {
  371.      bs.seek(table_offset + offset_list[i]);
  372.      if(bs.fail()) return error("Stream seek failure.");
  373.  
  374.      // read texture information
  375.      // 0x08 bytes
  376.      uint08 b1 = bs.BE_read_uint08(); // unknown
  377.      uint08 b2 = bs.BE_read_uint08(); // texture type
  378.      uint08 b3 = bs.BE_read_uint08(); // dx/dy
  379.      uint08 b4 = bs.BE_read_uint08(); // unknown
  380.      uint16 s1 = bs.BE_read_uint16(); // unknown
  381.      uint16 s2 = bs.BE_read_uint16(); // unknown
  382.  
  383.      // header is extended depending on s2
  384.      // 0x0C bytes
  385.      if(s2 == 0x1201) { // version == 0x30303630) {
  386.         uint32 v1 = bs.BE_read_uint32(); // 12
  387.         uint32 v2 = bs.BE_read_uint32(); // 0
  388.         uint32 v3 = bs.BE_read_uint32(); // 0 or 1
  389.        }
  390.  
  391.      // number of bytes in header
  392.      uint32 headerBytes = 0x08;
  393.      if(s2 == 0x1201) headerBytes += 0x0C;
  394.  
  395.      // compute dimensions
  396.      uint32 temp1 = ((b3 & 0xF0) >> 4);
  397.      uint32 temp2 = ((b3 & 0x0F));
  398.      uint32 dx = 1 << temp1;
  399.      uint32 dy = 1 << temp2;
  400.  
  401.      // create texture file
  402.      stringstream filename;
  403.      filename << filepath << setfill('0') << setw(3) << i << ".dds";
  404.      ofstream ofile(filename.str().c_str(), ios::binary);
  405.  
  406.      // save texture
  407.      if(b2 == 0)
  408.        {
  409.         // read texture
  410.         DWORD filesize = UncompressedDDSFileSize(dx, dy, 0, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
  411.         boost::shared_array<char> buffer(new char[filesize]);
  412.         bs.read((char*)buffer.get(), filesize);
  413.  
  414.         // save texture
  415.         DDS_HEADER ddsh;
  416.         CreateUncompressedDDSHeader(dx, dy, 0, 0xFF000000, 0xFF0000, 0xFF00, 0xFF, FALSE, &ddsh);
  417.         DWORD signature = 0x20534444;
  418.         ofile.write((char*)&signature, sizeof(signature));
  419.         ofile.write((char*)&ddsh, sizeof(ddsh));
  420.         ofile.write((char*)buffer.get(), filesize);
  421.        }
  422.      // UNCOMPRESSED DDS (PS3 works good)
  423.      else if(b2 == 1)
  424.        {
  425.         // read texture
  426.         DWORD filesize = UncompressedDDSFileSize(dx, dy, 0, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
  427.         boost::shared_array<char> buffer(new char[filesize]);
  428.         bs.read((char*)buffer.get(), filesize);
  429.  
  430.         // save texture
  431.         DDS_HEADER ddsh;
  432.         CreateUncompressedDDSHeader(dx, dy, 0, 0xFF000000, 0xFF0000, 0xFF00, 0xFF, FALSE, &ddsh);
  433.         DWORD signature = 0x20534444;
  434.         ofile.write((char*)&signature, sizeof(signature));
  435.         ofile.write((char*)&ddsh, sizeof(ddsh));
  436.         ofile.write((char*)buffer.get(), filesize);
  437.        }
  438.      // DXT1 (PS3 works good)
  439.      else if(b2 == 6)
  440.        {
  441.         // read texture
  442.         DWORD filesize = DXT1Filesize(dx, dy, 0);
  443.         boost::shared_array<char> buffer(new char[filesize]);
  444.         bs.read((char*)buffer.get(), filesize);
  445.  
  446.         // save texture
  447.         DDS_HEADER ddsh;
  448.         CreateDXT1Header(dx, dy, 0, FALSE, &ddsh);
  449.         DWORD signature = 0x20534444;
  450.         ofile.write((char*)&signature, sizeof(signature));
  451.         ofile.write((char*)&ddsh, sizeof(ddsh));
  452.         ofile.write((char*)buffer.get(), filesize);
  453.        }
  454.      // DXT5 (PS3 works good)
  455.      else if(b2 == 8)
  456.        {
  457.         // read texture
  458.         DWORD filesize = DXT5Filesize(dx, dy, 0);
  459.         boost::shared_array<char> buffer(new char[filesize]);
  460.         bs.read((char*)buffer.get(), filesize);
  461.  
  462.         // save texture
  463.         DDS_HEADER ddsh;
  464.         CreateDXT5Header(dx, dy, 0, FALSE, &ddsh);
  465.         DWORD signature = 0x20534444;
  466.         ofile.write((char*)&signature, sizeof(signature));
  467.         ofile.write((char*)&ddsh, sizeof(ddsh));
  468.         ofile.write((char*)buffer.get(), filesize);
  469.        }
  470.      else {
  471.         stringstream msg;
  472.         msg << "Unsupported texture type #" << (uint32)b2 << ".";
  473.         return error(msg.str().c_str());
  474.        }
  475.     }
  476.  
  477.  return true;
  478. }
  479.  
  480. bool extractor::processG1M(binary_stream& bs, const std::string& filepath)
  481. {
  482.  using namespace std;
  483.  
  484.  // create model container
  485.  SIMPLEMODELCONTAINER smc;
  486.  
  487.  // create folder to save files
  488.  CreateDirectoryA(filepath.c_str(), NULL);
  489.  
  490.  // read header
  491.  uint32 head01 = bs.BE_read_uint32(); // magic
  492.  uint32 head02 = bs.BE_read_uint32(); // version
  493.  uint32 head03 = bs.BE_read_uint32(); // total section size
  494.  uint32 head04 = bs.BE_read_uint32(); // start offset
  495.  uint32 head05 = bs.BE_read_uint32(); // 0x00
  496.  uint32 head06 = bs.BE_read_uint32(); // number of chunks to read
  497.  
  498.  // validate header
  499.  if(head01 != 0x47314D5F) return error("Expecting G1M_ section.");
  500.  if(head02 != 0x30303334) return error("Invalid G1M_ version.");
  501.  if(head03 == 0) return error("Invalid G1M_.");
  502.  if(head04 == 0) return error("Invalid G1M_.");
  503.  
  504.  // move to start
  505.  bs.seek(head04);
  506.  if(bs.fail()) return error("processG1M: Seek failure.");
  507.  
  508.  // read chunks
  509.  for(uint32 i = 0; i < head06; i++)
  510.     {
  511.      // read first chunk
  512.      uint32 chunkname = bs.BE_read_uint32(); // chunk name
  513.      uint32 chunkvers = bs.BE_read_uint32(); // chunk version
  514.      uint32 chunksize = bs.BE_read_uint32(); // chunk size
  515.  
  516.      // process chunk
  517.      switch(chunkname) {
  518.        case(0x47314D46) : { // G1MF
  519.             bs.move(chunksize - 0x0C);
  520.             break;
  521.            }
  522.        case(0x47314D53) : { // G1MS
  523.             bs.move(chunksize - 0x0C);
  524.             break;
  525.            }
  526.        case(0x47314D4D) : { // G1MM
  527.             bs.move(chunksize - 0x0C);
  528.             break;
  529.            }
  530.        case(0x47314D47) : { // G1MG
  531.             if(!processG1MG0044(bs, smc)) return false;
  532.             bs.move(chunksize - 0x0C);
  533.             break;
  534.            }
  535.        case(0x45585452) : { // EXTR
  536.             bs.move(chunksize - 0x0C);
  537.             break;
  538.            }
  539.        default : {
  540.             stringstream ss;
  541.             ss << "processG1M: Unknown chunk 0x" << std::hex << chunkname << std::dec << ".";
  542.             return error(ss.str().c_str());
  543.            }
  544.       }
  545.     }
  546.  
  547.  return true;
  548. }
  549.  
  550. bool extractor::processG1MG0044(const binary_stream& bs, SIMPLEMODELCONTAINER& smc)
  551. {
  552.  using namespace std;
  553.  
  554.  // copy stream
  555.  binary_stream stream(bs);
  556.  if(stream.fail()) return error("Cannot copy binary stream.");
  557.  
  558.  // read header
  559.  uint32 platform = stream.BE_read_uint32();
  560.  uint32 unknown1 = stream.BE_read_uint32();
  561.  real32 min_x = stream.BE_read_real32();
  562.  real32 min_y = stream.BE_read_real32();
  563.  real32 min_z = stream.BE_read_real32();
  564.  real32 max_x = stream.BE_read_real32();
  565.  real32 max_y = stream.BE_read_real32();
  566.  real32 max_z = stream.BE_read_real32();
  567.  uint32 sections = stream.BE_read_uint32();
  568.  
  569.  // validate header
  570.  if(platform != 0x50533300) return error("Only PS3 version of game is supported.");
  571.  if(sections == 0) return error("Invalid number of sections.");
  572.  
  573.  // section information
  574.  struct G1MG0044_ITEM {
  575.   uint32 type;
  576.   uint32 size;
  577.   boost::shared_array<char> data;
  578.  };
  579.  
  580.  // read section information
  581.  deque<G1MG0044_ITEM> items;
  582.  for(size_t i = 0; i < sections; i++) {
  583.      G1MG0044_ITEM item;
  584.      item.type = stream.BE_read_uint32();
  585.      item.size = stream.BE_read_uint32();
  586.      item.data.reset(new char[item.size - 0x8]);
  587.      stream.read(item.data.get(), item.size - 0x8);
  588.      items.push_back(item);
  589.     }
  590.  
  591.  // for each section
  592.  for(size_t i = 0; i < items.size(); i++)
  593.     {
  594.      // vertex section
  595.      if(items[i].type == 0x00010004)
  596.        {
  597.         // binary stream from data
  598.         binary_stream ss(items[i].data, items[i].size - 0x8);
  599.         ss.seek(0);
  600.  
  601.         // read vertex sections
  602.         uint32 n_meshes = ss.BE_read_uint32();
  603.         for(size_t j = 0; j < n_meshes; j++)
  604.            {
  605.             // read mesh vertex info
  606.             uint32 unknown1 = ss.BE_read_uint32();
  607.             uint32 vertsize = ss.BE_read_uint32();
  608.             uint32 vertices = ss.BE_read_uint32();
  609.             uint32 unknown2 = ss.BE_read_uint32();
  610.  
  611.             // buffer name
  612.             stringstream name;
  613.             name << "vb_" << setfill('0') << setw(2) << i;
  614.  
  615.             // set vertex buffer properties
  616.             VTX_BUFFER vb;
  617.             vb.flags = 0;
  618.             vb.name = name.str();
  619.             vb.elem = vertices;
  620.             vb.data.reset(new VERTEX[vertices]);
  621.  
  622.             // set vertex buffer flags
  623.             if(vertsize == 0x10) {
  624.                vb.flags |= VERTEX_POSITION;
  625.                vb.flags |= VERTEX_NORMAL;
  626.                vb.flags |= VERTEX_UV;
  627.               }
  628.             else if(vertsize == 0x14) {
  629.                vb.flags |= VERTEX_POSITION;
  630.                vb.flags |= VERTEX_NORMAL;
  631.                vb.flags |= VERTEX_UV;
  632.               }
  633.             else if(vertsize == 0x18) {
  634.                vb.flags |= VERTEX_POSITION;
  635.                vb.flags |= VERTEX_NORMAL;
  636.               }
  637.             else if(vertsize == 0x1C) {
  638.                vb.flags |= VERTEX_POSITION;
  639.                vb.flags |= VERTEX_NORMAL;
  640.                vb.flags |= VERTEX_UV;
  641.               }
  642.             else if(vertsize == 0x20) {
  643.                vb.flags |= VERTEX_POSITION;
  644.                vb.flags |= VERTEX_NORMAL;
  645.                vb.flags |= VERTEX_UV;
  646.               }
  647.             else if(vertsize == 0x24) {
  648.                vb.flags |= VERTEX_POSITION;
  649.                vb.flags |= VERTEX_NORMAL;
  650.                vb.flags |= VERTEX_UV;
  651.               }
  652.             else
  653.                return error("Unknown vertex format.");
  654.  
  655.             // read vertices
  656.             for(size_t k = 0; k < vertices; k++)
  657.                {
  658.                 VERTEX vertex;
  659.                 if(vertsize == 0x10) {
  660.                    vertex.vx = ss.BE_read_real16();
  661.                    vertex.vy = ss.BE_read_real16();
  662.                    vertex.vz = ss.BE_read_real16();
  663.                    ss.BE_read_real16();
  664.                    vertex.nx = ss.BE_read_real16();
  665.                    vertex.ny = ss.BE_read_real16();
  666.                    vertex.nz = ss.BE_read_real16();
  667.                    ss.BE_read_real16();
  668.                   }
  669.                 else if(vertsize == 0x14) {
  670.                    vertex.vx = ss.BE_read_real16();
  671.                    vertex.vy = ss.BE_read_real16();
  672.                    vertex.vz = ss.BE_read_real16();
  673.                    ss.BE_read_real16();
  674.                    vertex.nx = ss.BE_read_real16();
  675.                    vertex.ny = ss.BE_read_real16();
  676.                    vertex.nz = ss.BE_read_real16();
  677.                    ss.BE_read_real16();
  678.                    vertex.tu = ss.BE_read_real16();
  679.                    vertex.tv = ss.BE_read_real16();
  680.                   }
  681.                 else if(vertsize == 0x18) {
  682.                    vertex.vx = ss.BE_read_real32();
  683.                    vertex.vy = ss.BE_read_real32();
  684.                    vertex.vz = ss.BE_read_real32();
  685.                    vertex.nx = ss.BE_read_real16();
  686.                    vertex.ny = ss.BE_read_real16();
  687.                    vertex.nz = ss.BE_read_real16();
  688.                    ss.BE_read_real16();
  689.                    ss.BE_read_real32();
  690.                   }
  691.                 else if(vertsize == 0x1C) {
  692.                    vertex.vx = ss.BE_read_real32();
  693.                    vertex.vy = ss.BE_read_real32();
  694.                    vertex.vz = ss.BE_read_real32();
  695.                    vertex.nx = ss.BE_read_real16();
  696.                    vertex.ny = ss.BE_read_real16();
  697.                    vertex.nz = ss.BE_read_real16();
  698.                    ss.BE_read_real16();
  699.                    ss.BE_read_real32();
  700.                    vertex.tu = ss.BE_read_real16();
  701.                    vertex.tv = ss.BE_read_real16();
  702.                   }
  703.                 else if(vertsize == 0x20) {
  704.                    vertex.vx = ss.BE_read_real32();
  705.                    vertex.vy = ss.BE_read_real32();
  706.                    vertex.vz = ss.BE_read_real32();
  707.                    vertex.nx = ss.BE_read_real16();
  708.                    vertex.ny = ss.BE_read_real16();
  709.                    vertex.nz = ss.BE_read_real16();
  710.                    ss.BE_read_real16();
  711.                    ss.BE_read_real32();
  712.                    ss.BE_read_real16();
  713.                    ss.BE_read_real16();
  714.                    vertex.tu = ss.BE_read_real16();
  715.                    vertex.tv = ss.BE_read_real16();
  716.                   }
  717.                 else if(vertsize == 0x24) {
  718.                    vertex.vx = ss.BE_read_real32();
  719.                    vertex.vy = ss.BE_read_real32();
  720.                    vertex.vz = ss.BE_read_real32();
  721.                    vertex.nx = ss.BE_read_real32();
  722.                    vertex.ny = ss.BE_read_real32();
  723.                    vertex.nz = ss.BE_read_real32();
  724.                    ss.BE_read_real32();
  725.                    vertex.tu = ss.BE_read_real32();
  726.                    vertex.tv = ss.BE_read_real32();
  727.                   }
  728.  
  729.                 // save vertex
  730.                 vb.data[k] = vertex;
  731.                }
  732.            }
  733.        }
  734.      // index buffer section
  735.      else if(items[i].type == 0x00010007)
  736.        {
  737.         // binary stream from data
  738.         binary_stream ss(items[i].data, items[i].size - 0x8);
  739.         ss.seek(0);
  740.  
  741.         // read face sections
  742.         uint32 n_meshes = ss.BE_read_uint32();
  743.         uint32 vb_index = 0;
  744.         for(size_t j = 0; j < n_meshes; j++)
  745.            {
  746.             // read face data
  747.             uint32 numindex = ss.BE_read_uint32();
  748.             uint32 datatype = ss.BE_read_uint32();
  749.             uint32 unknown1 = ss.BE_read_uint32();
  750.  
  751.             // set index buffer properties
  752.             IDX_BUFFER ib;
  753.             ib.type = FACE_TYPE_TRISTRIP;
  754.             ib.elem = numindex;
  755.             if(datatype == 0x10) ib.format = FACE_FORMAT_UINT_16;
  756.             else if(datatype == 0x20) ib.format = FACE_FORMAT_UINT_32;
  757.             else return error("Unknown index buffer data format.");
  758.  
  759.             // set index buffer name
  760.             stringstream surface;
  761.             surface << "surface_" << setfill('0') << setw(3) << j << ends;
  762.             ib.name = surface.str();
  763.  
  764.             // determine index buffer data type size
  765.             unsigned int typesize = 0;
  766.             if(datatype == 0x10) typesize = sizeof(uint16);
  767.             else if(datatype == 0x20) typesize = sizeof(uint32);
  768.             else return error("Unknown index buffer data type.");
  769.  
  770.             // read face data
  771.             unsigned int total_bytes = ib.elem*typesize;
  772.             ib.data.reset(new char[total_bytes]);
  773.             if(ib.format == FACE_FORMAT_UINT_16) ss.BE_read_array(reinterpret_cast<uint16*>(ib.data.get()), ib.elem);
  774.             else if(ib.format == FACE_FORMAT_UINT_32) ss.BE_read_array(reinterpret_cast<uint32*>(ib.data.get()), ib.elem);
  775.  
  776.             // test face data
  777.             uint32 min_index = 0;
  778.             uint32 max_index = 0;
  779.             if(ib.format == FACE_FORMAT_UINT_16) {
  780.                //uint16 a; minimum(reinterpret_cast<uint16*>(ib.data.get()), ib.elem, a);
  781.                //uint16 b; maximum(reinterpret_cast<uint16*>(ib.data.get()), ib.elem, b);
  782.                //min_index = a;
  783.                //max_index = b;
  784.               }
  785.             else if(ib.format == FACE_FORMAT_UINT_32) {
  786.                //uint32 a; minimum(reinterpret_cast<uint32*>(ib.data.get()), ib.elem, a);
  787.                //uint32 b; maximum(reinterpret_cast<uint32*>(ib.data.get()), ib.elem, b);
  788.                //min_index = a;
  789.                //max_index = b;
  790.               }
  791.             cout << " min index = " << min_index << endl;
  792.             cout << " max index = " << max_index << endl;
  793.  
  794.             // set vertex buffer reference
  795.             //if(min_index == 0) vb_index++; // there has got to be a better way
  796.             //if(vb_index > 0) ib.reference = vb_index - 1;
  797.             //else return error("Unexpected vertex buffer reference.");
  798.  
  799.             // save face data
  800.             //fdlist.push_back(ib);
  801.            }
  802.        }
  803.     }
  804.  
  805.  return true;
  806. }
  807.  
  808. bool extractor::extract(void)
  809. {
  810.  using namespace std;
  811.  debug = true;
  812.  
  813.  bool unpackA = false;
  814.  bool unpackB = false;
  815.  bool unpackC = false;
  816.  bool doBin = true;
  817.  
  818.  cout << "STAGE 1" << endl;
  819.  if(unpackA) {
  820.     cout << "Unpacking .A files..." << endl;
  821.     deque<string> filelist;
  822.     BuildFilenameList(filelist, ".A", pathname.c_str());
  823.     for(size_t i = 0; i < filelist.size(); i++) {
  824.         cout << "Processing file " << (i + 1) << " of " << filelist.size() << ": " << filelist[i] << "." << endl;
  825.         if(!unpack(filelist[i])) return false;
  826.        }
  827.     cout << endl;
  828.    }
  829.  
  830.  cout << "STAGE 2" << endl;
  831.  if(unpackB) {
  832.     cout << "Unpacking .B files..." << endl;
  833.     deque<string> filelist;
  834.     BuildFilenameList(filelist, ".B", pathname.c_str());
  835.     for(size_t i = 0; i < filelist.size(); i++) {
  836.         cout << "Processing file " << (i + 1) << " of " << filelist.size() << ": " << filelist[i] << "." << endl;
  837.         if(!unpack(filelist[i])) return false;
  838.        }
  839.     cout << endl;
  840.    }
  841.  
  842.  cout << "STAGE 3" << endl;
  843.  if(unpackC) {
  844.     cout << "Unpacking .C files..." << endl;
  845.     deque<string> filelist;
  846.     BuildFilenameList(filelist, ".C", pathname.c_str());
  847.     for(size_t i = 0; i < filelist.size(); i++) {
  848.         cout << "Processing file " << (i + 1) << " of " << filelist.size() << ": " << filelist[i] << "." << endl;
  849.         if(!unpack(filelist[i])) return false;
  850.        }
  851.     cout << endl;
  852.    }
  853.  
  854.  cout << "STAGE 4" << endl;
  855.  if(doBin) {
  856.     cout << "Analyzing .bin files..." << endl;
  857.     deque<string> filelist;
  858.     BuildFilenameList(filelist, ".bin", pathname.c_str());
  859.     for(size_t i = 0; i < filelist.size(); i++) {
  860.         cout << "Processing file " << (i + 1) << " of " << filelist.size() << ": " << filelist[i] << "." << endl;
  861.         if(!processBIN(filelist[i])) return false;
  862.        }
  863.     cout << endl;
  864.    }
  865.  
  866.  return true;
  867. }
  868.  
  869. };};
  870.  
  871. namespace X_SYSTEM { namespace X_GAME {
  872.  
  873. bool extract(void)
  874. {
  875.  char pathname[MAX_PATH];
  876.  GetModulePathname(pathname, MAX_PATH);
  877.  return extract(pathname);
  878. }
  879.  
  880. bool extract(const char* pathname)
  881. {
  882.  return extractor(pathname).extract();
  883. }
  884.  
  885. };};