base64 编码最初是为了电子邮件开发的。因为电子邮件是个文本协议,不能传输二进制数据,甚至中文也无法进行传输。只能传输ascii编码的文本。这样一来就诞生了多种将二进制数据编码到ascii里的编码方案,base64是其中之一。
base64是一种非常简单的编码,只要进行一次迭代即可完成解码。
什么?一次迭代???
这就让我们有机会借助 Boost 提供的迭代器非常简洁的写出base64解码器。
Boost 提供了一个叫 boost::archive::iterators::binary_from_base64 的迭代器。但是直接使用它并不能完成 base64解码。
还应该外面再套一层 archive::iterators::transform_width 以 6bit 为单位转换到 8bit。
typedef archive::iterators::transform_width<
archive::iterators::binary_from_base64<const char* >, 8, 6, char>
base64decodeIterator;
那么这个就应该是用于解码的 base64decodeIterator
但是,稍等。如果用来解码电子邮件里的东西,会经常出异常,说有不能允许的字符出现在了base64输入里。
为什么呢? 因为电子邮件以 78个字符断行了。也就是出现了base64里不允许的 CRLF。
那么,怎么办? 解码前先替换删除 CRLF ?
非也非也,这么做是愚蠢的哦,因为我们要的就是一次迭代的效果。 所以,archive::iterators::binary_from_base64<const char* > 使用的是 const char * 这个迭代器,对吧,我们改一下,使用 boost::filter_iterator 这个迭代器。过滤掉非base64编码字符。
boost::filter_iterator 需要使用一个模板参数,参数是一个过滤用的仿函数。
于是我们写一个
struct is_base64_char {
bool operator()(char x) { return boost::is_any_of("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/=")(x);}
};
然后使用 boost::filter_iterator<is_base64_char, const char*> 作为 archive::iterators::binary_from_base64 的迭代器,就形如
typedef archive::iterators::transform_width<
archive::iterators::binary_from_base64<filter_iterator<detail::is_base64_char, const char*> >, 8, 6, char>
base64decodeIterator;
然后只要使用 base64decodeIterator(base64string) ,然后执行 ++ 不停的迭代,直到遇到 nul 字符即可完成 base64 字符串解码。为了简化这个迭代过程,可以使用
std::string result(base64Iterator(str.begin()) , base64Iterator(str.end()));
这样的形式,则 result 的构造函数内部即会执行迭代,将遍历结果存储于 result 字符串内。
做一个总结,就编写了如下的函数:
Comments