Embedding Multiples Files in an Executable - Windows - Part 3
Tags: cpp, programming, desktop
Published: 2023-03-19 03:38:36

This example deals with multiple files. Is now also stored:
```
content name size: 8
content name: data.txt
content size: 10
content: 1234567890
```
This symbol  is used to signal that a new file exists
```
std::string symbol = "^";
```

**1) Create program.cpp**

```cpp
#include <fstream>
#include <iostream>
#include <windows.h>
#include <sstream>
#include <string> 
#include <locale>

int assetsCount = 0;
 
std::vector<char> file_read_bin(const std::string& fileName) {
  std::string filePath = fileName;
  std::ifstream file(filePath, std::ios::binary);
  if (file.fail()) {
    std::cerr << "Erro ao abrir o arquivo " << filePath << std::endl;
   } 
 // Read bytes 
  std::vector<char> bytFile((std::istreambuf_iterator<char>(file)),
                             std::istreambuf_iterator<char>());
  file.close(); 
  return bytFile;
}

std::string getHexValue(const std::vector<char>& bytFile, int size, int byteCount) {
    std::stringstream ss;
    ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned int>(static_cast<unsigned char>(bytFile[size - byteCount]));
    return ss.str();
}

int hexToInt(std::string hexStr) {
    return std::stoi(hexStr, nullptr, 16);
}

int getContent(std::vector<char> bytFile, int size) {

    if( bytFile[size - 1] != '^') { // Exist new file?
        std::cout << "end" << "\n";
        return 0; 
    }

    assetsCount+=1;

    std::cout << assetsCount << "-----------------" << "\n"; 
        
    // Get file name size in last byte    
    std::cout << "content name size: ";    
    std::string sizeHex = getHexValue(bytFile, size, 2); 
    int fileNameSize = hexToInt( sizeHex );
    std::cout << fileNameSize << "\n";

    // Get file name in last byte 
    std::string fileName = "content name: ";     
    for (int i = fileNameSize+2; i > 1; i--) { 
        std::string byteInStringFormat;
        byteInStringFormat.push_back(static_cast<char>(bytFile[size - i])); // convert byte to char
        fileName += byteInStringFormat;
    } 
    std::cout << fileName << std::endl;
 
    // Get content size in last byte    
    std::cout << "content size: ";    
    std::string contentSizeHex = getHexValue(bytFile, size, fileNameSize + 3); 
    int contentSize = hexToInt( contentSizeHex );
    std::cout << contentSize << "\n";

    // Print content
    std::string content = "content: ";
    int contentStart = contentSize+fileNameSize+3;   //9   5 
    for (int i = contentStart; i > fileNameSize+3; i--) { 
        std::string byteInStringFormat;
        byteInStringFormat.push_back(static_cast<char>(bytFile[size - i])); // convert byte to char 
        content += byteInStringFormat;
    }  
    std::cout << content << "\n"; 

    // End
    int final = size - (contentStart + 1);
    std::cout << "-----------------" << "\n"; 
    
    getContent(bytFile, final+1); // get new file

    return 0;
}

int main(int argc, char *argv[]){   
 
    // Read file
    std::string filename = std::string(argv[0]) + ".exe";
    std::vector<char> bytFile = file_read_bin( filename ); 
    int size = bytFile.size(); 

    // Logs
    std::cout << "file size: " << size << std::endl;
    std::cout << "last byte: " << getHexValue(bytFile, size, 1) << std::endl;
    //std::cout << "int size : " << contentSize << std::endl;    
     
    // console "pt-BR" accentuation errors
    system("chcp 1252 > nul"); 
    setlocale(LC_ALL, "pt_BR.UTF-8");

    getContent(bytFile, size);

    return 0;
}

```
 
**2) Compile**

```
g++ program.cpp -o program
```

**3) Exec and get "file size"**

```
program
```
```
file size: 168960
last byte: 00
end
```
Or get file size by cmd
```
for %I in (program.exe) do @echo %~zI
168960
```

**4) Create patch.cpp**

```cpp
#include <fstream>
#include <iostream>
#include <string> 
#include <vector>
#include <sstream>

std::vector<char> file_read_bin(const std::string& fileName) {
  std::string filePath = fileName;
  std::ifstream file(filePath, std::ios::binary);
  if (file.fail()) {
    std::cerr << "Erro ao abrir o arquivo " << filePath << std::endl;
   } 
 // Read bytes 
  std::vector<char> bytFile((std::istreambuf_iterator<char>(file)),
                             std::istreambuf_iterator<char>());
  file.close(); 
  return bytFile;
}

void file_write_bin(const std::string& filePath, std::vector<char> bytFile) { 
  // Write bytes
  std::ofstream outFile(filePath, std::ios::binary);
  if (outFile.fail()) {
    std::cerr << "Erro ao abrir o arquivo " << filePath << " para escrita" << std::endl;  
  } 
  outFile.write(bytFile.data(), bytFile.size());
  outFile.close();

  std::cout << "Arquivo alterado com sucesso" << std::endl;
} 

int main(int argc, char *argv[]){   

  if (argc != 4) {
      std::cout << "Require 3 args: program.exe data.txt 163857\n";
      return 1;
  }

  const char* program_file = argv[1];
  const char* data_file = argv[2];

  std::vector<char> bytFile = file_read_bin( program_file );
  std::vector<char> bytText = file_read_bin( data_file );
  int correctSize = std::stoi(argv[3]); 

  int size = bytFile.size(); 
  int diff = size - correctSize;
 
  // Logs
  std::cout << "size: " << size << "\n";
  std::cout << "correctSize: " << correctSize << "\n";

  // Remove old code
  if(size > correctSize ){
    bytFile.erase(bytFile.end() - diff, bytFile.end() );
  }

  // Add content
  bytFile.insert(bytFile.end(), bytText.begin(), bytText.end());

  // Add content size
  bytFile.insert( bytFile.end(), bytText.size() );
 
  // Add file name
  std::string data_filename_str(data_file);
  data_filename_str+="\0";
  bytFile.insert(bytFile.end(), data_filename_str.c_str(), data_filename_str.c_str() + data_filename_str.size() );
 
  // Add name size
  bytFile.insert( bytFile.end(), data_filename_str.size() );  

  // Add symbol exist new file
  std::string symbol = "^";
  bytFile.insert(bytFile.end(), symbol.c_str(), symbol.c_str() + symbol.size() );

  // Rewrite 
  file_write_bin(program_file, bytFile);

  return 0;
}
```

**5) Create content file: data.txt**
```
1234567890Xkãj56
```

**6) Apply patch**
```
patch program.exe data.txt 168960
```

**7) Run program.exe and get new size**
```
program
```
```
file size: 168988
last byte: 5e
1-----------------
content name size: 8
content name: data.txt
content size: 17
content: 1234567890Xkãj56
-----------------
end
```

**8) Create new content file: data2.txt**
```
1234567890Xkãj56888
```

**9) Apply patch with new size**
```
patch program.exe data2.txt 168988
```

**10) Run program.exe**
```
program
```
```
file size: 169020
last byte: 5e
1-----------------
content name size: 9
content name: data2.txt
content size: 20
content: 1234567890Xkãj56888
-----------------
2-----------------
content name size: 8
content name: data.txt
content size: 17
content: 1234567890Xkãj56
-----------------
end
```

### Embedding Big Files in an Executable - Windows - Part 4
https://dev.to/gurigraphics/embedding-big-files-in-an-executable-windows-part-4-25hf