1

I'm having problems reading a serializaed object back from its stored file. (See code below).

The serialization process "works", (albeit, probably written very poorly), and because there is no way of knowing whether the user is passing a std::ios::binary flag or not I opted NOT to use formatted output with whitespace. (It also saves on memory as the potential for massive amounts of pixel data was not lost on me.)

My first attempt looked the same as the sample but the ints were unsigned chars with the intent of bit-packing the lower and upper halves into chars and later reassembling them.

Currently I can read all data to a file but when I attempt to read the first piece of non-checksum data it either returned 0 (in the case of the attempt with the chars) or garbage (in the case of the attempt with the ints)

Serialization:

std::ostream& operator<<(std::ostream& os, const Sprite& data) {
    int dF = data._dimensions.first;
    int dS = data._dimensions.second;

    int cF = data._center.first;
    int cS = data._center.second;

    int fF = data._frameDimensions.first;
    int fS = data._frameDimensions.second;

    double sF = data._scaleDimensions.first;
    double sS = data._scaleDimensions.second;


    std::string name(*data._file);
    name.shrink_to_fit();
    os << 'S' << 'P' << 'R' << (name.length() + 1) << name.c_str() << dF << dS << cF << cS << fF << fS << sF << sS;
    for(int x = 0; x < data._dimensions.first; ++x) {
        for(int y = 0; y < data._dimensions.second; ++y) {
            int color = getpixel(data._image, x, y);
            os << static_cast<unsigned char>(getr(color)) << static_cast<unsigned char>(getg(color)) << static_cast<unsigned char>(getb(color));
        }
    }
    int tint = data._tint;
    os << static_cast<unsigned char>(getr(tint)) << static_cast<unsigned char>(getg(tint)) << static_cast<unsigned char>(getb(tint));
    os << data._tintIntensity << data._alpha;
    return os;
}

Deserialization:

std::istream& operator>>(std::istream& is, Sprite& data) {
    char checksum[3];
    is >> checksum[0] >> checksum[1] >> checksum[2];
    if(checksum[0] != 'S' || checksum[1] != 'P' || checksum[2] != 'R') {
        is.setstate(std::ios::failbit);
        return is;
    }
    int name_length;
    is >> name_length;

    std::string name(name_length, '\0');

    for(int i = 0; i <= name_length; ++i) {
        char current_char = '\0';
        is >> current_char;
        name[i] = current_char;
    }

    int upper = 0;
    int lower = 0;
    is >> upper;
    is >> lower;
    data._dimensions.first = (upper << 8) | lower;

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._dimensions.second = ((upper << 8) | lower);

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._center.first = ((upper << 8) | lower);

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._center.second = ((upper << 8) | lower);

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._frameDimensions.first = ((upper << 8) | lower);

    upper = 0;
    lower = 0;
    is >> upper >> lower;
    data._frameDimensions.second = ((upper << 8) | lower);

    double f = 0.0;
    double s = 0.0;
    is >> f >> s;
    data._scaleDimensions.first = f;
    data._scaleDimensions.second = s;

    destroy_bitmap(data._image);
    data._image = NULL;
    data._image = create_bitmap(data._dimensions.first, data._dimensions.second);
    for(int x = 0; x < data._dimensions.first; ++x) {
        for(int y = 0; y < data._dimensions.second; ++y) {
            unsigned char r = 0;
            unsigned char g = 0;
            unsigned char b = 0;
            is >> r >> g >> b;
            int color = ((r << 16)  | (g << 8) | b); //0xRRGGBB
            putpixel(data._image, x, y, color);
        }
    }
    unsigned char rtint = 0;
    unsigned char gtint = 0;
    unsigned char btint = 0;
    is >> rtint >> gtint >> btint;
    data._tint = ((rtint << 16)  | (gtint << 8) | btint); //0xRRGGBB

    is >> data._tintIntensity;
    is >> data._alpha;
    return is;
}
Casey
  • 10,297
  • 11
  • 59
  • 88
  • 1
    What has the format flag `std::ios_base::binary` to do with not doing formatted I/O? This flag just determines how end of line sequences are processed: when writing a `\n' in non-binary mode it may get replaced (e.g. by CR/LF) while in binary mode it isn't replaced. Similarly when reading end of line sequences are replaced by a single '\n' in non-binary mode or retained as is in binary mode. To protect against the user opening with or without this flag, you should actually use formatted I/O! – Dietmar Kühl Jan 08 '12 at 23:40
  • Looking at the code: writing multiple values without intervening spaces will cause the `std::istream` to read one big value instead of multiple smaller ones. Probably the big value will cause an overflow error putting the stream into a bad state. This is where your problems start... – Dietmar Kühl Jan 08 '12 at 23:42
  • @DietmarKühl: Make than an answer and I'll accept it. :D – Casey Jan 09 '12 at 03:04

2 Answers2

0

shouldn't deserialization be something like this:

int upper = 0;
int lower = 0;
is >> upper;
is >> lower;
data._dimensions.first = upper;
data._dimensions.second = lower;

and similar for center, and frameDimensions

Greg Ra
  • 70
  • 3
-1

I would use bitfileds. Just don't forget to add #pragma pack(1) before and #pragma pack() after. Since the computer can only address bytes, you have to make sure your bit-fields are the multiple of 8. Also the packing of bits is compiler/machine dependent, so your reader should be compiled with the same compiler. Then just use for example:

somefilestream.write(&some_bitfield_struct, sizeof(some_bitfield_struct));
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
nulleight
  • 794
  • 1
  • 5
  • 12