Here's the relevant code in my project, though I pulled out a lot of vailidity checking and is using my own data structures, so it's not directly usable... only for informational purposes. But you should be able to adapt it to your project. The structure of blk0001.dat really is quite simple:
4 | 4 | 80 | TxData | 4 | 4 | 80 | TxData | 4 | 4 | 80 | TxData | ...
First 4 bytes - magic bytes (identifying which network you are on)
Second 4 bytes- the number of bytes of the remaining block
Next 80 bytes - block header itself
NumBlockBytes-80 - Transaction data in this block [ numTx | Tx1 | Tx2 | Tx3 | ... ]
uint32_t importHeadersFromBlockFile(std::string filename)
{
BinaryData thisHash(32);
BinaryData magicNum(4);
BinaryData thisHeaderSer(80)
BlockHeader thisHeader;
// While there is still data left in the stream (file)...
while(!bsb.isEof())
{
// Get the magic bytes
magicNum = bsb.reader().get_BinaryData(4);
// Get total number of bytes in this block (including header)
numBlockBytes = bsb.reader().get_uint32_t();
// In case I want to retrieve block data from file later
uint64_t blkByteOffset = bsb.getFileByteLocation();
// Pull the header from the block data
thisHeaderSer = bsb.reader().get_BinaryData(80);
// Interpret header data and compute hash
thisHeader.unserialize(thisHeaderSer);
thisHash = thisHeaderSer.getHash256Digest();
// Finally, skip the rest of the block data because only pulling headers
bsb.reader().advance(numBlockBytes-80);
}
}