How to design a proper file format?

Started by
6 comments, last by Metorical 18 years, 4 months ago
Hi. Usually, I do use binary file formats for my games' level files. I like that way, because I can easily store and restore a C++ class, containing the level's attributes by simply writing the whole class to a file in the level editor and restoring it in the game. However, one major disadvantage of this approach is that whenever I add an attribute (member variable) to the class, I need to change both my editor and game exporting and importing functions and so level files that have been saved in the "old" format become obsolete! I need to write a converter everytime I change the fileformat, which is very time consuming... I would enjoy an approach, which allows me to still use the "old" files and just applies default values to the recently added attributes. Now, I would like to know what you'd suggest and how you are dealing with this problem. Cheers.
Advertisement
This is something XML is good for, although I'm not sure you'll want to use it for a game format file as it is a lot larger than a binary file.

If you decide to keep things as a binary file, make sure you include a version number of the format in the file so that you can read in old files and automatically use them as if they were the new format.
Have an old struct definition, and the new one. Read the values into the old struct and copy the relevant members across to the new one.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
One approach is to divide your file format into various chunks (see also this topic).

This way a reader can read all that is present and ignore anything it doesn't know about (for example things from a newer version); also it can try to convert old things on-the-fly. The exporter you will have to rewrite at any rate but you can't expect things to pop up without putting them in there now can you. If you abstract the chunks correctly, though, it might be a lot easier since it amounts to adding a new chunk to the chunk list to be written.

Writing a converter would be easy since it can simply convert existing 'old' chunks to the new definitions.

Greetz,

Illco
@iMalc: The problem with XML in this particular case is, that the target platform is not the PC so I would need to write a proper XML parser (or at least greatly modify an existing one)...

@Illco: Ahh... right, the good old chuncked data approach. I remember that from the 3DS file format which is also using this method, but I didn't think about that. Thank you for the hint! This is exactly what I was looking for.
you could also apply versions to each chunk which makes it easier for you to convert chunks of dated formats to the latest format what ilici suggested above
http://www.8ung.at/basiror/theironcross.html
Dont know how much this will help but for my first game to read in save files, I made a function that would open the file and read through it looking for stuff like:
HP:
MP:
Items:

Ectect, then it would take the number beside the corresponding token (such as, "HP") and save it in a variable. Maybe that will trigger an idea in your head? Hope it helps!
Well, if size is just a problem, an xml.gz would have fixed that perfectly (plain text compresses amazingly well). However, if you're making something for a cellphone or a gameboy, what you'll probably want to do is design your own extensible file format. This is better for you anyways, as outputing the primary-memory contents of a class file is a BAD idea. You could kill a vtable when you input it back in, and not even realize it.

That said, a proper file format is usualy laid out in bytes like so:
 0h-> 7h: Magic Key "MYFILE00" 8h-> fh: Some information10h->13h: An integer

And the save routine for this would step through the class's members and output them one by one. Now, whats important is that you reserve a lot of space. Engineer the problem a bit and figure out what the file format may look like when you finish designing it. Then, in your code, you'll just flood this reserved space with zeros, until you have something to put there later.

Don't drive yourself *too* crazy. It might be worth while to just investigate solutions that already exist and use those.
william bubel
I think you should look in to object serialisation. Rather than writing object specific code you need to write code that can serialise an object of any class.

Then when you save the file it strips all the data and puts it in to your data file. When you load a file you create a dummy object, using the default constructor and hence setting up all the defaults, then load in the values.

Depending on your implementation you might be able to inherit from a Serialiser class (warning: using multiple inheritance) so that the functionality is transparent.

This topic is closed to new replies.

Advertisement