Artalus
Artalus

Reputation: 1162

Can't read binary file past some point

I need to parse several binary files containing 2-byte integer values. Since I've recently figured I have no idea of how the streams in C++ work, I decided to try them instead of good ole fopen(); fread(). So I've got this function:

void work( string filename )
{
    ifstream f( filename );

    if ( !f.is_open() )
        throw exception( ("File not found: "+filename).c_str() );

    //first 128 bytes are header that shouldn't be parsed
    f.seekg( 0, f.end );
    uint64_t length = f.tellg();
    f.seekg( 128, f.beg );
    if ( !f.good() )
        throw exception( "Couldn't skip the 128byte header" );
    length -= 128;


    uint8_t buf[4];
    vector<int> first, second;
    size_t v = 0;
    int a = -1;
    int b = -1;

    while ( !f.eof() )
    {
        f.read( reinterpret_cast<char*>(buf), 4 );

        if ( !f.good() )
        {
            cerr << "Couldn't read two 2byte values: read " << f.gcount() << "/4 bytes" << endl
                << "Bytes parsed: " << v << "/" << length << endl
                << "last 4 bytes: "
                << hex << +buf[0] << " " << +buf[1] << " | " << +buf[2] << " " << +buf[3] << endl;
            string s;
            if ( f.bad() )
                s = "BAD";
            else if ( f.fail() )
                s = "FAIL";
            else
                s = "WAT";
            throw exception( s.c_str() );
        }

        //only first 10 bits of values actually matter
        a = get10bit( buf[0], buf[1] );
        first.push_back( a );
        b = get10bit( buf[2], buf[3] );
        second.push_back( b );
        v += 4;
    }

    doStuff( first, second );
}

However for some reason, the cycle stops after reading only a part of a file, so I get next output:

Couldn't read two 2byte values: read 0/4 bytes

Bytes parsed: 88/1000000

last 4 bytes: 57 f0 | 3d 0

Exception: FAIL

I supposed that the problem was with my incorrect use of streams, so I tried to switch to fread(), but result was the same. I then tested both version of the program on several other files, guessing that there's something wrong with this one... But to my surprise, f.fail() eventually triggers at whatever file I'm trying to parse! The amount of successfully parsed bytes is different for each file, though.

As my dad advised, I then tried to read bigger chunks of data (and even whole files) instead of multiple 4-byte portions, but that didn't help too. Now I'm completely out of ideas.

Just in case: the contents (in hexademical) of my original file, skipping the header. I've highlighted in bold the last pair of values that was read correctly.

E7 FF 4C 00 FD FF 01 00 2A 00 ED FF 0A 00 43 00

12 00 26 00 53 00 DB FF F3 FF 0C 00 EC FF 50 00

6E 00 10 00 37 00 D1 FF FA FF 0D 00 29 00 44 00

4E 00 2F 00 15 00 1C 00 9F FF 36 00 35 FE ED FF

E4 FB C4 FF C1 F4 23 00 E6 EA 39 00 73 EB D5 FF

99 EF DF FF 57 F0 3D 00 1A F3 2C 00 97 F5 E7 EF

Upvotes: 3

Views: 1435

Answers (1)

Andrey Nasonov
Andrey Nasonov

Reputation: 2629

You are opening the file in text mode while you should open it in binary mode. In text mode, the symbol ^Z (ASCII 26 = 0x1A) is the EOF (end of file) control code.

Change the code to:

ifstream f( filename, ifstream::binary );

Upvotes: 10

Related Questions