[Edit: having read the OP again, I realize I’m way off-base with my code below since the original question was more about batching files together than obfuscation. But the data could easily be stored in a large xml file, and SDL_RWFromConstMem
could be key to loading/handling chunks of those files at a time. I’ll leave things like this for now, but I’ll work on a better option to post tomorrow.]
Here’s something simple yet complex:
Most image formats expect to have a “magic number” in a determined position in the file. So shift it by one byte and change the file extension.
This following code will specifically take a test file named “test.png” in the active folder and does the above to it by adding the letter ‘D’ to the beginning of the data.
It outputs the obfuscated data as “output.flux”.
Then the retrieve function reads that file, ignoring the first letter while reading it, so the data is the original PNG data again. I am pretty confident that any file explorer or image viewer will throw a fit when they try to open “output.flux”
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
SDL_Texture * textureFromVec(SDL_Renderer * screen, std::vector <Uint8> &data)
{
SDL_RWops* imageStream = SDL_RWFromConstMem(&data[0], data.size());
if(imageStream == NULL)
{
SDL_Log("Failed to load texture data in textureFromVec(), datasize: %d", data.size());
}
return IMG_LoadTexture_RW(screen, imageStream, 1);
}
void obfuscate(std::string imagePath, std::string output)
{
std::ifstream ifile(imagePath.c_str(), std::fstream::binary);
ifile.seekg(0, ifile.end);
size_t fileSize = ifile.tellg();
ifile.seekg(0, ifile.beg);
std::vector <Uint8> data;
data.push_back({'D'});
data.reserve(fileSize + 4);
ifile.read(reinterpret_cast<char *>(&data[1]), fileSize);
ifile.close();
std::ofstream ofile(output.c_str(), std::fstream::binary);
ofile.write(reinterpret_cast<char *>(&data[0]), fileSize + 1);
ofile.close();
}
// returns NULL on failure. Returned texture must be freed by caller.
SDL_Texture * retrieve(SDL_Renderer * screen, std::string filePath)
{
std::ifstream ifile(filePath.c_str(), std::fstream::binary);
ifile.seekg(0, ifile.end);
size_t fileSize = ifile.tellg();
ifile.seekg(0, ifile.beg);
std::vector <Uint8> data;
data.reserve(fileSize + 4);
char * temp = new char[fileSize + 1];
ifile.read(temp, fileSize);
for(size_t i = 1; i < fileSize; i ++)
{
data.push_back(temp[i]);
}
ifile.close();
SDL_Texture * image = textureFromVec(screen, data);
if(image == NULL)
{
SDL_Log("Error on textureFromVec: %s", SDL_GetError());
}
return image;
}
int main()
{
std::string testImagePath = "test.png";
SDL_Init(SDL_INIT_EVERYTHING);
IMG_Init(IMG_INIT_PNG);
SDL_Window * win = SDL_CreateWindow("imageFromStr", 10, 10, 400, 400, SDL_WINDOW_SHOWN);
SDL_Renderer * screen = SDL_CreateRenderer(win, -1, SDL_RENDERER_PRESENTVSYNC);
obfuscate(testImagePath, "output.flux");
SDL_Texture * texture = retrieve(screen, "output.flux");
SDL_Rect pos = {10, 10, 200, 200};
SDL_SetRenderDrawColor(screen, 120, 120, 120, 255);
bool run = true;
while(run)
{
SDL_Event ev;
while(SDL_PollEvent(&ev))
{
switch(ev.type)
{
case SDL_QUIT:
run = false;
break;
}
}
SDL_RenderClear(screen);
SDL_RenderCopy(screen, texture, NULL, &pos);
SDL_RenderPresent(screen);
}
SDL_DestroyTexture(texture);
SDL_DestroyWindow(win);
IMG_Quit();
SDL_Quit();
}