📄 encoding.cpp
字号:
* eQPstate [IN/OUT] state; caller must preserve
*
* Returns: The length of the quoted-printable data
*/
long EncodeQP(
char *pBin,
long nLen,
char *pQP,
EncQPPtr eQPstate)
{
/* These characters are legal to leave UNQUOTED, everything else must be quoted */
const char *gQPEncodeChars
= "\t\n\r %&'()*+,-./0123456789:;<>?ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
/* The hex digits -- in order */
const char *pHexArr = "0123456789ABCDEF";
const char *pQPStart = pQP; /* Remember the start pos */
char *pEnd, ch, cLastChar;
int nLineChars, bEncode;
/* Check if this call is to close the encoding */
if ((pBin == NULL) || (nLen < 1))
{
/* If there is anything on the current line, cap it with an equal */
/* This avoids having trailing whitespace that would be ignored */
/* Newline is added for good measure, because we assume TEXT, this */
/* shouldn't be a problem */
if ((eQPstate->nCurLineLen) > 0)
{
*pQP++ = '=';
pQP = newline_copy(pQP);
eQPstate->nCurLineLen = 0;
return (pQP - pQPStart);
}
return (0);
}
/* Restore the state from the caller data */
nLineChars = eQPstate->nCurLineLen;
cLastChar = eQPstate->cLastChar;
/* Loop through the binary data */
for (pEnd = pBin + nLen; pBin < pEnd; pBin++)
{
/* Check if the binary character must be encoded */
bEncode = (strchr(gQPEncodeChars, (ch = *pBin)) ? 0 : 1);
/* Will this action put us past the 76 char limit? */
if ((nLineChars + (bEncode ? 3 : 1)) > 76)
{
/* Cap the line, and add a newline */
*pQP++ = '=';
pQP = newline_copy(pQP);
nLineChars = 0; /* Starting new line */
}
if (bEncode) /* Encode the character using hex (ie. "A" -> "=41") */
{
*pQP++ = '=';
*pQP++ = pHexArr[(ch>>4) & 0xF];
*pQP++ = pHexArr[ch & 0xF];
nLineChars += 3;
}
else /* No encoding needed, just copy character over */
{
*pQP++ = ch;
/* If we copied a newline, then we need to reset the line char count */
if (newline_test(cLastChar, ch))
nLineChars = 0;
else
nLineChars++;
}
/* Keep track of the last character */
cLastChar = ch;
}
/* Save the state */
eQPstate->nCurLineLen = nLineChars;
eQPstate->cLastChar = cLastChar;
/* Return the number of characters we but in the buffer */
return (pQP - pQPStart);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Convert quoted printable data to binary
*
* Args:
* pQP [IN] the quoted printable data (or NULL to close the decoder)
* nLen [IN] the length of the quoted printable data (or 0 to close the decoder)
* pBin [IN] pointer to buffer to hold binary data
* dQPstate [IN/OUT] pointer to decoder state; caller must preserve
* decErrCnt [OUT] the number of decoding errors found
*
* Returns: The length of the binary data
*/
long DecodeQP(
char *pQP,
long nLen,
char *pBin,
DecQPPtr dQPstate,
long *decErrCnt)
{
const char *pBinStart = pBin;
char *pEnd, ch;
/* Restore the state from the caller */
QPStates CurState = dQPstate->CurState;
char cLastChar = dQPstate->cLastChar;
/* Check if this call is to close the decoding */
if ((pQP == NULL) || (nLen < 1))
{
/* If the state is in the middle of doing something, then error */
if ((CurState == qpEqual) || (CurState == qpEncoded))
{
(*decErrCnt)++;
CurState = qpNormal;
}
return (0);
}
/* Loop through the QP data */
for (pEnd = pQP + nLen; pQP < pEnd; pQP++)
{
/* Get the current character */
ch = *pQP;
/* What state are we in? */
switch (CurState)
{
case qpNormal: /* Normal: copy everything until an 'equal' */
if (ch == '=')
CurState = qpEqual; /* Found an 'equal' char */
else
*pBin++ = ch;
break;
case qpEqual: /* qpEqual: Last char was an equal */
if (isxdigit(ch)) /* This char should be a hex digit */
CurState = qpEncoded;
else if (newline_test(cLastChar, ch)) /* Or it could be a newline */
CurState = qpNormal;
else if (isspace(ch)) /* Or some whitespace before the newline */
CurState = qpTrailingWhitespace;
else
CurState = qpError; /* Otherwise, an error */
break;
case qpEncoded: /* qpEncoded: Last char was the first hex digit of an encoding */
if ((isxdigit(ch)) && (isxdigit(cLastChar)))
{
int left = hex2dec(cLastChar);
int right = hex2dec(ch);
int leftshift = left << 4;
int final = leftshift | right;
/* Decode the hex digits into a character */
*pBin++ = final;
CurState = qpNormal;
}
else
CurState = qpError; /* This char is not a hex digit: an error */
break;
case qpTrailingWhitespace: /* qpTrailingWhitespace: whitespace is allowed after */
/* an equals and before the newline */
if (newline_test(cLastChar, ch))
CurState = qpNormal; /* When we find the newline, don't copy it */
else if (!isspace(ch))
CurState = qpError; /* If we get to some char BEFORE a newline: an error */
break;
}
if (CurState == qpError) /* Count the errors, reset to normal state (keep trying) */
{
(*decErrCnt)++;
CurState = qpNormal;
}
/* Keep track of the last character */
cLastChar = ch;
}
/* Save the state for next time */
dQPstate->CurState = CurState;
dQPstate->cLastChar = cLastChar;
/* Return the number of characters we but in the buffer */
return (pBin - pBinStart);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Parse Content-Transer-Encoding header line
*
* Args:
* src [IN] Valid Transfer-Encoding header.
*
* Returns: enumerated integer 'TrEncType' type specifying CTE.
*/
TrEncType rfc822_parse_cte(const char *src)
{
const char *kPrefixStr = "Content-Transfer-Encoding:";
const unsigned int kPrefixStrLen = strlen(kPrefixStr);
char *cp = (char *) src + kPrefixStrLen, *mechanism = NULL;
TrEncType cte = CTE_Error;
// Check prefix
if (strnicmp(src, kPrefixStr, kPrefixStrLen) == 0)
{
// Get first token (skips whitespace/comments)
mechanism = rfc822_extract_token(&cp);
// If we got something
if ((mechanism) && (strlen(mechanism) > 0))
{
if (stricmp(mechanism, "base64") == 0)
cte = CTE_Base64;
else if (stricmp(mechanism, "quoted-printable") == 0)
cte = CTE_QP;
else if (stricmp(mechanism, "7bit") == 0)
cte = CTE_7bit;
else if (stricmp(mechanism, "8bit") == 0)
cte = CTE_8bit;
else if (stricmp(mechanism, "binary") == 0)
cte = CTE_Binary;
}
safefree(mechanism);
}
return (cte);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Create Content-Transer-Encoding header line
*
* NOTE: The user of this function is responsible for freeing the
* returned string.
*
* Args:
* mechanism [IN] Enumerated integer 'TrEncType' type specifying CTE.
*
* Returns: Content tranfer encoding header line string.
*/
char *rfc822_make_cte(TrEncType mechanism)
{
const char *kPrefix = "Content-Transfer-Encoding: ";
char pBuf[40], *pCTE;
switch (mechanism)
{
case CTE_Base64: strcpy(pBuf, "base64"); break;
case CTE_QP: strcpy(pBuf, "quoted-printable"); break;
case CTE_7bit: strcpy(pBuf, "7bit"); break;
case CTE_8bit: strcpy(pBuf, "8bit"); break;
case CTE_Binary: strcpy(pBuf, "binary"); break;
default:
return (NULL);
}
pCTE = (char *) malloc(strlen(pBuf) + strlen(kPrefix) + 1);
strcpy(pCTE, kPrefix);
strcat(pCTE, pBuf);
return (pCTE);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Finds and extracts the content transfer encoding header line from a full
* multi-lined header. All unfolding (removing newlines) is done before
* header line is returned.
*
* NOTE: The user of this function is responsible for freeing the
* returned string.
*
* Args:
* pFullHeader [IN] Pointer to a full RFC822 header, including newlines
*
* Returns: Extracted header line string; dynamically allocated.
*/
char *rfc822_extract_cte(const char *pFullHeader)
{
return rfc822_extract_header(pFullHeader, "Content-Transfer-Encoding:");
}
/* ========================================================================== */
/* LOCAL FUNCTIONS */
/* ========================================================================== */
/* NEWLINE STUFF: Used locally to copy and test for newlines */
static const char gNewlineCh1 = '\r';
static const char gNewlineCh2 = '\n';
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Insert a newline, returning position after newline */
/* static */ char *newline_copy(char *dst)
{
*dst++ = gNewlineCh1;
*dst++ = gNewlineCh2;
return dst;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Check if these two characters represent a newline */
/* static */ int newline_test(const char prev, const char curr)
{
return ((prev == gNewlineCh1) && (curr == gNewlineCh2));
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Convert a single HEX character-digit (0123456789ABCDEF) to the decimal */
/* value. NOTE: This function assumes the character is a valid hex digit */
/* static */ int hex2dec(const char ch)
{
if (isdigit(ch))
return (ch -'0');
return ((toupper(ch) - 'A') + 10);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -