It’s been a while since my last post, where I explained how to build protobuf with zlib support. In this post I’ll explain how you can use zlib-based streams in C++ to serialize and deserialize protobuf messages. We’ll use a small Mona Lisa bitmap for this example, since its uncompressed format will compress well with zlib’s default Deflate lossless compression algorithm.

Take a look at Simverge/howto-protobuf-zlib in GitHub for a more complete implementation of this example.

Define a Protobuf Message Schema

First, let’s create a file called blob.proto that defines a simple Protobuf message to store an arbitrary blob of data along with a string identifying its source:

Compile blob.proto with the Protobuf compiler (protoc) using the instructions from the official Protobuf C++ tutorial. For example, the following command will generate the blob.pb.cc C++ source file and the blob.pb.h C++ header file in the same directory as blob.proto:

You can instead use the FindProtobuf module if you are building with CMake, for example:

Once blob.proto is compiled into C++ files and blob.pb.cc is included in your build, you can include blob.pb.h to create a simverge::Blob Protobuf message, set its source and data fields, and determine the uncompressed Protobuf message size:

Running this program reveals the size of the Mona Lisa bitmap and the Protobuf message that wraps it:

Compress and Write the Protobuf Message to Disk

We can then use a GzipOutputStream from the google::protobuf::io namespace to serialize and compress the message. The constructor for this class requires a pointer to a  ZeroCopyOutputStream substream to process the compressed data. We will use a ArrayOutputStream to determine the size of the compressed data and then an std::ofstream to write the buffer disk. We will also check that there are no zlib errors before writing the compressed Protobuf message to disk:

Running the updated program reveals that the default GzipOutputStream settings yield roughly a 22.6% compression ratio on the Mona Lisa bitmap. You can tweak the zlib compression settings by passing a GzipOutputStream::Options object to the GzipOutputStream constructor.

A more straightforward way to serialize the compressed data is to use an OstreamOutputStream or a FileOutputStream instead of a ArrayOutputStream as the substream.

Read and Decompress Protobuf Message from Disk

We will use the GzipInputStream class from the google::protobuf::io namespace to read and decompress the message. The constructor for this class requires a pointer to a ZeroCopyInputStream substream to read the data before decompression. We will use an IstreamInputStream as the substream (which requires a pointer to an std::istream) since we already used an array-based stream on the output example. Just like in the output example, we will check if there are any zlib errors before processing the decompressed data.

Running this program shows that the decompressed and parsed Protobuf message matches the one reported by the writer, as well as the bitmap data size.

Creative Commons License
This work by Simverge Software LLC is licensed under a Creative Commons Attribution 4.0 International License.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments