fstream.read, make struct from bytes.

I made a class for the G2DA file format for Dragon Age: Origins modding and it all went well in C#. I want now a real challange and began doing so in C++. I start by reading in the header, which is a struct I know. Problem is, it doesn't always give me the same data and the conversion doesn't work.

This is in a method with (char* path, LoadError& error), the latter being an enum.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fstream stream = fstream(path, ios::in | ios::binary);
// Aqcuire header from file
char buffer[sizeof(gff::Header)];
if(stream.good())
{
	stream.read(buffer, sizeof(buffer));
	header = new gff::Header();
	header = (gff::Header*)buffer;
}
else
{
	error = LoadError::COULDNT_OPEN;
	return false;
}
(... conteniues)

The struct header is as follows
1
2
3
4
5
6
7
8
9
10
struct Header
{
	char		magic[4];
	char		version[4];
	char		platform[4];
	char		fileType[4];
	char		fileVersion[4];
	unsigned int	structCount;
	unsigned int	dataOffset;
};


File's starts with.
 
GFF V4.0PC  G2DAV0.2   Ä   

8 last bytes are two unsigned ints (little endian).

I try to cout the header.magic property and it doesn't give me "GFF " as I would anticipate, but a seemingly arbitrary string of four chars. GFF is DA:O's generic file format, hence fileType and fileVerison.

Is it something fundanmental about reading files the binary way I don't understand? I don't see it returning an int as C#'s counterpart did for how much it actually read, which was easy to work with.
Last edited on
Line 8 has one definite bug and one probable bug. The definite bug is that you're overwriting the pointer to dynamic memory, so you've created a memory leak. The probable bug is that if you try to return that pointer from a function, the memory it points to is on the stack, and is likely to get overwritten after the function returns.

You can just read directly into a Header:
1
2
gff::Header header;
stream.read((char *)&header,sizeof(header));

One word of warning, though: this is only completely safe to do with POD structures.
I get an access violation trying to read it. Here's the whole class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class G2DA
{
public:
	// Constructor/destructor
	G2DA()
	{
		isReady		= new bool();
		columnCount = new int();
		*isReady	 = false;
		*columnCount = 0;
	}
	~G2DA()
	{
		if(*isReady)
		{
			delete   header;
			delete[] arrayHeaders;
			delete[] fields;
		}
		delete isReady;
		delete columnCount;
	}
	// Initialisation methods
	bool loadFromFile(char* path, LoadError& error)
	{
		*isReady = false;
		fstream stream = fstream(path, ios::in | ios::binary);
		// Aqcuire header from file
		if(stream.good())
		{
			stream.read((char*)&header, sizeof(header));
		}
		else
		{
			error = LoadError::COULDNT_OPEN;
			return false;
		}

		// At this point, consider it a success
		*isReady = true;
		return true;
	}
	// Temporary debug functions
	gff::Header getHeader()
	{
		return *header;
	}
private:
	// GFF structures
	gff::Header* header;
	gff::ArrayHeader* arrayHeaders;
	gff::Field* fields;
	// variable
	bool* isReady;
	int* columnCount;
	// Row structure
	struct cell
	{
		void* value;
	};
	struct row
	{
		cell* values;
	};
};


Unhandled exception at 0x00a21ad0 in G2DA_C++.exe: 0xC0000005: Access violation reading location 0x20464647.

(line 46)
Last edited on
Your 'header' is a pointer. My 'header' is an object.
Ok, it works now. Thanks.

EDIT: The unsigned ints are still zero when they should not be.
EDIT2: Only the first variable in the header struct seems to have a value at all.
Last edited on
Well, it's certainly not anything to do with how you're reading the file. Either they were previously written wrong, or there's something else overwriting their values.
I found out. Seems sizeof(header) was wrong, sizeof(gff::Header) worked.
Again, my code used an object 'header'. The correct operand for sizeof in your case was *header.
Yeah, found out that. The pointer being 32-bit made it so I could ready magic[4] only.

Edit: for some pecular reason, cout << header->magic; returns the whole struct spewed out in chars. It seems to start off at the specified variable and go all the way to the structs end. I thought char[4] meant four chars. Edit2: It seems to go on until null-termination.

Edit3: As all these strings are char[4], I made a function that copies it to a char[5], adds a null terminator and returns it.
Last edited on
Topic archived. No new replies allowed.