badcode
badcode

Reputation: 610

position of bits in binary stream

I wrote a C++ program for boost/serialization. I already write and read the items on binary stream. But problem is that, i want to change some items position.

example case:

void write(...){
 if(!file_streamer_) {
 ...
 a_ = new boost::archive::binary_oarchive(*file_streamer_);
 }
 for(...){
     (*oa_) & obj[i] ;}
 // calculating the some properties of objects (long x long y long z)
 // and add them to stream
 (*oa_) & x;
 (*oa_) & y;
 (*oa_) & z;

 }
          // read


        void read(...){
       ia_=new boost::archive::binary_iarchive(*file_streamer_in_);
       std::streampos archive_offset = file_streamer_in_->tellg();
       std::streampos stream_end = file_streamer_in_->seekg(0, std::ios_base::end).tellg();
       file_streamer_in_->seekg(archive_offset);
        while (file_streamer_in_->tellg() < stream_end){
        //read objects 
          ...
    } 
    }

that is my binary stream :

obj_1 obj_2 obj_3 obj_4 obj_5 x y z

but i want to change like this:

 x y z obj_1 obj_2 obj_3 obj_4 obj_5 

How can I add the last part to start of the stream? Thanks in advance.

Upvotes: 1

Views: 131

Answers (1)

sehe
sehe

Reputation: 393507

I don't think that a binary archive is what you think it is in the first place.

docs The existence of the << and >> suggests a relationship between archives and C++ i/o streams. Archives are not C++ i/o streams

There's even an entire section in the Rationale of the docs:

Archives are not streams

Archive classes are NOT derived from streams even though they have similar syntax rules.

  • Archive classes are not kinds of streams though they are implemented in terms of streams. This distinction is addressed in [5] item number 41.
  • We don't want users to insert/extract data directly into/from the stream . This could create a corrupted archive. Were archives derived from streams, it would possible to accidentally do this. So archive classes only define operations which are safe and necessary.
  • The usage of streams to implement the archive classes that are included in the library is merely convenient - not necessary. Library users may well want to define their own archive format which doesn't use streams at all.

Specifically note bullet 2, (my bold). That's completely at odds with the code I see here:

void read(...){
   ia_=new boost::archive::binary_iarchive(*file_streamer_in_);
   std::streampos archive_offset = file_streamer_in_->tellg();
   std::streampos stream_end = file_streamer_in_->seekg(0, std::ios_base::end).tellg();
   file_streamer_in_->seekg(archive_offset);
    while (file_streamer_in_->tellg() < stream_end){
    //read objects 

This code violates that contract in every way possible.


Versioning

To change the format in your files to some new layout, define different versions. See Class Versioning

That way you can do a version 1:

struct MyType {
    int a, b;
    template <typename Ar> void serialize(Ar& ar, unsigned v) {
        switch (v) {
            case 0: ar & a & b; return;
            case 1:
            default: ar & b & a; return;
        }
    }
};

BOOST_CLASS_VERSION(MyType, 0)

int main() {
    std::vector<MyType> many(10, MyType{5,7});
    std::ofstream ofs("v0.dat", std::ios::binary);
    boost::archive::binary_oarchive oa(ofs);
    oa << many;
}

And then when you decide you want to change the order or a and b:

struct MyType {
    int a, b;
    template <typename Ar> void serialize(Ar& ar, unsigned v) {
        switch (v) {
            case 0: ar & a & b; return;
            case 1:
            default: ar & b & a; return;
        }
    }
};

BOOST_CLASS_VERSION(MyType, 1)

int main() {
    std::vector<MyType> many;
    {
        std::ifstream ifs("v0.dat", std::ios::binary);
        boost::archive::binary_iarchive ia(ifs);
        ia >> many;
    }

    {
        std::ofstream ofs("v1.dat", std::ios::binary);
        boost::archive::binary_oarchive oa(ofs);
        oa << many;
    }
}

You will still be able to read the old format correctly.

What Else... Worst Case

What if you messed up? Using my crystal ball, you might have implemented matrix serialization in reverse, and now you CANNOT read the archive, even in version 0, because you don't know how many elements were there in the first place?

This problem is not solvable (in the general case): You cannot possibly know the framing of elements because the binary data stream doesn't have any structure information. It's just bytes.

Only by look at hex-dumps you may be able to figure out what is what. E.g. here's v0.dat from the previous example:

enter image description here

Contrast with v1.dat:

enter image description here

What-ever you find would be guess-work. In principle it is wise to conclude that you messed up and lost that data.

Upvotes: 2

Related Questions