Please help me with reading a BMP file header using ifstream

I'm trying to read a .bmp file header using ifstream but my output isn't right, please help :<

From what I've researched a bmp file's header should have 14 bytes like the information in this image: http://imgur.com/BocfJuy

I have created my own struct to represent those:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <fstream>
using namespace std;

struct BmpSignature
{
	unsigned char data[2];
};

struct BmpHeader
{
	BmpSignature signature;
	unsigned int fileSize;
	unsigned short reserved1;
	unsigned short reserved2;
	unsigned int dataOffset;
};


I open a file using ifstream
1
2
ifstream fin;
fin.open("Untitled.bmp",ios::binary);


Here's how I read the header

1
2
3
4
5
6
7
8
void ReadHeader(ifstream &fin, BmpHeader &header)
{
	if(!fin)
		return;

	fin.seekg(0, ios::beg);
	fin.read((char*) &header, sizeof(header));
}


My output function
1
2
3
4
5
6
7
8
9
void PrintHeader(BmpHeader header)
{
	cout<<"==== BMP HEADER ===="<<endl;
	cout<<header.signature.data[0]<<header.signature.data[1]<<endl;
	cout<<"+ File Size  : "<<header.fileSize<<" byte(s)"<<endl;
	cout<<"+ Reserved1  : "<<header.reserved1<<endl;
	cout<<"+ Reserved2  : "<<header.reserved2<<endl;
	cout<<"+ Data Offset: "<<header.dataOffset<<" byte(s)"<<endl;
}


The problem is, I can't get the right output from my program, i.e. the file size is some random number completely different from my file's size in the hard disk.
I can get the right output if I change my reading function into this
1
2
3
4
5
6
7
8
9
10
11
void ReadHeader(ifstream &fin, BmpHeader &header)
{
	if(!fin)
		return;

	fin.seekg(2, ios::beg); //skipping the  first 'BM' 2 bytes
	fin.read((char*) &header.fileSize, sizeof(unsigned int)); //read file size
	fin.read((char*) &header.reserved1, sizeof(unsigned short)); //read reserved1
	fin.read((char*) &header.reserved2, sizeof(unsigned short)); //read reserved2
	fin.read((char*) &header.dataOffset, sizeof(unsigned int)); //read the data offset	
}


My question is, what's wrong with my first approach because I can still read the first 2 bytes as 'BM' but all information after that is all jacked up. How can I fix the first approach to be usable then?

Thank you for your help and sorry for my bad English
Yes, there are probably padding bytes inserted into the struct so that for example a 4-byte integer is located on an appropriate memory boundary.

One workaround is to break the first two bytes into a completely separate struct, and read it separately from the rest of the header.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <fstream>
using namespace std;

struct BmpSignature
{
    unsigned char data[2];
    BmpSignature() { data[0] = data[1] = 0; }
};

struct BmpHeader
{
    unsigned int fileSize;
    unsigned short reserved1;
    unsigned short reserved2;
    unsigned int dataOffset;
    BmpHeader() : fileSize(0),  reserved1(0), reserved2(0), dataOffset(0) { }
};

void ReadHeader(ifstream &fin, BmpSignature & sig, BmpHeader &header)
{
    if(!fin)
        return;

    fin.seekg(0, ios::beg);
    
    fin.read((char*) &sig, sizeof(sig));
    fin.read((char*) &header, sizeof(header));
}

void PrintHeader(BmpSignature sig, BmpHeader header)
{
    cout<<"==== BMP HEADER ===="<<endl;
    cout<<"+ Signature  : " << sig.data[0]<<sig.data[1]<<endl;
    cout<<"+ File Size  : " << header.fileSize<<" byte(s)"<<endl;
    cout<<"+ Reserved1  : " << header.reserved1<<endl;
    cout<<"+ Reserved2  : " << header.reserved2<<endl;
    cout<<"+ Data Offset: " << header.dataOffset<<" byte(s)"<<endl;
}

int main()
{
    
    ifstream fin("untitled.bmp", ios::binary);
    
    BmpSignature sig;
    BmpHeader hdr;
    PrintHeader(sig, hdr);
    ReadHeader(fin, sig, hdr);
    PrintHeader(sig, hdr);
    
    return 0;  
}

Last edited on
Thanks guys and sorry for the late reply x) Both of your solutions work wonderfully
Topic archived. No new replies allowed.