Leaked source code of windows server 2003
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.
 
 
 
 
 
 

752 lines
25 KiB

/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1993-1996 Microsoft Corporation. All Rights Reserved.
//
// MODULE: URL.cpp
//
// PURPOSE: All the URL parsing routines THOR would ever need.
//
#include "pch.hxx"
#include "strconst.h"
#include "urltest.h"
#include "url.h"
#include "xpcomm.h"
#include <shlwapi.h>
#include <shlwapip.h>
#include "mimeole.h"
#include <urlmon.h>
#include <wininet.h>
#include "imnact.h"
#include "demand.h"
#include <mlang.h>
//
// FUNCTION: URL_ParseNewsUrls
//
// PURPOSE: Takes a URL passed to the news view and validates it. If the
// URL is valid, then the server, group, and article-id are
// returned as appropriate.
//
// PARAMETERS:
// pszURL - Pointer to the URL to parse.
// ppszServer - Name of the server, this function allocates the memory.
// puPort - Port number on the server to use.
// ppszGroup - Name of the group, this function allocates the memory.
// ppszArticle - Article id, this function allocates the memory.
// pfSecure - whether to use SSL to connect
//
// RETURN VALUE:
// Returns S_OK if the URL is valid, or an appropriate error code
// otherwise.
//
// COMMENTS:
// The URLs that are valid for news are:
//
// news:<newsgroup-name>
// news:<article-id>
// news://<server> (for Netscape compatibility)
// news://<server>/ (for URL.DLL compatibility)
// news://<server>/<newsgroup-name>
// news://<server>/<article-id>
// nntp://<host>:<port>/<newsgroup-name>/<article-id>
//
// $LOCALIZE - Need a separate code path for DBCS
HRESULT URL_ParseNewsUrls(LPTSTR pszURL, LPTSTR* ppszServer, LPUINT puPort,
LPTSTR* ppszGroup, LPTSTR* ppszArticle, LPBOOL pfSecure)
{
HRESULT hr;
UINT cchBuffer ;
LPTSTR pszBuffer,
pszTemp;
Assert(pszURL != NULL);
// Allocate a temp buffer to work with.
cchBuffer = lstrlen(pszURL) + sizeof(TCHAR);
if (!MemAlloc((LPVOID*)&pszBuffer, cchBuffer))
return E_OUTOFMEMORY;
ZeroMemory(pszBuffer, cchBuffer);
// Loop through the URL looking for the first ":". We're trying to discern
// what the prefix is - either "nntp" or "news".
pszTemp = pszURL;
while (*pszTemp && *pszTemp != TEXT(':'))
pszTemp++;
CopyMemory(pszBuffer, pszURL, ((LPBYTE) pszTemp - (LPBYTE) pszURL));
*ppszServer = NULL;
*ppszGroup = NULL;
*ppszArticle = NULL;
*puPort = (UINT) -1;
*pfSecure = FALSE;
if (0 == lstrcmpi(pszBuffer, c_szURLNews))
{
// The URL starts with "news:", so advance the pointer past the ":"
// and pass what's left to the appropriate parser.
pszTemp++;
hr = URL_ParseNEWS(pszTemp, ppszServer, ppszGroup, ppszArticle);
}
else if (0 == lstrcmpi(pszBuffer, c_szURLNNTP))
{
// The URL starts with "nntp:", so advance the pointer past the ":"
// and pass what's left to the appropriate parser.
pszTemp++;
hr = URL_ParseNNTP(pszTemp, ppszServer, puPort, ppszGroup, ppszArticle);
}
else if (0 == lstrcmpi(pszBuffer, c_szURLSnews))
{
// The URL starts with "snews:", so advance the pointer past the ":"
// and pass what's left to the appropriate parser.
pszTemp++;
*pfSecure = TRUE;
hr = URL_ParseNEWS(pszTemp, ppszServer, ppszGroup, ppszArticle);
}
else
{
// this protocol is not a supported NEWS protocol
hr = INET_E_UNKNOWN_PROTOCOL;
}
MemFree(pszBuffer);
return hr;
}
// $LOCALIZE - Need a separate code path for DBCS
HRESULT URL_ParseNEWS(LPTSTR pszURL, LPTSTR* ppszServer, LPTSTR* ppszGroup,
LPTSTR* ppszArticle)
{
LPTSTR pszBuffer;
LPTSTR pszBegin;
UINT cch = 0;
if (pszURL == NULL || *pszURL == '\0')
return INET_E_INVALID_URL;
// First check to see if a server has been specified. If so, then the
// first two characters will be "//".
if (*pszURL == TEXT('/'))
{
// Make sure there are two '/'
pszURL++;
if (*pszURL != TEXT('/'))
return INET_E_INVALID_URL;
pszURL++;
pszBegin = pszURL;
// Ok, got a server name. Find the end and copy it to ppszServer.
while (*pszURL && (*pszURL != TEXT('/')))
pszURL++;
cch = (UINT) ((LPBYTE) pszURL - (LPBYTE) pszBegin) + sizeof(TCHAR);
if (cch <= 1)
return S_OK; // bug 12467
if (!MemAlloc((LPVOID*) ppszServer, cch))
return E_OUTOFMEMORY;
ZeroMemory(*ppszServer, cch);
CopyMemory(*ppszServer, pszBegin, cch - sizeof(TCHAR));
// if we found the last '/' skip over it
if (*pszURL)
pszURL++;
//
// NOTE: This code makes the following URLs valid, taking us to the
// root node for the server.
//
// news://<server>
// news://<server>/
//
// The first form is necessary for compatibility with Netscape, and
// the second form is necessary because URL.DLL adds the trailing
// slash before passing the first form to us.
//
// If we're at the end, fake a news://server/* URL.
if (!*pszURL)
pszURL = (LPTSTR)g_szAsterisk;
}
// The difference between a group and article string is that the article
// must have "@" in it somewhere.
if (!lstrlen(pszURL))
{
if (*ppszServer)
{
MemFree(*ppszServer);
*ppszServer = 0;
}
return INET_E_INVALID_URL;
}
ULONG cchURL = lstrlen(pszURL)+1;
if (!MemAlloc((LPVOID*) &pszBuffer, cchURL * sizeof(TCHAR)))
{
if (*ppszServer)
{
MemFree(*ppszServer);
*ppszServer = 0;
}
return INET_E_INVALID_URL;
}
StrCpyN(pszBuffer, pszURL, cchURL);
while (*pszURL && *pszURL != TEXT('@'))
pszURL++;
if (*pszURL == TEXT('@'))
{
// This is an article
*ppszGroup = NULL;
*ppszArticle = pszBuffer;
}
else
{
*ppszGroup = pszBuffer;
*ppszArticle = NULL;
}
return S_OK;
}
// $LOCALIZE - Need a separate code path for DBCS
// Validates a URL of the form NNTP://<host>:<port>/<newsgroup-name>/<message-id>
HRESULT URL_ParseNNTP(LPTSTR pszURL, LPTSTR* ppszServer, LPUINT puPort,
LPTSTR* ppszGroup, LPTSTR* ppszArticle)
{
LPTSTR pszTemp;
UINT cch;
HRESULT hrReturn = S_OK;
Assert(pszURL != NULL);
if (pszURL == NULL || *pszURL == '\0')
return INET_E_INVALID_URL;
// Make sure there are leading "//"
if (*pszURL != TEXT('/'))
return INET_E_INVALID_URL;
pszURL++;
if (*pszURL != TEXT('/'))
return INET_E_INVALID_URL;
pszURL++;
pszTemp = pszURL;
// Search for the host name.
while (*pszTemp && (*pszTemp != TEXT('/')) && (*pszTemp != TEXT(':')))
pszTemp++;
if (*pszTemp != TEXT('/') && *pszTemp != TEXT(':'))
return INET_E_INVALID_URL;
// Copy the host name to the server return value
cch = (UINT) ((LPBYTE) pszTemp - (LPBYTE) pszURL) + sizeof(TCHAR);
if (cch <= 1)
return INET_E_INVALID_URL;
if (!MemAlloc((LPVOID*) ppszServer, cch))
return E_OUTOFMEMORY;
ZeroMemory(*ppszServer, cch);
CopyMemory(*ppszServer, pszURL, (LPBYTE) pszTemp - (LPBYTE) pszURL);
if (*pszTemp == TEXT(':'))
{
// The URL specified a port, so parse that puppy out.
pszTemp++;
pszURL = pszTemp;
while (*pszTemp && (*pszTemp != TEXT('/')))
pszTemp++;
cch = (UINT) ((LPBYTE) pszTemp - (LPBYTE) pszURL);
if (cch <= 1)
{
hrReturn = INET_E_INVALID_URL;
goto error;
}
*puPort = StrToInt(pszURL);
}
if (*pszTemp != TEXT('/'))
{
hrReturn = INET_E_INVALID_URL;
goto error;
}
// Get the newsgroup name
pszTemp++; // Pass the '/'
pszURL = pszTemp;
while (*pszTemp && (*pszTemp != TEXT('/')))
pszTemp++;
if (*pszTemp != TEXT('/'))
{
hrReturn = INET_E_INVALID_URL;
goto error;
}
// Copy the group name to the group return value
cch = (UINT) ((LPBYTE) pszTemp - (LPBYTE) pszURL) + sizeof(TCHAR);
if (cch <= 0)
{
hrReturn = INET_E_INVALID_URL;
goto error;
}
if (!MemAlloc((LPVOID*) ppszGroup, cch))
return (E_OUTOFMEMORY);
ZeroMemory(*ppszGroup, cch);
CopyMemory(*ppszGroup, pszURL, (LPBYTE) pszTemp - (LPBYTE) pszURL);
// Now copy from here to the end of the string as the article id
pszTemp++;
cch = lstrlen(pszTemp) + 1;
if (cch <= 0)
{
hrReturn = INET_E_INVALID_URL;
goto error;
}
if (!MemAlloc((LPVOID*) ppszArticle, cch*sizeof(TCHAR)))
return (E_OUTOFMEMORY);
StrCpyN(*ppszArticle, pszTemp, cch);
return (S_OK);
error:
if (*ppszServer)
MemFree(*ppszServer);
if (*ppszGroup)
MemFree(*ppszGroup);
if (*ppszArticle)
MemFree(*ppszArticle);
*ppszServer = NULL;
*ppszGroup = NULL;
*ppszArticle = NULL;
*puPort = (UINT) -1;
return (hrReturn);
}
static const TCHAR c_szColon[] = ":";
static const TCHAR c_szQuestion[] = "?";
static const TCHAR c_szEquals[] = "=";
static const TCHAR c_szAmpersand[] = "&";
static const TCHAR c_szBody[] = "body";
static const TCHAR c_szBcc[] = "bcc";
//
// FUNCTION: URL_ParseMailTo()
//
// PURPOSE: This function takes a mailto: URL and determines if it is a valid
// URL for mail. The function then fill in a pMsg from the URL
//
// PARAMETERS:
// pszURL - The URL to parse.
// pMsg - The LPMIMEMESSAGE to fill in from the URL.
//
// RETURN VALUE:
// Returns S_OK if the URL is a valid mail URL and the message is filled,
// or an appropriate HRESULT describing why the function failed.
//
// COMMENTS:
// Right now the only valid URL is
// mailto:<SMTP address>
//
HRESULT URL_ParseMailTo(LPTSTR pszURL, LPMIMEMESSAGE pMsg)
{
CStringParser sp;
HRESULT hr;
HADDRESS hAddress;
LPMIMEADDRESSTABLE pAddrTable = 0;
sp.Init(pszURL, lstrlen(pszURL), 0);
if (sp.ChParse(c_szColon))
{
// verify that this is a "mailto:" URL
if (lstrcmpi(sp.PszValue(), c_szURLMailTo))
return INET_E_UNKNOWN_PROTOCOL;
hr = pMsg->GetAddressTable(&pAddrTable);
if (FAILED(hr))
return(hr);
Assert(pAddrTable != NULL);
sp.ChParse(c_szQuestion);
if (sp.CchValue())
{
// opie says it's cool that I'm about to clobber his buffer
UrlUnescapeInPlace((LPTSTR)sp.PszValue(), 0);
pAddrTable->Append(IAT_TO, IET_DECODED, sp.PszValue(), NULL, &hAddress);
}
while (sp.ChParse(c_szEquals))
{
LPTSTR pszAttr = StringDup(sp.PszValue());
if (pszAttr)
{
sp.ChParse(c_szAmpersand);
if (sp.CchValue())
{
UrlUnescapeInPlace((LPTSTR)sp.PszValue(), 0);
// are we trying to set the body?
if (!lstrcmpi(c_szBody, pszAttr))
{
LPSTREAM pStream;
if (SUCCEEDED(MimeOleCreateVirtualStream(&pStream)))
{
if (SUCCEEDED(pStream->Write(sp.PszValue(), lstrlen(sp.PszValue()) * sizeof(TCHAR), NULL)))
{
pMsg->SetTextBody(TXT_PLAIN, IET_DECODED, NULL, pStream, NULL);
}
pStream->Release();
}
}
else if (0 == lstrcmpi(c_szCC, pszAttr))
{
pAddrTable->Append(IAT_CC, IET_DECODED, sp.PszValue(), NULL, &hAddress);
}
else if (0 == lstrcmpi(c_szBcc, pszAttr))
{
pAddrTable->Append(IAT_BCC, IET_DECODED, sp.PszValue(), NULL, &hAddress);
}
else if (0 == lstrcmpi(c_szTo, pszAttr))
{
pAddrTable->Append(IAT_TO, IET_DECODED, sp.PszValue(), NULL, &hAddress);
}
else
{
// just stuff the prop into the message
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, pszAttr, NOFLAGS, sp.PszValue());
}
}
MemFree(pszAttr);
}
}
pAddrTable->Release();
}
return S_OK;
}
#define MAX_SUBSTR_SIZE CCHMAX_DISPLAY_NAME
typedef struct tagURLSub
{
LPCTSTR szTag;
DWORD dwType;
} URLSUB;
const static URLSUB c_UrlSub[] = {
{TEXT("{SUB_CLCID}"), URLSUB_CLCID},
{TEXT("{SUB_PRD}"), URLSUB_PRD},
{TEXT("{SUB_PVER}"), URLSUB_PVER},
{TEXT("{SUB_NAME}"), URLSUB_NAME},
{TEXT("{SUB_EMAIL}"), URLSUB_EMAIL},
};
HRESULT URLSubstitutionA(LPCSTR pszUrlIn, LPSTR pszUrlOut, DWORD cchSize, DWORD dwSubstitutions, IImnAccount *pCertAccount)
{
HRESULT hr = S_OK;
DWORD dwIndex;
CHAR szTempUrl[INTERNET_MAX_URL_LENGTH];
Assert(cchSize <= ARRAYSIZE(szTempUrl)); // We will truncate anything longer than INTERNET_MAX_URL_LENGTH
StrCpyN(szTempUrl, pszUrlIn, ARRAYSIZE(szTempUrl));
for (dwIndex = 0; dwIndex < ARRAYSIZE(c_UrlSub); dwIndex++)
{
while (dwSubstitutions & c_UrlSub[dwIndex].dwType)
{
LPSTR pszTag = StrStrA(szTempUrl, c_UrlSub[dwIndex].szTag);
if (pszTag)
{
TCHAR szCopyUrl[INTERNET_MAX_URL_LENGTH];
TCHAR szSubStr[MAX_SUBSTR_SIZE]; // The Substitution
// Copy URL Before Substitution.
CopyMemory(szCopyUrl, szTempUrl, (int)min((pszTag - szTempUrl), sizeof(szCopyUrl)));
szCopyUrl[(pszTag - szTempUrl)/sizeof(CHAR)] = TEXT('\0');
pszTag += lstrlen(c_UrlSub[dwIndex].szTag);
switch (c_UrlSub[dwIndex].dwType)
{
case URLSUB_CLCID:
{
LCID lcid = GetUserDefaultLCID();
wnsprintf(szSubStr, ARRAYSIZE(szSubStr), "%#04lx", lcid);
}
break;
case URLSUB_PRD:
StrCpyN(szSubStr, c_szUrlSubPRD, ARRAYSIZE(szSubStr));
break;
case URLSUB_PVER:
StrCpyN(szSubStr, c_szUrlSubPVER, ARRAYSIZE(szSubStr));
break;
case URLSUB_NAME:
case URLSUB_EMAIL:
{
IImnAccount *pAccount = NULL;
hr = E_FAIL;
if(pCertAccount)
{
hr = pCertAccount->GetPropSz((c_UrlSub[dwIndex].dwType == URLSUB_NAME) ? AP_SMTP_DISPLAY_NAME : AP_SMTP_EMAIL_ADDRESS,
szSubStr,
ARRAYSIZE(szSubStr));
}
else if (g_pAcctMan && SUCCEEDED(g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount)))
{
hr = pAccount->GetPropSz((c_UrlSub[dwIndex].dwType == URLSUB_NAME) ? AP_SMTP_DISPLAY_NAME : AP_SMTP_EMAIL_ADDRESS,
szSubStr,
ARRAYSIZE(szSubStr));
pAccount->Release();
}
if (FAILED(hr))
return hr;
}
break;
default:
szSubStr[0] = TEXT('\0');
Assert(FALSE); // Not Impl.
hr = E_NOTIMPL;
break;
}
// Add the Substitution String to the end (will become the middle)
StrCatBuff(szCopyUrl, szSubStr, ARRAYSIZE(szCopyUrl));
// Add the rest of the URL after the substitution substring.
StrCatBuff(szCopyUrl, pszTag, ARRAYSIZE(szCopyUrl));
StrCpyN(szTempUrl, szCopyUrl, ARRAYSIZE(szTempUrl));
}
else
break; // This will allow us to replace all the occurances of this string.
}
}
StrCpyN(pszUrlOut, szTempUrl, cchSize);
return hr;
}
HRESULT URLSubLoadStringA(UINT idRes, LPSTR pszUrlOut, DWORD cchSizeOut, DWORD dwSubstitutions, IImnAccount *pCertAccount)
{
HRESULT hr = E_FAIL;
CHAR szTempUrl[INTERNET_MAX_URL_LENGTH];
if (LoadStringA(g_hLocRes, idRes, szTempUrl, ARRAYSIZE(szTempUrl)))
hr = URLSubstitutionA(szTempUrl, pszUrlOut, cchSizeOut, dwSubstitutions, pCertAccount);
return hr;
}
HRESULT HrConvertStringToUnicode(UINT uiSrcCodePage, CHAR *pSrcStr, UINT cSrcSize, WCHAR *pDstStr, UINT cDstSize)
{
IMultiLanguage *pMLang = NULL;
IMLangConvertCharset *pMLangConv = NULL;
HRESULT hr = E_FAIL;
IF_FAILEXIT(hr = CoCreateInstance(CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&pMLang));
IF_FAILEXIT(hr = pMLang->CreateConvertCharset(uiSrcCodePage, 1200, NULL, &pMLangConv));
hr = pMLangConv->DoConversionToUnicode(pSrcStr, &cSrcSize, pDstStr, &cDstSize);
exit:
ReleaseObj(pMLangConv);
ReleaseObj(pMLang);
return hr;
}
static const char c_szBaseFmt[]="<BASE HREF=\"%s\">\n\r";
static const char c_szBaseFileFmt[]="<BASE HREF=\"file://%s\\\">\n\r";
static const WCHAR c_wszBaseFmt[]=L"<BASE HREF=\"%s\">\n\r";
static const WCHAR c_wszBaseFileFmt[]=L"<BASE HREF=\"file://%s\\\">\n\r";
HRESULT HrCreateBasedWebPage(LPWSTR pwszUrl, LPSTREAM *ppstmHtml)
{
HRESULT hr;
LPSTREAM pstm = NULL,
pstmCopy = NULL,
pstmTemp = NULL;
CHAR szBase[MAX_PATH+50],
szCopy[MAX_PATH];
WCHAR wszBase[MAX_PATH+50],
wszCopy[MAX_PATH];
ULONG cb,
cbTemp;
BOOL fLittleEndian;
LPSTR pszUrl = NULL,
pszStream = NULL,
pszCharset = NULL;
LPWSTR pwszStream = NULL,
pwszTempUrl = NULL;
BOOL fIsURL = PathIsURLW(pwszUrl),
fForceUnicode,
fIsUnicode;
IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pstmCopy));
// Are we a file or a URL?
if(fIsURL)
{
// Since we have a url, then must be ansi
IF_NULLEXIT(pszUrl = PszToANSI(CP_ACP, pwszUrl));
// we can not write to this pstm, so we have pstmCopy.
IF_FAILEXIT(hr = URLOpenBlockingStream(NULL, pszUrl, &pstm, 0, NULL));
if (S_OK == HrIsStreamUnicode(pstm, &fLittleEndian))
{
BYTE rgb[2];
IF_FAILEXIT(hr = pstm->Read(rgb, 2, &cb));
Assert(2 == cb);
IF_FAILEXIT(hr = pstmCopy->Write(rgb, 2, NULL));
wnsprintfW((LPWSTR)wszBase, ARRAYSIZE(wszBase), c_wszBaseFmt, pwszUrl);
IF_FAILEXIT(hr = pstmCopy->Write(wszBase, lstrlenW(wszBase) * sizeof(WCHAR), NULL));
}
else
{
wnsprintf(szBase, ARRAYSIZE(szBase), c_szBaseFmt, pszUrl);
IF_FAILEXIT(hr = pstmCopy->Write(szBase, lstrlen(szBase), NULL));
}
}
else
{
// If filename can't be converted to ansi, then we must do this in UNICODE
// even if the stationery itself is normally ansi.
IF_NULLEXIT(pszUrl = PszToANSI(CP_ACP, pwszUrl));
IF_NULLEXIT(pwszTempUrl = PszToUnicode(CP_ACP, pszUrl));
fForceUnicode = (0 != StrCmpW(pwszUrl, pwszTempUrl));
IF_FAILEXIT(hr = CreateStreamOnHFileW(pwszUrl, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, &pstm));
fIsUnicode = (S_OK == HrIsStreamUnicode(pstm, &fLittleEndian));
if (fForceUnicode || fIsUnicode)
{
BYTE bUniMark = 0xFF;
IF_FAILEXIT(hr = pstmCopy->Write(&bUniMark, sizeof(bUniMark), NULL));
bUniMark = 0xFE;
IF_FAILEXIT(hr = pstmCopy->Write(&bUniMark, sizeof(bUniMark), NULL));
StrCpyNW(wszCopy, pwszUrl, ARRAYSIZE(wszCopy));
PathRemoveFileSpecW(wszCopy);
wnsprintfW((LPWSTR)wszBase, ARRAYSIZE(wszBase), c_wszBaseFileFmt, wszCopy);
IF_FAILEXIT(hr = pstmCopy->Write(wszBase, lstrlenW(wszBase) * sizeof(WCHAR), NULL));
}
else
{
StrCpyN(szCopy, pszUrl, ARRAYSIZE(szCopy));
PathRemoveFileSpec(szCopy);
wnsprintf((LPSTR)szBase, ARRAYSIZE(szBase), c_szBaseFileFmt, szCopy);
IF_FAILEXIT(hr = pstmCopy->Write(szBase, lstrlen(szBase), NULL));
}
if (fIsUnicode)
{
WCHAR bom;
IF_FAILEXIT(hr = pstm->Read(&bom, 2, &cb));
Assert(2 == cb);
}
// This is an ANSI stream that we are forcing into UNICODE
// This area will only occur if we are streaming a file
else if (fForceUnicode)
{
LARGE_INTEGER pos = {0};
UINT uiHtmlCodepage = 0;
Assert(!fIsURL);
// In order for the file name to write to the stream properly, we
// must convert the stream to unicode before we copy.
// Get the charset
GetHtmlCharset(pstm, &pszCharset);
if(pszCharset)
{
INETCSETINFO CSetInfo = {0};
HCHARSET hCharset = NULL;
if (SUCCEEDED(MimeOleFindCharset(pszCharset, &hCharset)))
{
if(SUCCEEDED(MimeOleGetCharsetInfo(hCharset,&CSetInfo)))
uiHtmlCodepage = CSetInfo.cpiInternet;
}
}
IF_FAILEXIT(hr = HrRewindStream(pstm));
// Allocate enough to read ANSI
IF_FAILEXIT(hr = HrSafeGetStreamSize(pstm, &cb));
IF_NULLEXIT(MemAlloc((LPVOID*)&pszStream, cb+1));
// Read in ANSI
IF_FAILEXIT(hr = pstm->Read(pszStream, cb, &cbTemp));
Assert(cbTemp == cb);
pszStream[cb] = 0;
// Alloc enough for the unicode conversion. Assume that each
// ANSI char will be one unicode char
IF_NULLEXIT(MemAlloc((LPVOID*)&pwszStream, (cb+1)*sizeof(WCHAR)));
//Convert including null, if the fancy call fails, we should at least continue
//with the old dumb way.
if(!uiHtmlCodepage || FAILED(HrConvertStringToUnicode(uiHtmlCodepage, pszStream, cb+1, pwszStream, cb+1)))
MultiByteToWideChar(CP_ACP, 0, pszStream, cb+1, pwszStream, cb+1);
// Create a new stream
IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&pstmTemp));
IF_FAILEXIT(hr = pstmTemp->Write(pwszStream, lstrlenW(pwszStream)*sizeof(WCHAR), &cb));
IF_FAILEXIT(hr = HrRewindStream(pstmTemp));
ReplaceInterface(pstm, pstmTemp);
}
}
IF_FAILEXIT(hr = HrCopyStream(pstm, pstmCopy, &cb));
IF_FAILEXIT(hr = HrRewindStream(pstmCopy));
*ppstmHtml=pstmCopy;
pstmCopy->AddRef();
exit:
ReleaseObj(pstm);
ReleaseObj(pstmTemp);
ReleaseObj(pstmCopy);
MemFree(pszUrl);
MemFree(pszStream);
MemFree(pwszStream);
MemFree(pwszTempUrl);
MemFree(pszCharset);
return hr;
}