C++ fstream.read() question...

SephirothSephiroth Fayetteville, NC, USA
I'm trying to go more to the C++ side of things and break away from plain old C and part of that is using fstream for file access instead of fread/fwrite. I know how to open a file for reading and/or writing, but when it comes to the actual reading and writing of binary files I am still not sure that I am coding it properly. Below is a chunk of code designed to read in a section of binary data from a GTA:SA save game. The code compiles without warning or error, but I just feel uneasy about it since everything has to be type-cast to char* just to read in. Can somebody offer me some advice on reading and writing data with fstream? I mean binary files, not text-mode.
//Read the car object data from the current stream location
pFile->read((char*)this->pPosition, 12); //float[3]
pFile->seekg(ios::cur, 4);
pFile->read((char*)&(this->ucFlags), 1); //unsigned char
pFile->seekg(ios::cur, 1);
pFile->read((char*)&(this->sModelID), 2); //short
pFile->read((char*)this->pMods, 30); //short[15]
pFile->read((char*)this->pColors[0], 1); //unsigned char[4]
pFile->read((char*)this->pColors[1], 1); //unsigned char[4]
pFile->read((char*)this->pColors[2], 1); //unsigned char[4]
pFile->read((char*)this->pColors[3], 1); //unsigned char[4]
pFile->read((char*)&(this->ucRadioStation), 1); //unsigned char
pFile->read((char*)this->pVariation, 2); unsigned char[2]
pFile->read((char*)&(this->ucBombType), 1); //unsigned char
pFile->read((char*)&(this->ucPaintJob), 1); //unsigned char
pFile->read((char*)&(this->ucNitrous), 1); //unsigned char
pFile->read((char*)this->pRotation, 3); //unsigned char[3]
pFile->read((char*)&(this->ucAlign), 1); //unsigned char
I am specifically not sure whether or not I coded the color section properly since I am specifying a specific point in the color array. Thanks for any help you can offer.



  • Sephiroth, one thing about pColors. I am assuming from your comment that it is of type "unsigned char[4]"? If that is correct then you would need:

    pFile->read((char*)&this->pColor[0], 1);
    pFile->read((char*)&this->pColor[1], 1);
    pFile->read((char*)&this->pColor[2], 1);
    pFile->read((char*)&this->pColor[3], 1);

    I think that you could code the reading of those four values like this as well:

    pFile->read((char*)this->pColor, 4);

    Perhaps another thing to consider adding is some error checking after the read calls using fstream::fail.
  • SephirothSephiroth Fayetteville, NC, USA
    You know, I can read it as a pointer to the array and reading in four bytes. I did that up top with the float array, so I don't know what I was thinking when I coded the colors section. It was late last night, so I must have been shutting my brain down. Thanks for pointing it out though.

    What about the read calls? I am specifying a pointer to a char, but am reading in all kinds of stuff. Is that OK?

  • That is OK, essentially all that does is give the starting memory address that read is supposed to use.

    However, I'll make a point, forgive me if you know this already:

    The issue with reading multi-byte values, like float, short or long for example, from a binary file or a binary data stream is [link=http://en.wikipedia.org/wiki/Endianness]endianness[/link]. So unless the file specification states a given endianness for its multi-byte values you may not read the correct values in the case where the file was written under one endian architecture and read under the other endian architecture.

    There is no issue when reading 1 byte values, or an array of 1 byte values.
  • SephirothSephiroth Fayetteville, NC, USA
    I've actually never run into a problem with endianness. I am writing a program that will edit a GTA:SA save and allow the user to modify, add, or remove vehicles from his or her garages in the game. GTA:SA runs on the PS2, XBox, and PC, but I am using my PC version for this project. Assuming a person could get a PS2 or XBox save onto a Windows machine, that may be the only place I could see a problem with endianness. That said, is there a way to detect this, or is it something that must be known beforehand?

  • In general there is no way to detect the endianness unless there is a (1 byte) field purposefully stored in the file to indicate the byte order. I did a quick google for the [link=http://www.gtamodding.com/index.php?title=GTA_SA_Saves#Data_Blocks]GTA:SA save game file format[/link] and I don't see that they built that into the structure. I'm not sure if any Windows versions run on big-endian HW but if you give you program to a friend you may want to make sure they are running on a compatible architecture :)

  • This has nothing to do with the OS, but the processor.

    PC and Xbox have Intel CPUs = little endian. Playstation seems to use some custom-made CPU, I don't know whether it is big/little endian.
  • Yes, it's the processor. Please read my post more carefully...

    :I'm not sure if any Windows versions run on big-endian [b]HW[/b]...

    Apparrently the XBox 360 is big-endian, interesting to hear that the original was little-endian.
  • SephirothSephiroth Fayetteville, NC, USA
    Yes, that is huge reason that the 360 is an epic failure. It can't play 90% of the games that were for the XBox. All of the Playstations are little-endian as far as I know, and they all play old games. You can even play PS1 games on a PS3!

    Consoles aside, I myself have already deciphered much of the save format myself and upon looking at that link, I was right in my discoveries. I have a few things that the link doesn't, however. I'm building the UI around the class now, since my fstream question was answered.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!