C/C++学习笔记 dlib中的base64编码源码分析

2024-03-06 10:59

本文主要是介绍C/C++学习笔记 dlib中的base64编码源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、头文件解析

        iostream标准输入输出流

        sstream 字符串输入输出流

        头文件climits定义了符号常量来表示类型的限制,编译器厂商提供了climits文件,该文件支持了其编译器中的值。例如,在使用16位int的老系统中,climits文件将INT_MAX定义为32676。

#include "base64_kernel_1.h"
#include <iostream>
#include <sstream>
#include <climits>

         fstream 文件输入输出流

二、换行符CR,LF和CRLF

        CR:\r 表示回车,MacIntosh操作系统(即早期的Mac操作系统)采用单个字符CR来进行换行

        LF:\n 转义字符表示换行,Unix/Linux/Mac OS X操作系统采用单个字符LF来进行换行

        CRLF:\r\n 表示回车并换行,Windows操作系统采用两个字符来进行换行,即CRLF

enum line_ending_type
{CR,  // i.e. "\r"LF,  // i.e. "\n"CRLF // i.e. "\r\n"
};// ----------------------------------------------------------------------------------------base64::line_ending_type base64::line_ending () const{return eol_style;}// ----------------------------------------------------------------------------------------void base64::set_line_ending (line_ending_type eol_style_){eol_style = eol_style_;}// ----------------------------------------------------------------------------------------

        根据RFC822规定,BASE64Encoder编码每76个字符,还需要加上一个回车换行,所以dlib这里定义了换行符。

三、构造函数

        这里组织了编码、解码的字符数组,下面是关于初始值的说明。

