Análisis del código fuente de codificación base64 en las notas de estudio de C/C++ dlib

Primero, el análisis del archivo de cabecera.

        iostream标准输入输出流

        flujo de entrada y salida de cadena sstream

        El archivo de encabezado climits define constantes simbólicas para representar restricciones en los tipos, y los proveedores de compiladores proporcionan archivos climits que admiten los valores en sus compiladores. Por ejemplo, en sistemas más antiguos que usan enteros de 16 bits, el archivo climits define INT_MAX como 32676.

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

         flujo de entrada y salida de archivos fstream

En segundo lugar, los caracteres de nueva línea CR, LF y CRLF

        CR:\r significa retorno de carro, el sistema operativo MacIntosh (es decir, el primer sistema operativo Mac) usa un solo carácter CR para salto de línea

        LF:\n El carácter de escape representa una nueva línea, y el sistema operativo Unix/Linux/Mac OS X usa un solo carácter LF para realizar una nueva línea.

        CRLF: \r\n significa retorno de carro y avance de línea, el sistema operativo Windows usa dos caracteres para el avance de línea, a saber, 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_;
    }

// ----------------------------------------------------------------------------------------

        De acuerdo con RFC822, BASE64Encoder necesita agregar un retorno de carro y un avance de línea por cada 76 caracteres de codificación , por lo que dlib define aquí un carácter de nueva línea.

3. Constructor

        Las matrices de caracteres codificados y decodificados se organizan aquí, y la siguiente es una descripción del valor inicial.

/*!
            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 its
                  initial value.
                  
        !*/

        código fuente

    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 stuff
        encode_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_table
        for (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;
        }
    }

4. Función destructora

        Aquí se elimina la matriz dentro del constructor.

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

5. Función de codificación

1. Aquí entendemos primero streambuf::sgetn, que se usa para obtener la secuencia de caracteres del búfer del objeto streambuf, obtener los caracteres nCount         después del puntero get y almacenarlos en el área que comienza desde pch . Cuando quedan menos de nCount  caracteres en el objeto streambuf , sgetn obtiene los caracteres restantes. La función cambia la posición del puntero de obtención para seguir al carácter obtenido.

        2. Por cada 76 caracteres , debe agregar un retorno de carro y un avance de línea, de modo que cuando vea el contador = 19, los 76 caracteres aquí se escriben en el flujo de salida.

    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 stream
        while (status != 0)
        {
            if (counter == 0)
            {
                counter = 19;
                // write a newline
                char 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 stream
                c1 = 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 stream
                if (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4)
                {
                    throw std::ios_base::failure("error occurred in the base64 object");
                }

                // get 3 more input bytes
                status = 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 stream
                c1 = 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 stream
                if (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 stream
                c1 = 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 stream
                if (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 channel
        out.pubsync();
    }

6. Función de decodificación

    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 filler
        if (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 stream
        while (status != 0)
        {
            // if we have 4 valid characters
            if (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;
                    else
                        outsize = 2;
                }

                // decode the incoming characters
                inbuf[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 chunks
                c1 = 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 stream
                if (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 channel
        out.pubsync();
    }

7. Dirección de origen

dlib/dlib/base64 en master · davisking/dlib · GitHub Un conjunto de herramientas para crear aplicaciones de análisis de datos y aprendizaje automático en el mundo real en C++ - dlib/dlib/base64 en master · davisking/dlib https://github.com/davisking/dlib /árbol/maestro/dlib/base64

Supongo que te gusta

Origin blog.csdn.net/bashendixie5/article/details/127259276
Recomendado
Clasificación