BufferedTransformation is the basic unit of data flow in Crypto++. An object which derives from BufferedTransformation can participate in Pipelining. Pipelining is a paradigm in Crypto++ which allows data to flow from a Source to a Sink. Each filter in the pipeline transforms the data in some way in the in route to the Sink, and BufferedTransformation provides the interface across objects.
Taking from the Crypto++ Source Code comments:
BufferedTransformation is a generalization of BlockTransformation, StreamTransformation, and HashTransformation.
A buffered transformation is an object that takes a stream of bytes as input (this may be done in stages), does some computation on them, and then places the result into an internal buffer for later retrieval. Any partial result already in the output buffer is not modified by further input.
If a method takes a "blocking" parameter, and you pass "false" for it, the method will return before all input has been processed if the input cannot be processed without waiting (for network buffers to become available, for example). In this case the method will return true or a non-zero integer value. When this happens you must continue to call the method with the same parameters until it returns false or zero, before calling any other method on it or attached BufferedTransformation. The integer return value in this case is approximately the number of bytes left to be processed, and can be used to implement a progress bar.For functions that take a "propagation" parameter, propagation != 0 means pass on the signal to attached BufferedTransformation objects, with propagation decremented at each step until it reaches 0. -1 means unlimited propagation.
To distinguish between a Filter and a BufferedTransformation, call, its Attachable method. If the object is a Filter, the method will return true; if it is a BufferedTransformation, it will return false.
Its not uncommon to experience Missing Data in a pipeline. A source will send data through a pipeline but have nothing in the sink. This is usually due to the compiler matching the wrong function. For example:
string source = "FF 88 00", destination; StringSink ss(source, new HexDecoder( new StringSink(destination) ) // HexDecoder ); // StringSink
After the above code executes, destination will likely be empty because the compiler coerces the HexDecoder (the pointer) to a bool (the pumpAll parameter), which leaves the StringSource's attached transformation NULL. The compiler will do so without warning, even with -Wall -Wextra -Wconversion. To resolve the issue, explicitly specify the pumpAll parameter:
string source = "FF 88 00", destination; StringSink ss(source, true /*pumpAll*/, new HexDecoder( new StringSink(destination) ) // HexDecoder ); // StringSink
Another way data ends up missing is failing to call MessageEnd() when pumping data. For example, the following may not produce expected results:
// The 4-bit nibble will be buffered waiting for another nibble string source = "FF 88 0", destination; HexDecoder decoder(new StringSink(destination)); decoder.Put(source.data(), source.size()); // Do something with destination
Be sure to call MessageEnd() when data comes up missing:
string source = "FF 88 0", destination; HexDecoder decoder(new StringSink(destination)); decoder.Put(source.data(), source.size()); decoder.MessageEnd(); // Do something with destination