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.
2601 lines
80 KiB
2601 lines
80 KiB
// --------------------------------------------------------------------------------
|
|
// Inetconv.cpp
|
|
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
|
|
// Steven J. Bailey
|
|
// --------------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "dllmain.h"
|
|
#include "inetconv.h"
|
|
#include "internat.h"
|
|
#ifndef MAC
|
|
#include <shlwapi.h>
|
|
#include <mlang.h>
|
|
#endif // !MAC
|
|
#include "mimeapi.h"
|
|
#include "icoint.h"
|
|
#include "demand.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// FGROWBUFFER
|
|
// --------------------------------------------------------------------------------
|
|
#define FGROWBUFFER(_pBuffer, _cb) ((_pBuffer)->cb + _cb >= (_pBuffer)->cbAlloc)
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// QP Encoder
|
|
// --------------------------------------------------------------------------------
|
|
const CHAR g_rgchHex[] = "0123456789ABCDEF";
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Base64 Decoding Table
|
|
// ---------------------
|
|
// Decodes one Base64 character into a numeric value
|
|
//
|
|
// 0 1 2 3 4 5 6
|
|
// 0123456789012345678901234567890123456789012345678901234567890123
|
|
// ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
|
|
// --------------------------------------------------------------------------------
|
|
const char g_rgchDecodeBase64[256] = {
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0x00
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0x10
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0x20
|
|
64, 64, 64, 62, 64, 64, 64, 63,
|
|
52, 53, 54, 55, 56, 57, 58, 59, // 0x30
|
|
60, 61, 64, 64, 64, 0, 64, 64,
|
|
64, 0, 1, 2, 3, 4, 5, 6, // 0x40
|
|
7, 8, 9, 10, 11, 12, 13, 14,
|
|
15, 16, 17, 18, 19, 20, 21, 22, // 0x50
|
|
23, 24, 25, 64, 64, 64, 64, 64,
|
|
64, 26, 27, 28, 29, 30, 31, 32, // 0x60
|
|
33, 34, 35, 36, 37, 38, 39, 40,
|
|
41, 42, 43, 44, 45, 46, 47, 48, // 0x70
|
|
49, 50, 51, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0x80
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0x90
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0xA0
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0xB0
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0xC0
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0xD0
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0xE0
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
64, 64, 64, 64, 64, 64, 64, 64, // 0xF0
|
|
64, 64, 64, 64, 64, 64, 64, 64,
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// Base64 Encoder
|
|
// --------------------------------------------------------------------------------
|
|
extern const CHAR g_rgchEncodeBase64[] =
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ ";
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// BinHex Decoding Table
|
|
// ---------------------
|
|
// Decodes one BinHex character into a numeric value
|
|
//
|
|
// 0 1 2 3 4 5 6
|
|
// 0123456789012345678901234567890123456789012345678901234567890123
|
|
// !"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr
|
|
// --------------------------------------------------------------------------------
|
|
#undef BINHEX_INVALID
|
|
#undef BINHEX_REPEAT
|
|
#undef XXXX
|
|
|
|
const UCHAR BINHEX_INVALID = 0x40;
|
|
const UCHAR BINHEX_REPEAT = 0x90;
|
|
const UCHAR BINHEX_TERM = ':';
|
|
const UCHAR XXXX = BINHEX_INVALID;
|
|
const ULONG cbMinBinHexHeader = 22;
|
|
const WORD wBinHexZero = 0;
|
|
|
|
const UCHAR g_rgchDecodeBinHex[256] = {
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x00
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x10
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x20
|
|
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, XXXX, XXXX,
|
|
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, XXXX, // 0x30
|
|
0x14, 0x15, 0x16, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, // 0x40
|
|
0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, XXXX,
|
|
0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, XXXX, // 0x50
|
|
0x2C, 0x2D, 0x2E, 0x2F, XXXX, XXXX, XXXX, XXXX,
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, XXXX, // 0x60
|
|
0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, XXXX, XXXX,
|
|
0x3D, 0x3E, 0x3F, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x70
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x80
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0x90
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xA0
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xB0
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xC0
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xD0
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xE0
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, // 0xF0
|
|
XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX, XXXX,
|
|
};
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrCreateLineBreaker
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrCreateLineBreaker(IMLangLineBreakConsole **ppLineBreak)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
PFNGETCLASSOBJECT pfnDllGetClassObject=NULL;
|
|
IClassFactory *pFactory=NULL;
|
|
|
|
// Invalid Args
|
|
Assert(ppLineBreak);
|
|
|
|
// Init
|
|
*ppLineBreak = NULL;
|
|
|
|
// Thread Safety
|
|
EnterCriticalSection(&g_csMLANG);
|
|
|
|
// If not loaded yet
|
|
if (NULL == g_hinstMLANG)
|
|
{
|
|
// Load MLANG - This should be fast most of the time because MLANG is usually loaded
|
|
g_hinstMLANG = LoadLibrary("MLANG.DLL");
|
|
if (NULL == g_hinstMLANG)
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Get DllClassObject
|
|
pfnDllGetClassObject = (PFNGETCLASSOBJECT)GetProcAddress(g_hinstMLANG, "DllGetClassObject");
|
|
if (NULL == pfnDllGetClassObject)
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
|
|
// Get the MLANG Class Factory
|
|
CHECKHR(hr = (*pfnDllGetClassObject)(CLSID_CMultiLanguage, IID_IClassFactory, (LPVOID *)&pFactory));
|
|
|
|
// Finally, create the object that I actually wanted
|
|
CHECKHR(hr = pFactory->CreateInstance(NULL, IID_IMLangLineBreakConsole, (LPVOID *)ppLineBreak));
|
|
|
|
exit:
|
|
// Thread Safety
|
|
LeaveCriticalSection(&g_csMLANG);
|
|
|
|
// Cleanup
|
|
SafeRelease(pFactory);
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrCreateInternetConverter
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrCreateInternetConverter(LPCONVINITINFO pInitInfo, CInternetConverter **ppConverter)
|
|
{
|
|
// Allocate It
|
|
*ppConverter = new CInternetConverter();
|
|
if (NULL == *ppConverter)
|
|
return TrapError(E_OUTOFMEMORY);
|
|
|
|
// Initialize
|
|
return TrapError((*ppConverter)->HrInit(pInitInfo));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// BinHexCalcCRC16
|
|
// --------------------------------------------------------------------------------
|
|
void BinHexCalcCRC16( LPBYTE lpbBuff, ULONG cBuff, WORD * wCRC )
|
|
{
|
|
LPBYTE lpb;
|
|
BYTE b;
|
|
WORD uCRC;
|
|
WORD fWrap;
|
|
ULONG i;
|
|
|
|
uCRC = *wCRC;
|
|
|
|
for ( lpb = lpbBuff; lpb < lpbBuff + cBuff; lpb++ )
|
|
{
|
|
b = *lpb;
|
|
|
|
for ( i = 0; i < 8; i++ )
|
|
{
|
|
fWrap = uCRC & 0x8000;
|
|
uCRC = (uCRC << 1) | (b >> 7);
|
|
|
|
if ( fWrap )
|
|
{
|
|
uCRC = uCRC ^ 0x1021;
|
|
}
|
|
|
|
b = b << 1;
|
|
}
|
|
}
|
|
|
|
*wCRC = uCRC;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// HrCreateMacBinaryHeader
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT HrCreateMacBinaryHeader(LPCONVERTBUFFER prBinHexHeader, LPCONVERTBUFFER prMacBinaryHeader)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPMACBINARY pmacbin;
|
|
LPBYTE pbBinHex;
|
|
#ifndef _MAC
|
|
WORD wCRC = 0;
|
|
#endif // _MAC
|
|
|
|
if ((NULL == prBinHexHeader) || (NULL == prMacBinaryHeader))
|
|
{
|
|
hr = ERROR_INVALID_PARAMETER;
|
|
goto exit;
|
|
}
|
|
|
|
pmacbin = (LPMACBINARY)(prMacBinaryHeader->pb);
|
|
pbBinHex = (LPBYTE)(prBinHexHeader->pb);
|
|
|
|
// Zero it out first
|
|
ZeroMemory(pmacbin, sizeof(MACBINARY));
|
|
|
|
// Write in the filename length
|
|
pmacbin->cchFileName = (BYTE)min(pbBinHex[0], sizeof(pmacbin->rgchFileName)-1);
|
|
pbBinHex += 1;
|
|
|
|
// Copy over the filename
|
|
CopyMemory(pmacbin->rgchFileName, pbBinHex, pmacbin->cchFileName);
|
|
pmacbin->rgchFileName[pmacbin->cchFileName] = '\0';
|
|
pbBinHex += pmacbin->cchFileName + 1;
|
|
|
|
// Copy over the type and creator
|
|
CopyMemory(&(pmacbin->dwType), pbBinHex, sizeof(pmacbin->dwType));
|
|
pbBinHex += 4;
|
|
|
|
CopyMemory(&(pmacbin->dwCreator), pbBinHex, sizeof(pmacbin->dwCreator));
|
|
pbBinHex += 4;
|
|
|
|
// Copy over the finder flags
|
|
pmacbin->bFinderFlags = *pbBinHex;
|
|
pbBinHex++;
|
|
|
|
pmacbin->bFinderFlags2 = *pbBinHex;
|
|
pbBinHex++;
|
|
|
|
// Copy over the data fork length
|
|
CopyMemory(&(pmacbin->lcbDataFork), pbBinHex, sizeof(pmacbin->lcbDataFork));
|
|
pbBinHex += 4;
|
|
|
|
// Copy over the resource fork length
|
|
CopyMemory(&(pmacbin->lcbResourceFork), pbBinHex, sizeof(pmacbin->lcbResourceFork));
|
|
pbBinHex += 4;
|
|
|
|
// Drop on the version stamps
|
|
pmacbin->bVerMacBin2 = 129;
|
|
pmacbin->bMinVerMacBin2 = 129;
|
|
|
|
// Calculate the CRC
|
|
#ifdef _MAC
|
|
BinHexCalcCRC16((LPBYTE) pmacbin, 124, &(pmacbin->wCRC));
|
|
BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(pmacbin->wCRC));
|
|
#else // !_MAC
|
|
BinHexCalcCRC16((LPBYTE) pmacbin, 124, &(wCRC));
|
|
BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(wCRC));
|
|
|
|
// Need to keep it in Mac order
|
|
pmacbin->wCRC = HIBYTE(wCRC);
|
|
pmacbin->wCRC |= (LOBYTE(wCRC) << 8);
|
|
#endif // _MAC
|
|
|
|
prMacBinaryHeader->cb += sizeof(MACBINARY);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter
|
|
// --------------------------------------------------------------------------------
|
|
CInternetConverter::CInternetConverter(void)
|
|
{
|
|
m_cRef = 1;
|
|
m_dwFlags = 0;
|
|
m_cbConvert = 0;
|
|
m_ietEncoding = IET_BINARY;
|
|
m_cpiSource = CP_ACP;
|
|
m_cpiDest = CP_ACP;
|
|
m_fLastBuffer = FALSE;
|
|
m_fEncoder = FALSE;
|
|
m_uchPrev = '\0';
|
|
m_pAppend = NULL;
|
|
m_pWrite = NULL;
|
|
m_convtype = ICT_UNKNOWN;
|
|
m_cchMaxLine = 0;
|
|
m_pBinhexEncode = NULL;
|
|
m_eBinHexStateDec = sSTARTING;
|
|
m_fRepeating = FALSE;
|
|
m_cAccum = 0;
|
|
m_prBinhexOutput = &m_rOut;
|
|
m_cbToProcess = 0;
|
|
m_cbDataFork = 0;
|
|
m_cbResourceFork = 0;
|
|
m_wCRC = 0;
|
|
m_wCRCForFork = 0;
|
|
m_fDataForkOnly = FALSE;
|
|
m_pLineBreak = NULL;
|
|
ZeroMemory(&m_rIn, sizeof(CONVERTBUFFER));
|
|
ZeroMemory(&m_rOut, sizeof(CONVERTBUFFER));
|
|
ZeroMemory(&m_rCset, sizeof(CONVERTBUFFER));
|
|
ZeroMemory(&m_rBinhexHeader, sizeof(CONVERTBUFFER));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::~CInternetConverter
|
|
// --------------------------------------------------------------------------------
|
|
CInternetConverter::~CInternetConverter(void)
|
|
{
|
|
if (m_pBinhexEncode)
|
|
delete m_pBinhexEncode;
|
|
SafeMemFree(m_rIn.pb);
|
|
SafeMemFree(m_rOut.pb);
|
|
SafeMemFree(m_rCset.pb);
|
|
SafeMemFree(m_rBinhexHeader.pb);
|
|
SafeRelease(m_pLineBreak);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::QueryInterface
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP CInternetConverter::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::AddRef
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CInternetConverter::AddRef(void)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::Release
|
|
// --------------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CInternetConverter::Release(void)
|
|
{
|
|
if (0 != --m_cRef)
|
|
return m_cRef;
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrInit
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrInit(LPCONVINITINFO pInitInfo)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Save Flags
|
|
m_dwFlags = pInitInfo->dwFlags;
|
|
|
|
// Save Format
|
|
m_ietEncoding = pInitInfo->ietEncoding;
|
|
|
|
// Save Source Code Page
|
|
m_cpiSource = pInitInfo->cpiSource;
|
|
|
|
// Save Dest Code Page
|
|
m_cpiDest = pInitInfo->cpiDest;
|
|
|
|
// Are we an encoder..
|
|
m_fEncoder = pInitInfo->fEncoder;
|
|
|
|
// Save Wrap Info
|
|
m_cchMaxLine = pInitInfo->cchMaxLine;
|
|
|
|
// Save MacBinary state
|
|
m_fDataForkOnly = !pInitInfo->fShowMacBinary;
|
|
|
|
// InitConvertType
|
|
CHECKHR(hr = HrInitConvertType(pInitInfo));
|
|
|
|
// DoubleCheck
|
|
Assert(m_pWrite && m_pAppend && ICT_UNKNOWN != m_convtype);
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrInitConvertType
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrInitConvertType(LPCONVINITINFO pInitInfo)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CODEPAGEINFO CodePage;
|
|
CODEPAGEID cpiLCID;
|
|
|
|
// Time to compute m_pAppend and m_pDump...
|
|
if (ICF_WRAPTEXT & m_dwFlags)
|
|
{
|
|
// Check Assumptions
|
|
Assert((IET_7BIT == m_ietEncoding || IET_8BIT == m_ietEncoding) && TRUE == m_fEncoder);
|
|
|
|
// Code Page Conversion...
|
|
if (ICF_CODEPAGE & m_dwFlags)
|
|
m_convtype = ICT_WRAPTEXT_CODEPAGE;
|
|
else
|
|
m_convtype = ICT_WRAPTEXT;
|
|
|
|
// Load MLANG
|
|
CHECKHR(hr = HrCreateLineBreaker(&m_pLineBreak));
|
|
|
|
// Set cpiLCID
|
|
cpiLCID = m_cpiSource;
|
|
|
|
// Unicode ?
|
|
if (CP_UNICODE == m_cpiSource)
|
|
{
|
|
// Get Destination Code Page Info
|
|
if (SUCCEEDED(g_pInternat->GetCodePageInfo(m_cpiDest, &CodePage)))
|
|
{
|
|
// Set cpiLCID
|
|
cpiLCID = CodePage.cpiFamily;
|
|
}
|
|
}
|
|
|
|
// Map m_cpiSource to lcid
|
|
switch(cpiLCID)
|
|
{
|
|
case 874: m_lcid = 0x041E; break;
|
|
case 932: m_lcid = 0x0411; break;
|
|
case 936: m_lcid = 0x0804; break;
|
|
case 949: m_lcid = 0x0412; break;
|
|
case 950: m_lcid = 0x0404; break;
|
|
case 1250: m_lcid = 0x040e; break;
|
|
case 1251: m_lcid = 0x0419; break;
|
|
case 1252: m_lcid = 0x0409; break;
|
|
case 1253: m_lcid = 0x0408; break;
|
|
case 1254: m_lcid = 0x041f; break;
|
|
case 1255: m_lcid = 0x040d; break;
|
|
case 1256: m_lcid = 0x0401; break;
|
|
case 1257: m_lcid = 0x0426; break;
|
|
default: m_lcid = GetSystemDefaultLCID(); break;
|
|
}
|
|
}
|
|
|
|
// Otherwise, if encoding
|
|
else if (TRUE == m_fEncoder)
|
|
{
|
|
// If CodePage Conversion
|
|
if (ICF_CODEPAGE & m_dwFlags)
|
|
m_convtype = ICT_CODEPAGE_ENCODE;
|
|
else
|
|
m_convtype = ICT_ENCODE;
|
|
|
|
// Need binhex encoder
|
|
if (IET_BINHEX40 == m_ietEncoding)
|
|
{
|
|
// Create me an encoder
|
|
CHECKALLOC(m_pBinhexEncode = new CBinhexEncoder);
|
|
|
|
// Initialize
|
|
CHECKHR(hr = m_pBinhexEncode->HrConfig(0, 0, &pInitInfo->rMacBinary));
|
|
}
|
|
}
|
|
|
|
// Otherwise, if not encoding
|
|
else
|
|
{
|
|
// If CodePage Conversion
|
|
if (ICF_CODEPAGE & m_dwFlags)
|
|
m_convtype = ICT_DECODE_CODEPAGE;
|
|
else
|
|
m_convtype = ICT_DECODE;
|
|
}
|
|
|
|
// Map Write and Append Buffers from Conversion Type
|
|
switch(m_convtype)
|
|
{
|
|
// m_rIn --> m_rCset
|
|
case ICT_WRAPTEXT_CODEPAGE:
|
|
case ICT_DECODE_CODEPAGE:
|
|
m_pAppend = &m_rIn;
|
|
m_pWrite = &m_rCset;
|
|
break;
|
|
|
|
// m_rIn --> m_rOut
|
|
case ICT_WRAPTEXT:
|
|
case ICT_ENCODE:
|
|
case ICT_DECODE:
|
|
m_pAppend = &m_rIn;
|
|
m_pWrite = &m_rOut;
|
|
break;
|
|
|
|
// m_rCset --> m_rOut
|
|
case ICT_CODEPAGE_ENCODE:
|
|
m_pAppend = &m_rCset;
|
|
m_pWrite = &m_rOut;
|
|
break;
|
|
|
|
// Error
|
|
default:
|
|
AssertSz(FALSE, "INVALID INETCONVTYPE");
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrConvBuffAppendBlock
|
|
// --------------------------------------------------------------------------------
|
|
inline HRESULT CInternetConverter::HrConvBuffAppendBlock(LPBYTE pb, ULONG cb)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(&m_rOut, cb))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, cb));
|
|
}
|
|
|
|
// Copy the buffer
|
|
CopyMemory(m_rOut.pb + m_rOut.cb, pb, cb);
|
|
|
|
// Increment Size
|
|
m_rOut.cb += cb;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::PszConvBuffGetNextLine
|
|
// --------------------------------------------------------------------------------
|
|
inline LPSTR CInternetConverter::PszConvBuffGetNextLine(ULONG *pcbLine, ULONG *pcbRead, BOOL *pfFound)
|
|
{
|
|
// Locals
|
|
UCHAR uchThis, uchPrev;
|
|
ULONG cbLine=0;
|
|
|
|
// Invalid Arg
|
|
Assert(pcbLine && pcbRead && pfFound);
|
|
|
|
// Init
|
|
*pfFound = FALSE;
|
|
|
|
// Read to next \n
|
|
while(m_rIn.i + cbLine < m_rIn.cb)
|
|
{
|
|
// Get a character...
|
|
uchThis = m_rIn.pb[m_rIn.i + cbLine];
|
|
|
|
// Better not be null
|
|
Assert(uchThis);
|
|
|
|
// Increment Line Length
|
|
cbLine++;
|
|
|
|
// Done
|
|
if (chLF == uchThis)
|
|
{
|
|
*pfFound = TRUE;
|
|
break;
|
|
}
|
|
|
|
// Remember Previous Char
|
|
uchPrev = uchThis;
|
|
}
|
|
|
|
// Set Next Line
|
|
*pcbRead = cbLine;
|
|
|
|
// Fixup cbLine
|
|
if (chLF == uchThis)
|
|
cbLine--;
|
|
if (chCR == uchPrev)
|
|
cbLine--;
|
|
|
|
// Set Length
|
|
*pcbLine = cbLine;
|
|
|
|
// Done
|
|
return (LPSTR)(m_rIn.pb + m_rIn.i);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::CopyMemoryRemoveNBSP
|
|
// --------------------------------------------------------------------------------
|
|
void CInternetConverter::CopyMemoryRemoveNBSP(LPBYTE pbDest, LPBYTE pbSource, ULONG cbSource)
|
|
{
|
|
// Locals
|
|
ULONG iDest=0;
|
|
ULONG iSource=0;
|
|
|
|
// Invalid ARg
|
|
Assert(pbDest && pbSource && CP_UNICODE == m_cpiSource);
|
|
|
|
// Do It
|
|
while(1)
|
|
{
|
|
// If not a null lead, copy next two bytes...
|
|
if (iSource + 1 < cbSource)
|
|
{
|
|
// Better not be 0x00A0 - insert space
|
|
Assert(iSource % 2 == 0);
|
|
if (0xA0 == pbSource[iSource] && 0x00 == pbSource[iSource + 1])
|
|
{
|
|
// 0x0020 = Space
|
|
pbDest[iDest++] = 0x20;
|
|
pbDest[iDest++] = 0x00;
|
|
|
|
// Step Over this character...
|
|
iSource+=2;
|
|
}
|
|
|
|
// Otherwise, copy the character
|
|
else
|
|
{
|
|
// Copy This Char
|
|
pbDest[iDest++] = pbSource[iSource++];
|
|
|
|
// Copy Next Char
|
|
if (iSource < cbSource)
|
|
pbDest[iDest++] = pbSource[iSource++];
|
|
}
|
|
}
|
|
|
|
// Otherwise, just copy this once character and stop
|
|
else
|
|
{
|
|
// Copy It
|
|
if (iSource < cbSource)
|
|
pbDest[iDest++] = pbSource[iSource++];
|
|
|
|
// Done
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrFillAppend
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrFillAppend(LPBLOB pData)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Invlaid ARg
|
|
Assert(pData && m_pAppend);
|
|
|
|
// Call Internal Function
|
|
CHECKHR(hr = HrAppendBuffer(m_pAppend, pData, (m_dwFlags & ICF_KILLNBSP)));
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrAppendBuffer
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrAppendBuffer(LPCONVERTBUFFER pBuffer, LPBLOB pData, BOOL fKillNBSP)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Collapse Current Buffer
|
|
if (pBuffer->i != 0)
|
|
{
|
|
// Move Memory
|
|
MoveMemory(pBuffer->pb, pBuffer->pb + pBuffer->i, pBuffer->cb - pBuffer->i);
|
|
|
|
// Decrease Size
|
|
pBuffer->cb -= pBuffer->i;
|
|
|
|
// Reset Start
|
|
pBuffer->i = 0;
|
|
}
|
|
|
|
// Enought Space ?
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(pBuffer, pData->cbSize))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(pBuffer, pData->cbSize));
|
|
}
|
|
|
|
// Append the buffer...
|
|
if (fKillNBSP)
|
|
CopyMemoryRemoveNBSP(pBuffer->pb + pBuffer->cb, pData->pBlobData, pData->cbSize);
|
|
|
|
// Otherwise, this is a simple copy
|
|
else
|
|
CopyMemory(pBuffer->pb + pBuffer->cb, pData->pBlobData, pData->cbSize);
|
|
|
|
// Increment Amount of Data
|
|
pBuffer->cb += pData->cbSize;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrGrowBuffer
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrGrowBuffer(LPCONVERTBUFFER pBuffer, ULONG cbAppend)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbGrow;
|
|
|
|
// Better need a grow
|
|
Assert(FGROWBUFFER(pBuffer, cbAppend));
|
|
|
|
// Compute Grow By
|
|
cbGrow = (cbAppend - (pBuffer->cbAlloc - pBuffer->cb)) + 256;
|
|
|
|
// Realloc the buffer
|
|
CHECKHR(hr = HrRealloc((LPVOID *)&pBuffer->pb, pBuffer->cbAlloc + cbGrow));
|
|
|
|
// Adjust cbAlloc
|
|
pBuffer->cbAlloc += cbGrow;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrWriteConverted
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrWriteConverted(IStream *pStream)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Anything to write
|
|
if (m_pWrite->cb)
|
|
{
|
|
// Write the current block
|
|
CHECKHR(hr = pStream->Write(m_pWrite->pb, m_pWrite->cb, NULL));
|
|
|
|
// Nothing in m_rOut
|
|
m_pWrite->cb = 0;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrWriteConverted
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrWriteConverted(CInternetConverter *pConverter)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
BLOB rData;
|
|
|
|
// Anything to write
|
|
if (m_pWrite->cb)
|
|
{
|
|
// Setup Blob
|
|
rData.pBlobData = m_pWrite->pb;
|
|
rData.cbSize = m_pWrite->cb;
|
|
|
|
// Write the current block
|
|
CHECKHR(hr = pConverter->HrFillAppend(&rData));
|
|
|
|
// Nothing in m_rOut
|
|
m_pWrite->cb = 0;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrInternetEncode
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrInternetEncode(BOOL fLastBuffer)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrWarnings=S_OK;
|
|
BLOB rData;
|
|
|
|
// We Better be an encoder
|
|
Assert(m_fEncoder);
|
|
|
|
// Set Last Buffer
|
|
m_fLastBuffer = fLastBuffer;
|
|
|
|
// Text Wrapping ?
|
|
if (ICF_WRAPTEXT & m_dwFlags)
|
|
{
|
|
// Wrap It: m_rIn -> m_rOut
|
|
if (CP_UNICODE == m_cpiSource)
|
|
CHECKHR(hr = HrWrapInternetTextW());
|
|
else
|
|
CHECKHR(hr = HrWrapInternetTextA());
|
|
|
|
// Character Set Encoding: m_rOut -> m_rCset
|
|
if (ICF_CODEPAGE & m_dwFlags)
|
|
{
|
|
// Charset Encode
|
|
CHECKHR(hr = HrCodePageFromOutToCset());
|
|
if ( S_OK != hr )
|
|
hrWarnings = TrapError(hr);
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else
|
|
{
|
|
// Character Set Encoding: m_rCset -> m_rIn
|
|
if (ICF_CODEPAGE & m_dwFlags)
|
|
{
|
|
// Charset Encode
|
|
CHECKHR(hr = HrCodePageFromCsetToIn());
|
|
if ( S_OK != hr )
|
|
hrWarnings = TrapError(hr);
|
|
}
|
|
|
|
// Handle Conversion type
|
|
switch(m_ietEncoding)
|
|
{
|
|
// Binary
|
|
case IET_BINARY:
|
|
case IET_7BIT:
|
|
case IET_8BIT:
|
|
// Better be at zero
|
|
Assert(m_rIn.i == 0);
|
|
|
|
// Initialize Blob to copy
|
|
rData.pBlobData = m_rIn.pb;
|
|
rData.cbSize = m_rIn.cb;
|
|
|
|
// Append to outbound buffer
|
|
CHECKHR(hr = HrAppendBuffer(&m_rOut, &rData, FALSE));
|
|
|
|
// Increment offset
|
|
m_rIn.i = m_rIn.cb = 0;
|
|
break;
|
|
|
|
// Quoted-Printable
|
|
case IET_QP:
|
|
CHECKHR(hr = HrEncodeQP());
|
|
break;
|
|
|
|
// Bas 64
|
|
case IET_BASE64:
|
|
CHECKHR(hr = HrEncode64());
|
|
break;
|
|
|
|
// UUENCODE
|
|
case IET_UUENCODE:
|
|
CHECKHR(hr = HrEncodeUU());
|
|
break;
|
|
|
|
// BINHEX
|
|
case IET_BINHEX40:
|
|
#ifdef NEVER
|
|
CHECKHR(hr = HrEncodeBinhex());
|
|
#endif // NEVER
|
|
// IE v. 5.0:33596 HrEncodeBinhex returns E_FAIL if body size is too small
|
|
// Binhex encoding doesn't currently work. I believe that it should work (or almost work)
|
|
// if the header CBinhexEncoder::m_lpmacbinHdr is initialized properly. However, this
|
|
// requires understanding the Mac file format and parsing the body stream contents into
|
|
// data and resource forks.
|
|
// - sethco 8/19/1998
|
|
CHECKHR(hr = MIME_E_INVALID_ENCODINGTYPE);
|
|
break;
|
|
|
|
// Bummer
|
|
default:
|
|
AssertSz(FALSE, "MIME_E_INVALID_ENCODINGTYPE");
|
|
break;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// If Last Buffer, we better be done
|
|
Assert(m_fLastBuffer ? m_rIn.i == m_rIn.cb : TRUE);
|
|
|
|
// Done
|
|
return (hr == S_OK) ? hrWarnings : hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrInternetDecode
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrInternetDecode(BOOL fLastBuffer)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrWarnings=S_OK;
|
|
BLOB rData;
|
|
|
|
// We Better not be an encoder
|
|
Assert(!m_fEncoder);
|
|
|
|
// Set Last Buffer
|
|
m_fLastBuffer = fLastBuffer;
|
|
|
|
// Handle Format
|
|
switch(m_ietEncoding)
|
|
{
|
|
// Binary
|
|
case IET_BINARY:
|
|
case IET_7BIT:
|
|
case IET_8BIT:
|
|
// Better be at zero
|
|
Assert(m_rIn.i == 0);
|
|
|
|
// Initialize Blob to copy
|
|
rData.pBlobData = m_rIn.pb;
|
|
rData.cbSize = m_rIn.cb;
|
|
|
|
// Append to outbound buffer
|
|
CHECKHR(hr = HrAppendBuffer(&m_rOut, &rData, FALSE));
|
|
|
|
// Increment offset
|
|
m_rIn.i = m_rIn.cb = 0;
|
|
break;
|
|
|
|
// Quoted-Printable
|
|
case IET_QP:
|
|
CHECKHR(hr = HrDecodeQP());
|
|
break;
|
|
|
|
// Bas64
|
|
case IET_BASE64:
|
|
CHECKHR(hr = HrDecode64());
|
|
break;
|
|
|
|
// UUENCODE
|
|
case IET_UUENCODE:
|
|
CHECKHR(hr = HrDecodeUU());
|
|
break;
|
|
|
|
// BINHEX
|
|
case IET_BINHEX40:
|
|
CHECKHR(hr = HrDecodeBinHex());
|
|
break;
|
|
|
|
// Bummer
|
|
default:
|
|
AssertSz(FALSE, "MIME_E_INVALID_ENCODINGTYPE");
|
|
break;
|
|
}
|
|
|
|
// Character Set Decoding ?
|
|
if (ICF_CODEPAGE & m_dwFlags)
|
|
{
|
|
// Charset Decoder
|
|
CHECKHR(hr = HrCodePageFromOutToCset());
|
|
if ( S_OK != hr )
|
|
hrWarnings = TrapError(hr);
|
|
}
|
|
|
|
exit:
|
|
// If Last Buffer, we better be done
|
|
Assert(m_fLastBuffer ? m_rIn.i == m_rIn.cb : TRUE);
|
|
|
|
// Done
|
|
return (hr == S_OK) ? hrWarnings : hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrCodePageFromOutToCset
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrCodePageFromOutToCset(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrWarnings=S_OK;
|
|
BLOB rData;
|
|
BLOB rDecoded={0};
|
|
ULONG cbRead;
|
|
|
|
// Nothing to convert...
|
|
if (0 == m_rOut.cb)
|
|
return S_OK;
|
|
|
|
// Setup Convert Blob
|
|
rData.pBlobData = m_rOut.pb;
|
|
rData.cbSize = m_rOut.cb;
|
|
|
|
// Decode text from m_intformat
|
|
hr = g_pInternat->ConvertBuffer(m_cpiSource, m_cpiDest, &rData, &rDecoded, &cbRead);
|
|
if (SUCCEEDED(hr) )
|
|
{
|
|
// save HRESULT from charset conversion
|
|
if ( S_OK != hr )
|
|
hrWarnings = TrapError(hr);
|
|
|
|
// Fill m_rIn...
|
|
CHECKHR(hr = HrAppendBuffer(&m_rCset, &rDecoded, FALSE));
|
|
}
|
|
|
|
// Otherwise, just put m_rCset as the inbound buffer
|
|
else
|
|
{
|
|
// SBAILEY: Raid-74506: MIMEOLE: error decoding text body in q-p encoded iso-2022-jp message
|
|
// CHECKHR(hr = HrAppendBuffer(&m_rCset, &rData, FALSE));
|
|
hr = S_OK;
|
|
|
|
// We read all of it
|
|
cbRead = rData.cbSize;
|
|
}
|
|
|
|
// Adjust m_rOut if cbRead != m_rOut.cb
|
|
if (cbRead != m_rOut.cb)
|
|
{
|
|
// Move Memory
|
|
MoveMemory(m_rOut.pb, m_rOut.pb + cbRead, m_rOut.cb - cbRead);
|
|
}
|
|
|
|
// Decrease Size
|
|
Assert(cbRead <= m_rOut.cb);
|
|
m_rOut.cb -= cbRead;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(rDecoded.pBlobData);
|
|
|
|
// Done
|
|
return (hr == S_OK) ? hrWarnings : hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrCodePageFromCsetToIn
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrCodePageFromCsetToIn(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrWarnings=S_OK;
|
|
BLOB rData;
|
|
BLOB rEncoded={0};
|
|
ULONG cbRead;
|
|
|
|
// Check State
|
|
Assert(m_rCset.i == 0);
|
|
|
|
// Nothing to convert
|
|
if (0 == m_rCset.cb)
|
|
return S_OK;
|
|
|
|
// Setup Convert Blob
|
|
rData.pBlobData = m_rCset.pb;
|
|
rData.cbSize = m_rCset.cb;
|
|
|
|
// Decode text from m_intformat
|
|
hr = g_pInternat->ConvertBuffer(m_cpiSource, m_cpiDest, &rData, &rEncoded, &cbRead);
|
|
if (SUCCEEDED(hr) )
|
|
{
|
|
// save HRESULT from charset conversion
|
|
if ( S_OK != hr )
|
|
hrWarnings = TrapError(hr);
|
|
|
|
// Fill m_rIn...
|
|
CHECKHR(hr = HrAppendBuffer(&m_rIn, &rEncoded, FALSE));
|
|
}
|
|
|
|
// Otherwise, just put m_rCset as the inbound buffer
|
|
else
|
|
{
|
|
// SBAILEY: Raid-74506: MIMEOLE: error decoding text body in q-p encoded iso-2022-jp message
|
|
// CHECKHR(hr = HrAppendBuffer(&m_rIn, &rData, FALSE));
|
|
hr = S_OK;
|
|
|
|
// Set Read
|
|
cbRead = m_rCset.cb;
|
|
}
|
|
|
|
// Adjust m_rOut if cbRead != m_rOut.cb
|
|
if (cbRead != m_rCset.cb)
|
|
{
|
|
// Move Memory
|
|
MoveMemory(m_rCset.pb, m_rCset.pb + cbRead, m_rCset.cb - cbRead);
|
|
}
|
|
|
|
// Decrease Size
|
|
Assert(cbRead <= m_rCset.cb);
|
|
m_rCset.cb -= cbRead;
|
|
m_rCset.i = 0;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeMemFree(rEncoded.pBlobData);
|
|
|
|
// Done
|
|
return (hr == S_OK) ? hrWarnings : hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrEncode64
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrEncode64(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbRead;
|
|
ULONG i;
|
|
UCHAR uch[3];
|
|
UCHAR *pbuf;
|
|
|
|
// Read lines and stuff dots
|
|
while(1)
|
|
{
|
|
// Compute encode buffer length
|
|
cbRead = min(CCHMAX_ENCODE64_IN, m_rIn.cb - m_rIn.i);
|
|
|
|
// Should we encode this buffer ?
|
|
if (0 == cbRead || (cbRead < CCHMAX_ENCODE64_IN && FALSE == m_fLastBuffer))
|
|
goto exit;
|
|
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(&m_rOut, CCHMAX_ENCODE64_OUT))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, CCHMAX_ENCODE64_OUT));
|
|
}
|
|
|
|
// Set Buffer Pointer
|
|
pbuf = (m_rIn.pb + m_rIn.i);
|
|
|
|
// Encodes 3 characters at a time
|
|
for (i=0; i<cbRead; i+=3)
|
|
{
|
|
// Setup Buffer
|
|
uch[0] = pbuf[i];
|
|
uch[1] = (i+1 < cbRead) ? pbuf[i+1] : '\0';
|
|
uch[2] = (i+2 < cbRead) ? pbuf[i+2] : '\0';
|
|
|
|
// Encode first tow
|
|
ConvBuffAppend(g_rgchEncodeBase64[(uch[0] >> 2) & 0x3F]);
|
|
ConvBuffAppend(g_rgchEncodeBase64[(uch[0] << 4 | uch[1] >> 4) & 0x3F]);
|
|
|
|
// Encode Next
|
|
if (i+1 < cbRead)
|
|
ConvBuffAppend(g_rgchEncodeBase64[(uch[1] << 2 | uch[2] >> 6) & 0x3F]);
|
|
else
|
|
ConvBuffAppend('=');
|
|
|
|
// Encode Net
|
|
if (i+2 < cbRead)
|
|
ConvBuffAppend(g_rgchEncodeBase64[(uch[2] ) & 0x3F]);
|
|
else
|
|
ConvBuffAppend('=');
|
|
}
|
|
|
|
// Increment iIn
|
|
m_rIn.i += cbRead;
|
|
|
|
// Ends encoded line and writes to storage
|
|
ConvBuffAppend(chCR);
|
|
ConvBuffAppend(chLF);
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrDecode64
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrDecode64(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
UCHAR uchThis;
|
|
ULONG i;
|
|
ULONG cPad=0;
|
|
ULONG cbRead=0;
|
|
ULONG cbLine;
|
|
BOOL fFound;
|
|
LPSTR pszLine;
|
|
|
|
// Read lines and stuff dots
|
|
while(1)
|
|
{
|
|
// Increment Index
|
|
m_rIn.i += cbRead;
|
|
|
|
// Get Next Line
|
|
pszLine = PszConvBuffGetNextLine(&cbLine, &cbRead, &fFound);
|
|
if (0 == cbRead || (FALSE == fFound && FALSE == m_fLastBuffer))
|
|
goto exit;
|
|
|
|
// Do I need to grow - decoded line will always be smaller than cbLine
|
|
if (FGROWBUFFER(&m_rOut, cbLine))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, cbLine));
|
|
}
|
|
|
|
// Decodes characters in line buffer
|
|
for (i=0; i<cbLine; i++)
|
|
{
|
|
// Gets 4 legal Base64 characters, ignores if illegal
|
|
uchThis = pszLine[i];
|
|
|
|
// Decode It
|
|
m_uchConvert[m_cbConvert] = DECODE64(uchThis);
|
|
|
|
// Test for valid non-pad
|
|
if ((m_uchConvert[m_cbConvert] < 64) || ((uchThis == '=') && (m_cbConvert > 1)))
|
|
m_cbConvert++;
|
|
|
|
// Test for pad
|
|
if ((uchThis == '=') && (m_cbConvert > 1))
|
|
cPad++;
|
|
|
|
// Outputs when 4 legal Base64 characters are in the buffer
|
|
if (4 == m_cbConvert)
|
|
{
|
|
// Validate Buffer
|
|
Assert(m_rOut.cb + 4 <= m_rOut.cbAlloc);
|
|
|
|
// Convert
|
|
if (cPad < 3)
|
|
ConvBuffAppend((m_uchConvert[0] << 2 | m_uchConvert[1] >> 4));
|
|
if (cPad < 2)
|
|
ConvBuffAppend((m_uchConvert[1] << 4 | m_uchConvert[2] >> 2));
|
|
if (cPad < 1)
|
|
ConvBuffAppend((m_uchConvert[2] << 6 | m_uchConvert[3]));
|
|
|
|
// Reset
|
|
m_cbConvert = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrEncodeUU
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrEncodeUU(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbRead, i;
|
|
UCHAR buf[CCHMAX_ENCODEUU_IN];
|
|
|
|
// Read lines and stuff dots
|
|
while(1)
|
|
{
|
|
// Compute encode buffer length
|
|
cbRead = min(CCHMAX_ENCODEUU_IN, m_rIn.cb - m_rIn.i);
|
|
if (0 == cbRead || (cbRead < CCHMAX_ENCODEUU_IN && FALSE == m_fLastBuffer))
|
|
goto exit;
|
|
|
|
// Copy the bytes
|
|
CopyMemory(buf, m_rIn.pb + m_rIn.i, cbRead);
|
|
|
|
// Zero the Rest
|
|
ZeroMemory(buf + cbRead, sizeof(buf) - cbRead);
|
|
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(&m_rOut, CCHMAX_ENCODEUU_OUT))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, CCHMAX_ENCODEUU_OUT));
|
|
}
|
|
|
|
// Encode Line length
|
|
ConvBuffAppend(UUENCODE((UCHAR)cbRead));
|
|
|
|
// Encodes 3 characters at a time
|
|
for (i=0; i<cbRead; i+=3)
|
|
{
|
|
ConvBuffAppend(UUENCODE((buf[i] >> 2)));
|
|
ConvBuffAppend(UUENCODE((buf[i] << 4) | (buf[i+1] >> 4)));
|
|
ConvBuffAppend(UUENCODE((buf[i+1] << 2) | (buf[i+2] >> 6)));
|
|
ConvBuffAppend(UUENCODE((buf[i+2])));
|
|
}
|
|
|
|
// Increment i
|
|
m_rIn.i += cbRead;
|
|
|
|
// Ends encoded line and writes to storage
|
|
ConvBuffAppend(chCR);
|
|
ConvBuffAppend(chLF);
|
|
}
|
|
|
|
exit:
|
|
// If last buffer and we can't read anymore
|
|
if (TRUE == m_fLastBuffer && FALSE == FConvBuffCanRead(m_rIn))
|
|
{
|
|
// RAID-21179: ZeroLength uuencoded attachments m_rOut may not have been allocated
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(&m_rOut, CCHMAX_ENCODEUU_OUT))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, CCHMAX_ENCODEUU_OUT));
|
|
}
|
|
|
|
// Better have space
|
|
Assert(m_rOut.cb + 3 < m_rOut.cbAlloc);
|
|
|
|
// End
|
|
ConvBuffAppend(UUENCODE(0));
|
|
ConvBuffAppend(chCR);
|
|
ConvBuffAppend(chLF);
|
|
}
|
|
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::FUUEncodeThrowAway
|
|
// --------------------------------------------------------------------------------
|
|
BOOL CInternetConverter::FUUEncodeThrowAway(LPSTR pszLine, ULONG cbLine, ULONG *pcbActual, ULONG *pcbLine)
|
|
{
|
|
// Locals
|
|
CHAR ch;
|
|
ULONG cchOffset, cbEncoded, cbTolerance=0, cbExpected;
|
|
|
|
// RAID-25953: "BEGIN --- CUT HERE --- Cut Here --- cut here ---" - WinVN post
|
|
// partial messages that have the following line at the beginning of
|
|
// each partial. B = 66 and the length of this line is 48, so the following
|
|
// code thinks that this line is a valid UUENCODED line, so, to fix this,
|
|
// we will throw out all lines that start with BEGIN since this is not valid
|
|
// to be in uuencode.
|
|
if (StrCmpNI("BEGIN", pszLine, 5) == 0)
|
|
return TRUE;
|
|
|
|
// END Line
|
|
else if (StrCmpNI("END", pszLine, 3) == 0)
|
|
return TRUE;
|
|
|
|
// Checks line length
|
|
ch = *pszLine;
|
|
*pcbLine = cbEncoded = UUDECODE(ch);
|
|
|
|
// Comput tolerance and offset for non-conforming even line lengths
|
|
cchOffset = (cbEncoded % 3);
|
|
if (cchOffset != 0)
|
|
{
|
|
cchOffset++;
|
|
cbTolerance = 4 - cchOffset;
|
|
}
|
|
|
|
// Compute expected line length
|
|
cbExpected = 4 * (cbEncoded / 3) + cchOffset;
|
|
|
|
// Always check for '-'
|
|
if (cbLine < cbExpected)
|
|
return TRUE;
|
|
|
|
// Wack off trailing spaces
|
|
while(pszLine[cbLine-1] == ' ' && cbLine > 0 && cbLine != cbExpected)
|
|
--cbLine;
|
|
|
|
// Checksum character and encoders which include the count char in the line count
|
|
if (cbExpected != cbLine && cbExpected + cbTolerance != cbLine &&
|
|
cbExpected + 1 != cbLine && cbExpected + cbTolerance + 1 != cbLine &&
|
|
cbExpected - 1 != cbLine && cbExpected + cbTolerance - 1 != cbLine)
|
|
return TRUE;
|
|
|
|
// Set actual line length
|
|
*pcbActual = cbLine;
|
|
|
|
// Done
|
|
return FALSE;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrDecodeUU
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrDecodeUU(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbLine;
|
|
LPSTR pszLine;
|
|
ULONG cbRead=0;
|
|
ULONG cbLineLength;
|
|
BOOL fFound;
|
|
ULONG cbConvert;
|
|
ULONG cbScan;
|
|
ULONG i;
|
|
UCHAR uchConvert[4];
|
|
UCHAR uchThis;
|
|
|
|
// Read lines and stuff dots
|
|
while(1)
|
|
{
|
|
// Increment Index
|
|
m_rIn.i += cbRead;
|
|
|
|
// Get Next Line
|
|
pszLine = PszConvBuffGetNextLine(&cbLine, &cbRead, &fFound);
|
|
if (0 == cbRead || (FALSE == fFound && FALSE == m_fLastBuffer))
|
|
goto exit;
|
|
|
|
// UUENCODE ThrowAway
|
|
if (FUUEncodeThrowAway(pszLine, cbLine, &cbLine, &cbLineLength))
|
|
continue;
|
|
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(&m_rOut, cbLineLength + 20))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, cbLineLength + 20));
|
|
}
|
|
|
|
// Decodes 4 characters at a time
|
|
for (cbConvert=0, cbScan=0, i=1; cbScan < cbLineLength; i++)
|
|
{
|
|
// Gets 4 characters, pads with blank if necessary
|
|
uchThis = (i < cbLine) ? pszLine[i] : ' ';
|
|
|
|
// Decode
|
|
uchConvert[cbConvert++] = UUDECODE(uchThis);
|
|
|
|
// Outputs decoded characters
|
|
if (cbConvert == 4)
|
|
{
|
|
// Covnert
|
|
if (cbScan++ < cbLineLength)
|
|
ConvBuffAppend((uchConvert[0] << 2) | (uchConvert[1] >> 4));
|
|
if (cbScan++ < cbLineLength)
|
|
ConvBuffAppend((uchConvert[1] << 4) | (uchConvert[2] >> 2));
|
|
if (cbScan++ < cbLineLength)
|
|
ConvBuffAppend((uchConvert[2] << 6) | (uchConvert[3]));
|
|
|
|
// Reset
|
|
cbConvert = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrEncodeQP
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrEncodeQP(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
UCHAR uchThis;
|
|
ULONG cbLine=0;
|
|
ULONG iCurrent;
|
|
LONG iLastWhite=-1;
|
|
LONG iLineWhite=-1;
|
|
UCHAR szLine[CCHMAX_QPLINE+30];
|
|
|
|
// Set iCurrent
|
|
iCurrent = m_rIn.i;
|
|
|
|
// Read lines and stuff dots
|
|
while (iCurrent < m_rIn.cb)
|
|
{
|
|
// Gets the next character
|
|
uchThis = m_rIn.pb[iCurrent];
|
|
|
|
// End of line...
|
|
if (chLF == uchThis || cbLine > CCHMAX_QPLINE)
|
|
{
|
|
// Soft Line break
|
|
if (chLF != uchThis)
|
|
{
|
|
// Lets back track to last white
|
|
if (iLastWhite != -1)
|
|
{
|
|
cbLine = iLineWhite + 1;
|
|
iCurrent = iLastWhite + 1;
|
|
}
|
|
|
|
// Hex encode the 8bit octet
|
|
Assert(cbLine + 3 <= sizeof(szLine));
|
|
szLine[cbLine++] = '=';
|
|
szLine[cbLine++] = chCR;
|
|
szLine[cbLine++] = chLF;
|
|
}
|
|
|
|
// Otherwise, we may need to encode the last space
|
|
else
|
|
{
|
|
// Encode Straggling '\n'
|
|
if (chCR != m_uchPrev)
|
|
{
|
|
Assert(cbLine + 4 <= sizeof(szLine));
|
|
szLine[cbLine++] = '=';
|
|
szLine[cbLine++] = g_rgchHex[uchThis >> 4];
|
|
szLine[cbLine++] = g_rgchHex[uchThis & 0x0F];
|
|
szLine[cbLine++] = '=';
|
|
}
|
|
|
|
// Detect preceding whitespace ...
|
|
if (cbLine && (' ' == szLine[cbLine - 1] || '\t' == szLine[cbLine - 1]))
|
|
{
|
|
// Hex encode the 8bit octet
|
|
UCHAR chWhite = szLine[cbLine - 1];
|
|
cbLine--;
|
|
Assert(cbLine + 3 <= sizeof(szLine));
|
|
szLine[cbLine++] = '=';
|
|
szLine[cbLine++] = g_rgchHex[chWhite >> 4];
|
|
szLine[cbLine++] = g_rgchHex[chWhite & 0x0F];
|
|
}
|
|
|
|
// Otherwise, hard line break
|
|
Assert(cbLine + 2 <= sizeof(szLine));
|
|
szLine[cbLine++] = chCR;
|
|
szLine[cbLine++] = chLF;
|
|
iCurrent++;
|
|
}
|
|
|
|
// Copy the line
|
|
CHECKHR(hr = HrConvBuffAppendBlock(szLine, cbLine));
|
|
|
|
// Reset
|
|
iLastWhite = -1;
|
|
iLineWhite = -1;
|
|
cbLine = 0;
|
|
*szLine = '\0';
|
|
|
|
// We processed this buffer
|
|
m_rIn.i = iCurrent;
|
|
}
|
|
|
|
// Encode empty '\r'
|
|
else if (chCR == uchThis)
|
|
{
|
|
// Overflow detection
|
|
if (iCurrent + 1 < m_rIn.cb && m_rIn.pb[iCurrent + 1] != chLF || iCurrent + 1 >= m_rIn.cb)
|
|
{
|
|
Assert(cbLine + 3 <= sizeof(szLine));
|
|
szLine[cbLine++] = '=';
|
|
szLine[cbLine++] = g_rgchHex[uchThis >> 4];
|
|
szLine[cbLine++] = g_rgchHex[uchThis & 0x0F];
|
|
}
|
|
|
|
// Next Character
|
|
iCurrent++;
|
|
}
|
|
|
|
// Rule #1: Replace 8-bit and equal signs
|
|
else if (('\t' != uchThis) && (uchThis < 32 || uchThis == 61 || uchThis > 126 || '=' == uchThis))
|
|
{
|
|
// Hex encode the 8bit octet
|
|
Assert(chLF != uchThis);
|
|
Assert(cbLine + 3 <= sizeof(szLine));
|
|
szLine[cbLine++] = '=';
|
|
szLine[cbLine++] = g_rgchHex[uchThis >> 4];
|
|
szLine[cbLine++] = g_rgchHex[uchThis & 0x0F];
|
|
iCurrent++;
|
|
}
|
|
|
|
// Otherwise, write the character
|
|
else
|
|
{
|
|
// Save position of last white space
|
|
if (' ' == uchThis || '\t' == uchThis)
|
|
{
|
|
iLastWhite = iCurrent;
|
|
iLineWhite = cbLine;
|
|
}
|
|
|
|
// Rule #2: Printable literals
|
|
Assert(cbLine + 1 <= sizeof(szLine));
|
|
szLine[cbLine++] = uchThis;
|
|
iCurrent++;
|
|
}
|
|
|
|
// Save Previous Char
|
|
m_uchPrev = uchThis;
|
|
}
|
|
|
|
// Last line
|
|
if (cbLine && m_fLastBuffer)
|
|
{
|
|
// Append the Line
|
|
CHECKHR(hr = HrConvBuffAppendBlock(szLine, cbLine));
|
|
|
|
// Set i
|
|
m_rIn.i = m_rIn.cb;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrDecodeQP
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrDecodeQP(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
UCHAR uchThis;
|
|
UCHAR uchNext1;
|
|
UCHAR uchNext2;
|
|
UCHAR uch1;
|
|
UCHAR uch2;
|
|
|
|
// Read lines and stuff dots
|
|
while (FConvBuffCanRead(m_rIn))
|
|
{
|
|
// bug #35230 - display trash in trident
|
|
// Can I read 2 more characters
|
|
if (FALSE == m_fLastBuffer && m_rIn.i + 2 >= m_rIn.cb)
|
|
break;
|
|
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(&m_rOut, 3))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, 3));
|
|
}
|
|
|
|
// Gets the next character
|
|
uchThis = m_rIn.pb[m_rIn.i];
|
|
|
|
// Determine next couple of characers for end of line detection...
|
|
uchNext1 = (m_rIn.i + 1 < m_rIn.cb) ? m_rIn.pb[m_rIn.i + 1] : '\0';
|
|
uchNext2 = (m_rIn.i + 2 < m_rIn.cb) ? m_rIn.pb[m_rIn.i + 2] : '\0';
|
|
|
|
// Dont break on \r\n
|
|
if (chCR == uchNext1 && chLF == uchNext2 && m_rIn.i + 3 >= m_rIn.cb)
|
|
{
|
|
// If last buffer, then save characters
|
|
if (m_fLastBuffer)
|
|
{
|
|
// If not a soft line break
|
|
if ('=' != uchThis)
|
|
{
|
|
ConvBuffAppend(uchThis);
|
|
ConvBuffAppend(chCR);
|
|
ConvBuffAppend(chLF);
|
|
}
|
|
|
|
// Done
|
|
m_rIn.i += 3;
|
|
}
|
|
|
|
// Done
|
|
goto exit;
|
|
}
|
|
|
|
// If not end of line...
|
|
if ('=' == uchThis)
|
|
{
|
|
// Soft NL
|
|
if (chCR == uchNext1 && chLF == uchNext2)
|
|
{
|
|
// Step over =\r\n
|
|
m_rIn.i += 3;
|
|
}
|
|
|
|
// If not end of line...
|
|
else if (m_rIn.i + 2 < m_rIn.cb)
|
|
{
|
|
// Step Over Equal Sign
|
|
m_rIn.i++;
|
|
|
|
// Convert Hex Characters
|
|
uch1 = ChConvertFromHex(m_rIn.pb[m_rIn.i++]);
|
|
uch2 = ChConvertFromHex(m_rIn.pb[m_rIn.i++]);
|
|
|
|
// Store Hex characters
|
|
if (uch1 == 255 || uch2 == 255)
|
|
ConvBuffAppend('=');
|
|
else
|
|
ConvBuffAppend((uch1 << 4) | uch2);
|
|
}
|
|
|
|
else
|
|
{
|
|
// Last Buffer ?
|
|
ConvBuffAppend(uchThis);
|
|
m_rIn.i++;
|
|
}
|
|
}
|
|
|
|
// Otherwise store the character
|
|
else if (chCR == uchThis && chLF == uchNext1)
|
|
{
|
|
// Stuff CRLF
|
|
ConvBuffAppend(chCR);
|
|
ConvBuffAppend(chLF);
|
|
|
|
// Increment i
|
|
m_rIn.i += 2;
|
|
}
|
|
|
|
// Otherwise, store the character
|
|
else
|
|
{
|
|
ConvBuffAppend(uchThis);
|
|
m_rIn.i++;
|
|
}
|
|
|
|
// Set Previous
|
|
m_uchPrev = uchThis;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrWrapInternetTextA
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrWrapInternetTextA(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LONG cchLine;
|
|
LONG cchSkip;
|
|
|
|
// Read lines and stuff dots
|
|
while(FConvBuffCanRead(m_rIn))
|
|
{
|
|
// Not enough to encode a full line and not the last buffer
|
|
if ((FALSE == m_fLastBuffer) && ((LONG)(m_rIn.cb - m_rIn.i) < m_cchMaxLine))
|
|
goto exit;
|
|
|
|
// Call LineBreaker
|
|
if (*((CHAR*)(m_rIn.pb + m_rIn.i)) == '\0')
|
|
{
|
|
// This is to prevent the endless loop in case of malformed data stream
|
|
hr = TrapError(MIME_E_BAD_TEXT_DATA);
|
|
goto exit;
|
|
}
|
|
|
|
CHECKHR(hr = m_pLineBreak->BreakLineA(m_lcid, m_cpiSource, (LPCSTR)(m_rIn.pb + m_rIn.i), (m_rIn.cb - m_rIn.i), m_cchMaxLine, &cchLine, &cchSkip));
|
|
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(&m_rOut, cchLine + 5))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, cchLine + 5));
|
|
}
|
|
|
|
// Have some data ?
|
|
if (cchLine)
|
|
{
|
|
// Write the line
|
|
CHECKHR(hr = HrConvBuffAppendBlock(m_rIn.pb + m_rIn.i, cchLine));
|
|
}
|
|
|
|
// Write CRLF
|
|
Assert(m_rOut.cb + 2 < m_rOut.cbAlloc);
|
|
ConvBuffAppend(chCR);
|
|
ConvBuffAppend(chLF);
|
|
|
|
// Increment iText
|
|
m_rIn.i += (cchLine + cchSkip);
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CInternetConverter::_GetEndOfURL(IN LPCWSTR pszLine, DWORD cchSize, DWORD * pdwMax)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD cchCurrent = 0;
|
|
|
|
for (cchCurrent = 0; cchCurrent < cchSize; cchCurrent++)
|
|
{
|
|
if ((L' ' == pszLine[cchCurrent]) ||
|
|
(L'\r' == pszLine[cchCurrent]))
|
|
{
|
|
(*pdwMax) = (cchCurrent + 2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CInternetConverter::_FixLineBreakingProblems(
|
|
IN LCID locale, IN const WCHAR* pszSrc,
|
|
IN long cchSrc, IN long cMaxColumns,
|
|
OUT long* pcchLine, OUT long* pcchSkip,
|
|
BOOL * pfDoURLFix)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// There was a bug where a signature marker, which is '-- '
|
|
// (dash, dash, space, end-of-line) would get stripped out.
|
|
// This happens in ILineBreak::BreakLineW(). It will strip off
|
|
// the extra space thinking it is just extra white space.
|
|
if ((3 <= cchSrc) &&
|
|
(m_rIn.cb >= 10) &&
|
|
(2 <= *pcchLine) &&
|
|
(1 <= *pcchSkip) &&
|
|
(L'-' == pszSrc[*pcchLine - 2]) &&
|
|
(L'-' == pszSrc[*pcchLine - 1]) &&
|
|
(L' ' == pszSrc[*pcchLine - 0]))
|
|
{
|
|
(*pcchLine)++;
|
|
(*pcchSkip)--;
|
|
// DebugTrace("MimeOLE - Sig Delimiter: Preserved.\n");
|
|
}
|
|
|
|
// We do not want to wrap if that causes a break in URLs.
|
|
// This is bad because when the receiver's newsgroup reader
|
|
// turns the URL into a hyperlink, it will no longer point
|
|
// to the right location because part of the URL is missing.
|
|
// This happens often with urls that contain '=' or '/', like:
|
|
// http://www.amazon.com/exec/obidos/ASIN/B0000633EM/qid=1027792220/sr=8-3/ref=sr_8_3/104-5930498-2421552
|
|
// http://www.amazon.com/exec/obidos/tg/stores/detail/-/electronics/B0000633EM/reviews/ref=e_wlt1_de_a_er/104-5930498-2421552#
|
|
if ((5 <= *pcchLine) &&
|
|
(cchSrc > *pcchLine) && // Make sure this isn't the end of the line.
|
|
(L' ' != pszSrc[*pcchLine]) &&
|
|
(L'\r' != pszSrc[*pcchLine])) // We worry if the char after this break isn't a space.
|
|
{
|
|
WCHAR szUrl[50]; // We only need the first part.
|
|
WCHAR szScheme[30];
|
|
DWORD cchScheme = ARRAYSIZE(szScheme);
|
|
|
|
StrCpyNW(szUrl, pszSrc, (int) min(ARRAYSIZE(szUrl), *pcchLine));
|
|
HRESULT hrUrlPart = UrlGetPartW(szUrl, szScheme, &cchScheme, URL_PART_SCHEME, 0);
|
|
if ((S_OK == hrUrlPart) &&
|
|
szScheme[0] &&
|
|
(!StrCmpIW(szScheme, L"http") ||
|
|
!StrCmpIW(szScheme, L"https") ||
|
|
!StrCmpIW(szScheme, L"mailto") ||
|
|
!StrCmpIW(szScheme, L"file") ||
|
|
!StrCmpIW(szScheme, L"news") ||
|
|
!StrCmpIW(szScheme, L"nntp") ||
|
|
!StrCmpIW(szScheme, L"telnet") ||
|
|
!StrCmpIW(szScheme, L"ftp")))
|
|
{
|
|
*pfDoURLFix = TRUE;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrWrapInternetTextW
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrWrapInternetTextW(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
LONG cchLine;
|
|
LONG cchSkip;
|
|
LPCWSTR pszNext = NULL;
|
|
BOOL fFollowingURLFix = FALSE;
|
|
|
|
// Invalid State
|
|
Assert(m_pLineBreak);
|
|
|
|
// Read lines and stuff dots
|
|
while(FConvBuffCanRead(m_rIn))
|
|
{
|
|
DWORD cchCurrentLineLen = ((m_rIn.cb - m_rIn.i) / sizeof(WCHAR));
|
|
|
|
pszNext = (LPCWSTR)(m_rIn.pb + m_rIn.i);
|
|
|
|
// Not enough to encode a full line and not the last buffer
|
|
if ((FALSE == m_fLastBuffer) && ((LONG)cchCurrentLineLen < m_cchMaxLine))
|
|
goto exit;
|
|
|
|
// Call LineBreaker
|
|
if (pszNext[0] == L'\0')
|
|
{
|
|
// This is to prevent the endless loop in case of malformed data stream
|
|
hr = TrapError(MIME_E_BAD_TEXT_DATA);
|
|
goto exit;
|
|
}
|
|
|
|
DWORD cchMax = m_cchMaxLine;
|
|
|
|
if (fFollowingURLFix)
|
|
{
|
|
_GetEndOfURL(pszNext, cchCurrentLineLen, &cchMax);
|
|
fFollowingURLFix = FALSE;
|
|
}
|
|
|
|
CHECKHR(hr = m_pLineBreak->BreakLineW(m_lcid, pszNext, cchCurrentLineLen, cchMax, &cchLine, &cchSkip));
|
|
|
|
BOOL fDoURLFix = FALSE;
|
|
_FixLineBreakingProblems(m_lcid, pszNext, cchCurrentLineLen, m_cchMaxLine, &cchLine, &cchSkip, &fDoURLFix);
|
|
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(&m_rOut, ((cchLine + 5) * sizeof(WCHAR))))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, ((cchLine + 5) * sizeof(WCHAR))));
|
|
}
|
|
|
|
// Have some data
|
|
if (cchLine)
|
|
{
|
|
// Write the line
|
|
CHECKHR(hr = HrConvBuffAppendBlock((BYTE *) pszNext, (cchLine * sizeof(WCHAR))));
|
|
}
|
|
|
|
// Write CRLF
|
|
Assert(m_rOut.cb + (2 * sizeof(WCHAR)) < m_rOut.cbAlloc);
|
|
if (!fDoURLFix)
|
|
{
|
|
ConvBuffAppendW(wchCR);
|
|
ConvBuffAppendW(wchLF);
|
|
}
|
|
else
|
|
{
|
|
fFollowingURLFix = TRUE;
|
|
}
|
|
|
|
// Increment iText
|
|
m_rIn.i += ((cchLine + cchSkip) * sizeof(WCHAR));
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrEncodeDecodeBinhex
|
|
// --------------------------------------------------------------------------------
|
|
const CHAR szBINHEXSTART[] = "(This file must be converted with BinHex";
|
|
const ULONG cbBINHEXSTART = ARRAYSIZE(szBINHEXSTART)-1;
|
|
HRESULT CInternetConverter::HrEncodeBinhex(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
HRESULT hrError;
|
|
ULONG cbLeft;
|
|
ULONG cbRead;
|
|
ULONG cbMaxEncode;
|
|
ULONG cbWrite;
|
|
|
|
// cbLeft
|
|
cbLeft = m_rIn.cb - m_rIn.i;
|
|
|
|
// cbMaxEncode - this should always insure enough room
|
|
cbMaxEncode = cbLeft * 2;
|
|
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(&m_rOut, cbMaxEncode))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rOut, cbMaxEncode));
|
|
}
|
|
|
|
// Set max amount to read
|
|
cbRead = cbLeft;
|
|
|
|
// Set max amount to write
|
|
cbWrite = cbLeft;
|
|
|
|
// We better want to read some
|
|
Assert(cbRead && cbWrite);
|
|
|
|
// Encode/Decode some data
|
|
if (m_fEncoder)
|
|
{
|
|
// Encode
|
|
if (ERROR_SUCCESS != m_pBinhexEncode->HrEmit(m_rIn.pb + m_rIn.i, &cbRead, m_rOut.pb + m_rOut.cb, &cbWrite))
|
|
{
|
|
hr = TrapError(E_FAIL);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
// Increment Amount Read
|
|
m_rIn.i += cbRead;
|
|
|
|
// Increment Amount Wrote
|
|
m_rOut.cb += cbWrite;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrBinhexThrowAway
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrBinhexDecodeBuffAppend(UCHAR uchIn, ULONG cchIn, ULONG cchLeft, ULONG * pcbProduced)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
ULONG cbPad = 0;
|
|
LPBYTE pbBinHex = NULL;
|
|
|
|
if (m_eBinHexStateDec == sHDRFILESIZE)
|
|
{
|
|
// First incoming character is always the size of the stream.
|
|
Assert(cchIn == 1);
|
|
if ((uchIn < 1) || (uchIn > 63))
|
|
{
|
|
hr = E_FAIL; // ERROR_INVALID_DATA
|
|
m_eBinHexStateDec = sENDED;
|
|
goto exit;
|
|
}
|
|
|
|
// Allocate the binhex header
|
|
if (FGROWBUFFER(&m_rBinhexHeader, cbMinBinHexHeader + uchIn))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rBinhexHeader, cbMinBinHexHeader + uchIn));
|
|
}
|
|
|
|
// Mark how many characters are left to process
|
|
m_cbToProcess = cbMinBinHexHeader + uchIn;
|
|
|
|
// Switch to filling the header sHEADER
|
|
m_prBinhexOutput = &m_rBinhexHeader;
|
|
m_eBinHexStateDec = sHEADER;
|
|
}
|
|
|
|
if (1 == cchIn)
|
|
{
|
|
m_prBinhexOutput->pb[m_prBinhexOutput->cb++] = uchIn;
|
|
}
|
|
else
|
|
{
|
|
// Check output buffer for space
|
|
if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cchIn))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cchIn));
|
|
}
|
|
|
|
// Fill output buffer
|
|
FillMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb), cchIn, uchIn);
|
|
m_prBinhexOutput->cb += cchIn;
|
|
}
|
|
|
|
// Are we done processing this fork?
|
|
if (m_cbToProcess <= (LONG) cchIn)
|
|
{
|
|
switch (m_eBinHexStateDec)
|
|
{
|
|
case sHEADER:
|
|
// Verify that we have the correct CRC
|
|
m_wCRC = 0;
|
|
|
|
BinHexCalcCRC16((LPBYTE) m_rBinhexHeader.pb, cbMinBinHexHeader + *(m_rBinhexHeader.pb) - 2, &(m_wCRC));
|
|
BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
|
|
|
|
if ( HIBYTE( m_wCRC ) != m_rBinhexHeader.pb[cbMinBinHexHeader + *(m_rBinhexHeader.pb) - 2]
|
|
|| LOBYTE( m_wCRC ) != m_rBinhexHeader.pb[cbMinBinHexHeader + *(m_rBinhexHeader.pb) - 1] )
|
|
{
|
|
hr = E_FAIL; // ERROR_INVALID_DATA
|
|
goto exit;
|
|
}
|
|
|
|
m_wCRC = 0;
|
|
*pcbProduced = 0;
|
|
|
|
// Switch to using the correct buffer
|
|
m_prBinhexOutput = &m_rOut;
|
|
cchIn -= m_cbToProcess;
|
|
|
|
// Save off the size of the two forks
|
|
pbBinHex = m_rBinhexHeader.pb + m_rBinhexHeader.pb[0] + cbMinBinHexHeader - 10;
|
|
m_cbDataFork = NATIVE_LONG_FROM_BIG(pbBinHex);
|
|
m_cbResourceFork =NATIVE_LONG_FROM_BIG(pbBinHex + 4);
|
|
|
|
if (FALSE == m_fDataForkOnly)
|
|
{
|
|
// Copy extra data into new buffer
|
|
if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cchIn + sizeof(MACBINARY)))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cchIn + sizeof(MACBINARY)));
|
|
}
|
|
|
|
// Write out the MacBinary header
|
|
CHECKHR(hr = HrCreateMacBinaryHeader(&m_rBinhexHeader, m_prBinhexOutput));
|
|
}
|
|
|
|
if (m_cbDataFork > 0)
|
|
{
|
|
// Fill output buffer
|
|
FillMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb), cchIn, uchIn);
|
|
m_prBinhexOutput->cb += cchIn;
|
|
|
|
// delete binhex header buffer
|
|
SafeMemFree(m_rBinhexHeader.pb);
|
|
ZeroMemory(&m_rBinhexHeader, sizeof(CONVERTBUFFER));
|
|
|
|
m_cbToProcess = m_cbDataFork;
|
|
|
|
// Switch to doing the data fork.
|
|
m_eBinHexStateDec = sDATA;
|
|
}
|
|
else
|
|
{
|
|
BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
|
|
|
|
// Save off the CRC until we can get the CRC from the fork.
|
|
m_wCRCForFork = m_wCRC;
|
|
|
|
m_prBinhexOutput = &m_rBinhexHeader;
|
|
|
|
// Remove the HEADER from the buffer
|
|
FillMemory(m_prBinhexOutput->pb, cchIn, uchIn);
|
|
m_prBinhexOutput->cb = cchIn;
|
|
|
|
// Switch to filling the data CRC
|
|
m_cbToProcess = 2;
|
|
m_eBinHexStateDec = sDATACRC;
|
|
|
|
}
|
|
break;
|
|
|
|
case sDATA:
|
|
// Verify that we have the correct CRC
|
|
BinHexCalcCRC16((LPBYTE) m_prBinhexOutput->pb + m_prBinhexOutput->cb - cchIn - *pcbProduced,
|
|
m_cbToProcess + *pcbProduced, &(m_wCRC));
|
|
BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
|
|
|
|
// Save off the CRC until we can get the CRC from the fork.
|
|
m_wCRCForFork = m_wCRC;
|
|
m_wCRC = 0;
|
|
*pcbProduced = 0;
|
|
cchIn -= m_cbToProcess;
|
|
|
|
// Switch to the proper buffer for CRC calculations
|
|
if (FGROWBUFFER(&m_rBinhexHeader, cchLeft + cchIn))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rBinhexHeader, cchLeft + cchIn));
|
|
}
|
|
|
|
// Move any current bytes so we don't overwrite anything
|
|
CopyMemory((m_rBinhexHeader.pb + m_rBinhexHeader.cb),
|
|
(m_prBinhexOutput->pb + m_prBinhexOutput->cb), cchIn);
|
|
m_rBinhexHeader.cb += cchIn;
|
|
|
|
// We only need to pad for a real Mac file...
|
|
if (FALSE == m_fDataForkOnly)
|
|
{
|
|
// Check to see if the size of the fork is a multiple of 128?
|
|
cbPad = 128 - (m_cbDataFork % 128);
|
|
if (cbPad != 0)
|
|
{
|
|
uchIn = '\0';
|
|
|
|
// Check output buffer for space
|
|
if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cbPad - cchIn))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cbPad - cchIn));
|
|
}
|
|
|
|
// Fill output buffer
|
|
FillMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb - cchIn), cbPad, uchIn);
|
|
m_prBinhexOutput->cb += cbPad - cchIn;
|
|
}
|
|
}
|
|
|
|
// Switch to filling the data fork CRC
|
|
m_prBinhexOutput = &m_rBinhexHeader;
|
|
m_cbToProcess = 2;
|
|
m_eBinHexStateDec = sDATACRC;
|
|
|
|
break;
|
|
|
|
case sDATACRC:
|
|
if ( HIBYTE( m_wCRCForFork ) != m_prBinhexOutput->pb[0]
|
|
|| LOBYTE( m_wCRCForFork ) != m_prBinhexOutput->pb[1] )
|
|
{
|
|
hr = E_FAIL; // ERROR_INVALID_DATA
|
|
goto exit;
|
|
}
|
|
|
|
m_wCRC = 0;
|
|
cchIn -= m_cbToProcess;
|
|
*pcbProduced = 0;
|
|
|
|
if (m_cbResourceFork > 0)
|
|
{
|
|
m_prBinhexOutput = &m_rOut;
|
|
|
|
// Switch to the proper buffer for CRC calculations
|
|
if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cchIn))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cchIn));
|
|
}
|
|
|
|
// Move any current bytes so we don't overwrite anything
|
|
CopyMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb),
|
|
(m_rBinhexHeader.pb + m_rBinhexHeader.cb), cchIn);
|
|
m_prBinhexOutput->cb += cchIn;
|
|
|
|
// delete binhex header buffer
|
|
SafeMemFree(m_rBinhexHeader.pb);
|
|
ZeroMemory(&m_rBinhexHeader, sizeof(CONVERTBUFFER));
|
|
|
|
// Switch to filling the resource fork
|
|
if (FALSE == m_fDataForkOnly)
|
|
{
|
|
m_cbToProcess = m_cbResourceFork;
|
|
m_eBinHexStateDec = sRESOURCE;
|
|
}
|
|
else
|
|
{
|
|
m_cbToProcess = 0x0;
|
|
m_eBinHexStateDec = sENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Set the CRC for the data fork.
|
|
BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
|
|
|
|
// Save off the CRC until we can get the CRC from the fork.
|
|
m_wCRCForFork = m_wCRC;
|
|
|
|
// Remove the DATA CRC from the buffer
|
|
MoveMemory(m_prBinhexOutput->pb, m_prBinhexOutput->pb + 2, m_prBinhexOutput->cb - 2);
|
|
m_prBinhexOutput->cb -= 2;
|
|
|
|
// Switch to filling the resource CRC
|
|
m_cbToProcess = 2;
|
|
m_eBinHexStateDec = sRESOURCECRC;
|
|
}
|
|
break;
|
|
|
|
case sRESOURCE:
|
|
// Verify that we have the correct CRC
|
|
BinHexCalcCRC16((LPBYTE) m_prBinhexOutput->pb + m_prBinhexOutput->cb - cchIn - *pcbProduced,
|
|
m_cbToProcess + *pcbProduced, &(m_wCRC));
|
|
BinHexCalcCRC16((LPBYTE) &wBinHexZero, sizeof(wBinHexZero), &(m_wCRC));
|
|
|
|
// Save off the CRC until we can get the CRC from the fork.
|
|
m_wCRCForFork = m_wCRC;
|
|
m_wCRC = 0;
|
|
*pcbProduced = 0;
|
|
cchIn -= m_cbToProcess;
|
|
|
|
// Switch to the proper buffer for CRC calculations
|
|
if (FGROWBUFFER(&m_rBinhexHeader, cchLeft + cchIn))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(&m_rBinhexHeader, cchLeft + cchIn));
|
|
}
|
|
|
|
// Move any current bytes so we don't overwrite anything
|
|
CopyMemory((m_rBinhexHeader.pb + m_rBinhexHeader.cb),
|
|
(m_prBinhexOutput->pb + m_prBinhexOutput->cb), cchIn);
|
|
m_rBinhexHeader.cb += cchIn;
|
|
|
|
// Check to see if the size of the fork is a multiple of 128?
|
|
cbPad = 128 - (m_cbResourceFork % 128);
|
|
if (cbPad != 0)
|
|
{
|
|
uchIn = '\0';
|
|
|
|
// Check output buffer for space
|
|
if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cbPad - cchIn))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cbPad - cchIn));
|
|
}
|
|
|
|
// Fill output buffer
|
|
FillMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb - cchIn), cbPad, uchIn);
|
|
m_prBinhexOutput->cb += cbPad - cchIn;
|
|
}
|
|
|
|
// Switch to filling the resource fork CRC
|
|
m_prBinhexOutput = &m_rBinhexHeader;
|
|
m_cbToProcess = 2;
|
|
m_eBinHexStateDec = sRESOURCECRC;
|
|
break;
|
|
|
|
case sRESOURCECRC:
|
|
if ( HIBYTE( m_wCRCForFork ) != m_prBinhexOutput->pb[0]
|
|
|| LOBYTE( m_wCRCForFork ) != m_prBinhexOutput->pb[1] )
|
|
{
|
|
hr = E_FAIL; // ERROR_INVALID_DATA
|
|
goto exit;
|
|
}
|
|
|
|
m_wCRC = 0;
|
|
cchIn -= m_cbToProcess;
|
|
m_prBinhexOutput = &m_rOut;
|
|
*pcbProduced = 0;
|
|
|
|
// Switch to the proper buffer for CRC calculations
|
|
if (FGROWBUFFER(m_prBinhexOutput, cchLeft + cchIn))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cchLeft + cchIn));
|
|
}
|
|
|
|
// Move any current bytes so we don't overwrite anything
|
|
CopyMemory((m_prBinhexOutput->pb + m_prBinhexOutput->cb),
|
|
(m_rBinhexHeader.pb + m_rBinhexHeader.cb), cchIn);
|
|
m_prBinhexOutput->cb += cchIn;
|
|
|
|
// delete binhex header buffer
|
|
SafeMemFree(m_rBinhexHeader.pb);
|
|
ZeroMemory(&m_rBinhexHeader, sizeof(CONVERTBUFFER));
|
|
|
|
// Switch to filling the resource fork
|
|
m_cbToProcess = 0x0;
|
|
m_eBinHexStateDec = sENDING;
|
|
break;
|
|
|
|
default:
|
|
Assert(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_cbToProcess -= cchIn;
|
|
|
|
*pcbProduced += cchIn;
|
|
|
|
hr = S_OK;
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrBinhexThrowAway
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrBinhexThrowAway(LPSTR pszLine, ULONG cbLine)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (m_eBinHexStateDec == sSTARTING)
|
|
{
|
|
// Ingore all lines before we start that only have whitespace characters
|
|
// or the start tag.
|
|
hr = S_OK;
|
|
|
|
for (LPSTR pszEnd = pszLine + cbLine; pszLine < pszEnd; pszLine++)
|
|
{
|
|
if (!FBINHEXRETURN(*pszLine))
|
|
{
|
|
// Need to ignore lines that start with the tag
|
|
if (((ULONG)(pszEnd - pszLine) >= cbBINHEXSTART) && (StrCmpNI(szBINHEXSTART, pszLine, cbBINHEXSTART) == 0))
|
|
{
|
|
m_eBinHexStateDec = sSTARTED;
|
|
break;
|
|
}
|
|
|
|
// We must have gotten bad data
|
|
hr = E_FAIL; // ERROR_INVALID_DATA
|
|
m_eBinHexStateDec = sENDED;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
}
|
|
else if (m_eBinHexStateDec == sENDED)
|
|
{
|
|
// We can ignore any lines after we are done.
|
|
hr = S_OK;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CInternetConverter::HrDecodeBinHex
|
|
// --------------------------------------------------------------------------------
|
|
HRESULT CInternetConverter::HrDecodeBinHex(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ULONG cbLine;
|
|
LPSTR pszLine;
|
|
ULONG cbRead=0;
|
|
ULONG cbLineLength;
|
|
BOOL fFound;
|
|
ULONG cbConvert;
|
|
ULONG cbScan;
|
|
ULONG i;
|
|
UCHAR uchConvert[4];
|
|
UCHAR uchThis;
|
|
UCHAR uchDecoded;
|
|
UCHAR cuchWrite;
|
|
UCHAR rgbShift[] = {0, 4, 2, 0};
|
|
ULONG cbProduced = 0;
|
|
|
|
// Read lines and stuff dots
|
|
while(1)
|
|
{
|
|
// Increment Index
|
|
m_rIn.i += cbRead;
|
|
|
|
// Get Next Line
|
|
pszLine = PszConvBuffGetNextLine(&cbLine, &cbRead, &fFound);
|
|
if (0 == cbRead || (FALSE == fFound && FALSE == m_fLastBuffer))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// UUENCODE ThrowAway
|
|
hr = HrBinhexThrowAway(pszLine, cbLine);
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit;
|
|
}
|
|
else if (S_OK == hr)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
// Do I need to grow
|
|
if (FGROWBUFFER(m_prBinhexOutput, cbLine + 20))
|
|
{
|
|
// Grow the buffer
|
|
CHECKHR(hr = HrGrowBuffer(m_prBinhexOutput, cbLine + 20));
|
|
}
|
|
|
|
AssertSz((m_eBinHexStateDec != sSTARTING) && (m_eBinHexStateDec != sENDED),
|
|
"Why haven't we found the start of the stream yet??\n");
|
|
|
|
// Decodes characters in line buffer
|
|
for (i=0; i<cbLine; i++)
|
|
{
|
|
uchThis = pszLine[i];
|
|
|
|
// Check for valid white space
|
|
if (FBINHEXRETURN(uchThis))
|
|
continue;
|
|
|
|
// Check for start or end of stream
|
|
if (BINHEX_TERM == uchThis)
|
|
{
|
|
if (m_eBinHexStateDec == sSTARTED)
|
|
{
|
|
m_eBinHexStateDec = sHDRFILESIZE;
|
|
continue;
|
|
}
|
|
else if (m_eBinHexStateDec == sENDING)
|
|
{
|
|
m_eBinHexStateDec = sENDED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_eBinHexStateDec == sENDING)
|
|
{
|
|
if (('!' == uchThis) || (TRUE == m_fDataForkOnly))
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// ensure that we're not in an invalid state. If we made it to sENDING and we got
|
|
// valid CRCs and everything is hunky dory, just ignore the terminating stuff.
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Decode It
|
|
uchDecoded = DECODEBINHEX(uchThis);
|
|
|
|
// Test for valid char
|
|
if (uchDecoded == BINHEX_INVALID)
|
|
{
|
|
hr = E_FAIL; // ERROR_INVALID_DATA
|
|
goto exit;
|
|
}
|
|
|
|
if ( m_cAccum == 0 )
|
|
{
|
|
m_ulAccum = uchDecoded;
|
|
++m_cAccum;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
m_ulAccum = ( m_ulAccum << 6 ) | uchDecoded;
|
|
uchDecoded = (BYTE)(m_ulAccum >> rgbShift[m_cAccum]) & 0xff;
|
|
m_cAccum++;
|
|
m_cAccum %= sizeof(m_ulAccum);
|
|
}
|
|
|
|
// If we are repeating then fill the buffer with char
|
|
if (m_fRepeating)
|
|
{
|
|
m_fRepeating = FALSE;
|
|
|
|
// Check to see if it's just a literal 0x90
|
|
if (0x00 == uchDecoded)
|
|
{
|
|
// Just write out one BINHEX_REPEAT char
|
|
m_uchPrev = BINHEX_REPEAT;
|
|
cuchWrite = 1;
|
|
}
|
|
else
|
|
{
|
|
cuchWrite = uchDecoded - 1;
|
|
}
|
|
}
|
|
|
|
// Check for repeat character
|
|
else if (BINHEX_REPEAT == uchDecoded)
|
|
{
|
|
m_fRepeating = TRUE;
|
|
continue;
|
|
}
|
|
|
|
// Else it's just a normal character.
|
|
else
|
|
{
|
|
m_uchPrev = uchDecoded;
|
|
cuchWrite = 1;
|
|
}
|
|
|
|
CHECKHR(HrBinhexDecodeBuffAppend(m_uchPrev, cuchWrite, cbLine - i, &cbProduced));
|
|
}
|
|
|
|
BinHexCalcCRC16((LPBYTE) m_prBinhexOutput->pb + m_prBinhexOutput->cb - cbProduced, cbProduced, &(m_wCRC));
|
|
cbProduced = 0;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
// Done
|
|
return hr;
|
|
}
|
|
|