How to include the two different versions of the s

2019-07-20 16:13发布

I am writing file conversion code from a proprietary file format to one more generic. My goal is to support multiple versions of the manufacturer's file format.

I have a multiple versions of the same proprietary headers. The headers define various structs which comprise the main file header (the file is simply a large header followed by raw data).

I need to read the first 4 bytes of the source file to determine the file version. The file version, in turn, tells me which version of the C-structs was used to create the file.

The issues are:

  1. I can't modify the proprietary headers
  2. The headers do not use namespaces or classes
  3. There are a good handful of macros defined in the headers

Possible solutions:

  • Build different converter binaries for each file version type :-(
    • Inconvenient for both user and developer
  • Dynamically load libraries for each version
    • The converter is plugin-oriented, so there's already a lot of this happening

I have tried hacking with namespaces:

namespace version1 {
    #include "version1.h"
}

namespace version2 {
    #include "version2.h"
}

int main (void) {
    version1::header *hdr = new version1::header;
    return 0;
}

But this won't work because of include guards, and because there are multiple macros are redefined in each header.

Is there an elegant way to handle this?

1条回答
倾城 Initia
2楼-- · 2019-07-20 16:56

You could use two different source files, together with a forward declaration:

// Forward declare in main.cpp:

namespace version1
{
   struct header;
}

namespace version2
{
   struct header;
}

// version1.cpp:

namespace version1
{
      #include <version1.h>
}

version1::header* new_v1_header()
{
   return new version1::header;
}

// other functions using `version1::header`

// version2.cpp:

namespace version2
{
      #include <version2.h>
}

version2::header* new_v2_header()
{
   return new version2::header;
}

// other functions using `version2::header`

Another alternative is to implement a wrapper class, which has a base-class that is just an empty shell:

class header_base
{
     virtual int func1(char *stuff) = 0; 
     ... many other virtual functions. 
};

// Create implementation of header_v1 or header_v2:
header_base* make_header(unsigned int magic);

header_base.cpp:

#include "header_v1.h"
#include "header_v2.h"

header_base* make_header(unsigned int magic)
{
    switch(magic)
    {
       case Magic_V1: 
          return new header_v1;
       case Magic_V2: 
          return new header_v2;
       default:
          assert(0);
          return 0;
    }
}

and then implement, in two separate

in headerv1.h:

class header_v1 : public header_base
{
    int func1(char *stuff);
    ... 
};

header_v1.cpp:

#include "header1.h"

int header_v1::func1(char *stuff)
{
   ... 
   return 17;
}

And similar for header_v2.h and header_v2.cpp.

查看更多
登录 后发表回答