I'm trying to write and read serialized data to file, but it always breaks when reading specific "PNG" struct, with stored "bed_feet_top.png" from minecraft 1.8.9 textures folder in it, and I can't find a way to get the error. Already tried errno and try and catch, but it always says sucess. It seems that it breaks after and not when reading the buggy "PNG" struct, because the read data is uncorrupted and I can recreate the stored image. I'm using "stb_image" library to read the image data and "zpp_bits" library for serializing the data.
the code i would use:
PNG srcImage; //The "PNG" struct it will break at
unsigned char* buffer = stbi_load("bed_feet_top.png", &image.imageWidth, &image.imageHeight, &image.colorChannels, STBI_rgb_alpha);
if (!buffer)
{
std::cout << "Failed to read image: " + path << std::endl;
return 1;
}
image.pixels = (char*)buffer;
DataBuffer srcBuffer;
srcBuffer.serialize("somePath", "someName", srcImage);
DataManager::writeToFile("someFile.dat", srcBuffer);
DataBuffer dstBuffer;
DataManager::readFromFile("someFile.dat", &dstbuffer);
PNG dstImage = dstBuffer.deserialize<PNG>("somePath", "someName"); //The buggy "PNG" struct data is uncorrupted
the "PNG" struct:
struct PNG
{
int imageWidth, imageHeight, colorChannels;
std::string pixels;
};
the struct I'm storing all serialized data in:
struct DataBuffer
{
std::map<std::string, std::vector<std::byte>> data; //All the serialized data is stored in this map
template<typename T>
void serialize(std::string path, std::string name, T obj)
{
path.append("/");
path.append(name);
serialize(path, obj);
}
template<typename T>
void serialize(std::string fullPath, T obj)
{
if (data.contains(fullPath))
{
std::cout << "Data buffer already contains value with te same path!" << std::endl;
return;
}
try
{
zpp::bits::out out(data[fullPath]);
out(obj).or_throw();
}
catch (const std::exception& error)
{
std::cerr << "Serialization failed with error: " << error.what() << std::endl;
}
catch (...) {
std::cerr << "Serialization failed with unknown error!" << std::endl;
}
}
template<typename T>
T deserialize(std::string path, std::string name)
{
path.append("/");
path.append(name);
return deserialize<T>(path);
}
template<typename T>
T deserialize(std::string fullPath)
{
T obj;
if (!data.contains(fullPath))
{
std::cout << "Data buffer doesn't contain value with the given path!" << std::endl;
return obj;
}
try
{
zpp::bits::in in(data[fullPath]);
in(obj).or_throw();
}
catch (const std::exception& error)
{
std::cerr << "Deserialization failed with error: " << error.what() << std::endl;
}
catch (...) {
std::cerr << "Deserialization failed with unknown error!" << std::endl;
}
return obj;
}
};
The write to file function:
void DataManager::writeToFile(std::string fileName, DataBuffer dataBuffer)
{
std::ofstream ofs(fileName, std::ios::out | std::ios::binary);
if (!ofs.is_open())
{
std::cerr << "Failed to open output file stream!" << std::endl;
return;
}
size_t dataCount = dataBuffer.data.size();
ofs.write((char*)&dataCount, 8);
for (auto const& [key, val] : dataBuffer.data)
{
size_t keySize = key.size();
ofs.write((char*)&keySize, sizeof(keySize));
ofs.write(&key[0], keySize);
size_t entryCount = val.size();
ofs.write((char*)&entryCount, 8);
ofs.write((char*)val.data(), entryCount);
if (!ofs.good()) //ofs.good() never returned false to me
{
std::cerr << "Something went wrong when writing " << key << " to the file!" << std::endl;
break;
}
}
ofs.close();
}
the read from file function:
void DataManager::readFromFile(std::string fileName, DataBuffer* dataBuffer)
{
std::ifstream ifs(fileName, std::ios::in, std::ios::binary);
if (!ifs)
{
std::cerr << "File doesnt exist!" << std::endl;
return;
}
if (!ifs.is_open())
{
std::cerr << "Failed to open input file stream!" << std::endl;
return;
}
size_t dataCount;
ifs.read((char*)&dataCount, 8);
for (size_t i = 0; i < dataCount; i++)
{
size_t keySize;
ifs.read((char*)&keySize, sizeof(keySize));
std::string key;
key.resize(keySize);
ifs.read(&key[0], keySize);
size_t entryCount;
ifs.read((char*)&entryCount, 8);
dataBuffer->data[key].resize(entryCount);
ifs.read((char*)dataBuffer->data[key].data(), entryCount);
if (!ifs.good()) //ifs.good() returns false after it reads the buggy "PNG" struct data
{
std::cerr << "Something went wrong when reading " << key << " from the file!" << std::endl;
break;
}
}
ifs.close();
}