I actually implemented a quick and dirty binary analyzer format to read .zip files (after describing the Wikipedia format) only last month, and being modern, I decided to use C ++ templates.
A packaged struct may work on some specific platforms, however there are things that it does not handle well ... for example, variable-length fields. With templates, however, there is no such problem: you can get arbitrarily complex structures (and return types).
A .zip archive is relatively simple, fortunately, so I implemented something simple. Above my head:
using Buffer = std::pair<unsigned char const*, size_t>; template <typename OffsetReader> class UInt16LEReader: private OffsetReader { public: UInt16LEReader() {} explicit UInt16LEReader(OffsetReader const or): OffsetReader(or) {} uint16_t read(Buffer const& buffer) const { OffsetReader const& or = *this; size_t const offset = or.read(buffer); assert(offset <= buffer.second && "Incorrect offset"); assert(offset + 2 <= buffer.second && "Too short buffer"); unsigned char const* begin = buffer.first + offset;
Of course, the base OffsetReader actually has a consistent result:
template <size_t O> class FixedOffsetReader { public: size_t read(Buffer const&) const { return O; } };
and since we are talking about templates, you can switch types at your leisure (you can implement a proxy reader that delegates all reads of shared_ptr , which memoizes them).
Interesting, however, is the end result:
// http://en.wikipedia.org/wiki/Zip_%28file_format%29#File_headers class LocalFileHeader { public: template <size_t O> using UInt32 = UInt32LEReader<FixedOffsetReader<O>>; template <size_t O> using UInt16 = UInt16LEReader<FixedOffsetReader<O>>; UInt32< 0> signature; UInt16< 4> versionNeededToExtract; UInt16< 6> generalPurposeBitFlag; UInt16< 8> compressionMethod; UInt16<10> fileLastModificationTime; UInt16<12> fileLastModificationDate; UInt32<14> crc32; UInt32<18> compressedSize; UInt32<22> uncompressedSize; using FileNameLength = UInt16<26>; using ExtraFieldLength = UInt16<28>; using FileName = StringReader<FixedOffsetReader<30>, FileNameLength>; using ExtraField = StringReader< CombinedAdd<FixedOffsetReader<30>, FileNameLength>, ExtraFieldLength >; FileName filename; ExtraField extraField; }; // class LocalFileHeader
This is quite simplistic, obvious, but incredibly flexible at the same time.
An obvious axis of improvement will be improved grip, since there is a risk of accidental overlap. The code for my archived reading worked the first time I tried this, although it was sufficient proof for me that this code was enough for this task.