📄 base64.cpp
字号:
////////////////////////////////////////////////////////////////////////////////
// Base64 编/解码
////////////////////////////////////////////////////////////////////////////////
// Author : 黎达文
// Description : Base64编码解码模块
//
// Version : 1.0
//
// Standard include files : std_inc.hpp(in precompile header)
//
// Start Date : 2003年5月9日
//
// Change Log :
// 2003年5月9日 by Darkay Li
// -- explant from xerces
// 2003年6月18日 by 黎达文
// -- 修改名字空间从stk改称util
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "charset.h"
#include "janitor.h"
#include "base64.h"
namespace stk
{
static const int BASELENGTH = 255;
static const int FOURBYTE = 4;
const unsigned char Base64::base64Alphabet[] = {
chLatin_A, chLatin_B, chLatin_C, chLatin_D, chLatin_E,
chLatin_F, chLatin_G, chLatin_H, chLatin_I, chLatin_J,
chLatin_K, chLatin_L, chLatin_M, chLatin_N, chLatin_O,
chLatin_P, chLatin_Q, chLatin_R, chLatin_S, chLatin_T,
chLatin_U, chLatin_V, chLatin_W, chLatin_X, chLatin_Y, chLatin_Z,
chLatin_a, chLatin_b, chLatin_c, chLatin_d, chLatin_e,
chLatin_f, chLatin_g, chLatin_h, chLatin_i, chLatin_j,
chLatin_k, chLatin_l, chLatin_m, chLatin_n, chLatin_o,
chLatin_p, chLatin_q, chLatin_r, chLatin_s, chLatin_t,
chLatin_u, chLatin_v, chLatin_w, chLatin_x, chLatin_y, chLatin_z,
chDigit_0, chDigit_1, chDigit_2, chDigit_3, chDigit_4,
chDigit_5, chDigit_6, chDigit_7, chDigit_8, chDigit_9,
chPlus, chForwardSlash, chNull
};
unsigned char Base64::base64Inverse[BASELENGTH];
const unsigned char Base64::base64Padding = chEqual;
bool Base64::isInitialized = false;
/**
* E2-9
*
* Canonical-base64Binary ::= (B64line* B64lastline)?
*
* B64line ::= B64x15 B64x15 B64x15 B64x15 B64x15 B64 #xA
* 76 Base64 characters followed by newline
*
* B64x15 ::= B64 B64 B64 B64 B64
* B64 B64 B64 B64 B64
* B64 B64 B64 B64 B64
*
* B64lastline ::= B64x4? B64x4? B64x4? B64x4?
* B64x4? B64x4? B64x4? B64x4?
* B64x4? B64x4? B64x4? B64x4?
* B64x4? B64x4? B64x4? B64x4?
* B64x4? B64x4?
* (B64x4 | (B64 B64 B16 '=') | (B64 B04 '=='))
* #xA
*
* B64x4 ::= B64 B64 B64 B64
* B04 ::= [AQgw]
* B16 ::= [AEIMQUYcgkosw048]
*/
// number of quadruplets per one line ( must be >1 and <19 )
const unsigned int Base64::quadsPerLine = 15;
unsigned char* Base64::encode(const unsigned char* const inputData,
const unsigned int inputLength,
unsigned int* outputLength)
{
if (!isInitialized)
init();
if (!inputData)
return 0;
int quadrupletCount = ( inputLength + 2 ) / 3;
if (quadrupletCount == 0)
return 0;
// number of rows in encoded stream ( including the last one )
int lineCount = ( quadrupletCount + quadsPerLine-1 ) / quadsPerLine;
//
// convert the triplet(s) to quadruplet(s)
//
unsigned char b1, b2, b3, b4; // base64 binary codes ( 0..63 )
unsigned int inputIndex = 0;
unsigned int outputIndex = 0;
unsigned char *encodedData = new unsigned char[ quadrupletCount*FOURBYTE + lineCount + 1 ];
//
// Process all quadruplet(s) except the last
//
int quad = 1;
for (; quad <= quadrupletCount-1; quad++ )
{
// read triplet from the input stream
split1stOctet( inputData[ inputIndex++ ], b1, b2 );
split2ndOctet( inputData[ inputIndex++ ], b2, b3 );
split3rdOctet( inputData[ inputIndex++ ], b3, b4 );
// write quadruplet to the output stream
encodedData[ outputIndex++ ] = base64Alphabet[ b1 ];
encodedData[ outputIndex++ ] = base64Alphabet[ b2 ];
encodedData[ outputIndex++ ] = base64Alphabet[ b3 ];
encodedData[ outputIndex++ ] = base64Alphabet[ b4 ];
if (( quad % quadsPerLine ) == 0 )
encodedData[ outputIndex++ ] = chLF;
}
//
// process the last Quadruplet
//
// first octet is present always, process it
split1stOctet( inputData[ inputIndex++ ], b1, b2 );
encodedData[ outputIndex++ ] = base64Alphabet[ b1 ];
if( inputIndex < inputLength )
{
// second octet is present, process it
split2ndOctet( inputData[ inputIndex++ ], b2, b3 );
encodedData[ outputIndex++ ] = base64Alphabet[ b2 ];
if( inputIndex < inputLength )
{
// third octet present, process it
// no PAD e.g. 3cQl
split3rdOctet( inputData[ inputIndex++ ], b3, b4 );
encodedData[ outputIndex++ ] = base64Alphabet[ b3 ];
encodedData[ outputIndex++ ] = base64Alphabet[ b4 ];
}
else
{
// third octet not present
// one PAD e.g. 3cQ=
encodedData[ outputIndex++ ] = base64Alphabet[ b3 ];
encodedData[ outputIndex++ ] = base64Padding;
}
}
else
{
// second octet not present
// two PADs e.g. 3c==
encodedData[ outputIndex++ ] = base64Alphabet[ b2 ];
encodedData[ outputIndex++ ] = base64Padding;
encodedData[ outputIndex++ ] = base64Padding;
}
// write out end of the last line
encodedData[ outputIndex++ ] = chLF;
// write out end of string
encodedData[ outputIndex ] = 0;
if( outputLength != 0 )
(*outputLength) = outputIndex;
return encodedData;
}
//
// return 0(null) if invalid data found.
// return the buffer containning decoded data otherwise
// the caller is responsible for the de-allocation of the
// buffer returned.
//
// temporary data, rawInputData, is ALWAYS released by this function.
//
/***
* E2-9
*
* Base64Binary ::= S? B64quartet* B64final?
*
* B64quartet ::= B64 S? B64 S? B64 S? B64 S?
*
* B64final ::= B64 S? B04 S? '=' S? '=' S?
* | B64 S? B64 S? B16 S? '=' S?
*
* B04 ::= [AQgw]
* B16 ::= [AEIMQUYcgkosw048]
* B64 ::= [A-Za-z0-9+/]
*/
unsigned char* Base64::decode(const unsigned char* const inputData,
unsigned int* outputLength)
{
if (!isInitialized)
init();
if ((!inputData) || (!*inputData))
return 0;
//
// remove all XML whitespaces from the base64Data
//
int inputLength = (int)strlen((const char *)inputData);
unsigned char* rawInputData = new unsigned char[ inputLength + 1 ];
ArrayJanitor<unsigned char> janInputData(rawInputData);
int inputIndex = 0;
int rawInputLength = 0;
bool inWhiteSpace = false;
while ( inputIndex < inputLength )
{
//if (!XMLChar1_0::isWhitespace(inputData[inputIndex]))
if(!isspace(inputData[inputIndex]))
{
rawInputData[ rawInputLength++ ] = inputData[ inputIndex ];
inWhiteSpace = false;
}
else
{
if (inWhiteSpace)
return 0; // more than 1 whitespaces encountered
else
inWhiteSpace = true;
}
inputIndex++;
}
rawInputData[ rawInputLength ] = 0;
// the length of raw data should be divisible by four
if (( rawInputLength % FOURBYTE ) != 0 )
return 0;
int quadrupletCount = rawInputLength / FOURBYTE;
if ( quadrupletCount == 0 )
return 0;
//
// convert the quadruplet(s) to triplet(s)
//
unsigned char d1, d2, d3, d4; // base64 characters
unsigned char b1, b2, b3, b4; // base64 binary codes ( 0..64 )
int rawInputIndex = 0;
int outputIndex = 0;
unsigned char *decodedData = new unsigned char[ quadrupletCount*3 + 1 ];
ArrayJanitor<unsigned char> janDecodeData(decodedData);
//
// Process all quadruplet(s) except the last
//
int quad = 1;
for (; quad <= quadrupletCount-1; quad++ )
{
// read quadruplet from the input stream
if (!isData( (d1 = rawInputData[ rawInputIndex++ ]) ) ||
!isData( (d2 = rawInputData[ rawInputIndex++ ]) ) ||
!isData( (d3 = rawInputData[ rawInputIndex++ ]) ) ||
!isData( (d4 = rawInputData[ rawInputIndex++ ]) ))
{
return 0;
}
b1 = base64Inverse[ d1 ];
b2 = base64Inverse[ d2 ];
b3 = base64Inverse[ d3 ];
b4 = base64Inverse[ d4 ];
// write triplet to the output stream
decodedData[ outputIndex++ ] = set1stOctet(b1, b2);
decodedData[ outputIndex++ ] = set2ndOctet(b2, b3);
decodedData[ outputIndex++ ] = set3rdOctet(b3, b4);
}
//
// process the last Quadruplet
//
// first two octets are present always, process them
if (!isData( (d1 = rawInputData[ rawInputIndex++ ]) ) ||
!isData( (d2 = rawInputData[ rawInputIndex++ ]) ))
{
return 0;
}
b1 = base64Inverse[ d1 ];
b2 = base64Inverse[ d2 ];
// try to process last two octets
d3 = rawInputData[ rawInputIndex++ ];
d4 = rawInputData[ rawInputIndex++ ];
if (!isData( d3 ) || !isData( d4 ))
{
// check if last two are PAD characters
if (isPad( d3 ) && isPad( d4 ))
{
// two PAD e.g. 3c==
if ((b2 & 0xf) != 0) // last 4 bits should be zero
{
return 0;
}
decodedData[ outputIndex++ ] = set1stOctet(b1, b2);
}
else if (!isPad( d3 ) && isPad( d4 ))
{
// one PAD e.g. 3cQ=
b3 = base64Inverse[ d3 ];
if (( b3 & 0x3 ) != 0 ) // last 2 bits should be zero
{
// delete[] decodedData;
return 0;
}
decodedData[ outputIndex++ ] = set1stOctet( b1, b2 );
decodedData[ outputIndex++ ] = set2ndOctet( b2, b3 );
}
else
{
// an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
return 0;
}
}
else
{
// no PAD e.g 3cQl
b3 = base64Inverse[ d3 ];
b4 = base64Inverse[ d4 ];
decodedData[ outputIndex++ ] = set1stOctet( b1, b2 );
decodedData[ outputIndex++ ] = set2ndOctet( b2, b3 );
decodedData[ outputIndex++ ] = set3rdOctet( b3, b4 );
}
// write out the end of string
decodedData[ outputIndex ] = 0;
*outputLength = outputIndex;
//don't guard anymore because it will return to the user
janDecodeData.orphan();
return decodedData;
}
// -----------------------------------------------------------------------
// Helper methods
// -----------------------------------------------------------------------
void Base64::init()
{
if (isInitialized)
return;
isInitialized = true;
// create inverse table for base64 decoding
// if base64Alphabet[ 17 ] = 'R', then base64Inverse[ 'R' ] = 17
// for characters not in base64Alphabet the base64Inverse[] = -1
int i;
// set all fields to -1
for ( i = 0; i < BASELENGTH; i++ )
base64Inverse[i] = (unsigned char)-1;
// compute inverse table
for ( i = 0; i < 64; i++ )
base64Inverse[ base64Alphabet[i] ] = (unsigned char)i;
}
bool Base64::isData(const unsigned char& octet)
{
return (base64Inverse[octet]!=(unsigned char)-1);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -