Advertisement
kubpica

Turok2 .lsm/.lss Packer/Unpacker

Apr 23rd, 2018
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.92 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <iostream>
  4. #include <fstream>
  5. #include <windows.h>
  6. #include <sstream>
  7. #include <algorithm>
  8.  
  9. namespace patch
  10. {
  11.     template < typename T > std::string to_string( const T& n )
  12.     {
  13.         std::ostringstream stm ;
  14.         stm << n ;
  15.         return stm.str() ;
  16.     }
  17. }
  18.  
  19. #include <string>
  20. #include <sys/stat.h> // stat
  21. #include <errno.h>    // errno, ENOENT, EEXIST
  22. #if defined(_WIN32)
  23. #include <direct.h>   // _mkdir
  24. #endif
  25.  
  26. bool isDirExist(const std::string& path)
  27. {
  28. #if defined(_WIN32)
  29.     struct _stat info;
  30.     if (_stat(path.c_str(), &info) != 0)
  31.     {
  32.         return false;
  33.     }
  34.     return (info.st_mode & _S_IFDIR) != 0;
  35. #else
  36.     struct stat info;
  37.     if (stat(path.c_str(), &info) != 0)
  38.     {
  39.         return false;
  40.     }
  41.     return (info.st_mode & S_IFDIR) != 0;
  42. #endif
  43. }
  44.  
  45. bool makePath(const std::string& path)
  46. {
  47. #if defined(_WIN32)
  48.     int ret = _mkdir(path.c_str());
  49. #else
  50.     mode_t mode = 0755;
  51.     int ret = mkdir(path.c_str(), mode);
  52. #endif
  53.     if (ret == 0)
  54.         return true;
  55.  
  56.     switch (errno)
  57.     {
  58.     case ENOENT:
  59.         // parent didn't exist, try to create it
  60.         {
  61.             int pos = path.find_last_of('/');
  62.             if (pos == std::string::npos)
  63. #if defined(_WIN32)
  64.                 pos = path.find_last_of('\\');
  65.             if (pos == std::string::npos)
  66. #endif
  67.                 return false;
  68.             if (!makePath( path.substr(0, pos) ))
  69.                 return false;
  70.         }
  71.         // now, try to create again
  72. #if defined(_WIN32)
  73.         return 0 == _mkdir(path.c_str());
  74. #else
  75.         return 0 == mkdir(path.c_str(), mode);
  76. #endif
  77.  
  78.     case EEXIST:
  79.         // done!
  80.         return isDirExist(path);
  81.  
  82.     default:
  83.         return false;
  84.     }
  85. }
  86.  
  87. using namespace std;
  88.  
  89. enum colour { DARKBLUE = 1, DARKGREEN, DARKTEAL, DARKRED, DARKPINK, DARKYELLOW, GRAY, DARKGRAY, BLUE, GREEN, TEAL, RED, PINK, YELLOW, WHITE };
  90.  
  91. struct setcolour
  92. {
  93.    colour _c;
  94.    HANDLE _console_handle;
  95.  
  96.  
  97.        setcolour(colour c, HANDLE console_handle)
  98.            : _c(c), _console_handle(0)
  99.        {
  100.            _console_handle = console_handle;
  101.        }
  102. };
  103.  
  104. // We could use a template here, making it more generic. Wide streams won't work with this version.
  105. basic_ostream<char> &operator<<(basic_ostream<char> &s, const setcolour &ref)
  106. {
  107.     SetConsoleTextAttribute(ref._console_handle, ref._c);
  108.     return s;
  109. }
  110.  
  111. struct MyStreamingHelper
  112. {
  113.     MyStreamingHelper(std::ostream& out1,
  114.                       std::ostream& out2) : out1_(out1), out2_(out2) {}
  115.     std::ostream& out1_;
  116.     std::ostream& out2_;
  117. };
  118.  
  119. template <typename T>
  120. MyStreamingHelper& operator<<(MyStreamingHelper& h, T const& t)
  121. {
  122.    //h.out1_ << t;
  123.    //h.out2_ << t;
  124.    return h;
  125. }
  126.  
  127. MyStreamingHelper& operator<<(MyStreamingHelper& h, std::ostream&(*f)(std::ostream&))
  128. {
  129.    //h.out1_ << f;
  130.    h.out2_ << f;
  131.    return h;
  132. }
  133.  
  134. static std::vector<unsigned char> ReadAllBytes(char const* filename)
  135. {
  136.     ifstream ifs(filename, ios::binary|ios::ate);
  137.     ifstream::pos_type pos = ifs.tellg();
  138.  
  139.     std::vector<unsigned char>  result(pos);
  140.  
  141.     ifs.seekg(0, ios::beg);
  142.     ifs.read((char*)result.data(), pos);
  143.  
  144.     return result;
  145. }
  146.  
  147. void writeBytes(char const* filename, std::vector<unsigned char>* bytes, int offset = 0, int amount = -1)
  148. {
  149.     if(amount<0)
  150.         amount = (*bytes).size()-offset;
  151.     ofstream outfile(filename, ios::out | ios::binary);
  152.     outfile.write((char*)(*bytes).data()+offset, amount);
  153.     outfile.close();
  154. }
  155.  
  156. int bytesToInt(std::vector<unsigned char>* bytes, int offset){ //little endian to int
  157.     char buf[4];
  158.     buf[0] = (*bytes)[offset];
  159.     buf[1] = (*bytes)[offset+1];
  160.     buf[2] = (*bytes)[offset+2];
  161.     buf[3] = (*bytes)[offset+3];
  162.     unsigned int* p_int = ( unsigned int * )buf;
  163.     return *p_int;
  164. }
  165.  
  166. void pushInt(std::vector<unsigned char>* bytes, unsigned int value, int offset = -1){
  167.     unsigned char b[4];
  168.     b[3] = (value >> 24) & 0xFF;
  169.     b[2] = (value >> 16) & 0xFF;
  170.     b[1] = (value >> 8) & 0xFF;
  171.     b[0] = value & 0xFF;
  172.     if(offset<0){
  173.         (*bytes).push_back(b[0]);
  174.         (*bytes).push_back(b[1]);
  175.         (*bytes).push_back(b[2]);
  176.         (*bytes).push_back(b[3]);
  177.     }else{
  178.         (*bytes)[offset] = b[0];
  179.         (*bytes)[offset+1] = b[1];
  180.         (*bytes)[offset+2] = b[2];
  181.         (*bytes)[offset+3] = b[3];
  182.     }
  183. }
  184.  
  185. ofstream structuretxt;
  186. MyStreamingHelper structure(structuretxt, std::cout);
  187.  
  188. bool isBlock(std::vector<unsigned char>* bytes, int offset, int subBlocksCount, int blocksize, int minSbToHeader = 0, int minSbToFooter = -1){
  189.     if(minSbToHeader>subBlocksCount)
  190.         return false;
  191.     int temp = subBlocksCount+2;
  192.     temp *= 4;
  193.     if(temp%8==4){
  194.         if(temp>blocksize || bytesToInt(bytes, offset+temp) != 0)
  195.             return false;
  196.         temp += 4;
  197.     }
  198.     int temp2 = bytesToInt(bytes, offset+4);
  199.     if(temp != temp2 || temp2 > blocksize || temp2%4!=0)
  200.         return false;
  201.     for(int i = 1; i<subBlocksCount+1; i++){
  202.         int temp3 = bytesToInt(bytes, offset+4+4*i);
  203.         if(temp2 >= temp3 || temp3 > blocksize || temp3%4!=0)
  204.             return false;
  205.         temp3 = temp2;
  206.     }
  207.     if(subBlocksCount>=minSbToFooter && minSbToFooter>0)
  208.         return true;
  209.     temp = offset+(subBlocksCount+1)*4;
  210.     if(bytesToInt(bytes, temp) != blocksize)
  211.         return false;
  212.     return true;
  213. }
  214.  
  215. int rawBytes = 0;
  216. int headerBytes = 0;
  217. int printDepth = -1;
  218.  
  219. void unpackBlock(std::vector<unsigned char>* bytes, int offset, int blocksize, string dir = "", int deeplvl = 0){
  220.     int subBlocksCount = bytesToInt(bytes, offset);
  221.     if(deeplvl==0){
  222.         if(deeplvl<=printDepth || printDepth < 0) structure << dir << ": [" << offset << "-" << offset+blocksize-1 << "] (" << blocksize;
  223.         dir += "/";
  224.     }
  225.     if(isBlock(bytes,offset,subBlocksCount,blocksize)){
  226.         if(deeplvl<=printDepth+1 || printDepth < 0) structure << " bytes defining " << subBlocksCount << " sub-blocks";
  227.         if(subBlocksCount==0){
  228.             if(deeplvl<=printDepth+1 || printDepth < 0) structure << " or raw data)" << endl;
  229.             makePath(dir);
  230.             writeBytes((dir+"data").c_str(),bytes,offset,blocksize);
  231.         } else if(deeplvl<=printDepth+1 || printDepth < 0) structure << ")" << endl;
  232.         int firtBlockAddress = bytesToInt(bytes, offset+4);
  233.         if(deeplvl<=printDepth || printDepth < 0){
  234.             for(int j = 0; j<deeplvl+1; j++)
  235.                     structure << "\t";
  236.             structure << "header: [0-" << firtBlockAddress-1 << "] (" << firtBlockAddress << " bytes of header)" << endl;
  237.         }
  238.         headerBytes += firtBlockAddress;
  239.         dir += "subBlock";
  240.         for(int i = 0; i<subBlocksCount; i++){
  241.             int suboff = offset+4+i*4;
  242.             int address = bytesToInt(bytes, suboff);
  243.             int subBlockSize = bytesToInt(bytes, suboff+4)-address;
  244.             if(deeplvl<=printDepth || printDepth < 0){
  245.                 for(int j = 0; j<deeplvl+1; j++)
  246.                     structure << "\t";
  247.                 structure << "sb" << i << ": [" << address << "-" << address+subBlockSize-1 << "] (" << subBlockSize;
  248.             }
  249.             unpackBlock(bytes,offset+address,subBlockSize,dir+patch::to_string(i)+"/",deeplvl+1);
  250.         }
  251.         int temp = offset+(subBlocksCount+1)*4;
  252.         temp = bytesToInt(bytes, temp);
  253.         if(temp < blocksize){
  254.             if(deeplvl<=printDepth || printDepth < 0){
  255.                 for(int j = 0; j<deeplvl+1; j++)
  256.                     structure << "\t";
  257.                 structure << "footer: [" << temp << "-" << blocksize-1 << "] (" << blocksize-temp;
  258.             }
  259.             unpackBlock(bytes,temp,blocksize-temp,dir+"Footer/",deeplvl+1);
  260.         }
  261.     }else if(blocksize>0){
  262.         rawBytes += blocksize;
  263.         if(deeplvl<=printDepth+1 || printDepth < 0) {
  264.             structure << " bytes of raw data)";
  265.             /* structure << " //ints:";
  266.             int maxToShow = min(8,blocksize);
  267.             for(int i = 0; i<maxToShow; i+=4){
  268.                 structure << " " << bytesToInt(bytes, offset+i);
  269.             }
  270.             if(blocksize>8)
  271.                 structure << " (...)";*/
  272.             structure << endl;
  273.         }
  274.         makePath(dir);
  275.         writeBytes((dir+"data").c_str(),bytes,offset,blocksize);
  276.     }
  277. }
  278.  
  279. int packBlock(std::vector<unsigned char>* bytes, string targetFolder = "block", int offset = 0, int deeplvl = 0){
  280.     if(!isDirExist(targetFolder))
  281.         return 0;
  282.     if(deeplvl==0){
  283.         structure << "PACKING: " << targetFolder << " [" << offset << "] (";
  284.     }
  285.     int bytesAdded = 0;
  286.     int subBlocksCount = 0;
  287.     string s = targetFolder + "/subBlock";
  288.     while(isDirExist(s+patch::to_string(subBlocksCount))){
  289.         subBlocksCount++;
  290.     }
  291.     if(subBlocksCount==0){
  292.         std::vector<unsigned char> rawData = ReadAllBytes((targetFolder+"/data").c_str());
  293.         (*bytes).reserve((*bytes).size() + rawData.size()); // preallocate memory
  294.         (*bytes).insert( (*bytes).end(), rawData.begin(), rawData.end() );
  295.         structure << rawData.size() << " bytes of raw data)" << endl;
  296.         return rawData.size();
  297.     }
  298.     structure << subBlocksCount << " sub-blocks)" << endl;
  299.     int bytesToReserve = subBlocksCount+2;
  300.     bytesToReserve *= 4;
  301.     if(bytesToReserve%8==4){
  302.         bytesToReserve += 4;
  303.     }
  304.     bytesAdded += bytesToReserve;
  305.     for(int i = 0; i<bytesToReserve; i++)
  306.         (*bytes).push_back(0x00);
  307.     //(*bytes).resize(offset+bytesToReserve);
  308.     pushInt(bytes,subBlocksCount,offset);
  309.     pushInt(bytes,bytesToReserve,offset+4);
  310.     for(int j = 0; j<deeplvl+1; j++)
  311.         structure << "\t";
  312.     structure << "header: [0-" << bytesToReserve-1 << "] (" << bytesToReserve << " bytes of header)" << endl;
  313.     for(int i = 0; i<subBlocksCount; i++){
  314.         for(int j = 0; j<deeplvl+1; j++)
  315.             structure << "\t";
  316.         structure << "sb" << i << ": [" << bytesAdded << "] (";
  317.         bytesAdded += packBlock(bytes,s+patch::to_string(i),offset+bytesAdded,deeplvl+1);
  318.         pushInt(bytes,bytesAdded,offset+8+i*4);
  319.     }
  320.     for(int j = 0; j<deeplvl; j++)
  321.             structure << "\t";
  322.     structure << "^ [" << offset << "-" << offset+bytesAdded-1 << "] (" << bytesAdded << " bytes defining " << subBlocksCount << " sub-blocks)" << endl;
  323.     return bytesAdded;
  324. }
  325.  
  326. int main()
  327. {
  328.     //unpacking:
  329.     std::vector<unsigned char> fileBytes = ReadAllBytes("Seeds of Evil.lsm");
  330.     structuretxt.open("struct.txt");
  331.     unpackBlock(&fileBytes,0,28296240,"block");
  332.     structure << "Headers: " << headerBytes << "B Real data: " << rawBytes << "B" << endl;
  333.     cout << "Unpacking finished." << endl;
  334.     structure << endl;
  335.  
  336.  
  337.     //packing:
  338.     std::vector<unsigned char> bytesToWrite;
  339.     packBlock(&bytesToWrite,"blockSingleplayer");
  340.     writeBytes("SingleAdded.lsm",&bytesToWrite);
  341.     cout << "Packing finished." << endl;
  342.     int t = 0; cin >> t;
  343.     return 0;
  344. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement