Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
March 20, 2023 05:24 am GMT

Embedding Files in an Executable - SDL/Windows - Part 5

In this example we will test this system using the SDL library.

Let's change the patch.

If using only 2 arguments it will get the size of the file itself

patch main.exe data.txt

If we use 3 arguments we can return to the original file size

patch main.exe data.txt 246784

1) Let's update the patch:

#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 << "Open file error " << 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 << "Open file error " << filePath << " to write" << std::endl;    }   outFile.write(bytFile.data(), bytFile.size());  outFile.close();  std::cout << "File sucessfull updated" << std::endl;} int main(int argc, char *argv[]){     int correctSize = 0;  if (argc < 2) {      std::cout << "Require 2 or 3 args: program.exe data.txt 163857
"; 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 size = bytFile.size(); if(argc == 3) { correctSize = size; }else if(argc == 4) { correctSize = std::stoi(argv[3]); } int diff = size - correctSize; // Logs std::cout << "size: " << size << "
"; std::cout << "correctSize: " << correctSize << "
"; // 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(), { static_cast<char>((bytText.size() >> 24) & 0xFF), static_cast<char>((bytText.size() >> 16) & 0xFF), static_cast<char>((bytText.size() >> 8) & 0xFF), static_cast<char>((bytText.size() >> 0) & 0xFF) }); // 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;}

2) Compile

g++ patch.cpp -o patch

3) Create patchFiles lib

Now separate that system. Put in a file "patchFiles.h"

We want it to be insanely simple to use.

patch! patch! end!

With few lines:

#include "./patchFiles.h"// Get filesstd::map<std::string, FileInfo> files = getFiles(); //Usestd::cout << files["data.txt"].contentString;  

For this we will use a map:

struct FileInfo {    int fileNameSize;    std::string fileName;    int contentSize;    int contentStart;    int gap;    std::string contentString;    std::vector<char> contentVector;    };std::map<std::string, FileInfo> files; 

patchFiles.h

#include <map>#include <string>#include <vector>#include <filesystem>#include <fstream>#include <iostream>#include <windows.h>#include <sstream>#include <string> #include <locale>struct FileInfo {    int fileNameSize;    std::string fileName;    int contentSize;    int contentStart;    int gap;    std::string contentString;    std::vector<char> contentVector;    };int assetsCount = 0;std::map<std::string, FileInfo> files; std::string getFileName(){    char filename[MAX_PATH];    GetModuleFileNameA(NULL, filename, MAX_PATH);    std::string filepath(filename);    std::string basename = filepath.substr(filepath.find_last_of("\\/") + 1);    return filename;}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 getFileNamesize(std::vector<char> bytFile, int size){    std::string sizeHex = getHexValue(bytFile, size, 2);     return hexToInt( sizeHex );}std::string getFileName(std::vector<char> bytFile, int size, int fileNameSize){    std::string fileName = "";    int startfileName = fileNameSize + 2;    for (int i = startfileName; i > 2; i--) {         std::string byteInStringFormat;        byteInStringFormat.push_back(static_cast<char>(bytFile[size - i])); // convert byte to char        fileName += byteInStringFormat;    }     return fileName;}int getContentSize(std::vector<char> bytFile, int size, int fileNameSize){    std::string byte_24 = getHexValue(bytFile, size, fileNameSize + 3);    std::string byte_16 = getHexValue(bytFile, size, fileNameSize + 4);    std::string byte_08 = getHexValue(bytFile, size, fileNameSize + 5);    std::string byte_00 = getHexValue(bytFile, size, fileNameSize + 6);    std::stringstream ss;       ss << std::hex << byte_00 << byte_08 << byte_16 << byte_24;    int contentSize;    ss >> contentSize;    return contentSize;}std::string getContent(std::vector<char> bytFile, int size, int fileNameSize, int contentSize, int contentStart){    std::string content = "";    for (int i = contentStart; i > fileNameSize+3+3; i--) {         std::string byteInStringFormat;        byteInStringFormat.push_back(static_cast<char>(bytFile[size - i])); // convert byte to char         content += byteInStringFormat;    }    return content;}int getContent(std::map<std::string, FileInfo>& files, const std::vector<char>& bytFile, int size) {    if( bytFile[size - 1] != '^') { // Exist new file?        std::cout << "end" << "
"; return 0; } std::cout << assetsCount << "-----------------" << "
"; // Get file name size in last byte int fileNameSize = getFileNamesize(bytFile, size); std::cout << "content name size: " << fileNameSize << "
"; // Get file name in last byte std::string fileName = getFileName(bytFile, size, fileNameSize); std::cout << "content name: " << fileName << "
"; // Get content size in 4 bytes int contentSize = getContentSize(bytFile, size, fileNameSize); std::cout << "content size: " << contentSize << "
"; // Get contentStart from final of file int contentStart = contentSize+fileNameSize+3+3; int gap = contentStart - contentSize; // Get content std::string contentString = ""; std::vector<char> contentVector; if(fileName.find(".txt") != fileName.npos){ contentString = getContent(bytFile, size, fileNameSize, contentSize, contentStart); }else if(fileName.find(".png") != fileName.npos){ for(int i = bytFile.size() - contentSize - gap; i < bytFile.size() + gap; i++) { contentVector.push_back(bytFile[i]); } } files[ fileName ] = {fileNameSize, fileName, contentSize, contentStart, gap, contentString, contentVector}; assetsCount+=1; // End int final = size - (contentStart + 1); std::cout << "-----------------" << "
"; getContent(files, bytFile, final+1); // get new file return 0;}std::map<std::string, FileInfo> getFiles() { // Read file std::string filename = getFileName(); 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; getContent(files, bytFile, size); return files;}

