Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cross Platform Custom File Header in C/C++

I'm currently working on a project that encrypts files and adds them to the application's library. I need to version the file format so that I'm planning to prepend a file header to the encrypted file. The project is in Qt and currently for Windows. Later will make app for android and mac as well.

FOr this I made these structures, the version 1 file.

struct Header_Meta
{
    char signature [4];
    char version [4];
};

struct Header_v1
{
    char id [12];
    char flag [8];
    char name [128];
    long size;
};

union File_v1
{
    Header_Meta meta;
    Header_v1 header;
    byte null [512 - sizeof (Header_Meta) - sizeof (Header_v1)];
    byte data [MAX_HEADERv1];
};

The file is binary file. Now in the getDetails() function, I'll read the MAX_HEADERv1 bytes to file_v1.data and will get the details in the member variables.

My questions are

  1. Is there a better approach?
  2. Is there any problem writing the long size of Header_v1 to file, in cases of platform differences?
  3. The logic should work the same way in all devices with file from another platform. Will this hold?
like image 581
Shijin Bose K Avatar asked Dec 06 '25 05:12

Shijin Bose K


1 Answers

There is a slight possibility that you will end up having a lot of #ifdef BIG/LITTLE_ENDIAN's in the code depending on the platform you are trying to deploy your product. I would use for the long size to be like: unsigned char size[8] (this would yield a 64 (=8*8) bit value) and then you could use a formula in your code, like:

uint64_t real_size = size[0] + size[1] << 8 + size[2] << 16 + ....

and when calculating individual size bytes you could do it like:

size[0] = real_size && 0xFF;
size[1] = (real_size && 0xFF00) >> 8;
size[2] = (real_size && 0xFF0000) >> 16;

and so on...

and from this point on you just need to worry about correctly writing out the bytes of size to their corresponding position.

Regarding the version string you want to add to the header (char version[4]) it all depends on what do you want to store there. If you want to put textual information (such as: "v1.0") you will limit the possible version you can have, so I would recommend again putting in a binary version, such as:

version[0] = VERSION      // customers usually pay for an increase in this
version[1] = RELEASE      // new functionality, it's up to you if customer pays or not :)
version[2] = MAINTENANCE  // planned maintenance, usually customers don't pay for this
version[3] = PATCH        // emergency patch, hopefully you never have to use this

This will allow for version numbers in the form of VERSION.RELEASE.MAINTENACE.PATCH and you can go up to 255.255.255.255

Also, please pay attention to @Ben's comment, the union just feels wrong. Usually these fields should come one after the other, but with the union they all will overlap each other, starting at the same location.

like image 175
Ferenc Deak Avatar answered Dec 07 '25 20:12

Ferenc Deak