/************************************************ * * * CBase64.cpp * * Base 64 de- and encoding class * * * * ============================================ * * * * This class was written on 28.05.2003 * * by Jan Raddatz [jan-raddatz@web.de] * * * * ============================================ * * * * Copyright (c) by Jan Raddatz * * This class was published @ codeguru.com * * 28.05.2003 * * * ************************************************/ #include "pch.h" #include "Base64.h" char CBase64Coder::ch64[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=' }; CBase64Coder::CBase64Coder() { buf = NULL; size = 0; } CBase64Coder::~CBase64Coder() { if (buf) { free(buf); buf = NULL; } } void CBase64Coder::allocMem(int NewSize) { if (buf) buf = (char*)realloc(buf, NewSize); else buf = (char*)malloc(NewSize); memset(buf, 0, NewSize); } const char* CBase64Coder::encode(const string& buffer) { return encode(buffer.c_str(), buffer.length()); } const char* CBase64Coder::encode(const char* buffer, int buflen) { #ifdef _DEBUG DWORD start, finish; start = GetTickCount(); #endif int nLeft = 3 - buflen % 3; //根据BASE64算法,总长度会变成原来的4/3倍 //所以内存分配=length*4/3并加1位作为结束符号(0) size = calc_base64_len(buflen); allocMem(size + 1); //临时变量, int index = 0; char *pOut = buf; while (buflen - index >= 3) { const char * p1 = buffer + index; const char * p2 = p1 + 1; const char * p3 = p2 + 1; char c1 = ((*p1) & (0xFC)) >> 2; char c2 = ((*p1) & (0x03)) << 4 | ((*p2) & 0xF0) >> 4; char c3 = ((*p2) & (0x0F)) << 2 | ((*p3) & 0xC0) >> 6; char c4 = (*p3) & (0x3F); *(pOut++) = _getBase64Char(c1); *(pOut++) = _getBase64Char(c2); *(pOut++) = _getBase64Char(c3); *(pOut++) = _getBase64Char(c4); index += 3; } int last = buflen - index; if (last == 1) { const char * p1 = buffer + index; char c1 = ((*p1) & (0xFC)) >> 2; char c2 = ((*p1) & (0x03)) << 4; *(pOut++) = _getBase64Char(c1); *(pOut++) = _getBase64Char(c2); *(pOut++) = '='; *(pOut++) = '='; } else if (last == 2) { const char * p1 = buffer + index; const char * p2 = p1 + 1; char c1 = ((*p1) & (0xFC)) >> 2; char c2 = ((*p1) & (0x03)) << 4 | ((*p2) & 0xF0) >> 4; char c3 = ((*p2) & (0x0F)) << 2; *(pOut++) = _getBase64Char(c1); *(pOut++) = _getBase64Char(c2); *(pOut++) = _getBase64Char(c3); *(pOut++) = '='; //*(pOut++)='='; } #ifdef _DEBUG finish = GetTickCount(); //TRACE("func Base64Encode spend %d ms\n", finish - start); #endif return buf; } const char* CBase64Coder::decode(const char* buffer, int Length) { #ifdef _DEBUG DWORD start, finish; start = GetTickCount(); #endif int length = Length; if (length % 4 != 0) return NULL; int nLen = calc_data_len(buffer,Length); size = nLen; allocMem(size + 1); int dec = 0; while (buffer[Length - 1 - dec] == '=') { dec++; } int real_len = length - dec; int index = 0; char *pOut = buf; while (real_len - index >= 4) { const char * p1 = buffer + index; const char * p2 = p1 + 1; const char * p3 = p2 + 1; const char * p4 = p3 + 1; char c1 = BinSearch(*p1); if (c1 == -1) { return NULL; } char c2 = BinSearch(*p2); if (c2 == -1) { return NULL; } char c3 = BinSearch(*p3); if (c3 == -1) { return NULL; } char c4 = BinSearch(*p4); if (c4 == -1) { return NULL; } *(pOut++) = (c1) << 2 | ((c2)&(0x30)) >> 4; *(pOut++) = ((c2)&(0xF)) << 4 | ((c3)&(0x3C)) >> 2; *(pOut++) = ((c3)&(0x03)) << 6 | (c4)&(0x3F); index += 4; } int last = real_len - index; if (last == 2) { const char * p1 = buffer + index; const char * p2 = p1 + 1; char c1 = BinSearch(*p1); char c2 = BinSearch(*p2); *(pOut++) = (c1) << 2 | ((c2)&(0x30)) >> 4; } else if (last == 3) { const char * p1 = buffer + index; const char * p2 = p1 + 1; const char * p3 = p2 + 1; char c1 = BinSearch(*p1); char c2 = BinSearch(*p2); char c3 = BinSearch(*p3); *(pOut++) = (c1) << 2 | ((c2)&(0x30)) >> 4; *(pOut++) = ((c2)&(0x0F)) << 4 | ((c3)&(0x30)) >> 2; } #ifdef _DEBUG finish = GetTickCount(); TRACE("func Base64Decode spend %d ms\n", finish - start); #endif return buf; } //采用二分法查找p在ch64数组中的位置,并返回。如果找不到则返回-1 int CBase64Coder::BinSearch(char p) { /*if (p >= 'A' && p <= 'Z') return (p - 'A'); else if (p >= 'a' && p <= 'z') return (p - 'a' + 26); else if (p >= '0' && p <= '9') return (p - '0' + 26 + 26); else if (p == '+') return 62; else if (p == '/') return 63; else if (p == '=') return 64;*/ switch (p) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': return p - 'A'; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': return p - 'a' + 26; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return p - '0' + 52; case '+': return 62; case '/': return 63; case '=': return 64; } return -1; } int CBase64Coder::calc_base64_len(int data_len) { int last = data_len * 8 % 6; if (last == 0) { return data_len * 8 / 6; } else { int base64_len = data_len * 8 / 6 + 1; base64_len += (last == 2 ? 2 : 1); return base64_len; } } int CBase64Coder::calc_data_len(const char * base64, int base64_len) { int dec = 0; while (base64[base64_len - 1 - dec] == '=') { dec++; } return ((base64_len - dec) * 6) / 8; } char CBase64Coder::_getBase64Char(char c) { return ch64[c]; }