/*!INITIAL VALUE- bad_value == 100- encode_table == a pointer to an array of 64 chars- where x is a 6 bit value the following is true:- encode_table[x] == the base64 encoding of x- decode_table == a pointer to an array of UCHAR_MAX chars- where x is any char value:- if (x is a valid character in the base64 coding scheme) then- decode_table[x] == the 6 bit value that x encodes- else- decode_table[x] == bad_value CONVENTION- The state of this object never changes so just refer to itsinitial value.!*/

        源码代码

    base64::base64 () : encode_table(0),decode_table(0),bad_value(100),eol_style(LF){try{encode_table = new char[64];decode_table = new unsigned char[UCHAR_MAX];}catch (...){if (encode_table) delete [] encode_table;if (decode_table) delete [] decode_table;throw;}// now set up the tables with the right stuffencode_table[0] = 'A';encode_table[17] = 'R';encode_table[34] = 'i';encode_table[51] = 'z';encode_table[1] = 'B';encode_table[18] = 'S';encode_table[35] = 'j';encode_table[52] = '0';encode_table[2] = 'C';encode_table[19] = 'T';encode_table[36] = 'k';encode_table[53] = '1';encode_table[3] = 'D';encode_table[20] = 'U';encode_table[37] = 'l';encode_table[54] = '2';encode_table[4] = 'E';encode_table[21] = 'V';encode_table[38] = 'm';encode_table[55] = '3';encode_table[5] = 'F';encode_table[22] = 'W';encode_table[39] = 'n';encode_table[56] = '4';encode_table[6] = 'G';encode_table[23] = 'X';encode_table[40] = 'o';encode_table[57] = '5';encode_table[7] = 'H';encode_table[24] = 'Y';encode_table[41] = 'p';encode_table[58] = '6';encode_table[8] = 'I';encode_table[25] = 'Z';encode_table[42] = 'q';encode_table[59] = '7';encode_table[9] = 'J';encode_table[26] = 'a';encode_table[43] = 'r';encode_table[60] = '8';encode_table[10] = 'K';encode_table[27] = 'b';encode_table[44] = 's';encode_table[61] = '9';encode_table[11] = 'L';encode_table[28] = 'c';encode_table[45] = 't';encode_table[62] = '+';encode_table[12] = 'M';encode_table[29] = 'd';encode_table[46] = 'u';encode_table[63] = '/';encode_table[13] = 'N';encode_table[30] = 'e';encode_table[47] = 'v';encode_table[14] = 'O';encode_table[31] = 'f';encode_table[48] = 'w';encode_table[15] = 'P';encode_table[32] = 'g';encode_table[49] = 'x';encode_table[16] = 'Q';encode_table[33] = 'h';encode_table[50] = 'y';// we can now fill out the decode_table by using the encode_tablefor (int i = 0; i < UCHAR_MAX; ++i){decode_table[i] = bad_value;}for (unsigned char i = 0; i < 64; ++i){decode_table[(unsigned char)encode_table[i]] = i;}}

四、析构函数

        这里删除了构造函数里面的数组。

    base64::~base64 (){delete [] encode_table;delete [] decode_table;}

五、编码函数

        1、这里首先了解streambuf::sgetn,是用于从streambuf对象的缓冲区中获取字符序列,获取 get 指针后面的nCount个字符并将它们存储在从pch开始的区域中。当streambuf对象中剩余的字符少于nCount时, sgetn获取剩余的任何字符。该函数重新定位 get 指针以跟随获取的字符。

        2、每76个字符,还需要加上一个回车换行,所以看到counter = 19,这里的76个字符是指写入到输出流的。

    void base64::encode (std::istream& in_,std::ostream& out_) const{using namespace std;streambuf& in = *in_.rdbuf();streambuf& out = *out_.rdbuf();unsigned char inbuf[3];unsigned char outbuf[4];streamsize status = in.sgetn(reinterpret_cast<char*>(&inbuf),3);unsigned char c1, c2, c3, c4, c5, c6;int counter = 19;// while we haven't hit the end of the input streamwhile (status != 0){if (counter == 0){counter = 19;// write a newlinechar ch;switch (eol_style){case CR:ch = '\r';if (out.sputn(&ch,1)!=1)throw std::ios_base::failure("error occurred in the base64 object");break;case LF:ch = '\n';if (out.sputn(&ch,1)!=1)throw std::ios_base::failure("error occurred in the base64 object");break;case CRLF:ch = '\r';if (out.sputn(&ch,1)!=1)throw std::ios_base::failure("error occurred in the base64 object");ch = '\n';if (out.sputn(&ch,1)!=1)throw std::ios_base::failure("error occurred in the base64 object");break;default:DLIB_CASSERT(false,"this should never happen");}}--counter;if (status == 3){// encode the bytes in inbuf to base64 and write them to the output streamc1 = inbuf[0]&0xfc;c2 = inbuf[0]&0x03;c3 = inbuf[1]&0xf0;c4 = inbuf[1]&0x0f;c5 = inbuf[2]&0xc0;c6 = inbuf[2]&0x3f;outbuf[0] = c1>>2;outbuf[1] = (c2<<4)|(c3>>4);outbuf[2] = (c4<<2)|(c5>>6);outbuf[3] = c6;outbuf[0] = encode_table[outbuf[0]];outbuf[1] = encode_table[outbuf[1]];outbuf[2] = encode_table[outbuf[2]];outbuf[3] = encode_table[outbuf[3]];// write the encoded bytes to the output streamif (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4){throw std::ios_base::failure("error occurred in the base64 object");}// get 3 more input bytesstatus = in.sgetn(reinterpret_cast<char*>(&inbuf),3);continue;}else if (status == 2){// we are at the end of the input stream and need to add some padding// encode the bytes in inbuf to base64 and write them to the output streamc1 = inbuf[0]&0xfc;c2 = inbuf[0]&0x03;c3 = inbuf[1]&0xf0;c4 = inbuf[1]&0x0f;c5 = 0;outbuf[0] = c1>>2;outbuf[1] = (c2<<4)|(c3>>4);outbuf[2] = (c4<<2)|(c5>>6);outbuf[3] = '=';outbuf[0] = encode_table[outbuf[0]];outbuf[1] = encode_table[outbuf[1]];outbuf[2] = encode_table[outbuf[2]];// write the encoded bytes to the output streamif (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4){throw std::ios_base::failure("error occurred in the base64 object");}break;}else // in this case status must be 1 {// we are at the end of the input stream and need to add some padding// encode the bytes in inbuf to base64 and write them to the output streamc1 = inbuf[0]&0xfc;c2 = inbuf[0]&0x03;c3 = 0;outbuf[0] = c1>>2;outbuf[1] = (c2<<4)|(c3>>4);outbuf[2] = '=';outbuf[3] = '=';outbuf[0] = encode_table[outbuf[0]];outbuf[1] = encode_table[outbuf[1]];// write the encoded bytes to the output streamif (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4){throw std::ios_base::failure("error occurred in the base64 object");}break;}} // while (status != 0)// make sure the stream buffer flushes to its I/O channelout.pubsync();}

六、解码函数

    void base64::decode (std::istream& in_,std::ostream& out_) const{using namespace std;streambuf& in = *in_.rdbuf();streambuf& out = *out_.rdbuf();unsigned char inbuf[4];unsigned char outbuf[3];int inbuf_pos = 0;streamsize status = in.sgetn(reinterpret_cast<char*>(inbuf),1);// only count this character if it isn't some kind of fillerif (status == 1 && decode_table[inbuf[0]] != bad_value )++inbuf_pos;unsigned char c1, c2, c3, c4, c5, c6;streamsize outsize;// while we haven't hit the end of the input streamwhile (status != 0){// if we have 4 valid charactersif (inbuf_pos == 4){inbuf_pos = 0;// this might be the end of the encoded data so we need to figure out if // there was any padding applied.outsize = 3;if (inbuf[3] == '='){if (inbuf[2] == '=')outsize = 1;elseoutsize = 2;}// decode the incoming charactersinbuf[0] = decode_table[inbuf[0]];inbuf[1] = decode_table[inbuf[1]];inbuf[2] = decode_table[inbuf[2]];inbuf[3] = decode_table[inbuf[3]];// now pack these guys into bytes rather than 6 bit chunksc1 = inbuf[0]<<2;c2 = inbuf[1]>>4;c3 = inbuf[1]<<4;c4 = inbuf[2]>>2;c5 = inbuf[2]<<6;c6 = inbuf[3];outbuf[0] = c1|c2;outbuf[1] = c3|c4;outbuf[2] = c5|c6;// write the encoded bytes to the output streamif (out.sputn(reinterpret_cast<char*>(&outbuf),outsize)!=outsize){throw std::ios_base::failure("error occurred in the base64 object");}}// get more input characters status = in.sgetn(reinterpret_cast<char*>(inbuf + inbuf_pos),1);// only count this character if it isn't some kind of filler if ((decode_table[inbuf[inbuf_pos]] != bad_value || inbuf[inbuf_pos] == '=') && status != 0)++inbuf_pos;} // while (status != 0)if (inbuf_pos != 0){ostringstream sout;sout << inbuf_pos << " extra characters were found at the end of the encoded data."<< "  This may indicate that the data stream has been truncated.";// this happens if we hit EOF in the middle of decoding a 24bit block.throw decode_error(sout.str());}// make sure the stream buffer flushes to its I/O channelout.pubsync();}

七、源码地址

dlib/dlib/base64 at master · davisking/dlib · GitHubA toolkit for making real world machine learning and data analysis applications in C++ - dlib/dlib/base64 at master · davisking/dlibhttps://github.com/davisking/dlib/tree/master/dlib/base64

这篇关于C/C++学习笔记 dlib中的base64编码源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/779849

相关文章

利用c++判断水仙花数并输出示例代码

《利用c++判断水仙花数并输出示例代码》水仙花数是指一个三位数,其各位数字的立方和恰好等于该数本身,:本文主要介绍利用c++判断水仙花数并输出的相关资料,文中通过代码介绍的非常详细,需要的朋友可以... 以下是使用C++实现的相同逻辑代码:#include <IOStream>#include <vec

基于C++的UDP网络通信系统设计与实现详解

《基于C++的UDP网络通信系统设计与实现详解》在网络编程领域,UDP作为一种无连接的传输层协议,以其高效、低延迟的特性在实时性要求高的应用场景中占据重要地位,下面我们就来看看如何从零开始构建一个完整... 目录前言一、UDP服务器UdpServer.hpp1.1 基本框架设计1.2 初始化函数Init详解

C++ 右值引用(rvalue references)与移动语义(move semantics)深度解析

《C++右值引用(rvaluereferences)与移动语义(movesemantics)深度解析》文章主要介绍了C++右值引用和移动语义的设计动机、基本概念、实现方式以及在实际编程中的应用,... 目录一、右值引用(rvalue references)与移动语义(move semantics)设计动机1

Springboot请求和响应相关注解及使用场景分析

《Springboot请求和响应相关注解及使用场景分析》本文介绍了SpringBoot中用于处理HTTP请求和构建HTTP响应的常用注解,包括@RequestMapping、@RequestParam... 目录1. 请求处理注解@RequestMapping@GetMapping, @PostMappin

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

C++打印 vector的几种方法小结

《C++打印vector的几种方法小结》本文介绍了C++中遍历vector的几种方法,包括使用迭代器、auto关键字、typedef、计数器以及C++11引入的范围基础循环,具有一定的参考价值,感兴... 目录1. 使用迭代器2. 使用 auto (C++11) / typedef / type alias