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

相关文章

Windows下C++使用SQLitede的操作过程

《Windows下C++使用SQLitede的操作过程》本文介绍了Windows下C++使用SQLite的安装配置、CppSQLite库封装优势、核心功能(如数据库连接、事务管理)、跨平台支持及性能优... 目录Windows下C++使用SQLite1、安装2、代码示例CppSQLite:C++轻松操作SQ

C++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三