Jump to content
  • Advertisement
Sign in to follow this  
DecipherOne

Data Corruption

This topic is 4144 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ok, I have a MFC Dialog "YES MFC" that takes a few different parameters to initialize the window, graphic settings, and sound for my application. You set the selections and it gets saved to a file that loads at runtime. The problem I'm having is that for a CEdit box, I'm taking in an argument that I place in a CString object that is later converted to a std::string to be saved in the struct for my video settings. This works fine up until a certain point. Beyond something like 25 characters, it doesn't work any more. I follow the process of conversion and everything is fine. Even after the writing of the information to disk the struct still contains the appropriate data. However, when I go to load the information or open the file to look at the data, it is corrupt. I've been trying to solve this for the past day and I'm at a loss as to what is causing this. Here is the file where the writing and reading is being done, and I'm assuming that this is where the error lies. The corrupted data lies in V_Settings.AppName (which is part of the V_Settings struct) and it is the only data that gets corrupt, but as stated only when the number of characters is beyond 25. As always any help would be greatly appreciated.
#include"Stdafx.h"
#include"Globals.h"
#include<fstream>

using namespace std;

int SettingsManager::Load_V_Settings()
{
	fstream stream;

    stream.open("../../config.ini",ios::in|ios::binary);
	if(stream.is_open())
	{
		
		stream.read((char *) &V_Settings, sizeof(VideoConfig)); //Load all the configuration settings.

		
		stream.close();
	}

	else
	{
		MessageBox(NULL,"Could not Load settings file!","Settings Load Error",MB_OK);
	}

	return 0;
}

int SettingsManager::Save_V_Settings ()
{

	
	fstream stream;
	stream.open("../../config.ini",ios::out|ios::binary);
	if(stream.is_open())
	{

		stream.write ((char *) &V_Settings, sizeof(VideoConfig)); //Save all the configuration settings.

		stream.flush();

		stream.close();
	}

	else
	{
		MessageBox(NULL,"Could not save settings file!","Settings Save Error",MB_OK);
	}


	return 0;
}

SettingsManager::SettingsManager()
{
	V_Settings.AppName.reserve(255);
}

SettingsManager::~SettingsManager()
{
}

Share this post


Link to post
Share on other sites
Advertisement
// EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL
stream.write((char *) &V_Settings, sizeof(VideoConfig));
// EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL EVIL


You cant just write the bytes of a class out, the reason it worked at the start is becase some implementations of std::string will alocate small strings on the stack and hence it is located somewhere in your object, but when its larger it will allocate the string on the heap hence your only writting out a pointer to the string which when you read it back later points to uselessness, think of it like doing this...
int* myInt = new int(7);
stream << myInt;
delete myInt;
// some time later (maybe a different execution of the application)
stream >> myInt;
and expecting myInt to point to
1) allocated, valid memory which,
2) contains a 7

What you have to do is write out each member of V_Settings seperatly and in doing that you have to write out each of the members of the members of V_Settings and so on... and if and of those members is a pointer then you have to write out the pointed to thing instead of the pointer. Then when you read it back you have to realocate all the memory for the pointed to things and so on....

In reality its alot more complicated then that because of circular dependencies etc but that should get you going, google serialization for more info and you might be interested in boost.serialization

Share this post


Link to post
Share on other sites
Thank you very much for your response. This is exactly what I was thinking was the problem but I wasn't sure how the internals of the string class were implemented. I know of serialization, but was wanting to hold off on learning those practices until I began writing larger save states for the engine itself, but I suppose seeing as the issue is arising right now, it can't hurt to go a head and delve into the subject.This also explains why in previous projects I've had errors with persistently saving things. I was simply shown this method of writing objects from a fellow developer years ago and have only recently became aware of some type of problem with the structure of such code. Thanks for pointing me in the right direction.

Share this post


Link to post
Share on other sites
Well it took me all night but I finally came up with a solution. I'm not sure if this is the best way to do it, but it works.

int SettingsManager::Load_V_Settings()
{
fstream stream;



stream.open("../../config.ini",ios::in|ios::binary);
if(stream.is_open())
{


//Load the AppNameSize to set up buffer size for string data
stream.read((char *) &V_Settings.AppNameSize, sizeof(V_Settings.AppNameSize));
//Setup a char buffer for string data

char * buffer = new char [V_Settings.AppNameSize]; //Allocate memory for buffer


//Read in each byte one at a time for the string data

int i=0; //used for counting characters



int b =0; //used for incrementing the buffer

do
{
stream.read((buffer+b),sizeof(char)); //Read in the string data

i +=1;
b +=1;

}
while(i!=V_Settings.AppNameSize);

V_Settings.AppName = buffer; //Convert the string data to the string in the struct



int buf = strlen(buffer); //Get the length of the string data and any extra padding

if(strlen(buffer) != V_Settings.AppNameSize) //If the lengths don't match
{
if(buf>V_Settings.AppNameSize) //IF the length is too long remove padding from string
{

V_Settings.AppName.erase(V_Settings.AppNameSize, buf);
}

else //Data has probably been corrupted.
{
MessageBox(NULL,"V_Settings.AppNameSize is not the correct size! Application will now quit!",
"Settings Load Error",MB_OK);
PostQuitMessage(0);
}

}



//delete our pointer
delete buffer;

//read the remaining config settings


stream.read((char *) &V_Settings.CBits,sizeof(V_Settings.CBits));
stream.read((char *) &V_Settings.fullscreen,sizeof(V_Settings.fullscreen));
stream.read((char *) &V_Settings.height,sizeof(V_Settings.height));
stream.read((char *) &V_Settings.width,sizeof(V_Settings.width));



stream.close();
}

else
{
MessageBox(NULL,"Could not Load settings file!","Settings Load Error",MB_OK);
}

return 0;
}

int SettingsManager::Save_V_Settings ()
{


fstream stream;
stream.open("../../config.ini",ios::out|ios::binary);
if(stream.is_open())
{

//Get the offset of our string object
V_Settings.AppNameSize = V_Settings.AppName.size();

//Check to make sure the offset is correct
if(V_Settings.AppName.size() != V_Settings.AppNameSize)
{
MessageBox(NULL,"V_Settings.AppName is not the correct size! Application will now quit!",
"Settings Save Error",MB_OK);
PostQuitMessage(0);
}

//Save the offset for the string to be loaded later : MUST BE LOADED FIRST BEFORE STRING DATA
stream.write((char *) & V_Settings.AppNameSize,sizeof(V_Settings.AppNameSize));

//Write the string to the file converting it to a const char * and as the actual size of the string
stream.write(V_Settings.AppName.c_str(),V_Settings.AppNameSize);


//write the additional config settings

stream.write((char *) &V_Settings.CBits,sizeof(V_Settings.CBits));
stream.write((char *) &V_Settings.fullscreen,sizeof(V_Settings.fullscreen));
stream.write((char *) &V_Settings.height,sizeof(V_Settings.height));
stream.write((char *) &V_Settings.width,sizeof(V_Settings.width));


stream.flush();

stream.close();
}

else
{
MessageBox(NULL,"Could not save settings file!","Settings Save Error",MB_OK);
}


return 0;
}

SettingsManager::SettingsManager()
{
V_Settings.AppName.reserve(255);
}

SettingsManager::~SettingsManager()
{
}




Hopefully this might help someone else out there. Or if there is a better approach , please let me know.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!