Stingray® Foundation : Chapter 15 XML Serialization Architecture : Base64 and Quoted-Printable Encoding Classes
Base64 and Quoted-Printable Encoding Classes
 
Content Transfer Encoding
Internet User Agents, especially those subscribing to the Simple Mail Transfer Protocol (SMTP)— such as mail programs and message transfer agents (MTAs), impose a restriction of 7-bit US-ASCII characters and short line lengths on the transferred content. However, to be able to send a rich body of content, such as multipart attachments, non-English messages, and binary data including bitmaps and executables, it is necessary to have a standard that specifies an encoding scheme that allows client programs to work with rich content.
The Multipurpose Internet Mail Extensions (MIME) specification defines such a format for encoding and decoding complex message bodies. Base64 and Quoted-Printable are two of the encoding schemes defined by MIME that ensure that binary as well as non US-ASCII content will properly pass through all MTAs and can be interpreted by all MIME compliant user agents. Base64 is a compact and efficient encoding scheme for binary data, while quoted-printable is a generally human-readable scheme used for mostly text data. Line length in both cases is restricted to 76.
Base64
Base64 is a fully mapped encoding scheme for transmitting binary data. In base64 encoding, the input data is sequenced into 24-bit groups— with each 6 bits of this group constituting an index into a base64 alphabet table. This is referred to as 3-to-4 encoding. The characters used in the base64 mapping table are only those deemed safe for MIME.
Quoted-Printable
The quoted-printable scheme is used mostly for data composed of printable US-ASCII text. User-readable input data composed of US-ASCII characters is, for the most part, retained as such in the encoded format. Non-printable and other 8-bit characters will be represented as an equal sign followed by their hexadecimal values.
SFL Content-Transfer-Encoding Classes
The Stingray Foundation Library XML (SFLXML) update includes two components, SECBase64Encoder and SECQPEncoder, that allow data to be encoded and decoded in the base64 and quoted-printable formats, respectively. These classes are built on tried and tested algorithms and provide a convenient object-oriented wrapper that makes it very simple to work with data streams as well as fixed-size buffers.
Class Hierarchy
 
SECCTEBase
SECCTEBase serves as the base class from which both SECBase64Encoder and SECQPEncoder are derived. This class defines the API for working with the encoding routines and also provides some of the common functionality for the two schemes. Certain attributes of the encoded data—such as line lengths, carriage-return line-feed sequences, and new-line terminator— can be set using the accessor functions implemented by SECCTEBase. SECCTEBase is an abstract class and cannot be instantiated.
SECBase64Encoder
SECBase64Encoder derives from SECCTEBase and implements the encoding/decoding logic for base64.
SECQPEncoder
Similar to SECBase64Encoder, the SECQPEncoder class also derives from SECCTEBase but it implements the quoted-printable encoding scheme.
To encode data in the base64 or quoted-printable formats or to decode existing encoded data, create an instance of SECBase64Encoder or SECQPEncoder, as appropriate, and invoke their Encode() or Decode() methods.
Usage
The encoder classes can be used in either streaming or non-streaming modes.
Non-Streaming Mode
The non-streaming mode is the default and usage is straightforward. An instance of the encoder is created and the Encode()/Decode() routine is called. If an output buffer is provided to the Encode()/Decode() routine, the encoded/decoded data will be written to this buffer. Passing a NULL output parameter, however, will instruct the encoder to maintain an internal buffer—in which case the encoded data can be obtained by a subsequent call to EndEncode()/EndDecode().
The following code demonstrates a simple case:
 
// Default constructor creates a non-streaming encoder
SECBase64Encoder encoder;
 
char srcInput[] = "Try to encode me!";
encoder.Encode((BYTE*)srcInput, strlen(srcInput));
int nLen = encoder.GetOutBufferSize();
char* pEncode = new char[nLen];
encoder.EndEncode((BYTE*)pEncode, nLen);
// The output buffer can also be directly provided
char* pDecode = new char[25];
nLen = encoder.Decode((BYTE*)pEncode,nOutLen,(BYTE*)pDecode,25);
pDecode[nLen] = '\0'; // Terminate with a NULL
 
delete pEncode;
delete pDecode;
 
Streaming Mode
In the streaming mode, an input stream is provided to the encoder by sequential calls to the SECCTEBase::Encode()/Decode() routine. The encoded output is stored in the internal buffer and can be obtained by a call to SECCTEBase::EndEncode()/EndDecode(). Passing a TRUE parameter to the constructor while creating an instance of the encoder will initialize the encoder for the streaming mode.