You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdepim/mimelib/dw_cte.cpp

902 lines
27 KiB

//=============================================================================
// File: dw_cte.cpp
// Contents: Function definitions for content transfer encodings
// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
//
// Copyright (c) 1996, 1997 Douglas W. Sauder
// All rights reserved.
//
// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSETQUENTIAL DAMAGES ARISING OUT OF
// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
//
//=============================================================================
#define DW_IMPLEMENTATION
#include <mimelib/config.h>
#include <mimelib/debug.h>
#include <string.h>
#include <mimelib/string.h>
#include <mimelib/utility.h>
#define MAXLINE 76
static size_t calc_crlf_buff_size(const char* srcBuf, size_t srcLen);
static int to_crlf(const char* srcBuf, size_t srcLen, char* destBuf,
size_t destSize, size_t* destLen);
static int to_lf(const char* srcBuf, size_t srcLen, char* destBuf,
size_t destSize, size_t* destLen);
static int to_cr(const char* srcBuf, size_t srcLen, char* destBuf,
size_t destSize, size_t* destLen);
static int encode_base64(const char* aIn, size_t aInLen, char* aOut,
size_t aOutSize, size_t* aOutLen);
static int decode_base64(const char* aIn, size_t aInLen, char* aOut,
size_t aOutSize, size_t* aOutLen);
static int encode_qp(const char* aIn, size_t aInLen, char* aOut,
size_t aOutSize, size_t* aOutLen);
static int decode_qp(const char* aIn, size_t aInLen, char* aOut,
size_t aOutSize, size_t* aOutLen);
static size_t calc_qp_buff_size(const char* aIn, size_t aInLen);
int DwToCrLfEol(const DwString& aSrcStr, DwString& aDestStr)
{
// Estimate required destination buffer size
size_t srcLen = aSrcStr.length();
const char* srcBuf = aSrcStr.data();
size_t destSize = calc_crlf_buff_size(srcBuf, srcLen);
// Allocate destination buffer
DwString destStr(destSize, (char)0);
char* destBuf = (char*) destStr.data();
// Encode source to destination
size_t destLen = 0;
to_crlf(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return 0;
}
int DwToLfEol(const DwString& aSrcStr, DwString& aDestStr)
{
size_t srcLen = aSrcStr.length();
const char* srcBuf = aSrcStr.data();
size_t destSize = srcLen;
// Allocate destination buffer
DwString destStr(destSize, (char)0);
char* destBuf = (char*) destStr.data();
// Encode source to destination
size_t destLen = 0;
to_lf(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return 0;
}
int DwToCrEol(const DwString& aSrcStr, DwString& aDestStr)
{
size_t srcLen = aSrcStr.length();
const char* srcBuf = aSrcStr.data();
size_t destSize = srcLen;
// Allocate destination buffer
DwString destStr(destSize, (char)0);
char* destBuf = (char*) destStr.data();
// Encode source to destination
size_t destLen = 0;
to_cr(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return 0;
}
int DwToLocalEol(const DwString& aSrcStr, DwString& aDestStr)
{
#if defined(DW_EOL_CRLF)
return DwToCrLfEol(aSrcStr, aDestStr);
#elif defined(DW_EOL_LF)
return DwToLfEol(aSrcStr, aDestStr);
#else
# error "Must define DW_EOL_CRLF, DW_EOL_LF"
#endif
}
int DwEncodeBase64(const DwString& aSrcStr, DwString& aDestStr)
{
// Estimate required destination buffer size
size_t srcLen = aSrcStr.length();
const char* srcBuf = aSrcStr.data();
size_t destSize = (srcLen+2)/3*4;
destSize += strlen(DW_EOL)*destSize/72 + 2;
destSize += 64; // a little extra room
// Allocate destination buffer
DwString destStr(destSize, (char)0);
char* destBuf = (char*) destStr.data();
// Encode source to destination
size_t destLen = 0;
int result =
encode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return result;
}
int DwDecodeBase64(const DwString& aSrcStr, DwString& aDestStr)
{
// Set destination buffer size same as source buffer size
size_t srcLen = aSrcStr.length();
const char* srcBuf = aSrcStr.data();
size_t destSize = srcLen;
// Allocate destination buffer
DwString destStr(destSize, (char)0);
char* destBuf = (char*) destStr.data();
// Encode source to destination
size_t destLen = 0;
int result =
decode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return result;
}
int DwEncodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
{
// Estimate required destination buffer size
size_t srcLen = aSrcStr.length();
const char* srcBuf = aSrcStr.data();
size_t destSize = calc_qp_buff_size(srcBuf, srcLen);
destSize += 64; // a little extra room
// Allocate destination buffer
DwString destStr(destSize, (char)0);
char* destBuf = (char*) destStr.data();
// Encode source to destination
size_t destLen = 0;
int result =
encode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return result;
}
int DwDecodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
{
// Set destination buffer size same as source buffer size
size_t srcLen = aSrcStr.length();
const char* srcBuf = aSrcStr.data();
size_t destSize = srcLen;
// Allocate destination buffer
DwString destStr(destSize, (char)0);
char* destBuf = (char*) destStr.data();
// Encode source to destination
size_t destLen = 0;
int result =
decode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
aDestStr.assign(destStr, 0, destLen);
return result;
}
//============================================================================
// Everything below this line is private to this file (static)
//============================================================================
static size_t calc_crlf_buff_size(const char* srcBuf, size_t srcLen)
{
size_t i, extra;
if (!srcBuf) return 0;
extra = 0;
for (i=0; i < srcLen; ) {
switch (srcBuf[i]) {
/* Bare LF (UNIX or C text) */
case '\n':
++extra;
++i;
break;
case '\r':
/* CR LF (DOS, Windows, or MIME text) */
if (i+1 < srcLen && srcBuf[i+1] == '\n') {
i += 2;
}
/* Bare CR (Macintosh text) */
else {
++extra;
++i;
}
break;
default:
++i;
}
}
return srcLen + extra;
}
static int to_crlf(const char* srcBuf, size_t srcLen, char* destBuf,
size_t destSize, size_t* destLen)
{
size_t iSrc, iDest;
if (!srcBuf || !destBuf || !destLen) return -1;
iSrc = iDest = 0;
while (iSrc < srcLen && iDest < destSize) {
switch (srcBuf[iSrc]) {
/* Bare LF (UNIX or C text) */
case '\n':
destBuf[iDest++] = '\r';
if (iDest < destSize) {
destBuf[iDest++] = srcBuf[iSrc++];
}
break;
case '\r':
/* CR LF (DOS, Windows, or MIME text) */
if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
destBuf[iDest++] = srcBuf[iSrc++];
if (iDest < destSize) {
destBuf[iDest++] = srcBuf[iSrc++];
}
}
/* Bare CR (Macintosh text) */
else {
destBuf[iDest++] = srcBuf[iSrc++];
if (iDest < destSize) {
destBuf[iDest++] = '\n';
}
}
break;
default:
destBuf[iDest++] = srcBuf[iSrc++];
}
}
*destLen = iDest;
if (iDest < destSize) {
destBuf[iDest] = 0;
}
return 0;
}
static int to_lf(const char* srcBuf, size_t srcLen, char* destBuf,
size_t destSize, size_t* destLen)
{
size_t iSrc, iDest;
if (!srcBuf || !destBuf || !destLen) return -1;
iSrc = iDest = 0;
while (iSrc < srcLen && iDest < destSize) {
switch (srcBuf[iSrc]) {
/* Bare LF (UNIX or C text) */
case '\n':
destBuf[iDest++] = srcBuf[iSrc++];
break;
case '\r':
/* CR LF (DOS, Windows, or MIME text) */
if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
++iSrc;
destBuf[iDest++] = srcBuf[iSrc++];
}
/* Bare CR (Macintosh text) */
else {
destBuf[iDest++] = '\n';
++iSrc;
}
break;
default:
destBuf[iDest++] = srcBuf[iSrc++];
}
}
*destLen = iDest;
if (iDest < destSize) {
destBuf[iDest] = 0;
}
return 0;
}
static int to_cr(const char* srcBuf, size_t srcLen, char* destBuf,
size_t destSize, size_t* destLen)
{
size_t iSrc, iDest;
if (!srcBuf || !destBuf || !destLen) return -1;
iSrc = iDest = 0;
while (iSrc < srcLen && iDest < destSize) {
switch (srcBuf[iSrc]) {
/* Bare LF (UNIX or C text) */
case '\n':
destBuf[iDest++] = '\r';
++iSrc;
break;
case '\r':
/* CR LF (DOS, Windows, or MIME text) */
if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
destBuf[iDest++] = srcBuf[iSrc++];
++iSrc;
}
/* Bare CR (Macintosh text) */
else {
destBuf[iDest++] = srcBuf[iSrc++];
}
break;
default:
destBuf[iDest++] = srcBuf[iSrc++];
}
}
*destLen = iDest;
if (iDest < destSize) {
destBuf[iDest] = 0;
}
return 0;
}
static char base64tab[] = "ABCDEFGHIJKLMNOPTQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz0123456789+/";
static char base64idx[128] = {
'\377','\377','\377','\377','\377','\377','\377','\377',
'\377','\377','\377','\377','\377','\377','\377','\377',
'\377','\377','\377','\377','\377','\377','\377','\377',
'\377','\377','\377','\377','\377','\377','\377','\377',
'\377','\377','\377','\377','\377','\377','\377','\377',
'\377','\377','\377', 62,'\377','\377','\377', 63,
52, 53, 54, 55, 56, 57, 58, 59,
60, 61,'\377','\377','\377','\377','\377','\377',
'\377', 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25,'\377','\377','\377','\377','\377',
'\377', 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51,'\377','\377','\377','\377','\377'
};
static char hextab[] = "0123456789ABCDEF";
#ifdef __cplusplus
inline int isbase64(int a) {
return ('A' <= a && a <= 'Z')
|| ('a' <= a && a <= 'z')
|| ('0' <= a && a <= '9')
|| a == '+' || a == '/';
}
#else
#define isbase64(a) ( ('A' <= (a) && (a) <= 'Z') \
|| ('a' <= (a) && (a) <= 'z') \
|| ('0' <= (a) && (a) <= '9') \
|| (a) == '+' || (a) == '/' )
#endif
static int encode_base64(const char* aIn, size_t aInLen, char* aOut,
size_t aOutSize, size_t* aOutLen)
{
if (!aIn || !aOut || !aOutLen)
return -1;
size_t inLen = aInLen;
char* out = aOut;
size_t outSize = (inLen+2)/3*4; /* 3:4 conversion ratio */
outSize += strlen(DW_EOL)*outSize/MAXLINE + 2; /* Space for newlines and NUL */
if (aOutSize < outSize)
return -1;
size_t inPos = 0;
size_t outPos = 0;
int c1, c2, c3;
int lineLen = 0;
/* Get three characters at a time and encode them. */
for (size_t i=0; i < inLen/3; ++i) {
c1 = aIn[inPos++] & 0xFF;
c2 = aIn[inPos++] & 0xFF;
c3 = aIn[inPos++] & 0xFF;
out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
out[outPos++] = base64tab[((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)];
out[outPos++] = base64tab[c3 & 0x3F];
lineLen += 4;
if (lineLen >= MAXLINE-3) {
const char* cp = DW_EOL;
out[outPos++] = *cp++;
if (*cp) {
out[outPos++] = *cp;
}
lineLen = 0;
}
}
/* Encode the remaining one or two characters. */
const char* cp;
switch (inLen % 3) {
case 0:
cp = DW_EOL;
out[outPos++] = *cp++;
if (*cp) {
out[outPos++] = *cp;
}
break;
case 1:
c1 = aIn[inPos] & 0xFF;
out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
out[outPos++] = base64tab[((c1 & 0x03) << 4)];
out[outPos++] = '=';
out[outPos++] = '=';
cp = DW_EOL;
out[outPos++] = *cp++;
if (*cp) {
out[outPos++] = *cp;
}
break;
case 2:
c1 = aIn[inPos++] & 0xFF;
c2 = aIn[inPos] & 0xFF;
out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
out[outPos++] = base64tab[((c2 & 0x0F) << 2)];
out[outPos++] = '=';
cp = DW_EOL;
out[outPos++] = *cp++;
if (*cp) {
out[outPos++] = *cp;
}
break;
}
out[outPos] = 0;
*aOutLen = outPos;
return 0;
}
static int decode_base64(const char* aIn, size_t aInLen, char* aOut,
size_t aOutSize, size_t* aOutLen)
{
if (!aIn || !aOut || !aOutLen)
return -1;
size_t inLen = aInLen;
char* out = aOut;
size_t outSize = ( ( inLen + 3 ) / 4 ) * 3;
if (aOutSize < outSize)
return -1;
/* Get four input chars at a time and decode them. Ignore white space
* chars (CR, LF, SP, HT). If '=' is encountered, terminate input. If
* a char other than white space, base64 char, or '=' is encountered,
* flag an input error, but otherwise ignore the char.
*/
int isErr = 0;
int isEndSeen = 0;
int b1, b2, b3;
int a1, a2, a3, a4;
size_t inPos = 0;
size_t outPos = 0;
while (inPos < inLen) {
a1 = a2 = a3 = a4 = 0;
while (inPos < inLen) {
a1 = aIn[inPos++] & 0xFF;
if (isbase64(a1)) {
break;
}
else if (a1 == '=') {
isEndSeen = 1;
break;
}
else if (a1 != '\r' && a1 != '\n' && a1 != ' ' && a1 != '\t') {
isErr = 1;
}
}
while (inPos < inLen) {
a2 = aIn[inPos++] & 0xFF;
if (isbase64(a2)) {
break;
}
else if (a2 == '=') {
isEndSeen = 1;
break;
}
else if (a2 != '\r' && a2 != '\n' && a2 != ' ' && a2 != '\t') {
isErr = 1;
}
}
while (inPos < inLen) {
a3 = aIn[inPos++] & 0xFF;
if (isbase64(a3)) {
break;
}
else if (a3 == '=') {
isEndSeen = 1;
break;
}
else if (a3 != '\r' && a3 != '\n' && a3 != ' ' && a3 != '\t') {
isErr = 1;
}
}
while (inPos < inLen) {
a4 = aIn[inPos++] & 0xFF;
if (isbase64(a4)) {
break;
}
else if (a4 == '=') {
isEndSeen = 1;
break;
}
else if (a4 != '\r' && a4 != '\n' && a4 != ' ' && a4 != '\t') {
isErr = 1;
}
}
if (isbase64(a1) && isbase64(a2) && isbase64(a3) && isbase64(a4)) {
a1 = base64idx[a1] & 0xFF;
a2 = base64idx[a2] & 0xFF;
a3 = base64idx[a3] & 0xFF;
a4 = base64idx[a4] & 0xFF;
b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
b3 = ((a3 << 6) & 0xC0) | ( a4 & 0x3F);
out[outPos++] = char(b1);
out[outPos++] = char(b2);
out[outPos++] = char(b3);
}
else if (isbase64(a1) && isbase64(a2) && isbase64(a3) && a4 == '=') {
a1 = base64idx[a1] & 0xFF;
a2 = base64idx[a2] & 0xFF;
a3 = base64idx[a3] & 0xFF;
b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
out[outPos++] = char(b1);
out[outPos++] = char(b2);
break;
}
else if (isbase64(a1) && isbase64(a2) && a3 == '=' && a4 == '=') {
a1 = base64idx[a1] & 0xFF;
a2 = base64idx[a2] & 0xFF;
b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
out[outPos++] = char(b1);
break;
}
else {
break;
}
if (isEndSeen) {
break;
}
} /* end while loop */
*aOutLen = outPos;
return (isErr) ? -1 : 0;
}
/***** Warning: calc_qp_buff_size must stay in sync with encode_qp ******/
static int encode_qp(const char* aIn, size_t aInLen, char* aOut,
size_t /*aOutSize */, size_t* aOutLen)
{
size_t inPos, outPos, lineLen;
int ch;
if (!aIn || !aOut || !aOutLen) {
return -1;
}
inPos = 0;
outPos = 0;
lineLen = 0;
while (inPos < aInLen) {
ch = aIn[inPos++] & 0xFF;
/* '.' at beginning of line (confuses some SMTPs) */
if (lineLen == 0 && ch == '.') {
aOut[outPos++] = '=';
aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
aOut[outPos++] = hextab[ch & 0x0F];
lineLen += 3;
}
/* "From " at beginning of line (gets mangled in mbox folders) */
else if (lineLen == 0 && inPos+3 < aInLen && ch == 'F'
&& aIn[inPos ] == 'r' && aIn[inPos+1] == 'o'
&& aIn[inPos+2] == 'm' && aIn[inPos+3] == ' ') {
aOut[outPos++] = '=';
aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
aOut[outPos++] = hextab[ch & 0x0F];
lineLen += 3;
}
/* Normal printable char */
else if ((62 <= ch && ch <= 126) || (33 <= ch && ch <= 60)) {
aOut[outPos++] = (char) ch;
++lineLen;
}
/* Space */
else if (ch == ' ') {
/* Space at end of line or end of input must be encoded */
#if defined(DW_EOL_LF)
if (inPos >= aInLen /* End of input? */
|| aIn[inPos] == '\n') { /* End of line? */
aOut[outPos++] = '=';
aOut[outPos++] = '2';
aOut[outPos++] = '0';
lineLen += 3;
}
#elif defined(DW_EOL_CRLF)
if (inPos >= aInLen /* End of input? */
|| (inPos < aInLen-1 /* End of line? */
&& aIn[inPos ] == '\r'
&& aIn[inPos+1] == '\n') ) {
aOut[outPos++] = '=';
aOut[outPos++] = '2';
aOut[outPos++] = '0';
lineLen += 3;
}
#else
# error Must define DW_EOL_LF or DW_EOL_CRLF
#endif
else {
aOut[outPos++] = ' ';
++lineLen;
}
}
/* Hard line break */
#if defined(DW_EOL_LF)
else if (ch == '\n') {
aOut[outPos++] = '\n';
lineLen = 0;
}
#elif defined(DW_EOL_CRLF)
else if (inPos < aInLen && ch == '\r' && aIn[inPos] == '\n') {
++inPos;
aOut[outPos++] = '\r';
aOut[outPos++] = '\n';
lineLen = 0;
}
#endif
/* Non-printable char */
else if (ch & 0x80 /* 8-bit char */
|| !(ch & 0xE0) /* control char */
|| ch == 0x7F /* DEL */
|| ch == '=') { /* special case */
aOut[outPos++] = '=';
aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
aOut[outPos++] = hextab[ch & 0x0F];
lineLen += 3;
}
/* Soft line break */
#if defined(DW_EOL_LF)
if (lineLen >= MAXLINE-3 && inPos < aInLen && aIn[inPos] != '\n') {
aOut[outPos++] = '=';
aOut[outPos++] = '\n';
lineLen = 0;
}
#elif defined(DW_EOL_CRLF)
if (lineLen >= MAXLINE-3 && !(inPos < aInLen-1 &&
aIn[inPos] == '\r' && aIn[inPos+1] == '\n')) {
aOut[outPos++] = '=';
aOut[outPos++] = '\r';
aOut[outPos++] = '\n';
lineLen = 0;
}
#endif
}
aOut[outPos] = 0;
*aOutLen = outPos;
return 0;
}
static int decode_qp(const char* aIn, size_t aInLen, char* aOut,
size_t /* aOutSize */, size_t* aOutLen)
{
size_t i, inPos, outPos, lineLen, nextLineStart, numChars, charsEnd;
int isEolFound, softLineBrk, isError;
int ch, c1, c2;
if (!aIn || !aOut || !aOutLen)
return -1;
isError = 0;
inPos = 0;
outPos = 0;
for (i=0; i < aInLen; ++i) {
if (aIn[i] == 0) {
aInLen = i;
break;
}
}
if (aInLen == 0) {
aOut[0] = 0;
*aOutLen = 0;
return 0;
}
while (inPos < aInLen) {
/* Get line */
lineLen = 0;
isEolFound = 0;
while (!isEolFound && lineLen < aInLen - inPos) {
ch = aIn[inPos+lineLen];
++lineLen;
if (ch == '\n') {
isEolFound = 1;
}
}
nextLineStart = inPos + lineLen;
numChars = lineLen;
/* Remove white space from end of line */
while (numChars > 0) {
ch = aIn[inPos+numChars-1] & 0x7F;
if (ch != '\n' && ch != '\r' && ch != ' ' && ch != '\t') {
break;
}
--numChars;
}
charsEnd = inPos + numChars;
/* Decode line */
softLineBrk = 0;
while (inPos < charsEnd) {
ch = aIn[inPos++] & 0x7F;
if (ch != '=') {
/* Normal printable char */
aOut[outPos++] = (char) ch;
}
else /* if (ch == '=') */ {
/* Soft line break */
if (inPos >= charsEnd) {
softLineBrk = 1;
break;
}
/* Non-printable char */
else if (inPos < charsEnd-1) {
c1 = aIn[inPos++] & 0x7F;
if ('0' <= c1 && c1 <= '9')
c1 -= '0';
else if ('A' <= c1 && c1 <= 'F')
c1 = c1 - 'A' + 10;
else if ('a' <= c1 && c1 <= 'f')
c1 = c1 - 'a' + 10;
else
isError = 1;
c2 = aIn[inPos++] & 0x7F;
if ('0' <= c2 && c2 <= '9')
c2 -= '0';
else if ('A' <= c2 && c2 <= 'F')
c2 = c2 - 'A' + 10;
else if ('a' <= c2 && c2 <= 'f')
c2 = c2 - 'a' + 10;
else
isError = 1;
aOut[outPos++] = (char) ((c1 << 4) + c2);
}
else /* if (inPos == charsEnd-1) */ {
isError = 1;
}
}
}
if (isEolFound && !softLineBrk) {
const char* cp = DW_EOL;
aOut[outPos++] = *cp++;
if (*cp) {
aOut[outPos++] = *cp;
}
}
inPos = nextLineStart;
}
aOut[outPos] = 0;
*aOutLen = outPos;
return (isError) ? -1 : 0;
}
/***** Warning: calc_qp_buff_size must stay in sync with encode_qp ******/
static size_t calc_qp_buff_size(const char* aIn, size_t aInLen)
{
size_t inPos, outLen, lineLen;
int ch;
if (!aIn || aInLen == 0) {
return 0;
}
inPos = 0;
outLen = 0;
lineLen = 0;
while (inPos < aInLen) {
ch = aIn[inPos++] & 0xFF;
/* '.' at beginning of line (confuses some SMTPs) */
if (lineLen == 0 && ch == '.') {
outLen += 3;
lineLen += 3;
}
/* "From " at beginning of line (gets mangled in mbox folders) */
else if (lineLen == 0 && inPos+3 < aInLen && ch == 'F'
&& aIn[inPos ] == 'r' && aIn[inPos+1] == 'o'
&& aIn[inPos+2] == 'm' && aIn[inPos+3] == ' ') {
outLen += 3;
lineLen += 3;
}
/* Normal printable char */
else if ((62 <= ch && ch <= 126) || (33 <= ch && ch <= 60)) {
++outLen;
++lineLen;
}
/* Space */
else if (ch == ' ') {
/* Space at end of line or end of input must be encoded */
#if defined(DW_EOL_LF)
if (inPos >= aInLen /* End of input? */
|| aIn[inPos] == '\n') { /* End of line? */
outLen += 3;
lineLen += 3;
}
#elif defined(DW_EOL_CRLF)
if (inPos >= aInLen /* End of input? */
|| (inPos < aInLen-1 /* End of line? */
&& aIn[inPos ] == '\r'
&& aIn[inPos+1] == '\n') ) {
outLen += 3;
lineLen += 3;
}
#else
# error Must define DW_EOL_LF or DW_EOL_CRLF
#endif
else {
++outLen;
++lineLen;
}
}
/* Hard line break */
#if defined(DW_EOL_LF)
else if (ch == '\n') {
++outLen;
lineLen = 0;
}
#elif defined(DW_EOL_CRLF)
else if (inPos < aInLen && ch == '\r' && aIn[inPos] == '\n') {
++inPos;
outLen += 2;
lineLen = 0;
}
#endif
/* Non-printable char */
else if (ch & 0x80 /* 8-bit char */
|| !(ch & 0xE0) /* control char */
|| ch == 0x7F /* DEL */
|| ch == '=') { /* special case */
outLen += 3;
lineLen += 3;
}
/* Soft line break */
#if defined(DW_EOL_LF)
if (lineLen >= MAXLINE-3 && inPos < aInLen && aIn[inPos] != '\n') {
outLen += 2;
lineLen = 0;
}
#elif defined(DW_EOL_CRLF)
if (lineLen >= MAXLINE-3 && !(inPos < aInLen-1 &&
aIn[inPos] == '\r' && aIn[inPos+1] == '\n')) {
outLen += 3;
lineLen = 0;
}
#endif
}
return outLen;
}