4) Download SDL

Download and export inside the project folder:

SDL2_image-devel-2.6.3-mingw.zip
https://github.com/libsdl-org/SDL_image/releases/download/release-2.6.3/SDL2_image-devel-2.6.3-mingw.zip

SDL2-devel-2.26.4-mingw.zip
https://github.com/libsdl-org/SDL/releases/download/release-2.26.4/SDL2-devel-2.26.4-mingw.zip

You can leave the folders with these same names.

SDL2_image-devel-2.6.3-mingwSDL2-devel-2.26.4-mingw

We're not even going to install it. Let's use it anyway.

Just grab these two files from bin folders and drop them in the project directory:

SDL2.dllSDL2_image.dll

5) Show images

I took two free images from Pexels and adjusted the size: 1280x720

Image app

Image app

Download these images. Rename one of the images to "bg.png"
https://dev-to-uploads.s3.amazonaws.com/uploads/articles/899pvtvcwx2zney81vr4.png
https://dev-to-uploads.s3.amazonaws.com/uploads/articles/agy0ayu8ul5xl78k8yzh.png

Also create a file: data.txt
Content: 123

Now just import our lib and use:

main.cpp

#include <SDL.h>#include <SDL_image.h>#include "./patchFiles.h"int main(int argc, char *argv[]){        // Get assets    std::map<std::string, FileInfo> files = getFiles();     // Use    std::vector<char> bytImage = files["bg.png"].contentVector;    std::cout << files["data.txt"].contentString;     SDL_Init(SDL_INIT_VIDEO);    SDL_Window* window = SDL_CreateWindow("App", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_SHOWN);    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);    SDL_RWops* rwops = SDL_RWFromMem(bytImage.data(), bytImage.size());    SDL_Surface* surface = IMG_Load_RW(rwops, 1);      SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);    SDL_FreeSurface(surface);    bool quit = false;    while (!quit) {        SDL_Event event;        while (SDL_PollEvent(&event)) {            switch (event.type) {                case SDL_QUIT:                    quit = true;                    break;                case SDL_KEYDOWN:                    if (event.key.keysym.sym == SDLK_ESCAPE) {                        quit = true;                        break;                    }            }        }        SDL_RenderClear(renderer);        SDL_RenderCopy(renderer, texture, NULL, NULL);        SDL_RenderPresent(renderer);    }    SDL_DestroyTexture(texture);    SDL_DestroyRenderer(renderer);    SDL_DestroyWindow(window);    SDL_Quit();    return 0;  }

6) Compile

Let's compile using all of that, no makefile or anything:

g++ -std=c++17 main.cpp -o main.exe -I.\ -I.\SDL2-devel-2.26.4-mingw\SDL2-2.26.4\x86_64-w64-mingw32\include\SDL2 -I.\SDL2_image-devel-2.6.3-mingw\SDL2_image-2.6.3\x86_64-w64-mingw32\include\SDL2 -L.\SDL2_image-devel-2.6.3-mingw\SDL2_image-2.6.3\x86_64-w64-mingw32\lib -L.\SDL2-devel-2.26.4-mingw\SDL2-2.26.4\x86_64-w64-mingw32\lib -w -Wl,-subsystem,console -lmingw32 -lSDL2main -lSDL2 -lSDL2_image

7) Now Patch

Now let's add the assets in this recipe:

patch main.exe data.txtpatch main.exe bg.png

8) Run
Run the program:

main

Image app

9) Test
Now let's test if this all really works.
Let's change the assets without having to compile.

Create a folder and drop the image there or delete it.
Rename the other image to "bg.png"
Change the content of data.txt to "0987654321" or whatever.

There in the prompt you can read what was the first file size.

> patch main.exe data.txtsize: 246784correctSize: 246784

Let's make the executable return to this size using a third argument:

patch main.exe data.txt 246784patch main.exe bg.png

8) Run
Run the program:

main

Image app


Original Link: https://dev.to/gurigraphics/embedding-files-in-an-executable-sdlwindows-part-5-2he4

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To