mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-14 17:00:52 +08:00
393 lines
7.7 KiB
C++
393 lines
7.7 KiB
C++
#include "acl_stdafx.hpp"
|
||
#ifndef ACL_PREPARE_COMPILE
|
||
#include "acl_cpp/stdlib/snprintf.hpp"
|
||
#include "acl_cpp/stdlib/log.hpp"
|
||
#include "acl_cpp/mime/mime_define.hpp"
|
||
#include "acl_cpp/mime/mime_base64.hpp"
|
||
#include "acl_cpp/mime/mime_uucode.hpp"
|
||
#include "acl_cpp/mime/mime_xxcode.hpp"
|
||
#include "acl_cpp/mime/mime_quoted_printable.hpp"
|
||
#include "acl_cpp/mime/mime_code.hpp"
|
||
#endif
|
||
|
||
namespace acl {
|
||
|
||
#define INVALID 0xff
|
||
#ifndef UCHAR_MAX
|
||
#define UCHAR_MAX 0xff
|
||
#endif
|
||
|
||
mime_code::mime_code(bool addCrlf, bool addInvalid, const char* encoding_type)
|
||
: m_addCrLf(addCrlf)
|
||
, m_addInvalid(addInvalid)
|
||
, m_encoding(false)
|
||
, m_toTab(NULL)
|
||
, m_unTab(NULL)
|
||
, m_fillChar('=')
|
||
, m_pBuf(NULL)
|
||
{
|
||
if (encoding_type)
|
||
encoding_type_ = acl_mystrdup(encoding_type);
|
||
else
|
||
encoding_type_ = acl_mystrdup("unknown");
|
||
reset();
|
||
}
|
||
|
||
mime_code::~mime_code()
|
||
{
|
||
acl_myfree(encoding_type_);
|
||
delete m_pBuf;
|
||
}
|
||
|
||
void mime_code::init(const unsigned char* toTab,
|
||
const unsigned char* unTab, unsigned char fillChar)
|
||
{
|
||
m_toTab = toTab;
|
||
m_unTab = unTab;
|
||
m_fillChar = fillChar;
|
||
}
|
||
|
||
void mime_code::reset()
|
||
{
|
||
m_encodeCnt = 0;
|
||
m_decodeCnt = 0;
|
||
}
|
||
|
||
void mime_code::add_crlf(bool on)
|
||
{
|
||
m_addCrLf = on;
|
||
}
|
||
|
||
void mime_code::add_invalid(bool on)
|
||
{
|
||
m_addInvalid = on;
|
||
}
|
||
|
||
void mime_code::encode_update(const char *src, int n, acl::string* out)
|
||
{
|
||
int i = 0;
|
||
|
||
while (n > 0) {
|
||
if (m_encodeCnt == (int) sizeof(m_encodeBuf)) {
|
||
encode(out);
|
||
m_encodeCnt = 0;
|
||
}
|
||
i = n;
|
||
if (i > (int) sizeof(m_encodeBuf) - m_encodeCnt)
|
||
i = (int) sizeof(m_encodeBuf) - m_encodeCnt;
|
||
memcpy(m_encodeBuf + m_encodeCnt, src, i);
|
||
m_encodeCnt += i;
|
||
src += i;
|
||
n -= i;
|
||
}
|
||
}
|
||
|
||
void mime_code::encode_finish(acl::string* out)
|
||
{
|
||
encode(out);
|
||
m_encodeCnt = 0;
|
||
}
|
||
|
||
void mime_code::encode(acl::string *out)
|
||
{
|
||
const unsigned char *cp;
|
||
int count;
|
||
|
||
/*
|
||
* Encode 3 -> 4.
|
||
*/
|
||
for (cp = (const unsigned char *) m_encodeBuf, count = m_encodeCnt;
|
||
count > 0; count -= 3, cp += 3)
|
||
{
|
||
out->push_back((char) m_toTab[cp[0] >> 2]);
|
||
if (count > 1) {
|
||
out->push_back((char) m_toTab[(cp[0] & 0x3) << 4 | cp[1] >> 4]);
|
||
if (count > 2) {
|
||
out->push_back((char) m_toTab[(cp[1] & 0xf) << 2 | cp[2] >> 6]);
|
||
out->push_back((char) m_toTab[cp[2] & 0x3f]);
|
||
} else {
|
||
out->push_back((char) m_toTab[(cp[1] & 0xf) << 2]);
|
||
out->push_back(m_fillChar);
|
||
break;
|
||
}
|
||
} else {
|
||
out->push_back((char) m_toTab[(cp[0] & 0x3) << 4]);
|
||
out->push_back(m_fillChar);
|
||
out->push_back(m_fillChar);
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (m_addCrLf) {
|
||
out->push_back('\r');
|
||
out->push_back('\n');
|
||
}
|
||
}
|
||
|
||
void mime_code::decode_update(const char *src, int n, acl::string* out)
|
||
{
|
||
int i = 0;
|
||
|
||
while (n > 0) {
|
||
if (m_decodeCnt == (int) sizeof(m_decodeBuf)) {
|
||
decode(out);
|
||
}
|
||
i = n;
|
||
if (i > (int) sizeof(m_decodeBuf) - m_decodeCnt)
|
||
i = (int) sizeof(m_decodeBuf) - m_decodeCnt;
|
||
memcpy(m_decodeBuf + m_decodeCnt, src, i);
|
||
src += i;
|
||
n -= i;
|
||
m_decodeCnt += i;
|
||
}
|
||
}
|
||
|
||
void mime_code::decode_finish(acl::string* out)
|
||
{
|
||
decode(out);
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڻ<EFBFBD><DABB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD>䲻<EFBFBD><E4B2BB>4<EFBFBD><34><EFBFBD>ֽڶ<D6BD><DAB6><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||
|
||
if (m_addInvalid)
|
||
{
|
||
if (m_decodeCnt == 1) {
|
||
out->push_back(m_decodeBuf[0]);
|
||
} else if (m_decodeCnt == 2) {
|
||
out->push_back(m_decodeBuf[0]);
|
||
out->push_back(m_decodeBuf[1]);
|
||
} else if (m_decodeCnt == 3) {
|
||
out->push_back(m_decodeBuf[0]);
|
||
out->push_back(m_decodeBuf[1]);
|
||
out->push_back(m_decodeBuf[2]);
|
||
}
|
||
}
|
||
m_decodeCnt = 0;
|
||
}
|
||
|
||
void mime_code::decode(acl::string* out)
|
||
{
|
||
const unsigned char *cp;
|
||
int ch0, ch1, ch2, ch3;
|
||
|
||
if (m_decodeCnt <= 0)
|
||
return;
|
||
|
||
/* <20><><EFBFBD>뻺<EFBFBD>嵽 4 <20><><EFBFBD>ֽڲſ<DAB2>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD> */
|
||
|
||
for (cp = (const unsigned char *) m_decodeBuf; m_decodeCnt >= 4;) {
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еĻس<C4BB><D8B3><EFBFBD><EFBFBD>з<EFBFBD><D0B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD> '=' */
|
||
|
||
if (*cp == '\r' || *cp == '\n' || *cp == m_fillChar) {
|
||
cp++;
|
||
m_decodeCnt--;
|
||
continue;
|
||
}
|
||
|
||
/* <20><>һ<EFBFBD><D2BB><EFBFBD>ֽ<EFBFBD> */
|
||
|
||
if ((ch0 = m_unTab[*cp])== INVALID) {
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>, <20><EFBFBD>ԭ<EFBFBD>ַ<EFBFBD> */
|
||
if(m_addInvalid)
|
||
out->push_back(*cp);
|
||
cp++;
|
||
m_decodeCnt--;
|
||
continue;
|
||
}
|
||
cp++;
|
||
m_decodeCnt--;
|
||
|
||
/* <20>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD>ֽ<EFBFBD> */
|
||
|
||
if ((ch1 = m_unTab[*cp])== INVALID) {
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>, <20><EFBFBD>ԭ<EFBFBD>ַ<EFBFBD> */
|
||
if (m_addInvalid)
|
||
out->push_back((char) (*cp));
|
||
cp++;
|
||
m_decodeCnt--;
|
||
continue;
|
||
}
|
||
cp++;
|
||
m_decodeCnt--;
|
||
|
||
out->push_back((char) (ch0 << 2 | ch1 >> 4));
|
||
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD> */
|
||
|
||
ch2 = *cp;
|
||
if (ch2 == m_fillChar) {
|
||
cp++;
|
||
m_decodeCnt--;
|
||
continue;
|
||
}
|
||
|
||
if ((ch2 = m_unTab[ch2]) == INVALID) {
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>, <20><EFBFBD>ԭ<EFBFBD>ַ<EFBFBD> */
|
||
if (m_addInvalid)
|
||
out->push_back((char) (*cp));
|
||
cp++;
|
||
m_decodeCnt--;
|
||
continue;
|
||
}
|
||
cp++;
|
||
m_decodeCnt--;
|
||
|
||
out->push_back((char) (ch1 << 4 | ch2 >> 2));
|
||
|
||
/* <20><><EFBFBD>ĸ<EFBFBD><C4B8>ֽ<EFBFBD> */
|
||
|
||
ch3 = *cp;
|
||
if (ch3 == m_fillChar) {
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽڷ<D6BD> '=' <20><><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD><C4B8>ֽ<EFBFBD>Ϊ '=',
|
||
* <20><>˵<EFBFBD><CBB5><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD><C4B8>ֽ<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD>
|
||
*/
|
||
cp++;
|
||
m_decodeCnt--;
|
||
continue;
|
||
}
|
||
if ((ch3 = m_unTab[ch3]) == INVALID) {
|
||
/* <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>, <20><EFBFBD>ԭ<EFBFBD>ַ<EFBFBD> */
|
||
if (m_addInvalid)
|
||
out->push_back((char) (*cp));
|
||
cp++;
|
||
m_decodeCnt--;
|
||
continue;
|
||
}
|
||
cp++;
|
||
m_decodeCnt--;
|
||
|
||
out->push_back((char) (ch2 << 6 | ch3));
|
||
}
|
||
|
||
if (m_decodeCnt == 1) {
|
||
m_decodeBuf[0] = *cp;
|
||
} else if (m_decodeCnt == 2) {
|
||
m_decodeBuf[0] = *cp;
|
||
m_decodeBuf[1] = *(cp + 1);
|
||
} else if (m_decodeCnt == 3) {
|
||
m_decodeBuf[0] = *cp;
|
||
m_decodeBuf[1] = *(cp + 1);
|
||
m_decodeBuf[2] = *(cp + 2);
|
||
}
|
||
}
|
||
|
||
void mime_code::create_decode_tab(const unsigned char *toTab,
|
||
acl::string *out)
|
||
{
|
||
unsigned char tab[255];
|
||
char buf[32];
|
||
unsigned char *cp;
|
||
int i, n = (int) strlen((const char*) toTab);
|
||
|
||
memset(tab, 0xff, sizeof(tab));
|
||
|
||
for (i = 0; i < n; i++) {
|
||
tab[toTab[i]] = (unsigned char) i;
|
||
}
|
||
|
||
out->clear();
|
||
for (i = 0, cp = tab; cp < tab + sizeof(tab); cp++) {
|
||
if (i++ % 16 == 0) {
|
||
out->append("\r\n");
|
||
}
|
||
safe_snprintf(buf, sizeof(buf), "%d, ", *cp);
|
||
out->append((char*) buf);
|
||
}
|
||
}
|
||
|
||
void mime_code::set_status(bool encoding)
|
||
{
|
||
m_encoding = encoding;
|
||
}
|
||
|
||
int mime_code::push_pop(const char* in, size_t len,
|
||
string* out, size_t max /* = 0 */)
|
||
{
|
||
if (m_pBuf == NULL)
|
||
m_pBuf = NEW acl::string(1024);
|
||
|
||
if (in && len > 0)
|
||
{
|
||
if (m_encoding)
|
||
encode_update(in, (int) len, m_pBuf);
|
||
else
|
||
decode_update(in, (int) len, m_pBuf);
|
||
}
|
||
|
||
if (out == NULL)
|
||
return (0);
|
||
|
||
len = m_pBuf->length();
|
||
if (len == 0)
|
||
return (0);
|
||
|
||
size_t n;
|
||
if (max > 0)
|
||
n = max > len ? len : max;
|
||
else
|
||
n = len;
|
||
|
||
out->append(m_pBuf->c_str(), n);
|
||
|
||
if (len > n)
|
||
m_pBuf->memmove(m_pBuf->c_str() + n, len - n);
|
||
else
|
||
m_pBuf->clear();
|
||
|
||
return (int) (n);
|
||
}
|
||
|
||
int mime_code::pop_end(acl::string* out, size_t max /* = 0 */)
|
||
{
|
||
if (m_pBuf == NULL)
|
||
{
|
||
logger_error("call push_pop first");
|
||
return (-1);
|
||
}
|
||
if (m_encoding)
|
||
encode_finish(m_pBuf);
|
||
else
|
||
decode_finish(m_pBuf);
|
||
|
||
if (out == NULL)
|
||
{
|
||
m_pBuf->clear();
|
||
return (0);
|
||
}
|
||
|
||
size_t n = m_pBuf->length();
|
||
if (n == 0)
|
||
return (0);
|
||
if (max > 0 && n > max)
|
||
n = max;
|
||
out->append(m_pBuf->c_str(), n);
|
||
m_pBuf->clear();
|
||
return (int) (n);
|
||
}
|
||
|
||
void mime_code::clear()
|
||
{
|
||
if (m_pBuf)
|
||
m_pBuf->clear();
|
||
}
|
||
|
||
mime_code* mime_code::create(int encoding, bool warn_unsupport /* = true */)
|
||
{
|
||
if(encoding == MIME_ENC_BASE64)
|
||
return (NEW acl::mime_base64());
|
||
else if (encoding == MIME_ENC_UUCODE)
|
||
return (NEW acl::mime_uucode());
|
||
else if (encoding == MIME_ENC_XXCODE)
|
||
return (NEW acl::mime_xxcode());
|
||
else if (encoding == MIME_ENC_QP)
|
||
return (NEW acl::mime_quoted_printable());
|
||
else
|
||
{
|
||
if (warn_unsupport)
|
||
logger_warn("unknown encoding(%d)", encoding);
|
||
return (NULL);
|
||
}
|
||
}
|
||
|
||
} // namespace acl
|