acl/lib_acl_cpp/src/mime/mime_code.cpp

393 lines
7.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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