Memory reading issue....

Started by
3 comments, last by BeerNutts 11 years, 9 months ago
Consider the following binary "file":


[font=courier new,courier,monospace]42 42 46 32 00 00 00 00 00 00 00 00 51 75 69 63 6B 20 53 [/font]
[font=courier new,courier,monospace]74 61 72 74 20 2D 20 4D 61 69 6E 20 4D 65 6E 75 00 00 00 [/font]
[font=courier new,courier,monospace]00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00[/font]
[font=courier new,courier,monospace]00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 [/font]
[font=courier new,courier,monospace]03 00 00 00 05 00 00 00 01 00 00 00 01[/font]

And the following file structure that goes with it:

[font=courier new,courier,monospace]char fontTag[5] //5 bytes BBF2[/font]
[font=courier new,courier,monospace]unsigned long misc //4 bytes 0[/font]
[font=courier new,courier,monospace]char desc[50] //50 bytes Quick Start - Main Menu[/font]
[font=courier new,courier,monospace]int firstASCII //4 bytes 0[/font]
[font=courier new,courier,monospace]int lastASCII //4 bytes 256 [/font]
[font=courier new,courier,monospace]int bitDepth //4 bytes 1 [/font]
[font=courier new,courier,monospace]int maxWidth //4 bytes 3 [/font]
[font=courier new,courier,monospace]int maxHeight //4 bytes 5 [/font]
[font=courier new,courier,monospace]int charSpacing //4 bytes 1 [/font]
[font=courier new,courier,monospace]int lineSpacing //4 bytes 1 [/font]
[font=courier new,courier,monospace]short transColor //2 bytes 1 [/font]


In my code I have a struct declared as follow:


[source lang="cpp"]
typedef struct _fntHeader{
char FontTag[5]; // (5 bytes) Data Identifier 'BBF2'
unsigned long misc; // (4 bytes) Unused
char desc[50]; // (50 bytes) Font description
int iFirstASCIIId; // (4 bytes) First ASCII Id
int iLastASCIIId; // (4 bytes) Last ASCII Id
int iBitDepth; // (4 bytes) BitDepth of Font
int iMaxFontWidth; // (4 bytes) Widest font size
int iMaxFontHeight; // (4 bytes) Tallest font size
int iCharSpacing; // (4 bytes) Extra layout spacing between characters
int iCharLineSpacing; // (4 bytes) Extra layout spacing between lines (rows)
short wTransColor; // (2 bytes) transparent color (packed)
} fntHeader;
[/source]


I'm in the process of writing a font editor for an existing game.
I have a window displaying the loaded font information - same as what is in the struct.

The file above is loaded in memory by the following code:

[source lang="cpp"]int loadFNTfile(char *fntFile)
{
ifstream file (fntFile, ios::in|ios::binary|ios::ate);

if (file.is_open())
{
fileSize = file.tellg();
memblock = new char [(int)fileSize];
file.seekg(0, ios::beg);
file.read(memblock, fileSize);
file.close();
return 1;
}
return 0;
}[/source]

I fill the structure with the data loaded in memory above (which is basically the font header).

Doing it this way works as expected - each member is assigned the right value:

[source lang="cpp"]
fntHeader *fnt = new fntHeader;
fnt = ((fntHeader *)memblock);
[/source]

The issue is when I'm doing it this way. Apparently my 'walker' doesn't move the right number of bytes in memory for some of the
struct members and I'd like to understand why:


[source lang="cpp"]
walker = (unsigned char *)memblock;
fntHeader *fnt = new fntHeader;

strcpy(fnt->FontTag, (char*)walker);
walker += sizeof(fnt->FontTag);
fnt->misc = *(unsigned long *)walker;
walker += (unsigned long);
strcpy(fnt->desc, (char*)walker);
walker += sizeof(fnt->desc);
fnt->iFirstASCIIId = *(int *)walker;
walker += sizeof(int);
fnt->iLastASCIIId = *(int *)walker;
walker += sizeof(int);
fnt->iBitDepth = *(int *)walker;
walker += sizeof(int);
fnt->iMaxFontWidth = *(int *)walker;
walker += sizeof(int);
fnt->iMaxFontHeight = *(int *)walker;
walker += sizeof(int);
fnt->iCharSpacing = *(int *)walker;
walker += sizeof(int);
fnt->iCharLineSpacing = *(int *)walker;
walker += sizeof(int);
fnt->wTransColor = *(unsigned short *)walker;
walker += sizeof(unsigned short);[/source]

If anyone could shed some lights on this I'd appreciate.
Advertisement
Probably some padding bytes are getting added to struct members. Look up #pragma pack(push, 1) and #pragma pack(pop) to avoid it or just try putting these around your struct.
As mrjones said, the issue here is padding. The compiler pads the 5-byte FontTag with three additional bytes to ensure that the following long is on a 4-byte alignment. But do not disable padding unless you have a really, really good reason to do so.

The first thing I would question is why you need five bytes for the tag if you given an example with 4 characters. You can probably make it four bytes if you needa four-byte tag. The tag really isn't, and shouldn't be, treated as a string.

You will have a similar padding problem after the desc member, since it's 50 bytes which is not a multiple of 4. Thus, two additional byte will be inserted for padding.
Thanks a lot to both of you guys for clearing that up!
You could do what Brother Bob suggested, and that's not a bad suggestion. In General, if you are creating osme kind of file header yourself, unless you are killing to save space, make sure the data falls on the data-size boundaries. So, if you are using an unsigned long, that's 4 bytes, so it should start on a 4-byte boundary.

If this is an external file you're reading, then you can still read it out, but you have to be careful about it, and watch out for endian-ness issues. For example, you could do something like this:

class FileReader
{
public:
// Opens the file, gets file size, allocates and reads data into pFileData, and sets FileLocation to 0
FileReader(std::string filename);

// deallocates memory
~FileReader();

// Reads data into the given memory buffer
bool ReadData(unsigned char *pData, unsigned int dataSize);

private:
unsigned int FileLocation;
unsigned int FileSize;
unsigned char *pFileData;
};

bool FileReader::ReadData(unsigned char *pData, unsigned int dataSize)
{
if (dataSize + FileLocation < FileSize) {
memcpy(pData, pFileData + FileLocation, dataSize);
FileLocation += dataSize;
return true;
}
return false;
}

// when reading your structure
FileReader FileReader(myFile.dat);

FileReader.ReadData((unsigned char *)&fntHeader->FntTag, 5);
FileReader.ReadData((unsigned char *)&fntHeader->misc, sizeof(fntHeader->misc));

// etc

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

This topic is closed to new replies.

Advertisement