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.
10611 lines
410 KiB
10611 lines
410 KiB
// HtmParse.cpp : Implementation of CHtmParse
|
|
// Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
|
|
#include "stdafx.h"
|
|
|
|
#include <designer.h>
|
|
#include <time.h> // for random number generation
|
|
|
|
#include "triedit.h"
|
|
#include "HtmParse.h"
|
|
#include "table.h"
|
|
#include "lexer.h"
|
|
#include "guids.h"
|
|
#include "util.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTriEditParse
|
|
#undef ASSERT
|
|
#define ASSERT(b) _ASSERTE(b)
|
|
|
|
#ifdef NEEDED
|
|
inline int
|
|
indexPrevtokTagStart(int index, TOKSTRUCT *pTokArray)
|
|
{
|
|
while ( (index >= 0)
|
|
&& (pTokArray[index].token.tokClass != tokTag)
|
|
&& (pTokArray[index].token.tok != TokTag_START)
|
|
)
|
|
{
|
|
index--;
|
|
}
|
|
return(index);
|
|
}
|
|
|
|
inline int
|
|
indexPrevTokElem(int index, TOKSTRUCT *pTokArray)
|
|
{
|
|
while ( (index >= 0)
|
|
&& (pTokArray[index].token.tokClass != tokElem)
|
|
)
|
|
{
|
|
index--;
|
|
}
|
|
return(index);
|
|
}
|
|
#endif //NEEDED
|
|
|
|
BOOL
|
|
FIsWhiteSpaceToken(WCHAR *pwOld, int indexStart, int indexEnd)
|
|
{
|
|
BOOL fWhiteSpace = TRUE;
|
|
int index;
|
|
|
|
for (index = indexStart; index < indexEnd; index++)
|
|
{
|
|
if ( pwOld[index] != ' '
|
|
&& pwOld[index] != '\t'
|
|
&& pwOld[index] != '\r'
|
|
&& pwOld[index] != '\n'
|
|
)
|
|
{
|
|
fWhiteSpace = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
return (fWhiteSpace);
|
|
} /* FIsWhiteSpaceToken() */
|
|
|
|
inline void GlobalUnlockFreeNull(HGLOBAL *phg)
|
|
{
|
|
GlobalUnlock(*phg); // do we need to check if this was already Unlocked?
|
|
GlobalFree(*phg);
|
|
*phg = NULL;
|
|
}
|
|
|
|
BOOL
|
|
FIsAbsURL(LPOLESTR pstr)
|
|
{
|
|
LPCWSTR szHttp[] = {L"http:"};
|
|
LPCWSTR szFile[] = {L"file:"};
|
|
BOOL fRet = FALSE;
|
|
|
|
if (pstr == NULL)
|
|
goto LRet;
|
|
|
|
if ( 0 == _wcsnicmp(szHttp[0], pstr, wcslen(szHttp[0]))
|
|
|| 0 == _wcsnicmp(szFile[0], pstr, wcslen(szFile[0]))
|
|
)
|
|
{
|
|
fRet = TRUE;
|
|
goto LRet;
|
|
}
|
|
LRet:
|
|
return(fRet);
|
|
}
|
|
|
|
BOOL
|
|
FURLNeedSpecialHandling(TOKSTRUCT *pTokArray, int iArray, LPWSTR pwOld, int cMaxToken, int *pichURL, int *pcchURL)
|
|
{
|
|
int index = iArray+1;
|
|
int iHref = -1;
|
|
int iURL = -1;
|
|
BOOL fRet = FALSE;
|
|
BOOL fCodeBase = FALSE;
|
|
|
|
while ( index < cMaxToken
|
|
&& pTokArray[index].token.tok != TokTag_CLOSE
|
|
&& pTokArray[index].token.tokClass != tokTag
|
|
) // look for TokAttrib_HREF
|
|
{
|
|
if ( iHref == -1
|
|
&& ( pTokArray[index].token.tok == TokAttrib_HREF
|
|
|| pTokArray[index].token.tok == TokAttrib_SRC
|
|
|| pTokArray[index].token.tok == TokAttrib_CODEBASE
|
|
)
|
|
&& pTokArray[index].token.tokClass == tokAttr
|
|
)
|
|
{
|
|
iHref = index;
|
|
// special case - if we have CODEBASE attribute, we always want special processing
|
|
if (pTokArray[index].token.tok == TokAttrib_CODEBASE)
|
|
fCodeBase = TRUE;
|
|
}
|
|
if ( iHref != -1
|
|
&& pTokArray[index].token.tok == 0
|
|
&& (pTokArray[index].token.tokClass == tokString || pTokArray[index].token.tokClass == tokValue)
|
|
)
|
|
{
|
|
iURL = index;
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
if (iURL != -1) // its set properly
|
|
{
|
|
int cchURL;
|
|
WCHAR *pszURL;
|
|
BOOL fQuote = (pwOld[pTokArray[iURL].token.ibTokMin] == '"');
|
|
|
|
cchURL = (fQuote)
|
|
? pTokArray[iURL].token.ibTokMac-pTokArray[iURL].token.ibTokMin-2
|
|
: pTokArray[iURL].token.ibTokMac-pTokArray[iURL].token.ibTokMin;
|
|
*pichURL = (fQuote)
|
|
? pTokArray[iURL].token.ibTokMin+1
|
|
: pTokArray[iURL].token.ibTokMin;
|
|
// special case - if the quoted value happens to be a serverside script,
|
|
// we can ignore it here and decalre that we don't need to do any special
|
|
// processing.
|
|
if ( ((pTokArray[iURL].token.ibTokMac-pTokArray[iURL].token.ibTokMin) == 1)
|
|
|| (cchURL < 0)
|
|
)
|
|
{
|
|
*pcchURL = 0;
|
|
goto LRet;
|
|
}
|
|
*pcchURL = cchURL;
|
|
// special case - if we have CODEBASE attribute, we always want special processing
|
|
// we don't need to see if its URL is absolute or not...
|
|
if (fCodeBase)
|
|
{
|
|
fRet = TRUE;
|
|
goto LRet;
|
|
}
|
|
|
|
pszURL = new WCHAR [cchURL+1];
|
|
|
|
ASSERT(pszURL != NULL);
|
|
memcpy( (BYTE *)pszURL,
|
|
(BYTE *)&pwOld[pTokArray[iURL].token.ibTokMin + ((fQuote)? 1 : 0)],
|
|
(cchURL)*sizeof(WCHAR));
|
|
pszURL[cchURL] = '\0';
|
|
if (!FIsAbsURL((LPOLESTR)pszURL))
|
|
fRet = TRUE;
|
|
delete pszURL;
|
|
} // if (iURL != -1)
|
|
|
|
LRet:
|
|
return(fRet);
|
|
}
|
|
|
|
|
|
// Copied from hu_url.cpp
|
|
//-----------------------------------------------------------------------------
|
|
// Useful directory separator check
|
|
//-----------------------------------------------------------------------------
|
|
inline BOOL IsDirSep(CHAR ch)
|
|
{
|
|
return ('\\' == ch || '/' == ch);
|
|
}
|
|
|
|
inline BOOL IsDirSep(WCHAR ch)
|
|
{
|
|
return (L'\\' == ch || L'/' == ch);
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// UtilConvertToRelativeURL
|
|
//
|
|
// Returns an item-relative URL.
|
|
// The URL is returned identical if
|
|
// the projects don't match
|
|
// the protocols don't match
|
|
//
|
|
// Assumes that protocol-less URLs are "http:". Must specify "file:" explicitly
|
|
// to play with file URLs.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static LPOLESTR
|
|
SkipServer(LPOLESTR pstr)
|
|
{
|
|
pstr = wcschr(pstr, L'/');
|
|
if (pstr == NULL)
|
|
return NULL;
|
|
pstr = wcschr(pstr+1, L'/');
|
|
if (pstr == NULL)
|
|
return NULL;
|
|
pstr = wcschr(pstr+1, L'/');
|
|
|
|
return pstr; // positioned on the slash if there was one.
|
|
}
|
|
|
|
static LPOLESTR
|
|
SkipFile(LPOLESTR pstr)
|
|
{
|
|
LPOLESTR pstrT;
|
|
|
|
pstrT = wcspbrk(pstr, L":\\/");
|
|
if (pstr == NULL || pstrT == NULL)
|
|
return pstr;
|
|
|
|
// Guard against the case "//\\".
|
|
|
|
if (pstrT == pstr &&
|
|
IsDirSep(pstr[0]) &&
|
|
IsDirSep(pstr[1]))
|
|
{
|
|
if (IsDirSep(pstr[2]) && IsDirSep(pstr[3]))
|
|
{
|
|
pstrT = pstr + 2; // saw a "//\\"
|
|
}
|
|
else if (pstr[2] != L'\0' && pstr[3] == L':')
|
|
{
|
|
pstrT = pstr + 3; // saw a "//c:"
|
|
}
|
|
}
|
|
|
|
ASSERT(!wcschr(pstrT + 1, ':')); // better not be more colons!
|
|
if (*pstrT == ':') // drive letter possibility
|
|
{
|
|
return pstrT + 1; // point at the character after the colon
|
|
}
|
|
if (pstrT[0] == pstrT[1]) // double slash?
|
|
{
|
|
// Skip server part.
|
|
|
|
pstrT = wcspbrk(pstrT + 2, L"\\/");
|
|
if (pstrT == NULL)
|
|
return pstr; // malformed!
|
|
|
|
// Skip share part.
|
|
|
|
pstrT = wcspbrk(pstrT + 1, L"\\/");
|
|
if (pstrT == NULL)
|
|
return pstr; // malformed!
|
|
|
|
return pstrT;
|
|
}
|
|
|
|
return pstr;
|
|
}
|
|
|
|
static LPOLESTR
|
|
FindLastSlash(LPOLESTR pstr)
|
|
{
|
|
LPOLESTR pstrSlash; // '/'
|
|
LPOLESTR pstrWhack; // '\'
|
|
|
|
pstrSlash = wcsrchr(pstr, L'/');
|
|
pstrWhack = wcsrchr(pstr, L'\\');
|
|
|
|
return pstrSlash > pstrWhack
|
|
? pstrSlash
|
|
: pstrWhack;
|
|
}
|
|
|
|
HRESULT
|
|
UtilConvertToRelativeURL(
|
|
LPOLESTR pstrDestURL, // URL to 'relativize'
|
|
LPOLESTR pstrDestFolder, // URL to be relative to.
|
|
LPOLESTR pstrDestProject, // Project to be relative to.
|
|
BSTR * pbstrRelativeURL)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPOLESTR pstrFolder;
|
|
LPOLESTR pstrURL;
|
|
LPOLESTR pchLastSlash;
|
|
CComBSTR strWork;
|
|
int cch;
|
|
int cchFolder;
|
|
int i;
|
|
int ichLastSlash;
|
|
bool fAbsoluteURL = false;
|
|
bool fAbsoluteFolder = false;
|
|
bool fFileURL = false;
|
|
|
|
// If there's a ':' in the URL we're relativizing, it's assumed
|
|
// to contain a protocol. If the protocol isn't "http:".
|
|
|
|
if (!FIsAbsURL(pstrDestURL)) // VID6 - bug 22895
|
|
goto Copy;
|
|
|
|
pstrURL = pstrDestURL;
|
|
if (wcschr(pstrDestURL, L':'))
|
|
{
|
|
// Check the protocol against the two we understand. If it is some other thing,
|
|
// we punt.
|
|
|
|
if (wcsncmp(pstrDestURL, L"http:", 5) != 0)
|
|
{
|
|
if (wcsncmp(pstrDestURL, L"file:", 5) != 0)
|
|
goto Copy;
|
|
|
|
// File URLs are normalized by skipping any '\\server\share' part.
|
|
|
|
fFileURL = true;
|
|
pstrURL = SkipFile(pstrDestURL + 5); // 5 skips the 'file:' prefix
|
|
}
|
|
else if (pstrDestProject != NULL)
|
|
{
|
|
// Project-relative URLs had better match the project prefix.
|
|
|
|
cch = wcslen(pstrDestProject);
|
|
if (_wcsnicmp(pstrDestURL, pstrDestProject, cch) != 0)
|
|
goto Copy;
|
|
|
|
// Project-relative URLs are normalized by skipping the project prefix.
|
|
|
|
pstrURL = pstrDestURL + cch - 1;
|
|
ASSERT(*pstrURL == '/');
|
|
}
|
|
else
|
|
{
|
|
// Generic 'http:' URLs skip the server part only.
|
|
|
|
pstrURL = SkipServer(pstrDestURL);
|
|
ASSERT(*pstrURL == '/');
|
|
}
|
|
|
|
if (!pstrURL)
|
|
goto Copy;
|
|
fAbsoluteURL = true;
|
|
}
|
|
|
|
// If the folder contains an 'http:' prefix, then find the server and skip that part.
|
|
// otherwise it's assumed the folder is already in a project-relative format.
|
|
|
|
pstrFolder = pstrDestFolder;
|
|
|
|
if (NULL == pstrFolder)
|
|
goto Copy;
|
|
|
|
if (wcsncmp(pstrDestFolder, L"file://", 7) == 0)
|
|
{
|
|
if (!fFileURL)
|
|
goto Copy;
|
|
|
|
pstrFolder = SkipFile(pstrDestFolder + 5);
|
|
fAbsoluteFolder = true;
|
|
}
|
|
else if (wcsncmp(pstrDestFolder, L"http://", 7) == 0)
|
|
{
|
|
if (pstrDestProject != NULL)
|
|
{
|
|
// If a project was passed in, make sure the place we're relativizing to has the same path.
|
|
// If they don't match, we're in trouble.
|
|
|
|
cch = wcslen(pstrDestProject);
|
|
if (_wcsnicmp(pstrDestFolder, pstrDestProject, cch) != 0)
|
|
goto Copy;
|
|
pstrFolder = pstrDestFolder + cch - 1;
|
|
}
|
|
else
|
|
{
|
|
pstrFolder = SkipServer(pstrDestFolder);
|
|
}
|
|
ASSERT(pstrFolder);
|
|
ASSERT(*pstrFolder == '/');
|
|
fAbsoluteFolder = true;
|
|
}
|
|
|
|
// If both the URL and the folder had absolute paths, we need to ensure
|
|
// that the servers are the same.
|
|
|
|
if (fAbsoluteFolder && fAbsoluteURL)
|
|
{
|
|
if (pstrURL - pstrDestURL != pstrFolder - pstrDestFolder ||
|
|
_wcsnicmp(pstrDestURL, pstrDestFolder, SAFE_PTR_DIFF_TO_INT(pstrURL - pstrDestURL)) != 0)
|
|
goto Copy;
|
|
}
|
|
|
|
// From now on, ignore the item at the end of pstrFolder
|
|
|
|
pchLastSlash = FindLastSlash(pstrFolder);
|
|
ASSERT(pchLastSlash);
|
|
cchFolder = 1 + SAFE_PTR_DIFF_TO_INT(pchLastSlash - pstrFolder);
|
|
|
|
// Both folder and item are now relative to the server root.
|
|
|
|
// Locate the last slash in the URL.
|
|
|
|
pchLastSlash = FindLastSlash(pstrURL);
|
|
|
|
if (pchLastSlash == NULL)
|
|
ichLastSlash = 0;
|
|
else
|
|
ichLastSlash = 1 + SAFE_PTR_DIFF_TO_INT(pchLastSlash - pstrURL);
|
|
|
|
// Find any common directories.
|
|
|
|
cch = min(cchFolder, ichLastSlash);
|
|
ichLastSlash = -1;
|
|
for (i = 0; i < cch && pstrFolder[i] == pstrURL[i]; ++i)
|
|
{
|
|
if (IsDirSep(pstrFolder[i]))
|
|
ichLastSlash = i;
|
|
}
|
|
|
|
// ichLastSlash should point beyond at last slash of the last common folder.
|
|
|
|
// For each remaining slash, append a ../ to the path.
|
|
|
|
for (; i < cchFolder; ++i)
|
|
{
|
|
if (IsDirSep(pstrFolder[i]))
|
|
{
|
|
strWork += (fFileURL ? L"..\\" : L"../");
|
|
}
|
|
}
|
|
|
|
if (-1 == ichLastSlash)
|
|
{ // no common parts, append all of the destination
|
|
strWork += pstrURL;
|
|
}
|
|
else
|
|
{ // append only the non-match part of the destination
|
|
|
|
strWork += (pstrURL + ichLastSlash + 1);
|
|
}
|
|
|
|
|
|
Cleanup:
|
|
*pbstrRelativeURL = strWork.Copy();
|
|
if (!*pbstrRelativeURL && ::wcslen(strWork) > 0)
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
return hr;
|
|
|
|
Copy:
|
|
strWork = pstrDestURL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
|
|
|
|
long CTriEditParse::m_bInit = 0;
|
|
|
|
CTriEditParse::CTriEditParse()
|
|
{
|
|
m_rgSublang = 0;
|
|
m_fHasTitleIn = FALSE;
|
|
m_hgPTDTC = NULL;
|
|
m_cchPTDTC = 0;
|
|
m_ichBeginHeadTagIn = -1;
|
|
m_ispInfoBase = 0;
|
|
|
|
if(0 == m_bInit++)
|
|
InitSublanguages();
|
|
}
|
|
|
|
CTriEditParse::~CTriEditParse()
|
|
{
|
|
// save last variant as default if it's not ASP
|
|
if (NULL != m_rgSublang)
|
|
{
|
|
for( int i= 0; NULL != m_rgSublang[i].szSubLang; i++)
|
|
{
|
|
delete [] (LPTSTR)(m_rgSublang[i].szSubLang);
|
|
}
|
|
delete [] m_rgSublang;
|
|
}
|
|
ASSERT(0 != m_bInit);
|
|
|
|
if(0 == --m_bInit)
|
|
{
|
|
ATLTRACE(_T("Releasing tables\n"));
|
|
|
|
// delete dynamically allocated tables
|
|
for (int i = 0; NULL != g_arpTables[i]; i++)
|
|
delete g_arpTables[i];
|
|
delete g_pTabDefault;
|
|
|
|
m_bInit = 0;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// copied from CColorHtml::NextToken
|
|
STDMETHODIMP CTriEditParse::NextToken
|
|
(
|
|
LPCWSTR pszText,
|
|
UINT cbText,
|
|
UINT* pcbCur,
|
|
DWORD* pLXS,
|
|
TXTB* pToken
|
|
)
|
|
{
|
|
ASSERT(pszText != NULL);
|
|
ASSERT(pcbCur != NULL);
|
|
ASSERT(pLXS != NULL);
|
|
ASSERT(pToken != NULL);
|
|
USES_CONVERSION;
|
|
|
|
if(pszText == NULL || pcbCur == NULL || pLXS == NULL || pToken == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
if(0 == cbText)
|
|
return S_FALSE;
|
|
|
|
SetTable(*pLXS); // set g_pTable according to state
|
|
|
|
#ifdef _UNICODE
|
|
*pcbCur = GetToken(pszText, cbText, *pcbCur, pLXS, *pToken);
|
|
#else // _UNICODE
|
|
int cch;
|
|
LPTSTR pszTemp;
|
|
|
|
// get the converted length
|
|
cch = WideCharToMultiByte(CP_ACP, 0, pszText, cbText,
|
|
NULL, 0, NULL, NULL);
|
|
pszTemp = new char[cch + 1];
|
|
|
|
ZeroMemory(pszTemp, cch + 1);
|
|
// copy the wide char to multibyte
|
|
WideCharToMultiByte(CP_ACP, 0, pszText, cbText, pszTemp, cch,
|
|
NULL, NULL);
|
|
|
|
*pcbCur = GetToken(pszTemp, cch, *pcbCur, pLXS, *pToken);
|
|
|
|
delete [] pszTemp;
|
|
#endif // _UNICODE
|
|
|
|
return (*pcbCur < cbText) ? NOERROR : S_FALSE;
|
|
}
|
|
|
|
|
|
|
|
// set g_pTable according to state
|
|
void CTriEditParse::SetTable(DWORD lxs)
|
|
{
|
|
ASSERT(SubLangIndexFromLxs(lxs) < sizeof g_arpTables/sizeof g_arpTables[0]);
|
|
g_pTable = g_arpTables[SubLangIndexFromLxs(lxs)];
|
|
|
|
ASSERT(g_pTable != NULL);
|
|
}
|
|
|
|
void CTriEditParse::InitSublanguages()
|
|
{
|
|
#define cHTML2Len 2048
|
|
|
|
g_pTabDefault = new CStaticTableSet(ALL, IDS_HTML);
|
|
int cl = CV_FIXED;
|
|
CTableSet * rgpts[CV_MAX +1];
|
|
memset(rgpts, 0, sizeof rgpts);
|
|
|
|
CTableSet* ptabset; // current
|
|
CTableSet* ptabBackup; // backup default
|
|
|
|
memset(g_arpTables, 0, sizeof g_arpTables);
|
|
|
|
m_rgSublang = new SUBLANG[cl+2]; // 0th + list + empty terminator
|
|
ASSERT(NULL != m_rgSublang);
|
|
if (NULL != m_rgSublang)
|
|
memset(m_rgSublang, 0, (cl+2)*sizeof SUBLANG);
|
|
|
|
UINT iLang = 1;
|
|
TCHAR strDefault[cHTML2Len];
|
|
|
|
// Microsoft browsers
|
|
// Internet Explorer 3
|
|
ptabset = MakeTableSet(rgpts, IEXP3, IDS_IEXP3);
|
|
SetLanguage( strDefault, m_rgSublang, ptabset, iLang, IDR_HTML, CLSID_NULL );
|
|
|
|
// Set backup default as IE 3
|
|
ptabBackup = ptabset;
|
|
if (lstrlen(strDefault) == 0)
|
|
{
|
|
ASSERT(lstrlen(ptabBackup->Name()) != 0);
|
|
lstrcpy(strDefault, ptabBackup->Name());
|
|
}
|
|
|
|
// User's additions
|
|
|
|
for (int n = 0; rgpts[n]; n++)
|
|
{
|
|
ptabset = rgpts[n];
|
|
SetLanguage( strDefault, m_rgSublang, ptabset, iLang, 0, CLSID_NULL );
|
|
ptabBackup = ptabset;
|
|
}
|
|
|
|
// HTML 2.0 base (if not overridden)
|
|
{
|
|
TCHAR strHTML2[cHTML2Len];
|
|
::LoadString( _Module.GetModuleInstance(),
|
|
IDS_RFC1866,
|
|
strHTML2,
|
|
cHTML2Len
|
|
);
|
|
if (!FindTable(rgpts,strHTML2))
|
|
{
|
|
ptabset = new CStaticTableSet(HTML2, IDS_RFC1866);
|
|
SetLanguage( strDefault, m_rgSublang, ptabset, iLang, 0, CLSID_NULL);
|
|
}
|
|
}
|
|
|
|
if (NULL == g_arpTables[0])
|
|
{
|
|
ASSERT(NULL != ptabBackup); // error: didn't get a default!
|
|
|
|
//Find the backup in the tables
|
|
int i;
|
|
for (i = 1; NULL != g_arpTables[i]; i++)
|
|
{
|
|
if (g_arpTables[i] == ptabBackup)
|
|
break;
|
|
}
|
|
|
|
ASSERT(NULL != g_arpTables[i]); // must be in table
|
|
|
|
// Set default
|
|
g_arpTables[0] = g_pTable = g_arpTables[i];
|
|
m_rgSublang[0] = m_rgSublang[i];
|
|
m_rgSublang[0].lxsInitial = LxsFromSubLangIndex(0);
|
|
|
|
// Move the rest down to fill the hole
|
|
for (; g_arpTables[i]; i++)
|
|
{
|
|
g_arpTables[i] = g_arpTables[i+1];
|
|
m_rgSublang[i] = m_rgSublang[i+1];
|
|
m_rgSublang[i].lxsInitial = LxsFromSubLangIndex(i);
|
|
}
|
|
}
|
|
ASSERT(NULL != g_arpTables[0]);
|
|
|
|
// set global ASP sublang ptr
|
|
// start at 1, since the default is at 0, and should never be ASP
|
|
for (int i = 1; NULL != m_rgSublang[i].szSubLang; i++)
|
|
{
|
|
if (m_rgSublang[i].nIdTemplate == IDR_ASP)
|
|
{
|
|
g_psublangASP = &m_rgSublang[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reallocs are expensive, so when we Realloc, should we add some more pad so that
|
|
// we wont have to call Realloc very often?
|
|
|
|
HRESULT
|
|
ReallocBuffer(HGLOBAL *phg, DWORD cbNew, UINT uFlags)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HGLOBAL hg;
|
|
|
|
ASSERT(*phg != NULL);
|
|
ASSERT(cbNew != 0); // will we ever get this?
|
|
GlobalUnlock(*phg);
|
|
hg = *phg;
|
|
#pragma prefast(suppress:308, "noise")
|
|
*phg = GlobalReAlloc(*phg, cbNew, uFlags);
|
|
if (*phg == NULL)
|
|
{
|
|
#ifdef DEBUG
|
|
hr = GetLastError();
|
|
#endif // DEBUG
|
|
GlobalFree(hg);
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return(hr);
|
|
} /* ReallocBuffer() */
|
|
|
|
HRESULT
|
|
ReallocIfNeeded(HGLOBAL *phg, WCHAR **ppwNew, UINT cbNeed, UINT uFlags)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(*phg != NULL);
|
|
if (GlobalSize(*phg) < cbNeed)
|
|
{
|
|
hr = ReallocBuffer(phg, cbNeed, uFlags);
|
|
if (hr == E_OUTOFMEMORY)
|
|
goto LRet;
|
|
ASSERT(*phg != NULL);
|
|
*ppwNew = (WCHAR *)GlobalLock(*phg);
|
|
}
|
|
LRet:
|
|
return(hr);
|
|
|
|
} /* ReallocIfNeeded() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreSSS(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT *pcSSSOut, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
// Server Side Script case
|
|
// This occurs inside <% %>. we assume simple SSS
|
|
// remove the added <SCRIPT LANGUAGE=SERVERASP> & </SCRIPT> text around it
|
|
UINT iArray = *piArrayStart;
|
|
INT i;
|
|
UINT ichScrStart, ichScrEnd, indexScrStart, indexScrEnd;
|
|
UINT ichSSSStart, ichSSSEnd;
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
INT cSSSOut = *pcSSSOut;
|
|
LPCWSTR szSSS[] = {L"SERVERASP", L"\"SERVERASP\""};
|
|
LPCWSTR szSSSSp[] = {L"SERVERASPSP"};
|
|
BOOL fSpecialSSS = FALSE;
|
|
LPWSTR pwNew = *ppwNew;
|
|
INT iMatchMax;
|
|
UINT cbNeed;
|
|
UINT ichScrWspBegin, ichScrWspEnd, ichSp;
|
|
|
|
ASSERT(cSSSOut >= 0); // make sure that this was initilized
|
|
if (cSSSOut == 0)
|
|
goto LRetOnly;
|
|
|
|
//{TokTag_START, TokElem_SCRIPT, TokTag_CLOSE, TokElem_SCRIPT, fnRestoreSSS}
|
|
ichScrStart = ichScrEnd = indexScrStart = indexScrEnd = ichSSSStart = ichSSSEnd = 0;
|
|
ichScrWspBegin = ichScrWspEnd = 0;
|
|
while (cSSSOut > 0)
|
|
{
|
|
// start at iArray of pTokArray and look for TokElem_SCRIPT
|
|
//while (pTokArray[iArray].token.tok != ft.tokBegin2)
|
|
// iArray++;
|
|
ASSERT(iArray < ptep->m_cMaxToken);
|
|
if (pTokArray[iArray].token.tok != TokElem_SCRIPT)
|
|
goto LRet;
|
|
|
|
// Here's the deal - we have to ignore all SSS that appear
|
|
// as values inside client scripts or insize objects/dtcs
|
|
// so, we need to skip this TokElem_SCRIPT tag if we found '</' before TokElem_SCRIPT
|
|
if ( pTokArray[iArray].token.tok == TokElem_SCRIPT
|
|
&& pTokArray[iArray-1].token.tok != TokTag_START
|
|
)
|
|
{
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
iArray++; // so that we don't come here again with the same iArray
|
|
ptep->m_fDontDeccItem = TRUE; // we can do things differently here next time around
|
|
ptep->m_cSSSOut++;
|
|
goto LRet;
|
|
}
|
|
|
|
//ASSERT(pTokArray[iArray].token.tok == TokElem_SCRIPT);
|
|
i = iArray; // the position at which we found ft.tokBegin2
|
|
// look for the special LANGUAGE arrtibute that we had set.
|
|
// if that doesn't exist, this is not the SSS we want
|
|
// we don't really need to look for this till ptep->m_cMaxToken,
|
|
// but this will cover boundary cases
|
|
iMatchMax = (pTokArray[iArray].iNextprev == -1)? ptep->m_cMaxToken : pTokArray[iArray].iNextprev;
|
|
while (i < iMatchMax)
|
|
{
|
|
if (pTokArray[i].token.tok == TokAttrib_LANGUAGE)
|
|
{
|
|
ASSERT(pTokArray[i].token.tokClass == tokAttr);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i < iMatchMax)
|
|
{
|
|
// make sure that the next one is tokOpEqual
|
|
ASSERT(pTokArray[i+1].token.tokClass == tokOp);
|
|
//ASSERT(((pwOld+pTokArray[i+1].token.ibTokMin)*sizeof(WCHAR)) == '=');
|
|
// get the next value and compare it with szSSS[]
|
|
// note that this may also match with szSSSSp[]
|
|
if ( 0 != _wcsnicmp(szSSS[0], &pwOld[pTokArray[i+2].token.ibTokMin], wcslen(szSSS[0]))
|
|
&& 0 != _wcsnicmp(szSSS[1], &pwOld[pTokArray[i+2].token.ibTokMin], wcslen(szSSS[1]))
|
|
)
|
|
{
|
|
iArray = i;
|
|
goto LNextSSS; // not this one
|
|
}
|
|
}
|
|
else // error case
|
|
{
|
|
iArray++;
|
|
goto LRet;
|
|
}
|
|
// compare with szSSSSp[] and set fSpecialSSS
|
|
if (0 == _wcsnicmp(szSSSSp[0], &pwOld[pTokArray[i+2].token.ibTokMin], wcslen(szSSSSp[0])))
|
|
fSpecialSSS = TRUE;
|
|
i = iArray; // we are OK, so lets look for < before SCRIPT tag
|
|
while (i >= 0)
|
|
{
|
|
// do we need to do anything else here?
|
|
if (pTokArray[i].token.tok == ft.tokBegin)
|
|
{
|
|
ASSERT(pTokArray[i].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
if (i >= 0) // found TokTag_START token
|
|
{
|
|
ichScrStart = pTokArray[i].token.ibTokMin;
|
|
indexScrStart = i;
|
|
}
|
|
else // error case
|
|
{
|
|
// we found SCRIPT, but didn't find < of <SCRIPT
|
|
// we can't process this SSS, so quit
|
|
goto LRet;
|
|
}
|
|
|
|
// now lets look for <! that would be after <SCRIPT LANGUAGE = SERVERASP>
|
|
while (i < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( pTokArray[i].token.tok == TokTag_CLOSE
|
|
&& pTokArray[i].token.tokClass == tokTag
|
|
)
|
|
ichScrWspBegin = pTokArray[i].token.ibTokMac; // if we had saved white space, it would begin here
|
|
|
|
if (pTokArray[i].token.tok == TokTag_BANG)
|
|
{
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
ASSERT(pTokArray[i+1].token.tokClass == tokComment);
|
|
//we can assert for next 2 chars as --
|
|
ichSSSStart = pTokArray[i].token.ibTokMin;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i >= (int)ptep->m_cMaxToken) // didn't find <!
|
|
{
|
|
goto LRet;
|
|
}
|
|
// look for ending -->
|
|
while (i < (int)ptep->m_cMaxToken)
|
|
{
|
|
if (pTokArray[i].token.tok == TokTag_CLOSE && pTokArray[i].token.tokClass == tokTag)
|
|
{
|
|
//we can assert for next 2 chars as --
|
|
ASSERT(*(pwOld+pTokArray[i].token.ibTokMin-1) == '-');
|
|
ASSERT(*(pwOld+pTokArray[i].token.ibTokMin-2) == '-');
|
|
ichSSSEnd = pTokArray[i].token.ibTokMac;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i >= (int)ptep->m_cMaxToken) // didn't find >
|
|
{
|
|
goto LRet;
|
|
}
|
|
|
|
// now look for ft.tokEnd2 & ft.tokEnd (i.e. TokElem_SCRIPT & >)
|
|
while (pTokArray[i].token.tok != ft.tokEnd2)
|
|
{
|
|
if (pTokArray[i].token.tok == TokTag_END && pTokArray[i].token.tokClass == tokTag)
|
|
ichScrWspEnd = pTokArray[i].token.ibTokMin; // past the last white space
|
|
i++;
|
|
}
|
|
ASSERT(i < (int)ptep->m_cMaxToken);
|
|
ASSERT(pTokArray[i].token.tok == TokElem_SCRIPT);
|
|
ASSERT(pTokArray[i].token.tokClass == tokElem);
|
|
// go forward and look for > of SCRIPT>
|
|
// as additional check, we can also check that previous token is </
|
|
while (i < (int)ptep->m_cMaxToken)
|
|
{
|
|
if (pTokArray[i].token.tok == ft.tokEnd)
|
|
{
|
|
ASSERT(pTokArray[i].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i < (int)ptep->m_cMaxToken) // found TokTag_CLOSE
|
|
{
|
|
ichScrEnd = pTokArray[i].token.ibTokMac;
|
|
indexScrEnd = i;
|
|
}
|
|
else // error case
|
|
{
|
|
// we found SCRIPT, but didn't find > of SCRIPT>
|
|
// we can't process this SSS, so quit
|
|
goto LRet;
|
|
}
|
|
iArray = i+1; // set it for next run
|
|
|
|
cbNeed = (ichNewCur+(ichScrStart-ichBeginCopy)+(ichSSSEnd-ichSSSStart))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
// do the Blts
|
|
// ichBeginCopy is a position in pwOld and
|
|
// ichNewCur is a position in pwNew
|
|
// copy from ichBeginCopy to begining of SSS
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichScrStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichScrStart-ichBeginCopy);
|
|
ichBeginCopy = ichScrEnd; // make it ready for next copy
|
|
|
|
if (fSpecialSSS)
|
|
{
|
|
// in special case, we need to make space for the <%@...%> at the begining of pwNew
|
|
// so, we move all the above stuff (ichNewCur chars) by (ichSSSEnd-ichSSSStart-3).
|
|
memmove((BYTE *)(&pwNew[ichSSSEnd-ichSSSStart-3]),
|
|
(BYTE *)pwNew,
|
|
(ichNewCur)*sizeof(WCHAR)
|
|
);
|
|
// we now copy <%@...%> at the begining of the doc instead of at ichNewCur
|
|
// now skip <SCRIPT LANGUAGE=SERVERASP> & only copy <% ....%>
|
|
// note that we have to get rid of 3 extra chars we had added when we converted going in Trident
|
|
memcpy( (BYTE *)(pwNew),
|
|
(BYTE *)&pwOld[ichSSSStart+2],/*get rid of 2 extra chars we had added at the begining*/
|
|
(ichSSSEnd-ichSSSStart-3)*sizeof(WCHAR));
|
|
pwNew[0] = '<'; pwNew[1] = '%'; // note that we have moved the SSS to the begining of the doc
|
|
ichNewCur += ichSSSEnd-ichSSSStart-3; // here we got rid of 1 extra char that was added
|
|
pwNew[(ichSSSEnd-ichSSSStart-3)-2] = '%';
|
|
pwNew[(ichSSSEnd-ichSSSStart-3)-1] = '>';
|
|
// change <!-- to <% and --> to %>
|
|
}
|
|
else
|
|
{
|
|
// in pwNew get rid of white space characters from ichNewCur backwards
|
|
ichSp = ichNewCur-1;
|
|
while ( ( pwNew[ichSp] == ' ' || pwNew[ichSp] == '\r'
|
|
|| pwNew[ichSp] == '\n' || pwNew[ichSp] == '\t'
|
|
)
|
|
)
|
|
{
|
|
ichSp--;
|
|
}
|
|
ichSp++; // compensate for the last decrement, ichSp points to the 1st white-space character
|
|
ichNewCur = ichSp;
|
|
// copy pre-script white space
|
|
if (ichScrWspBegin > 0 && ichSSSStart > ichScrWspBegin) // has been set
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichScrWspBegin],
|
|
(ichSSSStart-ichScrWspBegin)*sizeof(WCHAR));
|
|
ichNewCur += ichSSSStart-ichScrWspBegin;
|
|
}
|
|
// now skip <SCRIPT LANGUAGE=SERVERASP> & only copy <% ....%>
|
|
// note that we have to get rid of 3 extra chars we had added when we converted going in Trident
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichSSSStart+2]),/*get rid of 2 extra chars we had added at the begining*/
|
|
(ichSSSEnd-ichSSSStart-3)*sizeof(WCHAR));
|
|
pwNew[ichNewCur] = '<';
|
|
pwNew[ichNewCur+1] = '%';
|
|
ichNewCur += ichSSSEnd-ichSSSStart-3; // here we got rid of 1 extra char that was added
|
|
pwNew[ichNewCur-2] = '%';
|
|
pwNew[ichNewCur-1] = '>';
|
|
// copy post-script white space
|
|
if (ichScrWspEnd > 0 && ichScrWspEnd > ichSSSEnd) // has been set
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichSSSEnd],
|
|
(ichScrWspEnd-ichSSSEnd)*sizeof(WCHAR));
|
|
ichNewCur += ichScrWspEnd-ichSSSEnd;
|
|
}
|
|
|
|
// increment iArray & ichBeginCopy till the next non-whitespace token
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
UINT ich;
|
|
BOOL fNonWspToken = FALSE; // assume the next token to be whitespace
|
|
// scan entire token and see if it has all white-space characters
|
|
for (ich = pTokArray[iArray].token.ibTokMin; ich < pTokArray[iArray].token.ibTokMac; ich++)
|
|
{
|
|
if ( pwOld[ich] != ' ' && pwOld[ich] != '\t'
|
|
&& pwOld[ich] != '\r' && pwOld[ich] != '\n'
|
|
)
|
|
{
|
|
fNonWspToken = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (fNonWspToken)
|
|
{
|
|
ichBeginCopy = pTokArray[iArray].token.ibTokMin;
|
|
break;
|
|
}
|
|
iArray++;
|
|
}
|
|
}
|
|
|
|
cSSSOut--;
|
|
} // while (cSSSOut > 0)
|
|
|
|
LNextSSS:
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
LRetOnly:
|
|
return;
|
|
|
|
} /* fnRestoreSSS() */
|
|
|
|
void
|
|
CTriEditParse::fnSaveSSS(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT *pcSSSIn, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
// Server Side Script case
|
|
// This occur inside <% %>. We assume simple SSS
|
|
// add <SCRIPT LANGUAGE=SERVERASP> & </SCRIPT> around it
|
|
// tag used for saving the SSS.
|
|
/* 2 spaces at the end of 1st element are important */
|
|
LPCWSTR rgSSSTags[] =
|
|
{
|
|
L"\r\n<SCRIPT LANGUAGE=\"SERVERASP\">",
|
|
L"\r\n<SCRIPT LANGUAGE=\"SERVERASPSP\">",
|
|
L"</SCRIPT>\r\n"
|
|
};
|
|
UINT iArray = *piArrayStart;
|
|
UINT i;
|
|
UINT ichSSSStart, ichSSSEnd, indexSSSStart, indexSSSEnd;
|
|
HGLOBAL hgSSS = NULL;
|
|
WCHAR *pSSS;
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
INT cSSSIn = *pcSSSIn;
|
|
LPWSTR pwNew = *ppwNew;
|
|
int indexSSSTag;
|
|
UINT cbNeed;
|
|
UINT ichSp;
|
|
|
|
ASSERT(cSSSIn >= 0); // make sure that this was initilized
|
|
if (cSSSIn == 0)
|
|
goto LRetOnly;
|
|
|
|
ichSSSStart = ichSSSEnd = indexSSSStart = indexSSSEnd = 0;
|
|
|
|
while (cSSSIn > 0)
|
|
{
|
|
INT cbMin = 0x4fff; // init & increment size of hgSSS
|
|
INT cchCurSSS = 0;
|
|
int index;
|
|
|
|
// handle special case here - if the script is inside <xmp> tag, we shouldn't convert the script
|
|
// NOTE that we are only handling <xmp> <%...%> </xmp> case here
|
|
// we don't have to worry about nested xmp's because its not valid html.
|
|
// such invalid cases are <xmp>...<xmp> </xmp> <% %> </xmp> OR <xmp>...<xmp> <% %> </xmp> </xmp>
|
|
// handle TokElem_PLAINTEXT as well
|
|
index = iArray;
|
|
while (index >= 0)
|
|
{
|
|
if ( (pTokArray[index].token.tok == TokElem_XMP || pTokArray[index].token.tok == TokElem_PLAINTEXT)
|
|
&& pTokArray[index].token.tokClass == tokElem
|
|
&& pTokArray[index].iNextprev > iArray
|
|
)
|
|
{
|
|
iArray++;
|
|
goto LRet;
|
|
}
|
|
index--;
|
|
}
|
|
|
|
// start at the begining of pTokArray and look for first <%
|
|
ASSERT(ft.tokBegin2 == -1);
|
|
ASSERT(ft.tokEnd2 == -1);
|
|
// Here both supporting tokens are -1, so we simply look for main tokens.
|
|
i = iArray;
|
|
while (i < ptep->m_cMaxToken)
|
|
{
|
|
// do we need to do anything else here?
|
|
if (pTokArray[i].token.tok == ft.tokBegin)
|
|
{
|
|
ASSERT(pTokArray[i].token.tok == TokTag_SSSOPEN);
|
|
ASSERT(pTokArray[i].token.tokClass == tokSSS);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i < ptep->m_cMaxToken) // found TokTag_SSSOPEN token
|
|
{
|
|
ichSSSStart = pTokArray[i].token.ibTokMin;
|
|
indexSSSStart = i;
|
|
}
|
|
|
|
// look for ft.tokEnd
|
|
if (pTokArray[i].iNextprev != -1)
|
|
{
|
|
// NOTE that this will give us topmost nested level of the SSS
|
|
indexSSSEnd = pTokArray[i].iNextprev;
|
|
ichSSSEnd = pTokArray[indexSSSEnd].token.ibTokMac;
|
|
ASSERT(indexSSSEnd < ptep->m_cMaxToken);
|
|
// this will be a wierd case where the iNextprev is incorrectly pointing to another token
|
|
// but lets handle that case.
|
|
if (pTokArray[indexSSSEnd].token.tok != TokTag_SSSCLOSE)
|
|
goto LFindSSSClose; // find it by looking at each token
|
|
}
|
|
else // actually, this is an error case, but rather than just giving assert, try to find the token
|
|
{
|
|
LFindSSSClose:
|
|
while (i < ptep->m_cMaxToken)
|
|
{
|
|
if (pTokArray[i].token.tok == ft.tokEnd)
|
|
{
|
|
ASSERT(pTokArray[i].token.tok == TokTag_SSSCLOSE);
|
|
ASSERT(pTokArray[i].token.tokClass == tokSSS);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i < ptep->m_cMaxToken) // found TokTag_SSSCLOSE token
|
|
{
|
|
ichSSSEnd = pTokArray[i].token.ibTokMac;
|
|
indexSSSEnd = i;
|
|
}
|
|
else // error case
|
|
{
|
|
goto LRet; // didn't find %>, but exhausted the token array
|
|
}
|
|
}
|
|
iArray = indexSSSEnd; // set for for next SSS
|
|
|
|
// now insert text from rgSSSTags[] into the source
|
|
// 0. Allocate a local buffer
|
|
cbNeed = wcslen(rgSSSTags[0]) + wcslen(rgSSSTags[0]) + wcslen(rgSSSTags[2])
|
|
+ (ichSSSEnd-ichSSSStart) + cbMin;
|
|
hgSSS = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, cbNeed*sizeof(WCHAR));
|
|
if (hgSSS == NULL)
|
|
goto LErrorRet;
|
|
pSSS = (WCHAR *) GlobalLock(hgSSS);
|
|
ASSERT(pSSS != NULL);
|
|
|
|
// NOTE - This flag would have been set to TRUE only if,
|
|
// we have found <%@ as the 1st SSS in the document
|
|
indexSSSTag = 0;
|
|
if (ptep->m_fSpecialSSS)
|
|
{
|
|
ptep->m_fSpecialSSS = FALSE;
|
|
indexSSSTag = 1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// ASSUMPTION - The big assumption we are making is that IE5 doesn't change
|
|
// anything inside the client sctipt. So far we have seen that.
|
|
// In the worst case, if they start mucking with the contents of client script,
|
|
// we will loose the spacing, but there will be NO DATA LOSS.
|
|
//
|
|
// Based on this assumption, we simply save the pre-post script spacing as is
|
|
// and expect to restore it on the way out.
|
|
//-------------------------------------------------------------------------------
|
|
|
|
// 1. Insert <SCRIPT> from rgSSSTags[indexSSSTag]
|
|
wcscpy(&pSSS[cchCurSSS], rgSSSTags[indexSSSTag]);
|
|
cchCurSSS += wcslen(rgSSSTags[indexSSSTag]);
|
|
// insert the white space as it occurs in pwOld, ichSSSStart is '<' of '<%', walk backwards
|
|
ichSp = ichSSSStart-1;
|
|
while ( ( pwOld[ichSp] == ' ' || pwOld[ichSp] == '\r'
|
|
|| pwOld[ichSp] == '\n' || pwOld[ichSp] == '\t'
|
|
)
|
|
)
|
|
{
|
|
ichSp--;
|
|
}
|
|
ichSp++; // compensate for the last decrement
|
|
if ((int)(ichSSSStart-ichSp) > 0)
|
|
{
|
|
wcsncpy(&pSSS[cchCurSSS], &pwOld[ichSp], ichSSSStart-ichSp);
|
|
cchCurSSS += ichSSSStart-ichSp;
|
|
}
|
|
// now add TokTag_BANG '<!'
|
|
pSSS[cchCurSSS++] = '<';
|
|
pSSS[cchCurSSS++] = '!';
|
|
// 2. copy the script from pwOld
|
|
wcsncpy(&pSSS[cchCurSSS], &pwOld[ichSSSStart], ichSSSEnd-ichSSSStart);
|
|
pSSS[cchCurSSS] = '-';
|
|
pSSS[cchCurSSS+1] = '-';
|
|
cchCurSSS += (ichSSSEnd-ichSSSStart);
|
|
pSSS[cchCurSSS] = pSSS[cchCurSSS-1]; //note : -1 is '>'
|
|
pSSS[cchCurSSS-2] = '-';
|
|
pSSS[cchCurSSS-1] = '-';
|
|
cchCurSSS++; // we are adding one extra character
|
|
// insert the white space as it occurs in pwOld, ichSSSEnd is past '%>', walk forward
|
|
ichSp = ichSSSEnd;
|
|
while ( (ichSp < pTokArray[ptep->m_cMaxToken-1].token.ibTokMac-1)
|
|
&& ( pwOld[ichSp] == ' ' || pwOld[ichSp] == '\r'
|
|
|| pwOld[ichSp] == '\n' || pwOld[ichSp] == '\t'
|
|
)
|
|
)
|
|
{
|
|
ichSp++;
|
|
}
|
|
if ((int)(ichSp-ichSSSEnd) > 0)
|
|
{
|
|
wcsncpy(&pSSS[cchCurSSS], &pwOld[ichSSSEnd], ichSp-ichSSSEnd);
|
|
cchCurSSS += ichSp-ichSSSEnd;
|
|
}
|
|
// 3. Insert </SCRIPT> from rgSSSTags[2]
|
|
wcscpy(&pSSS[cchCurSSS], rgSSSTags[2]);
|
|
cchCurSSS += wcslen(rgSSSTags[2]);
|
|
|
|
|
|
|
|
/* REALLOCATE pwNew IF NEEDED here, use cache value for GlobalSize(*phgNew) and don't forget to update it too */
|
|
cbNeed = (ichNewCur+(ichSSSStart-ichBeginCopy)+(cchCurSSS))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
|
|
|
|
// ichBeginCopy is a position in pwOld and
|
|
// ichNewCur is a position in pwNew
|
|
|
|
if ((int)(ichSSSStart-ichBeginCopy) >= 0)
|
|
{
|
|
// copy till begining of the <%
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichSSSStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += ichSSSStart-ichBeginCopy;
|
|
ichBeginCopy = ichSSSEnd; // set it for next script
|
|
|
|
// copy the converted SSS
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(pSSS),
|
|
cchCurSSS*sizeof(WCHAR));
|
|
ichNewCur += cchCurSSS;
|
|
}
|
|
|
|
if (hgSSS != NULL)
|
|
GlobalUnlockFreeNull(&hgSSS);
|
|
|
|
cSSSIn--;
|
|
} // while(cSSSIn > 0)
|
|
|
|
LErrorRet:
|
|
if (hgSSS != NULL)
|
|
GlobalUnlockFreeNull(&hgSSS);
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
LRetOnly:
|
|
return;
|
|
|
|
} /* fnSaveSSS() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreDTC(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT *piObj, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD dwFlags)
|
|
{
|
|
// OBJECTS case - (These were converted from DTCs in modeInput
|
|
// if we get OBJECT, search backwards (carefully) for tokTag/TokTag_START (<) in pTokArray
|
|
// once we find that, remember the ibTokMin for Object conversion
|
|
// look for the /OBJECT (i.e. look for OBJECT and look for previous /) and
|
|
// once we get those two next to each other, wait for upcoming toktag_CLOSE which will end that Object
|
|
// remember ibTokMac at that position. This is the OBJECT range.
|
|
// First, insert the startspan text
|
|
// Then generate and insert the endspan text (note that we may have to extend our
|
|
// buffer becausethe generated text mey not fit.
|
|
// Do the appropriate Blts to adjust the buffer.
|
|
|
|
UINT cchObjStart, indexObjStart, cchObjEnd, indexObjEnd;
|
|
HGLOBAL hgDTC = NULL;
|
|
WCHAR *pDTC;
|
|
UINT iArray = *piArrayStart;
|
|
INT i;
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
HRESULT hr;
|
|
LPWSTR pwNew = *ppwNew;
|
|
UINT cbNeed;
|
|
|
|
long iControlMac;
|
|
CComPtr<IHTMLDocument2> pHTMLDoc;
|
|
CComPtr<IHTMLElementCollection> pHTMLColl;
|
|
CComPtr<IDispatch> pDispControl;
|
|
CComPtr<IActiveDesigner> pActiveDesigner;
|
|
VARIANT vaName, vaIndex;
|
|
// DTC tag used for saving the DTC.
|
|
LPCWSTR rgDTCTags[] =
|
|
{
|
|
L"<!--METADATA TYPE=\"DesignerControl\" startspan\r\n",
|
|
L"\r\n-->\r\n",
|
|
L"\r\n<!--METADATA TYPE=\"DesignerControl\" endspan-->"
|
|
};
|
|
LPCWSTR rgCommentRT[] =
|
|
{
|
|
L"DTCRUNTIME",
|
|
L"--DTCRUNTIME ",
|
|
L" DTCRUNTIME--",
|
|
};
|
|
int ichRT, cchRT, ichRTComment, cchRTComment, indexRTComment;
|
|
|
|
ichRTComment = ichRT = -1;
|
|
indexRTComment = -1;
|
|
cchRT = cchRTComment = 0;
|
|
|
|
cchObjStart = indexObjStart = cchObjEnd = indexObjEnd = 0;
|
|
|
|
// start at the begining of pTokArray and look for first OBJECT
|
|
//while (pTokArray[iArray].token.tok != ft.tokBegin2)
|
|
// iArray++;
|
|
ASSERT(iArray < ptep->m_cMaxToken);
|
|
|
|
if (pTokArray[iArray].token.tok != TokElem_OBJECT)
|
|
goto LRet;
|
|
|
|
//ASSERT(pTokArray[iArray].token.tok == TokElem_OBJECT);
|
|
i = iArray; // the position at which we found ft.tokBegin2
|
|
while (i >=0)
|
|
{
|
|
// do we need to do anything else here?
|
|
if (pTokArray[i].token.tok == ft.tokBegin)
|
|
{
|
|
ASSERT(pTokArray[i].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
if (i >= 0) // found TokTag_START token
|
|
{
|
|
cchObjStart = pTokArray[i].token.ibTokMin;
|
|
indexObjStart = i;
|
|
}
|
|
i = pTokArray[iArray].iNextprev;
|
|
if (i == -1) // no matching end, skip this <OBJECT>
|
|
goto LRet;
|
|
ASSERT(pTokArray[pTokArray[iArray].iNextprev].token.tok == TokElem_OBJECT);
|
|
ASSERT(pTokArray[pTokArray[iArray].iNextprev].token.tokClass == tokElem);
|
|
ASSERT(pTokArray[i-1].token.tok == TokTag_END);
|
|
// from this ith position, look for ft.tokEnd
|
|
while (i < (int)ptep->m_cMaxToken)
|
|
{
|
|
if (pTokArray[i].token.tok == ft.tokEnd)
|
|
{
|
|
ASSERT(pTokArray[i].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i < (int)ptep->m_cMaxToken) // found TokTag_CLOSE token
|
|
{
|
|
cchObjEnd = pTokArray[i].token.ibTokMac;
|
|
indexObjEnd = i;
|
|
}
|
|
|
|
// look for the special comment that has the runtime text saved
|
|
// we will need it if SaveRuntimeText() failed
|
|
i = indexObjStart;
|
|
while (i < (int)indexObjEnd)
|
|
{
|
|
if ( pTokArray[i].token.tok == TokTag_BANG
|
|
&& pTokArray[i].token.tokClass == tokTag)
|
|
{
|
|
// found the comment, now make sure that this is the comment with DTCRUNTIME
|
|
if ( (pwOld[pTokArray[i+1].token.ibTokMin] == '-')
|
|
&& (pwOld[pTokArray[i+1].token.ibTokMin+1] == '-')
|
|
&& (0 == _wcsnicmp(rgCommentRT[0], &pwOld[pTokArray[i+1].token.ibTokMin+2], wcslen(rgCommentRT[0])))
|
|
&& (pwOld[pTokArray[i+1].token.ibTokMac-1] == '-')
|
|
&& (pwOld[pTokArray[i+1].token.ibTokMac-2] == '-')
|
|
&& (0 == _wcsnicmp(rgCommentRT[0], &pwOld[pTokArray[i+1].token.ibTokMac-2-wcslen(rgCommentRT[0])], wcslen(rgCommentRT[0])))
|
|
)
|
|
{
|
|
ichRT = pTokArray[i+1].token.ibTokMin + wcslen(rgCommentRT[1]);
|
|
cchRT = pTokArray[i+1].token.ibTokMac-pTokArray[i+1].token.ibTokMin - wcslen(rgCommentRT[2]) - wcslen(rgCommentRT[1]);
|
|
indexRTComment = i;
|
|
ichRTComment = pTokArray[i].token.ibTokMin;
|
|
cchRTComment = pTokArray[i+2].token.ibTokMac-pTokArray[i].token.ibTokMin;
|
|
break;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
iArray = indexObjEnd; // set it for the next Object
|
|
|
|
// now, replace the OBJECT - Insert startspan and endspan stuff
|
|
pHTMLDoc = NULL;
|
|
hr = ptep->m_pUnkTrident->QueryInterface(IID_IHTMLDocument2, (void **) &pHTMLDoc);
|
|
if (hr != S_OK)
|
|
goto LErrorRet;
|
|
|
|
pHTMLColl = NULL;
|
|
hr = pHTMLDoc->get_applets(&pHTMLColl);
|
|
if (hr != S_OK)
|
|
{
|
|
goto LErrorRet;
|
|
}
|
|
|
|
pHTMLColl->get_length(&iControlMac);
|
|
ASSERT(*piObj <= iControlMac);
|
|
|
|
hr = S_FALSE;
|
|
VariantInit(&vaName);
|
|
VariantInit(&vaIndex);
|
|
|
|
V_VT(&vaName) = VT_ERROR;
|
|
V_ERROR(&vaName) = DISP_E_PARAMNOTFOUND;
|
|
|
|
V_VT(&vaIndex) = VT_I4;
|
|
V_I4(&vaIndex) = *piObj;
|
|
*piObj += 1; // get it ready for the next control
|
|
ptep->m_iControl = *piObj; // get it ready for the next control
|
|
|
|
pDispControl = NULL;
|
|
hr = pHTMLColl->item(vaIndex, vaName, &pDispControl);
|
|
// Trident has a bug that if the object was nested inside <scripts> tags,
|
|
// it returns S_OK with pDispControl as NULL. (See VID BUG 11303)
|
|
if (hr != S_OK || pDispControl == NULL)
|
|
{
|
|
goto LErrorRet;
|
|
}
|
|
pActiveDesigner = NULL;
|
|
hr = pDispControl->QueryInterface(IID_IActiveDesigner, (void **) &pActiveDesigner);
|
|
if (hr != S_OK) // release pActiveDesigner
|
|
{
|
|
pActiveDesigner.Release();
|
|
pDispControl.Release();
|
|
}
|
|
|
|
if (hr == S_OK) // Found the control!
|
|
{
|
|
// This is a DTC
|
|
IStream *pStm;
|
|
HGLOBAL hg = NULL;
|
|
INT cbMin = 0x8fff; // init & increment size of hgDTC
|
|
INT cchCurDTC = 0;
|
|
|
|
#ifdef DEBUG
|
|
CComPtr<IHTMLElement> pHTMLElem = NULL;
|
|
|
|
hr = pDispControl->QueryInterface(IID_IHTMLElement, (void **) &pHTMLElem);
|
|
if (hr != S_OK)
|
|
{
|
|
goto LErrorRet;
|
|
}
|
|
|
|
// get the index for TokAttrib_ID from pTokArray
|
|
// from here get the actual value for future comparison
|
|
|
|
i = indexObjStart;
|
|
// actually, this has to exist before TokElem_PARAM,
|
|
// but this takes care of boundary cases
|
|
while (i < (int)indexObjEnd)
|
|
{
|
|
if (pTokArray[i].token.tok == TokAttrib_CLASSID)
|
|
{
|
|
ASSERT(pTokArray[i].token.tokClass == tokAttr);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (i < (int)indexObjEnd -1) // found TokAttrib_CLASSID
|
|
{
|
|
CComPtr<IPersistPropertyBag> pPersistPropBag;
|
|
INT ichClsid;
|
|
|
|
// make sure that the next one is tokOpEqual
|
|
ASSERT(pTokArray[i+1].token.tokClass == tokOp);
|
|
// make sure that the next one is the id and get that value
|
|
//ASSERT(pTokArray[i].token.tok == );
|
|
|
|
// Is there any other way to skip "clsid:" string that appears before the clsid?
|
|
ichClsid = pTokArray[i+2].token.ibTokMin + strlen("clsid:");
|
|
|
|
pPersistPropBag = NULL;
|
|
hr = pDispControl->QueryInterface(IID_IPersistPropertyBag, (void **) &pPersistPropBag);
|
|
if (hr == S_OK)
|
|
{
|
|
CLSID clsid;
|
|
LPOLESTR szClsid;
|
|
|
|
if (S_OK == pPersistPropBag->GetClassID(&clsid))
|
|
{
|
|
if (S_OK == StringFromCLSID(clsid, &szClsid))
|
|
ASSERT(0 == _wcsnicmp(szClsid+1/* for {*/, &pwOld[ichClsid], sizeof(CLSID)));
|
|
::CoTaskMemFree(szClsid);
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif // DEBUG
|
|
|
|
ASSERT(*piObj <= iControlMac);
|
|
// Do the Blts.
|
|
// 0. Allocate a local buffer
|
|
hgDTC = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, ((cchObjEnd-cchObjStart)+cbMin)*sizeof(WCHAR)); // stack
|
|
if (hgDTC == NULL)
|
|
goto LErrorRet;
|
|
pDTC= (WCHAR *) GlobalLock(hgDTC);
|
|
ASSERT(pDTC != NULL);
|
|
|
|
if (!(dwFlags & dwFilterDTCsWithoutMetaTags))
|
|
{
|
|
INT indexTokOp = -1;
|
|
INT indexClsId = -1;
|
|
|
|
// 1. Insert MetaData1 tag from rgDTCTags[0]
|
|
wcscpy(&pDTC[cchCurDTC], rgDTCTags[0]);
|
|
cchCurDTC += wcslen(rgDTCTags[0]);
|
|
|
|
// 2. copy the <OBJECT> </OBJECT> from pwOld
|
|
|
|
// Split the copy into 3 parts...
|
|
// part 1 - copy from cchObjStart till = following the ClassId
|
|
// part 2 - add a quote around the classId value (if needed) and copy the value
|
|
// part 3 - copy rest of the object till cchObjEnd
|
|
|
|
// VID98-BUG 5649 - Fix DaVinci bug by adding quote around classId's.
|
|
// NOTE - we want to make sure that the classId value is inside quotes,
|
|
// if there is one for this <OBJECT> tag,
|
|
|
|
// we actually don't need to go this far, but thats the indexObjEnd is the
|
|
// only index know
|
|
for (i = indexObjStart; i < (INT)indexObjEnd; i++)
|
|
{
|
|
if ( pTokArray[i].token.tok == TokAttrib_CLASSID
|
|
&& pTokArray[i].token.tokClass == tokAttr)
|
|
{
|
|
indexClsId = i;
|
|
}
|
|
if ( pwOld[pTokArray[i].token.ibTokMin] == '='
|
|
&& pTokArray[i].token.tokClass == tokOp
|
|
&& indexTokOp == -1)
|
|
{
|
|
indexTokOp = i;
|
|
}
|
|
} // for ()
|
|
// following are simply error cases, we won't run into them unless we have
|
|
// incomplete HTML
|
|
if ( indexClsId == -1 /* we didn't have clsid for this <OBJECT> */
|
|
|| indexTokOp == -1 /* rare but possible error case of incomplete HTML */
|
|
)
|
|
{
|
|
if (ichRTComment == -1)
|
|
{
|
|
wcsncpy(&pDTC[cchCurDTC], &pwOld[cchObjStart], cchObjEnd - cchObjStart);
|
|
cchCurDTC += cchObjEnd - cchObjStart;
|
|
}
|
|
else
|
|
{
|
|
wcsncpy(&pDTC[cchCurDTC], &pwOld[cchObjStart], ichRTComment - cchObjStart);
|
|
cchCurDTC += ichRTComment - cchObjStart;
|
|
|
|
wcsncpy(&pDTC[cchCurDTC], &pwOld[ichRTComment+cchRTComment], cchObjEnd - (ichRTComment+cchRTComment));
|
|
cchCurDTC += cchObjEnd - (ichRTComment+cchRTComment);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPCWSTR szClsId[] =
|
|
{
|
|
L"clsid:",
|
|
};
|
|
|
|
ASSERT(indexTokOp != -1);
|
|
// copy till '=' of 'classid=clsid:XXXX'
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[cchObjStart]),
|
|
(pTokArray[indexTokOp].token.ibTokMac-cchObjStart)*sizeof(WCHAR));
|
|
cchCurDTC += (pTokArray[indexTokOp].token.ibTokMac-cchObjStart);
|
|
|
|
if (0 == _wcsnicmp(szClsId[0], &pwOld[pTokArray[indexTokOp+1].token.ibTokMin], wcslen(szClsId[0])))
|
|
{
|
|
ASSERT(pwOld[pTokArray[indexTokOp+1].token.ibTokMin] != '"');
|
|
pDTC[cchCurDTC] = '"';
|
|
cchCurDTC++;
|
|
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[pTokArray[indexTokOp+1].token.ibTokMin]),
|
|
(pTokArray[indexTokOp+1].token.ibTokMac - pTokArray[indexTokOp+1].token.ibTokMin)*sizeof(WCHAR));
|
|
cchCurDTC += pTokArray[indexTokOp+1].token.ibTokMac - pTokArray[indexTokOp+1].token.ibTokMin;
|
|
|
|
pDTC[cchCurDTC] = '"';
|
|
cchCurDTC++;
|
|
|
|
if (ichRTComment == -1)
|
|
{
|
|
ASSERT((int)(cchObjEnd-pTokArray[indexTokOp+1].token.ibTokMac) >= 0);
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[pTokArray[indexTokOp+1].token.ibTokMac]),
|
|
(cchObjEnd-pTokArray[indexTokOp+1].token.ibTokMac)*sizeof(WCHAR));
|
|
cchCurDTC += (cchObjEnd-pTokArray[indexTokOp+1].token.ibTokMac);
|
|
}
|
|
else
|
|
{
|
|
if (indexRTComment == -1)
|
|
{
|
|
ASSERT((int)(ichRTComment-pTokArray[indexTokOp+1].token.ibTokMac) >= 0);
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[pTokArray[indexTokOp+1].token.ibTokMac]),
|
|
(ichRTComment-pTokArray[indexTokOp+1].token.ibTokMac)*sizeof(WCHAR));
|
|
cchCurDTC += (ichRTComment-pTokArray[indexTokOp+1].token.ibTokMac);
|
|
|
|
ASSERT((int)(cchObjEnd-(ichRTComment+cchRTComment)) >= 0);
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[ichRTComment+cchRTComment]),
|
|
(cchObjEnd-(ichRTComment+cchRTComment))*sizeof(WCHAR));
|
|
cchCurDTC += (cchObjEnd-(ichRTComment+cchRTComment));
|
|
}
|
|
else
|
|
{
|
|
// format and copy from indexTokOp+2 till indexRTComment
|
|
for (i = indexTokOp+2; i < indexRTComment; i++)
|
|
{
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[pTokArray[i].token.ibTokMin]),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
cchCurDTC += pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin;
|
|
if (pTokArray[i].token.tok == TokTag_CLOSE && pTokArray[i].token.tokClass == tokTag)
|
|
{
|
|
// Don't bother checking for existing EOLs...
|
|
// add \r\n
|
|
pDTC[cchCurDTC++] = '\r';
|
|
pDTC[cchCurDTC++] = '\n';
|
|
pDTC[cchCurDTC++] = '\t';
|
|
}
|
|
|
|
}
|
|
|
|
// copy from end of the comment till </object>
|
|
ASSERT((int)(cchObjEnd-(ichRTComment+cchRTComment)) >= 0);
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[ichRTComment+cchRTComment]),
|
|
(cchObjEnd-(ichRTComment+cchRTComment))*sizeof(WCHAR));
|
|
cchCurDTC += (cchObjEnd-(ichRTComment+cchRTComment));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ichRTComment == -1)
|
|
{
|
|
ASSERT((int)(cchObjEnd-pTokArray[indexTokOp+1].token.ibTokMin) >= 0);
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[pTokArray[indexTokOp+1].token.ibTokMin]),
|
|
(cchObjEnd-pTokArray[indexTokOp+1].token.ibTokMin)*sizeof(WCHAR));
|
|
cchCurDTC += (cchObjEnd-pTokArray[indexTokOp+1].token.ibTokMin);
|
|
}
|
|
else
|
|
{
|
|
ASSERT((int)(ichRTComment-pTokArray[indexTokOp+1].token.ibTokMin) >= 0);
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[pTokArray[indexTokOp+1].token.ibTokMin]),
|
|
(ichRTComment-pTokArray[indexTokOp+1].token.ibTokMin)*sizeof(WCHAR));
|
|
cchCurDTC += (ichRTComment-pTokArray[indexTokOp+1].token.ibTokMin);
|
|
|
|
ASSERT((int)(cchObjEnd-(ichRTComment+cchRTComment)) >= 0);
|
|
memcpy( (BYTE *)(&pDTC[cchCurDTC]),
|
|
(BYTE *)(&pwOld[ichRTComment+cchRTComment]),
|
|
(cchObjEnd-(ichRTComment+cchRTComment))*sizeof(WCHAR));
|
|
cchCurDTC += (cchObjEnd-(ichRTComment+cchRTComment));
|
|
}
|
|
}
|
|
}
|
|
|
|
// 3. Insert MetaData2 tag from rgDTCtags[1]
|
|
wcscpy(&pDTC[cchCurDTC], rgDTCTags[1]);
|
|
cchCurDTC += wcslen(rgDTCTags[1]);
|
|
}
|
|
|
|
// 4. Add runtime text (copy code from old stuff)
|
|
if ((hr = CreateStreamOnHGlobal(NULL, TRUE, &pStm)) != S_OK)
|
|
goto LErrorRet;
|
|
|
|
ASSERT(pActiveDesigner != NULL);
|
|
if ((hr = pActiveDesigner->SaveRuntimeState(IID_IPersistTextStream, IID_IStream, pStm)) == S_OK)
|
|
{
|
|
if ((hr = GetHGlobalFromStream(pStm, &hg)) != S_OK)
|
|
goto LErrorRet;
|
|
|
|
STATSTG stat;
|
|
if ((hr = pStm->Stat(&stat, STATFLAG_NONAME)) != S_OK)
|
|
goto LErrorRet;
|
|
|
|
int cch = stat.cbSize.LowPart / sizeof(WCHAR);
|
|
|
|
// before we put stuff from hg into pDTC,
|
|
// lets make sure that its big enough
|
|
cbNeed = (cchCurDTC+cch)*sizeof(WCHAR)+cbBufPadding;
|
|
if (GlobalSize(hgDTC) < cbNeed)
|
|
{
|
|
hr = ReallocBuffer( &hgDTC, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
if (hr == E_OUTOFMEMORY)
|
|
goto LErrorRet;
|
|
ASSERT(hgDTC != NULL);
|
|
pDTC = (WCHAR *)GlobalLock(hgDTC);
|
|
}
|
|
|
|
wcsncpy(&pDTC[cchCurDTC], (LPCWSTR) GlobalLock(hg), cch);
|
|
cchCurDTC += cch;
|
|
|
|
// HACK - BUG fix 9844
|
|
// Some DTCs add a NULL at the end of their runtime text
|
|
if (pDTC[cchCurDTC-1] == '\0')
|
|
cchCurDTC--;
|
|
|
|
GlobalUnlock(hg);
|
|
}
|
|
else if (hr == S_FALSE)
|
|
{
|
|
// copy the commented runtime text into pDTC & incremtn cchCurDTC
|
|
if (ichRTComment != -1 && ichRT != -1) // we have the runtime text
|
|
{
|
|
ASSERT(cchRT >= 0);
|
|
cbNeed = (cchCurDTC+cchRT)*sizeof(WCHAR)+cbBufPadding;
|
|
if (GlobalSize(hgDTC) < cbNeed)
|
|
{
|
|
hr = ReallocBuffer( &hgDTC, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
if (hr == E_OUTOFMEMORY)
|
|
goto LErrorRet;
|
|
ASSERT(hgDTC != NULL);
|
|
pDTC = (WCHAR *)GlobalLock(hgDTC);
|
|
}
|
|
wcsncpy(&pDTC[cchCurDTC], &pwOld[ichRT], cchRT);
|
|
cchCurDTC += cchRT;
|
|
}
|
|
}
|
|
|
|
if (!(dwFlags & dwFilterDTCsWithoutMetaTags))
|
|
{
|
|
// 5. Insert MetaData2 tag from rgDTCtags[2]
|
|
wcscpy(&pDTC[cchCurDTC], rgDTCTags[2]);
|
|
cchCurDTC += wcslen(rgDTCTags[2]);
|
|
}
|
|
|
|
// now insert/replace contents of pDTC into pwNew
|
|
// we are insert/replacing (cchObjEnd-cchObjStart) wchars
|
|
// by cchCurDTC wchars, so realloc pwNew first
|
|
|
|
|
|
|
|
/* Reallocate pwNew IF NEEDED here use cache value for GlobalSize(*phgNew) and don't forget to update it too */
|
|
cbNeed = (ichNewCur+(cchObjStart-ichBeginCopy)+(cchCurDTC))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
|
|
|
|
// cchObjStart/End are actually ich's
|
|
// ichBeginCopy is a position in pwOld and
|
|
// ichNewCur is a position in pwNew
|
|
|
|
// copy till begining of the <OBJECT>
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(cchObjStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += cchObjStart-ichBeginCopy;
|
|
ichBeginCopy = cchObjEnd; // set it for next object
|
|
|
|
CComPtr<IPersistPropertyBag> pPersistPropBag = NULL;
|
|
|
|
hr = pDispControl->QueryInterface(IID_IPersistPropertyBag, (void **) &pPersistPropBag);
|
|
if (hr == S_OK)
|
|
{
|
|
CLSID clsid;
|
|
|
|
if (S_OK == pPersistPropBag->GetClassID(&clsid))
|
|
{
|
|
if (IsEqualCLSID(clsid, CLSID_PageTr))
|
|
{
|
|
if (ptep->m_cchPTDTC != 0)
|
|
{
|
|
// Note that there is no need to realloc here since our buffer will already be bigger than we need it to be.
|
|
if (cchCurDTC != ptep->m_cchPTDTC)
|
|
{
|
|
memmove((BYTE *)(pwNew+ptep->m_ichPTDTC+cchCurDTC),
|
|
(BYTE *)(pwNew+ptep->m_ichPTDTC+ptep->m_cchPTDTC),
|
|
(ichNewCur-ptep->m_ichPTDTC-ptep->m_cchPTDTC)*sizeof(WCHAR));
|
|
|
|
ichNewCur += cchCurDTC-ptep->m_cchPTDTC;
|
|
}
|
|
|
|
memcpy( (BYTE *)(pwNew+ptep->m_ichPTDTC),
|
|
(BYTE *)(pDTC),
|
|
cchCurDTC*sizeof(WCHAR));
|
|
|
|
ptep->m_cchPTDTC = 0;
|
|
ptep->m_ichBeginHeadTagIn = 0; // reset, so that if we had multiple PTDTCs,
|
|
//we won't try to stuff them inside HEAD
|
|
goto LSkipDTC;
|
|
}
|
|
else // this is the case where the PTDTC didn't exist before going to Trident
|
|
{
|
|
// we need to move this between <head> </head> tags if they exist
|
|
if (ptep->m_ichBeginHeadTagIn > 0) // we had HEAD tag in Source view
|
|
{
|
|
int ichInsertPTDTC = ptep->m_ichBeginHeadTagIn;
|
|
|
|
// insert the control immediately after the <HEAD> tag
|
|
//in pwNew look for '>' after ichInsertPTDTC
|
|
while (pwNew[ichInsertPTDTC] != '>')
|
|
ichInsertPTDTC++;
|
|
ichInsertPTDTC++; // skip '>'
|
|
|
|
ASSERT(ichInsertPTDTC < (INT)ichNewCur);
|
|
memmove((BYTE *)(pwNew+ichInsertPTDTC+cchCurDTC),
|
|
(BYTE *)(pwNew+ichInsertPTDTC),
|
|
(ichNewCur-ichInsertPTDTC)*sizeof(WCHAR));
|
|
ichNewCur += cchCurDTC;
|
|
memcpy( (BYTE *)(pwNew+ichInsertPTDTC),
|
|
(BYTE *)(pDTC),
|
|
cchCurDTC*sizeof(WCHAR));
|
|
|
|
ptep->m_ichBeginHeadTagIn = 0;
|
|
goto LSkipDTC;
|
|
}
|
|
}
|
|
|
|
} // else if (IsEqualCLSID(clsid, CLSID_PageTr))
|
|
} // if (S_OK == pPersistPropBag->GetClassID(&clsid))
|
|
} // if (hr == S_OK)
|
|
|
|
// copy the converted DTC
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(pDTC),
|
|
cchCurDTC*sizeof(WCHAR));
|
|
ichNewCur += cchCurDTC;
|
|
|
|
LSkipDTC:
|
|
|
|
if (hgDTC != NULL)
|
|
GlobalUnlockFreeNull(&hgDTC);
|
|
|
|
} // if (hr == S_OK)
|
|
else // this object was not a DTC
|
|
{
|
|
// we don't need to do the same for DTC's, but lets visit this in next release
|
|
LPCWSTR rgComment[] =
|
|
{
|
|
L"ERRORPARAM",
|
|
L"--ERRORPARAM ",
|
|
L" ERRORPARAM--",
|
|
};
|
|
BOOL fFoundParam = FALSE;
|
|
INT iParam = -1;
|
|
INT ichObjStartEnd, iCommentStart, iCommentEnd;
|
|
UINT iObjTagEnd;
|
|
INT cComment, iFirstComment, iComment;
|
|
|
|
iCommentStart = iCommentEnd = iComment = -1;
|
|
// loop through indexObjStart till indexObjEnd to see if we have any <PARAM> tags
|
|
for (i = indexObjStart; i < (INT)indexObjEnd; i++)
|
|
{
|
|
if ( pTokArray[i].token.tok == TokElem_PARAM
|
|
&& pTokArray[i].token.tokClass == tokElem)
|
|
{
|
|
fFoundParam = TRUE;
|
|
iParam = i;
|
|
break;
|
|
}
|
|
} // for ()
|
|
if (fFoundParam)
|
|
ASSERT(iParam != -1);
|
|
|
|
// We need to copy till end of <OBJECT...> irrespective of if we find <PARAM>s or not.
|
|
// copy till end of <OBJECT...> tag and set ichBeginCopy to be after the commented <PARAM> tags
|
|
// calculate ichObjStartEnd
|
|
iObjTagEnd = indexObjStart;
|
|
while (iObjTagEnd < indexObjEnd)
|
|
{
|
|
if ( pTokArray[iObjTagEnd].token.tok == TokTag_CLOSE
|
|
&& pTokArray[iObjTagEnd].token.tokClass == tokTag)
|
|
break;
|
|
iObjTagEnd++;
|
|
}
|
|
if (iObjTagEnd >= indexObjEnd) // error case
|
|
goto LErrorRet;
|
|
ichObjStartEnd = pTokArray[iObjTagEnd].token.ibTokMac;
|
|
|
|
cbNeed = (ichNewCur+ichObjStartEnd-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
ASSERT((INT)(ichObjStartEnd-ichBeginCopy) >= 0);
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichObjStartEnd-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichObjStartEnd-ichBeginCopy);
|
|
ichBeginCopy = ichObjStartEnd;
|
|
iArray = iObjTagEnd + 1;
|
|
|
|
// generally, we don't expect Trident to move the comment from where it was put
|
|
// but if it does, be prepared.
|
|
// NOTE - Lets not worry about the following case for this release becasue prior assumption
|
|
// Also, should we look for more comments if the first one wasn't the magic one?
|
|
// Would Trident move it form where it originally inserted?
|
|
|
|
// ASSUMPTION - that Trident doesn't muck with the contents inside a comment block
|
|
// if rgComment[0] matches and rgComment[1] does not, Trident may have mucked with the
|
|
// comment contents. This invalidates our original assumption.
|
|
// NOTE - We can get away with ignoring this case for thie release
|
|
i = iObjTagEnd;
|
|
cComment = 0;
|
|
iFirstComment = -1;
|
|
while ((UINT)i < indexObjEnd)
|
|
{
|
|
if ( pTokArray[i].token.tok == TokTag_BANG
|
|
&& pTokArray[i].token.tokClass == tokTag)
|
|
{
|
|
cComment++;
|
|
if (iFirstComment == -1)
|
|
iFirstComment = i;
|
|
}
|
|
i++;
|
|
}
|
|
if (cComment == 0) // error, didn't find the comment
|
|
goto LErrorRet;
|
|
|
|
// early return cases
|
|
// 1. see if these are comments or not.They could be anything that start with '<!'
|
|
// e.g. <!DOCTYPE
|
|
i = iFirstComment;
|
|
while (i < (INT)indexObjEnd)
|
|
{
|
|
if ( (i < (INT)ptep->m_cMaxToken)
|
|
&& (pwOld[pTokArray[i].token.ibTokMin] == '-')
|
|
&& (pwOld[pTokArray[i].token.ibTokMin+1] == '-')
|
|
&& (0 == _wcsnicmp(rgComment[0], &pwOld[pTokArray[i].token.ibTokMin+2], wcslen(rgComment[0])))
|
|
)
|
|
{
|
|
ASSERT(i-1 >= 0);
|
|
iCommentStart = i-1; // this is a comment we are interested in
|
|
}
|
|
else
|
|
goto LNextComment;
|
|
|
|
// The first part matched, look at the end of the comment
|
|
if ( (pwOld[pTokArray[i].token.ibTokMac-1] == '-')
|
|
&& (pwOld[pTokArray[i].token.ibTokMac-2] == '-')
|
|
&& (0 == _wcsnicmp( rgComment[0],
|
|
&pwOld[pTokArray[i].token.ibTokMac-(wcslen(rgComment[0])+2)],
|
|
wcslen(rgComment[0])
|
|
)
|
|
)
|
|
)
|
|
{
|
|
iCommentEnd = i + 1;
|
|
iComment = i;
|
|
ASSERT(iCommentEnd < (INT)ptep->m_cMaxToken);
|
|
break;
|
|
}
|
|
else // error case (our assumption was not valid). ignore and return with iArraySav+1
|
|
goto LNextComment;
|
|
LNextComment:
|
|
i++;
|
|
} // while ()
|
|
|
|
|
|
// HANDLE THIS CASE - WHAT IF WE DIDN'T FIND A SINGLE COMMENT????
|
|
|
|
|
|
if (fFoundParam)
|
|
{
|
|
if (iCommentStart != -1 && iCommentEnd != -1)
|
|
{
|
|
cbNeed = (ichNewCur+(pTokArray[iCommentEnd].token.ibTokMac-pTokArray[iObjTagEnd].token.ibTokMin)+(iCommentStart-iObjTagEnd)*3/*for eol,tab*/+(pTokArray[iObjTagEnd].token.ibTokMac-ichBeginCopy))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
|
|
// we need to format the param tags because trident puts them on one line
|
|
// copy till the first param tag
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(pTokArray[iObjTagEnd].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[iObjTagEnd].token.ibTokMac-ichBeginCopy);
|
|
// From here, copy each param tag and insert an EOL after each.
|
|
// Stop at iCommentStart
|
|
for (i = iObjTagEnd+1; i < iCommentStart; i++)
|
|
{
|
|
// if its TokTag_START, insert EOL
|
|
if ( pTokArray[i].token.tok == TokTag_START
|
|
&& pTokArray[i].token.tokClass == tokTag
|
|
)
|
|
{
|
|
pwNew[ichNewCur] = '\r';
|
|
ichNewCur++;
|
|
pwNew[ichNewCur] = '\n';
|
|
ichNewCur++;
|
|
pwNew[ichNewCur] = '\t'; // replace this with appropriate alignment
|
|
ichNewCur++;
|
|
}
|
|
// copy the tag
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[pTokArray[i].token.ibTokMin]),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
} // for ()
|
|
|
|
// from here, look for extra spaces/tabs/eols that trident has accumulated
|
|
// at the end of the PARAM tags and remove them.
|
|
for (i = iCommentEnd+1; i <= (int)indexObjEnd; i++)
|
|
{
|
|
if ( (pTokArray[i].token.tokClass == tokIDENTIFIER && pTokArray[i].token.tok == 0)
|
|
|| ( pTokArray[i].token.tokClass == tokOp
|
|
&& pTokArray[i].token.tok == 0
|
|
&& pwOld[pTokArray[i].token.ibTokMin] == 0x0a
|
|
&& pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin == 1
|
|
)
|
|
)
|
|
{
|
|
int iChar;
|
|
BOOL fCopy = FALSE;
|
|
|
|
// see if all the characters in this token are spaces/tabs/eols
|
|
for (iChar = pTokArray[i].token.ibTokMin; iChar < (int)pTokArray[i].token.ibTokMac; iChar++)
|
|
{
|
|
if ( pwOld[iChar] != ' '
|
|
&& pwOld[iChar] != '\r'
|
|
&& pwOld[iChar] != '\n'
|
|
&& pwOld[iChar] != '\t'
|
|
)
|
|
{
|
|
// we need to copy this token
|
|
fCopy = TRUE;
|
|
break;
|
|
}
|
|
} // for (iChar)
|
|
if (fCopy)
|
|
{
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[pTokArray[i].token.ibTokMin]),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[pTokArray[i].token.ibTokMin]),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
if (pTokArray[i].token.tok == TokTag_CLOSE && pTokArray[i].token.tokClass == tokTag)
|
|
{
|
|
pwNew[ichNewCur++] = '\r';
|
|
pwNew[ichNewCur++] = '\n';
|
|
}
|
|
}
|
|
} // for ()
|
|
ichBeginCopy = pTokArray[indexObjEnd].token.ibTokMac;
|
|
iArray = indexObjEnd + 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (iCommentStart != -1 && iCommentEnd != -1 && iComment != -1)
|
|
{
|
|
INT cchComment1, cchComment2;
|
|
INT ichCommentStart, ichParamStart, cchCommentToken;
|
|
|
|
// We didn't have any <PARAM> for this object. It means one of the following
|
|
// (a)Trident deleted those or (b)it didn't have any before going to Trident
|
|
// If Trident deleted those, we should have them in form of a comment.
|
|
// If we didn't have those before doing to Trident, we won't have that magic comment
|
|
// BUT by the time we come here, we are sure that we have found the magic comment
|
|
|
|
// ASSUME that trident won't move the comment from its original place
|
|
// NOTE - In this release, we don't need to handle the case of Trident moving the comment location
|
|
// which was originally placed just after <OBJECT ...>
|
|
|
|
// remove the comment tokens surrounding the <PARAM>s.
|
|
cchComment1 = wcslen(rgComment[1]);
|
|
cchComment2 = wcslen(rgComment[2]);
|
|
// remove cchComment1 chars from begining of pwOld[pTokArray[i+1].token.ibTokMin
|
|
// remove cchComment2 chars from the end of pwOld[pTokArray[i+1].token.ibTokMac
|
|
// and copy the rest into pwNew
|
|
|
|
ichCommentStart = pTokArray[iCommentStart].token.ibTokMin;
|
|
ichParamStart = pTokArray[iCommentStart+1].token.ibTokMin+cchComment1;
|
|
ASSERT((INT)(ichCommentStart-ichBeginCopy) >= 0);
|
|
cbNeed = (ichNewCur+ichCommentStart-ichBeginCopy+pTokArray[iComment].token.ibTokMac-pTokArray[iComment].token.ibTokMin)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
// copy till begining of the comment
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+ichBeginCopy),
|
|
(ichCommentStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += ichCommentStart-ichBeginCopy;
|
|
ichBeginCopy = pTokArray[iCommentEnd].token.ibTokMac;
|
|
|
|
cchCommentToken = pTokArray[iComment].token.ibTokMac-pTokArray[iComment].token.ibTokMin;
|
|
ASSERT((INT)(cchCommentToken-cchComment1-cchComment2) >= 0);
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)&(pwOld[ichParamStart]),
|
|
(cchCommentToken-cchComment1-cchComment2)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iComment].token.ibTokMac-pTokArray[iComment].token.ibTokMin-cchComment1-cchComment2;
|
|
iArray = iCommentEnd + 1;
|
|
}
|
|
} // if (!fFoundParam)
|
|
} // else of if (hr == S_OK)
|
|
|
|
LErrorRet:
|
|
//free hgDTC if its not NULL
|
|
if (hgDTC != NULL)
|
|
GlobalUnlockFreeNull(&hgDTC);
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
//LRetOnly:
|
|
return;
|
|
|
|
} /* fnRestoreDTC() */
|
|
|
|
void
|
|
CTriEditParse::fnSaveDTC(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT *pcDTC, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
// DTC case -
|
|
// if we get STARTSPAN, search backwords (carefully) for tokTag_BANG in pTokArray
|
|
// once we find that, remember the ibTokMin for DTC replacement
|
|
// once we get a ENDSPAN tagID, wait for upcoming toktag_CLOSE which will end DTC
|
|
// remember ibTokMac at that position. This is the DTC range.
|
|
// In pTokArray, start at METADATA and look for matching OBJECT & /OBJECT tokIDs
|
|
// Blt the OBJECT block over to ibTokMin and NULL remaining area in DEBUG build
|
|
|
|
UINT indexDTCStart, indexDTCEnd, cchDTCStart, cchDTCEnd;
|
|
UINT indexObjectStart, indexObjectEnd, cchObjectStart, cchObjectEnd;
|
|
BOOL fFindFirstObj;
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
INT cDTC = *pcDTC;
|
|
INT i;
|
|
INT ichClsid = 0; // init
|
|
LPOLESTR szClsid;
|
|
UINT iStartSpan;
|
|
LPWSTR pwNew = *ppwNew;
|
|
LPCWSTR rgCommentRT[] =
|
|
{
|
|
L" <!--DTCRUNTIME ",
|
|
L" DTCRUNTIME--> ",
|
|
L"-->",
|
|
};
|
|
LPCWSTR szDesignerControl[] =
|
|
{
|
|
L"\"DesignerControl\"",
|
|
L"DesignerControl",
|
|
};
|
|
BOOL fDesignerControlFound;
|
|
UINT iArraySav = iArray;
|
|
|
|
UINT ichObjectEndBegin, indexRTMac, indexRTStart;
|
|
BOOL fFirstDash;
|
|
UINT cbNeed;
|
|
|
|
indexDTCStart = indexDTCEnd = cchDTCStart = cchDTCEnd = 0;
|
|
indexObjectStart = indexObjectEnd = cchObjectStart = cchObjectEnd = 0;
|
|
|
|
ASSERT(cDTC >= 0); // make sure that this was initilized
|
|
if (cDTC == 0)
|
|
goto LRetOnly;
|
|
while (cDTC > 0)
|
|
{
|
|
// start at iArray of pTokArray and look for STARTSPAN
|
|
//while (pTokArray[iArray].token.tok != ft.tokBegin2)
|
|
// iArray++;
|
|
ASSERT(iArray < ptep->m_cMaxToken);
|
|
|
|
if (pTokArray[iArray].token.tok != TokAttrib_STARTSPAN)
|
|
goto LRet; // something is wrong
|
|
|
|
iStartSpan = iArray;
|
|
ASSERT(pTokArray[iArray].token.tok == TokAttrib_STARTSPAN);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokAttr);
|
|
i = iArray; // the position at which we found ft.tokBegin2
|
|
fDesignerControlFound = FALSE;
|
|
while (i >= 0)
|
|
{
|
|
// do we need to do anything else here?
|
|
if (pTokArray[i].token.tok == ft.tokBegin)
|
|
{
|
|
ASSERT(pTokArray[i].token.tok == TokTag_BANG);
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
break;
|
|
}
|
|
if ( ( pTokArray[i].token.tokClass == tokString
|
|
&& 0 == _wcsnicmp(szDesignerControl[0], &pwOld[pTokArray[i].token.ibTokMin], wcslen(szDesignerControl[0]))
|
|
)
|
|
|| ( pTokArray[i].token.tokClass == tokValue
|
|
&& 0 == _wcsnicmp(szDesignerControl[1], &pwOld[pTokArray[i].token.ibTokMin], wcslen(szDesignerControl[1]))
|
|
)
|
|
)
|
|
{
|
|
fDesignerControlFound = TRUE;
|
|
}
|
|
|
|
i--;
|
|
}
|
|
if (i >= 0) // found TokTag_BANG token
|
|
{
|
|
cchDTCStart = pTokArray[i].token.ibTokMin;
|
|
indexDTCStart = i;
|
|
}
|
|
else // error case
|
|
{
|
|
// we found STARTSPAN, but didn't find <! of <!--METADATA
|
|
// we can't process this DTC, so quit
|
|
goto LRet;
|
|
}
|
|
if (!fDesignerControlFound)
|
|
{
|
|
// we didn't find DesignerControl for the DTC, which means this is not the DTC we care about
|
|
// we can't process this DTC, so quit
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// now, look for ft.tokEnd2 i.e. TokAttrib_ENDSPAN
|
|
if ( pTokArray[iStartSpan].iNextprev != -1 /* validate */
|
|
&& pTokArray[pTokArray[iStartSpan].iNextprev].token.tok == ft.tokEnd2)
|
|
{
|
|
ASSERT(pTokArray[pTokArray[iStartSpan].iNextprev].token.tokClass == tokAttr);
|
|
i = iStartSpan;
|
|
while (i < (int)ptep->m_cMaxToken && pTokArray[i].token.tok != TokElem_OBJECT)
|
|
i++;
|
|
if (i < (int)ptep->m_cMaxToken) // found the first <OBJECT> tag
|
|
indexObjectStart = i;
|
|
i = pTokArray[iStartSpan].iNextprev;
|
|
}
|
|
else // actually, we should have found ft.tokEnd2 in the if case, but if stack unwinding didn't happen correctly...
|
|
{
|
|
// on the way, look for 1st <OBJECT> tag
|
|
fFindFirstObj = TRUE;
|
|
i = iArray;
|
|
while (pTokArray[i].token.tok != ft.tokEnd2)
|
|
{
|
|
if (fFindFirstObj && pTokArray[i].token.tok == TokElem_OBJECT)
|
|
{
|
|
ASSERT(pTokArray[i].token.tokClass == tokElem);
|
|
indexObjectStart = i;
|
|
fFindFirstObj = FALSE;
|
|
}
|
|
i++;
|
|
if (i >= (int)ptep->m_cMaxToken)
|
|
break;
|
|
}
|
|
if (i >= (int)ptep->m_cMaxToken)
|
|
{
|
|
// we didn't find ENDSPAN before hitting ptep->m_cMaxToken
|
|
// we can't process this DTC, so quit
|
|
goto LRet;
|
|
}
|
|
}
|
|
ASSERT(pTokArray[i].token.tok == TokAttrib_ENDSPAN);
|
|
ASSERT(pTokArray[i].token.tokClass == tokAttr);
|
|
|
|
// from this i'th position, look backwards to find '<!' of '<!--METADATA ...endspan...'
|
|
indexRTMac = i;
|
|
while (indexRTMac > indexObjectStart)
|
|
{
|
|
if ( pTokArray[indexRTMac].token.tok == TokTag_BANG
|
|
&& pTokArray[indexRTMac].token.tokClass == tokTag
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
indexRTMac--;
|
|
}
|
|
if (indexRTMac <= indexObjectStart) // error case
|
|
goto LRet;
|
|
|
|
// save this ith position to find last </OBJECT> tag
|
|
indexObjectEnd = indexObjectStart;
|
|
// from this ith poistion, look for ft.tokEnd
|
|
while (i < (int)ptep->m_cMaxToken)
|
|
{
|
|
if (pTokArray[i].token.tok == ft.tokEnd)
|
|
{
|
|
ASSERT(pTokArray[i].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i < (int)ptep->m_cMaxToken) // found TokTag_CLOSE token
|
|
{
|
|
cchDTCEnd = pTokArray[i].token.ibTokMac;
|
|
indexDTCEnd = i;
|
|
}
|
|
else
|
|
{
|
|
// we didn't find TokTag_CLOSE after ENDSPAN,
|
|
// we can't process this DTC, so quit
|
|
goto LRet;
|
|
}
|
|
// look forward from indexObjectEnd for the </OBJECT> tag
|
|
while (indexObjectEnd < ptep->m_cMaxToken)
|
|
{
|
|
if ( pTokArray[indexObjectEnd].token.tok == TokElem_OBJECT
|
|
&& pTokArray[indexObjectEnd].token.tokClass == tokElem
|
|
&& pTokArray[indexObjectEnd-1].token.tok == TokTag_END /* </ */
|
|
)
|
|
break;
|
|
indexObjectEnd++;
|
|
}
|
|
if (indexObjectEnd >= ptep->m_cMaxToken) // didn't find </OBJECT>, error case
|
|
{
|
|
goto LRet;
|
|
}
|
|
if (indexObjectEnd > indexObjectStart) // </OBJECT> found
|
|
{
|
|
// get ibTokMin of the previous < tag for indexObjectStart
|
|
i = indexObjectStart;
|
|
// generally, the previous tag should be the one we want,
|
|
// but this covers the boundary cases
|
|
while (i > (int)indexDTCStart)
|
|
{
|
|
if (pTokArray[i].token.tok == TokTag_START)
|
|
{
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
//ASSERT(i > (int)indexDTCStart+1); // atleast
|
|
cchObjectStart = pTokArray[i].token.ibTokMin;
|
|
// get ibTokMac of the next > tag for indexObjectEnd
|
|
i = indexObjectEnd;
|
|
// generally, the next tag should be the one we want,
|
|
// but this covers the boundary cases
|
|
while (i < (int)indexDTCEnd)
|
|
{
|
|
if (pTokArray[i].token.tok == TokTag_CLOSE)
|
|
{
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
ASSERT(i < (int)indexDTCEnd -1); // atleast
|
|
cchObjectEnd = pTokArray[i].token.ibTokMac; // do we need -1 here?
|
|
}
|
|
else
|
|
goto LRet;
|
|
|
|
// from indexObjectEnd look backwards to get tokTag_END
|
|
indexRTStart = i+1;
|
|
i = indexObjectEnd;
|
|
while (i > (int)indexObjectStart) // we don't have to go this far
|
|
{
|
|
if ( pTokArray[i].token.tok == TokTag_END
|
|
&& pTokArray[i].token.tokClass == tokTag
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
if (i <= (int)indexObjectStart) // error case, do we care?
|
|
goto LRet;
|
|
ichObjectEndBegin = pTokArray[i].token.ibTokMin;
|
|
|
|
iArray = indexDTCEnd; // set it for next DTC entry
|
|
|
|
// now Replace the DTC
|
|
|
|
// ichBeginCopy is a position in pwOld and
|
|
// ichNewCur is a position in pwNew
|
|
// copy from ichBeginCopy to begining of DTC
|
|
if ((int)(cchDTCStart-ichBeginCopy) >= 0)
|
|
{
|
|
cbNeed = (ichNewCur+cchDTCStart-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LSkipCopy;
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(cchDTCStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (cchDTCStart-ichBeginCopy);
|
|
ichBeginCopy = cchDTCEnd; // make it ready for next copy
|
|
}
|
|
|
|
i = indexObjectStart;
|
|
|
|
while (i < (int)indexObjectEnd)
|
|
{
|
|
if (pTokArray[i].token.tok == TokAttrib_CLASSID)
|
|
{
|
|
ASSERT(pTokArray[i].token.tokClass == tokAttr);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (i < (int)indexObjectEnd -1) // found TokAttrib_CLASSID
|
|
{
|
|
// make sure that the next one is tokOpEqual
|
|
ASSERT(pTokArray[i+1].token.tokClass == tokOp);
|
|
// make sure that the next one is the id and get that value
|
|
//ASSERT(pTokArray[i].token.tok == );
|
|
|
|
// Is there any other way to skip "clsid:" string that appears before the clsid?
|
|
ichClsid = pTokArray[i+2].token.ibTokMin + strlen("clsid:");
|
|
// This is a HACK to fix DaVinci's bug, where they can't handle non-quoted
|
|
// classId
|
|
if (pwOld[pTokArray[i+2].token.ibTokMin] == '"')
|
|
ichClsid++;
|
|
}
|
|
|
|
if (ptep->m_fInHdrIn)
|
|
{
|
|
if ( (S_OK == StringFromCLSID(CLSID_PageTr, &szClsid))
|
|
&& (0 == _wcsnicmp(szClsid+1/* for {*/, &pwOld[ichClsid], sizeof(CLSID)))
|
|
)
|
|
{
|
|
// copy the object part of the DTC into m_pPTDTC
|
|
if (ptep->m_pPTDTC != NULL) // means that we have more than one PTDTC on the page
|
|
goto LMultPTDTC;
|
|
|
|
ptep->m_hgPTDTC = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, (cchObjectEnd-cchObjectStart)*sizeof(WCHAR));
|
|
// if the allocation failed, just don't copy into ptep->m_hgPTDTC
|
|
if (ptep->m_hgPTDTC != NULL)
|
|
{
|
|
ptep->m_pPTDTC = (WORD *) GlobalLock(ptep->m_hgPTDTC);
|
|
ASSERT(ptep->m_pPTDTC != NULL);
|
|
memcpy( (BYTE *)(ptep->m_pPTDTC),
|
|
(BYTE *)(&pwOld[cchObjectStart]),
|
|
(cchObjectEnd-cchObjectStart)*sizeof(WCHAR));
|
|
ptep->m_cchPTDTCObj = cchObjectEnd-cchObjectStart;
|
|
ptep->m_ichPTDTC = cchDTCStart; // with respect to the saved header
|
|
ptep->m_cchPTDTC = cchDTCEnd - cchDTCStart;
|
|
|
|
::CoTaskMemFree(szClsid);
|
|
goto LSkipCopy;
|
|
}
|
|
}
|
|
LMultPTDTC:
|
|
::CoTaskMemFree(szClsid);
|
|
}
|
|
|
|
cbNeed = (ichNewCur+(cchObjectEnd-cchObjectStart)+(pTokArray[indexRTMac].token.ibTokMin-cchObjectEnd)+wcslen(rgCommentRT[0])+wcslen(rgCommentRT[1]))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LSkipCopy;
|
|
// STEP 1 - copy till the begining of </OBJECT>
|
|
ASSERT((int)(ichObjectEndBegin-cchObjectStart) >= 0);
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[cchObjectStart]),
|
|
(ichObjectEndBegin-cchObjectStart)*sizeof(WCHAR));
|
|
ichNewCur += ichObjectEndBegin-cchObjectStart;
|
|
|
|
// STEP 2 - Insert the runtime text as a comment
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(rgCommentRT[0]),
|
|
wcslen(rgCommentRT[0])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgCommentRT[0]);
|
|
|
|
// we need to loop thr indexRTStart & indexRTMac and copy token by token
|
|
// and modify TokTag_BANG on the way
|
|
fFirstDash = TRUE;
|
|
while (indexRTStart < indexRTMac)
|
|
{
|
|
// (4/14/98)
|
|
// VID-BUG 17453 Fotm Manager DTC puts in 0x0d (\r) as an end of line instead of
|
|
// putting 0x0d 0xa (\r\n) as an end of line.
|
|
// In this case, the token thats generated is tokIdentifier => "0x0d - - >"
|
|
// instead of getting 3 separate tokens for the normal case as "0x0d 0x0a"
|
|
// & "- -" & ">".
|
|
// Two ways to fix this problem ...
|
|
// 1. Handle this would be in our tokenizer that treats "0x0d" as an
|
|
// end of line as well. But at this time, its not a safe change to do.
|
|
// 2. In the below if condition, add the fact that we may have "0x0d" followed
|
|
// by "-->" for end of metadata comment.
|
|
if ( fFirstDash
|
|
&& ( (0 == _wcsnicmp(rgCommentRT[2], &pwOld[pTokArray[indexRTStart].token.ibTokMin], wcslen(rgCommentRT[2])))
|
|
|| ( (0 == _wcsnicmp(rgCommentRT[2], &pwOld[pTokArray[indexRTStart].token.ibTokMin+1], wcslen(rgCommentRT[2])))
|
|
&& (pwOld[pTokArray[indexRTStart].token.ibTokMin] == 0x0d)
|
|
)
|
|
)
|
|
)
|
|
{
|
|
indexRTStart++;
|
|
fFirstDash = FALSE;
|
|
continue;
|
|
}
|
|
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[indexRTStart].token.ibTokMin],
|
|
(pTokArray[indexRTStart].token.ibTokMac-pTokArray[indexRTStart].token.ibTokMin)*sizeof(WCHAR)
|
|
);
|
|
ichNewCur += pTokArray[indexRTStart].token.ibTokMac-pTokArray[indexRTStart].token.ibTokMin;
|
|
if ( pTokArray[indexRTStart].token.tok == TokTag_BANG
|
|
&& pTokArray[indexRTStart].token.tokClass == tokTag
|
|
)
|
|
{
|
|
pwNew[ichNewCur-2] = '?';
|
|
}
|
|
if ( pTokArray[indexRTStart].token.tok == TokTag_CLOSE
|
|
&& pTokArray[indexRTStart].token.tokClass == tokTag
|
|
&& pwOld[pTokArray[indexRTStart-1].token.ibTokMac-1] == '-'
|
|
&& pwOld[pTokArray[indexRTStart-1].token.ibTokMac-2] == '-'
|
|
)
|
|
{
|
|
pwNew[ichNewCur-1] = '?';
|
|
}
|
|
// following is a hack for the NavBar DTC
|
|
if ( pTokArray[indexRTStart].token.tok == TokElem_METADATA
|
|
&& pTokArray[indexRTStart].token.tokClass == tokElem
|
|
)
|
|
{
|
|
pwNew[ichNewCur-1] = '?';
|
|
}
|
|
indexRTStart++;
|
|
} // while ()
|
|
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(rgCommentRT[1]),
|
|
wcslen(rgCommentRT[1])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgCommentRT[1]);
|
|
|
|
// STEP 3 - copy the rest of the object, i.e. the </OBJECT> tag
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichObjectEndBegin]),
|
|
(cchObjectEnd-ichObjectEndBegin)*sizeof(WCHAR));
|
|
ichNewCur += cchObjectEnd-ichObjectEndBegin;
|
|
|
|
LSkipCopy:
|
|
cDTC--;
|
|
} // while (cDTC > 0)
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
LRetOnly:
|
|
return;
|
|
} /* fnSaveDTC() */
|
|
|
|
void
|
|
CTriEditParse::fnSaveHtmlTag(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
BOOL fFoundTag, fFoundHtmlBegin;
|
|
INT i;
|
|
UINT cchHtml, iHtmlBegin, iHtmlEnd;
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
UINT cbNeed;
|
|
|
|
// assert that iArray'th element in pTokArry is TokTag_HTML
|
|
// Look for any non -1 tags before iArray
|
|
// if we find any, it indicates that we have some stuff before <HTML> that trident doesn't like
|
|
// in pwNew, move all ichNewCur bytes (copied so far) to make space for <HTML> at the begining
|
|
// copy from pwOld <HTML location=> tag
|
|
// adjust ichNewCur and ichBeginCopy
|
|
|
|
// **** don't bother about maintaning info about <HTML> tag's location for Restore
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_HTML);
|
|
iHtmlBegin = i = iArray-1; // init
|
|
fFoundTag = fFoundHtmlBegin = FALSE;
|
|
while (i >= 0)
|
|
{
|
|
if (pTokArray[i].token.tokClass == tokElem || pTokArray[i].token.tokClass == tokSSS)
|
|
{
|
|
fFoundTag = TRUE;
|
|
break;
|
|
}
|
|
if (!fFoundHtmlBegin && pTokArray[i].token.tok == ft.tokBegin) // look for < of <HTML>
|
|
{
|
|
fFoundHtmlBegin = TRUE;
|
|
iHtmlBegin = i; // generally, this should be the right before TokElem_HTML
|
|
}
|
|
i--;
|
|
}
|
|
if (!fFoundHtmlBegin) // we didn't find < for <HTML>, so we are in deep trouble, lets quit here
|
|
{
|
|
goto LRet;
|
|
}
|
|
if (!fFoundTag) // we didn't find any tag before TokElem_HTML, so we don't need to do anything, quit
|
|
{
|
|
goto LRet;
|
|
}
|
|
|
|
// move <HTML> tag at the begining of pwNew
|
|
i = iHtmlBegin; // iArray;
|
|
ASSERT(pTokArray[i].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[i].token.tokClass == tokTag);
|
|
|
|
// look for > of <HTML>
|
|
while (i < (int)ptep->m_cMaxToken) // generally, this will be the very next tag, but this covers boundary cases
|
|
{
|
|
if (pTokArray[i].token.tok == ft.tokEnd)
|
|
break;
|
|
i++;
|
|
}
|
|
if (i >= (int)ptep->m_cMaxToken) // error case, didn't find > of <HTML>, so quit
|
|
{
|
|
iArray++; // so that we won't come back here for the same token
|
|
goto LRet;
|
|
}
|
|
iHtmlEnd = i; // found > of <HTML>
|
|
iArray = i; // set it after > of <HTML>
|
|
|
|
cbNeed = (ichNewCur+pTokArray[iHtmlBegin].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
// copy till begining of the <HTML>
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(pTokArray[iHtmlBegin].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iHtmlBegin].token.ibTokMin-ichBeginCopy;
|
|
ichBeginCopy = pTokArray[iHtmlEnd].token.ibTokMac; // set it for next thing
|
|
|
|
// move all the stuff from pwNew+0 till pwNew+ichNewCur by cchHtml (make space for <HTML>)
|
|
cchHtml = pTokArray[iHtmlEnd].token.ibTokMac-pTokArray[iHtmlBegin].token.ibTokMin;
|
|
memmove((BYTE *)(&pwNew[cchHtml]),
|
|
(BYTE *)pwNew,
|
|
ichNewCur*sizeof(WCHAR));
|
|
ichNewCur += cchHtml;
|
|
|
|
// copy <HTML>
|
|
memcpy( (BYTE *)pwNew,
|
|
(BYTE *)(&pwOld[pTokArray[iHtmlBegin].token.ibTokMin]),
|
|
cchHtml*sizeof(WCHAR));
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
} /* fnSaveHtmlTag() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreHtmlTag(CTriEditParse* /*ptep*/, LPWSTR /*pwOld*/,
|
|
LPWSTR* /*ppwNew*/, UINT* /*pcchNew*/, HGLOBAL* /*phgNew*/,
|
|
TOKSTRUCT* /*pTokArray*/, UINT* /*piArrayStart*/, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT* /*pichNewCur*/, UINT* /*pichBeginCopy*/,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
// ****
|
|
// because we didn't save any info about <HTML> tag's location for Restore, we just return
|
|
return;
|
|
|
|
} /* fnRestoreHtmlTag() */
|
|
|
|
void
|
|
CTriEditParse::fnSaveNBSP(CTriEditParse* /*ptep*/, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
LPCWSTR szNBSP[] = {L"&NBSP"};
|
|
LPCWSTR szNBSPlower[] = {L" "};
|
|
INT ichNbspStart, ichNbspEnd;
|
|
UINT cbNeed;
|
|
|
|
// see if pwOld[pTokArray->token.ibtokMin] matches with " ",
|
|
// and convert it to lower case
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokEntity);
|
|
if (0 == _wcsnicmp(szNBSP[0], &pwOld[pTokArray[iArray].token.ibTokMin], wcslen(szNBSP[0])))
|
|
{
|
|
// ichBeginCopy is a position in pwOld and
|
|
// ichNewCur is a position in pwNew
|
|
// copy from ichBeginCopy to begining of  
|
|
|
|
// check if we have enough memory - If not, realloc
|
|
ichNbspStart = pTokArray[iArray].token.ibTokMin;
|
|
ichNbspEnd = pTokArray[iArray].token.ibTokMac;
|
|
cbNeed = (ichNewCur+ichNbspStart-ichBeginCopy+wcslen(szNBSPlower[0]))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichNbspStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichNbspStart-ichBeginCopy);
|
|
ichBeginCopy = ichNbspEnd; // make it ready for next copy
|
|
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(szNBSPlower[0]),
|
|
(wcslen(szNBSPlower[0]))*sizeof(WCHAR));
|
|
ichNewCur += wcslen(szNBSPlower[0]);
|
|
}
|
|
LErrorRet:
|
|
iArray++; // so that we won't look at the same token again
|
|
|
|
//LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
} /* fnSaveNBSP() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreNBSP(CTriEditParse* /*ptep*/, LPWSTR /*pwOld*/,
|
|
LPWSTR* /*ppwNew*/, UINT* /*pcchNew*/, HGLOBAL* /*phgNew*/,
|
|
TOKSTRUCT* /*pTokArray*/, UINT* /*piArrayStart*/, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT* /*pichNewCur*/, UINT* /*pichBeginCopy*/,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
return;
|
|
} /* fnRestoreNBSP() */
|
|
|
|
|
|
BOOL
|
|
FIsSpecialTag(TOKSTRUCT *pTokArray, int iTag, WCHAR* /*pwOld*/)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
if ( ( pTokArray[iTag].token.tokClass == tokSpace
|
|
|| pTokArray[iTag].token.tokClass == tokComment)
|
|
&& pTokArray[iTag].token.tok == 0
|
|
&& iTag > 0
|
|
&& ( pTokArray[iTag-1].token.tok == TokTag_START
|
|
|| pTokArray[iTag-1].token.tok == TokTag_PI
|
|
|| ( pTokArray[iTag-1].token.tok == TokTag_BANG
|
|
&& pTokArray[iTag+1].token.tok == TokTag_CLOSE
|
|
&& pTokArray[iTag+1].token.tokClass == tokTag
|
|
)
|
|
)
|
|
&& pTokArray[iTag-1].token.tokClass == tokTag
|
|
)
|
|
{
|
|
fRet = TRUE;
|
|
#ifdef WFC_FIX
|
|
int cch = pTokArray[iTag].token.ibTokMac-pTokArray[iTag].token.ibTokMin;
|
|
WCHAR *pStr = new WCHAR[cch+1];
|
|
WCHAR *pFound = NULL;
|
|
|
|
// see if this is xml tag
|
|
// for now we will check tags that have a ':' in them.
|
|
// NOTE - This will get changed when parser change to recognise xml tags is made
|
|
if (pStr != NULL)
|
|
{
|
|
memcpy( (BYTE *)pStr,
|
|
(BYTE *)&pwOld[pTokArray[iTag].token.ibTokMin],
|
|
cch*sizeof(WCHAR));
|
|
pStr[cch] = '\0';
|
|
pFound = wcschr(pStr, ':');
|
|
if (pFound)
|
|
fRet = TRUE;
|
|
|
|
delete pStr;
|
|
}
|
|
#endif //WFC_FIX
|
|
}
|
|
return(fRet);
|
|
}
|
|
|
|
void
|
|
GetTagRange(TOKSTRUCT *pTokArray, int iArrayLast, int *piTag, int *pichTokTagClose, BOOL fMatch)
|
|
{
|
|
int index = *piTag;
|
|
int iTokTagClose = -1;
|
|
|
|
if (fMatch) // we should look fot pTokArray[iTag].iNextprev
|
|
{
|
|
if (pTokArray[*piTag].iNextprev == -1)
|
|
goto LRet;
|
|
index = pTokArray[*piTag].iNextprev; // that way, we will look for '>' after matching end
|
|
}
|
|
// look for TokTag_CLOSE, from iTag onwards
|
|
while (index < iArrayLast)
|
|
{
|
|
if ( pTokArray[index].token.tokClass == tokTag
|
|
&& pTokArray[index].token.tok == TokTag_CLOSE)
|
|
{
|
|
iTokTagClose = index;
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
if (iTokTagClose != -1) // we found it
|
|
{
|
|
*pichTokTagClose = pTokArray[iTokTagClose].token.ibTokMac;
|
|
*piTag = iTokTagClose + 1;
|
|
}
|
|
LRet:
|
|
return;
|
|
} /* GetTagRange() */
|
|
|
|
|
|
void CTriEditParse::fnSaveHdr(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy, DWORD dwFlags)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
INT cchBeforeBody = 0;
|
|
UINT i, iFound;
|
|
WCHAR *pHdr;
|
|
UINT cbNeed;
|
|
|
|
if (ptep->m_hgDocRestore == NULL)
|
|
goto LRetOnly;
|
|
|
|
// lock
|
|
pHdr = (WCHAR *)GlobalLock(ptep->m_hgDocRestore);
|
|
ASSERT(pHdr != NULL);
|
|
|
|
// look forward to make sure that we don't have multiple <BODY> tags
|
|
// this may be a result of a typo in user's document or trident inserting it
|
|
i = iArray+1;
|
|
iFound = iArray;
|
|
while (i < ptep->m_cMaxToken)
|
|
{
|
|
if ( (pTokArray[i].token.tok == TokElem_BODY)
|
|
&& (pTokArray[i].token.tokClass == tokElem)
|
|
&& (pTokArray[i-1].token.tok == TokTag_START)
|
|
&& (pTokArray[i-1].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
iFound = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (iFound > iArray) // this means that we found the last <BODY> tag Trident inserted
|
|
iArray = iFound;
|
|
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_BODY);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
// what if we DON'T have a <BODY> tag at all. We would have found </BODY> here.
|
|
// If thats the case, we just don't save anything
|
|
ASSERT(iArray-1 >= 0);
|
|
if (pTokArray[iArray-1].token.tok != TokTag_START)
|
|
cchBeforeBody = 0;
|
|
else
|
|
cchBeforeBody = pTokArray[iArray].token.ibTokMin;
|
|
|
|
// realloc if needed
|
|
if (cchBeforeBody*sizeof(WCHAR)+sizeof(int) > GlobalSize(ptep->m_hgDocRestore))
|
|
{
|
|
HGLOBAL hgDocRestore;
|
|
GlobalUnlock(ptep->m_hgDocRestore);
|
|
hgDocRestore = ptep->m_hgDocRestore;
|
|
#pragma prefast(suppress:308, "noise")
|
|
ptep->m_hgDocRestore = GlobalReAlloc(ptep->m_hgDocRestore, cchBeforeBody*sizeof(WCHAR)+sizeof(int), GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
// if this alloc failed, we may still want to continue
|
|
if (ptep->m_hgDocRestore == NULL)
|
|
{
|
|
GlobalFree(hgDocRestore);
|
|
goto LRet;
|
|
}
|
|
else
|
|
{
|
|
pHdr = (WCHAR *)GlobalLock(ptep->m_hgDocRestore); // do we need to unlock this first?
|
|
ASSERT(pHdr != NULL);
|
|
}
|
|
}
|
|
|
|
// copy from pwOld
|
|
memcpy( (BYTE *)pHdr,
|
|
(BYTE *)&cchBeforeBody,
|
|
sizeof(INT));
|
|
memcpy( (BYTE *)(pHdr)+sizeof(INT),
|
|
(BYTE *)pwOld,
|
|
cchBeforeBody*sizeof(WCHAR));
|
|
|
|
// reconstruct the pre_BODY part of the document
|
|
// NOTE - for next time around ...
|
|
// If we get the title & body tags from pwNew instead of pwOld, we won't
|
|
// loose the DESIGNTIMESPs for those 2 tags
|
|
if (cchBeforeBody > 0)
|
|
{
|
|
int iTag = 0;
|
|
int ichTokTagClose = -1;
|
|
BOOL fMatch = FALSE;
|
|
LPCWSTR rgSpaceTags[] =
|
|
{
|
|
L" DESIGNTIMESP=",
|
|
L" designtimesp=",
|
|
};
|
|
WCHAR szIndex[cchspBlockMax]; // will we have more than 20 digit numbers as number of DESIGNTIMESPx?
|
|
|
|
int index = iArray;
|
|
int ichBodyTokenStart, ichBodyTokenEnd;
|
|
LPCWSTR rgPreBody[] = {L"<BODY",};
|
|
|
|
memset((BYTE *)pwNew, 0, ichNewCur*sizeof(WCHAR));
|
|
// if we have a unicode stream, we should preserve 0xff,0xfe that occurs at the
|
|
// beginning of the file
|
|
ichNewCur = 0;
|
|
if (ptep->m_fUnicodeFile)
|
|
{
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, sizeof(WCHAR));
|
|
ichNewCur = 1;
|
|
}
|
|
|
|
// loop through all tags starting from index of '<' of <html> till iArray
|
|
// if the tag we see is one of the following, then copy that tag into pwNew
|
|
// ------------------------------------------------------------------------
|
|
// <HTML>, <HEAD>..</HEAD>, <TITLE>..</TITLE>, <STYLE>..</STYLE>,
|
|
// <LINK>, <BASE>, <BASEFONT>
|
|
// ------------------------------------------------------------------------
|
|
iTag = 0;
|
|
ichTokTagClose = -1;
|
|
while (iTag < (int)iArray)
|
|
{
|
|
if ( pTokArray[iTag].token.tokClass == tokAttr
|
|
&& pTokArray[iTag].token.tok == TokAttrib_STARTSPAN)
|
|
{
|
|
GetTagRange(pTokArray, iArray, &iTag, &ichTokTagClose, TRUE);
|
|
}
|
|
else if ( ( (pTokArray[iTag].token.tokClass == tokElem)
|
|
&& ( pTokArray[iTag].token.tok == TokElem_HTML
|
|
|| pTokArray[iTag].token.tok == TokElem_HEAD
|
|
|| pTokArray[iTag].token.tok == TokElem_META
|
|
|| pTokArray[iTag].token.tok == TokElem_LINK
|
|
|| pTokArray[iTag].token.tok == TokElem_BASE
|
|
|| pTokArray[iTag].token.tok == TokElem_BASEFONT
|
|
|| pTokArray[iTag].token.tok == TokElem_TITLE
|
|
|| pTokArray[iTag].token.tok == TokElem_STYLE
|
|
|| pTokArray[iTag].token.tok == TokElem_OBJECT
|
|
)
|
|
)
|
|
|| (FIsSpecialTag(pTokArray, iTag, pwOld))
|
|
)
|
|
{
|
|
int iTagSav = iTag;
|
|
|
|
fMatch = FALSE;
|
|
ichTokTagClose = -1;
|
|
if ( pTokArray[iTag].token.tok == TokElem_TITLE
|
|
|| pTokArray[iTag].token.tok == TokElem_STYLE
|
|
|| pTokArray[iTag].token.tok == TokElem_OBJECT
|
|
)
|
|
fMatch = TRUE;
|
|
GetTagRange(pTokArray, iArray, &iTag, &ichTokTagClose, fMatch);
|
|
if (ichTokTagClose != -1)
|
|
{
|
|
// copy the stuff into pwNew
|
|
pwNew[ichNewCur++] = '<';
|
|
if ( pTokArray[iTagSav-1].token.tok == TokTag_END
|
|
&& pTokArray[iTagSav-1].token.tokClass == tokTag)
|
|
{
|
|
pwNew[ichNewCur++] = '/';
|
|
}
|
|
else if ( pTokArray[iTagSav-1].token.tok == TokTag_PI
|
|
&& pTokArray[iTagSav-1].token.tokClass == tokTag)
|
|
{
|
|
pwNew[ichNewCur++] = '?';
|
|
}
|
|
else if ( pTokArray[iTagSav-1].token.tok == TokTag_BANG
|
|
&& pTokArray[iTagSav-1].token.tokClass == tokTag)
|
|
{
|
|
pwNew[ichNewCur++] = '!';
|
|
}
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[iTagSav].token.ibTokMin],
|
|
(ichTokTagClose-pTokArray[iTagSav].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += ichTokTagClose-pTokArray[iTagSav].token.ibTokMin;
|
|
// do we want to add \r\n after each tag we copy?
|
|
}
|
|
else
|
|
goto LNext;
|
|
}
|
|
else
|
|
{
|
|
LNext:
|
|
iTag++;
|
|
}
|
|
} // while (iTag < (int)iArray)
|
|
|
|
|
|
// we know that iArray is currently pointing to tokElem_BODY
|
|
// go backwards and look for '<', so that we can copy from that point
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_BODY);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
index = iArray;
|
|
while (index >= 0)
|
|
{
|
|
if ( pTokArray[index].token.tok == TokTag_START
|
|
&& pTokArray[index].token.tokClass == tokTag)
|
|
{
|
|
break;
|
|
}
|
|
index--;
|
|
}
|
|
if (index < 0) // error case, we didn't find '<' before BODY
|
|
goto LSkipBody;
|
|
ichBodyTokenStart = pTokArray[index].token.ibTokMin;
|
|
|
|
// now go forward till we get the '>' of <BODY>, we don't have to go this far,
|
|
// but this covers boundary cases
|
|
index = iArray;
|
|
while (index < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( pTokArray[index].token.tok == TokTag_CLOSE
|
|
&& pTokArray[index].token.tokClass == tokTag)
|
|
{
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
if (index > (int)ptep->m_cMaxToken) // error case, we didn't find '>' before BODY
|
|
goto LSkipBody;
|
|
ichBodyTokenEnd = pTokArray[index-1].token.ibTokMac; // BUG 15391 - don't copy TokTag_CLOSE here, it gets added later
|
|
|
|
// blt part of the <BODY> tag into pwNew. (BUG 15391 - excluding the ending >)
|
|
ASSERT(ichBodyTokenEnd-ichBodyTokenStart >= 0);
|
|
memcpy((BYTE *)&pwNew[ichNewCur], (BYTE *)&pwOld[ichBodyTokenStart], (ichBodyTokenEnd-ichBodyTokenStart)*sizeof(WCHAR));
|
|
ichNewCur += (ichBodyTokenEnd-ichBodyTokenStart);
|
|
|
|
// only if spacing flag is set
|
|
if (dwFlags & dwPreserveSourceCode)
|
|
{
|
|
// BUG 15391 - insert DESIGNTIMESP with (ptep->m_ispInfoBlock+ptep->m_ispInfoBase-1) & add '>' at the end
|
|
ASSERT(wcslen(rgSpaceTags[1]) == wcslen(rgSpaceTags[0]));
|
|
if (iswupper(pwOld[pTokArray[iArray].token.ibTokMin]) != 0) // upper case - BUG 15389
|
|
{
|
|
memcpy((BYTE *)&pwNew[ichNewCur], (BYTE *)rgSpaceTags[0], wcslen(rgSpaceTags[0])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgSpaceTags[0]);
|
|
}
|
|
else
|
|
{
|
|
memcpy((BYTE *)&pwNew[ichNewCur], (BYTE *)rgSpaceTags[1], wcslen(rgSpaceTags[1])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgSpaceTags[1]);
|
|
}
|
|
(WCHAR)_itow(ptep->m_ispInfoBlock+ptep->m_ispInfoBase-1, szIndex, 10);
|
|
ASSERT(wcslen(szIndex) < sizeof(szIndex));
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(szIndex),
|
|
wcslen(szIndex)*sizeof(WCHAR));
|
|
ichNewCur += wcslen(szIndex);
|
|
}
|
|
goto LBodyCopyDone;
|
|
|
|
LSkipBody:
|
|
// if we skipped copying <BODY> tag, we must put in a dummy <BODY> at ichNewCur
|
|
memcpy((BYTE *)&pwNew[ichNewCur], (BYTE *)rgPreBody[0], wcslen(rgPreBody[0])*sizeof(WCHAR));
|
|
ichNewCur = wcslen(rgPreBody[0]);
|
|
|
|
LBodyCopyDone:
|
|
pwNew[ichNewCur++] = '>'; //ending '>' that we skipped copying before
|
|
// set ichBeginCopy and iArray appropriately
|
|
iArray = index+1;
|
|
ichBeginCopy = pTokArray[iArray].token.ibTokMin;
|
|
}
|
|
|
|
// Copy everything upto and including <BODY>
|
|
|
|
//LSkipCopy:
|
|
|
|
if (ptep->m_pPTDTC != NULL) // we had saved PageTransitionDTC in a temporary
|
|
{
|
|
ASSERT(ptep->m_cchPTDTCObj >= 0);
|
|
cbNeed = (ichNewCur+ptep->m_cchPTDTCObj)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)ptep->m_pPTDTC,
|
|
ptep->m_cchPTDTCObj*sizeof(WCHAR));
|
|
ichNewCur += ptep->m_cchPTDTCObj;
|
|
GlobalUnlockFreeNull(&(ptep->m_hgPTDTC));
|
|
}
|
|
|
|
ptep->m_fInHdrIn = FALSE;
|
|
|
|
LRet:
|
|
// unlock
|
|
GlobalUnlock(ptep->m_hgDocRestore);
|
|
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
LRetOnly:
|
|
return;
|
|
|
|
} /* fnSaveHdr() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreHdr(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy, DWORD dwFlags)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
INT cchBeforeBody = 0;
|
|
WCHAR *pHdr;
|
|
INT ichBodyStart, ichBodyEnd;
|
|
UINT i, iFound;
|
|
UINT cbNeed;
|
|
|
|
if (ptep->m_hgDocRestore == NULL)
|
|
goto LRetOnly;
|
|
|
|
// lock, copy, unlock
|
|
pHdr = (WCHAR *)GlobalLock(ptep->m_hgDocRestore);
|
|
ASSERT(pHdr != NULL);
|
|
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_BODY);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
|
|
// HACK to fix a TRIDENT misbehaviour
|
|
// If we had any text before <BODY> tag going into Trident, it will add 2nd <BODY>
|
|
// tag before this text comming out of Trident without looking forward and
|
|
// recognizing that a <BODY> tag already exists. Ideally, Trident should move teh
|
|
// <BODY> tag at appropriate place rather than inserting a 2nd one.
|
|
// Lets assume that Trident will insert only one extra <BODY> tag.
|
|
i = iArray + 1; // we know iArray is the 1st <BODY> tag
|
|
iFound = iArray;
|
|
while (i < ptep->m_cMaxToken)
|
|
{
|
|
if ( (pTokArray[i].token.tok == ft.tokBegin2) /*TokElem_BODY*/
|
|
&& (pTokArray[i-1].token.tok == TokTag_START)
|
|
)
|
|
{
|
|
iFound = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (iFound > iArray) // this means that we found the last <BODY> tag Trident inserted
|
|
iArray = iFound;
|
|
|
|
memcpy((BYTE *)&cchBeforeBody, (BYTE *)pHdr, sizeof(INT));
|
|
|
|
// realloc if needed
|
|
ichBodyStart = pTokArray[iArray].token.ibTokMin;
|
|
ichBodyEnd = pTokArray[iArray].token.ibTokMac;
|
|
cbNeed = (ichNewCur+cchBeforeBody+ichBodyEnd-ichBodyStart)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
|
|
if (cchBeforeBody > 0)
|
|
{
|
|
// ichBeginCopy is a position in pwOld and
|
|
// ichNewCur is a position in pwNew
|
|
// copy from ichBeginCopy to begining of  
|
|
memcpy( (BYTE *)(pwNew),
|
|
(BYTE *)(pHdr)+sizeof(INT),
|
|
cchBeforeBody*sizeof(WCHAR));
|
|
|
|
// fill 0s from pwNew+cchBeforeBody till pwNew+ichNewCur-1 (inclusive)
|
|
if ((int)ichNewCur-cchBeforeBody > 0)
|
|
memset((BYTE *)(pwNew+cchBeforeBody), 0, (ichNewCur-cchBeforeBody)*sizeof(WCHAR));
|
|
|
|
ichNewCur = cchBeforeBody; // note that we are initializing ichNewCur here ***
|
|
ichBeginCopy = ichBodyEnd; // make it ready for next copy
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBodyStart]),
|
|
(ichBodyEnd-ichBodyStart)*sizeof(WCHAR));
|
|
ichNewCur += (ichBodyEnd-ichBodyStart);
|
|
}
|
|
else // if we didn't save anything, it means that we had no pre-BODY stuff in the doc (bug 15393)
|
|
{
|
|
if (ptep->m_fUnicodeFile && ichNewCur == 0)
|
|
{
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, sizeof(WCHAR));
|
|
ichNewCur = ichBeginCopy = 1;
|
|
}
|
|
// actually, we should get the '>' of <body> tag instead of using iArray+1
|
|
if (dwFlags & dwFilterSourceCode)
|
|
ichBeginCopy = pTokArray[iArray+1].token.ibTokMac; // '>' of <BODY> tag
|
|
else
|
|
{
|
|
#ifdef NEEDED // VID6 - bug 22781 (This is going to generate some debate, so #ifdef instead of removing.
|
|
LPCWSTR rgPreBody[] =
|
|
{
|
|
L"<HTML>\r\n<HEAD><TITLE></TITLE></HEAD>\r\n",
|
|
};
|
|
ASSERT(ichNewCur >= 0); // make sure its not invalid
|
|
memcpy( (BYTE *)&pwNew[ichNewCur], (BYTE *)rgPreBody[0], wcslen(rgPreBody[0])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgPreBody[0]);
|
|
#endif //NEEDED
|
|
// Note that we had not saved any thing before going to design view because there was
|
|
// no <BODY> tag. we should now copy from current pwOld[ichBeginCopy] till
|
|
// the new pwOld[ichBeginCopy] into pwNew[ichNewCur] and then set ichBeginCopy.
|
|
if (pTokArray[iArray-1].token.ibTokMin > ichBeginCopy)
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichBeginCopy],
|
|
(pTokArray[iArray-1].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iArray-1].token.ibTokMin-ichBeginCopy;
|
|
}
|
|
ichBeginCopy = pTokArray[iArray-1].token.ibTokMin; // '<' of <BODY> tag
|
|
}
|
|
}
|
|
|
|
LErrorRet:
|
|
// unlock
|
|
GlobalUnlock(ptep->m_hgDocRestore);
|
|
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
LRetOnly:
|
|
return;
|
|
|
|
} /* fnRestoreHdr() */
|
|
|
|
|
|
void CTriEditParse::fnSaveFtr(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy, DWORD /*dwFlags*/)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
INT cchAfterBody = 0;
|
|
INT cchBeforeBody = 0;
|
|
INT cchPreEndBody = 0;
|
|
WCHAR *pFtr;
|
|
INT ichStart, ichEnd;
|
|
UINT iArraySav = iArray;
|
|
UINT cbNeed;
|
|
|
|
if (ptep->m_hgDocRestore == NULL)
|
|
goto LRetOnly;
|
|
|
|
// lock
|
|
pFtr = (WCHAR *)GlobalLock(ptep->m_hgDocRestore);
|
|
ASSERT(pFtr != NULL);
|
|
ichStart = pTokArray[iArray-1].token.ibTokMin; // init
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_BODY);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
ASSERT(pTokArray[iArray-1].token.tok == TokTag_END);
|
|
// what if we DON'T have a </BODY> tag at all. Lets handle the error case here
|
|
// If thats the case, we just don't save anything
|
|
ASSERT(iArray-1 >= 0);
|
|
if (pTokArray[iArray-1].token.tok != TokTag_END)
|
|
{
|
|
cchAfterBody = 0;
|
|
cchPreEndBody = 0;
|
|
}
|
|
else
|
|
{
|
|
// following was added for Bug fix for 7542
|
|
cchAfterBody = pTokArray[ptep->m_cMaxToken-1].token.ibTokMac-pTokArray[iArray].token.ibTokMac;
|
|
|
|
// now calculate the space required to save stuff from before </BODY>
|
|
// till the previous meaningful token
|
|
ichStart = ichEnd = pTokArray[iArray-1].token.ibTokMin;
|
|
ichStart--; // now ichStart is pointing to a character before </BODY>
|
|
while ( (ichStart >= 0)
|
|
&& ( pwOld[ichStart] == ' '
|
|
|| pwOld[ichStart] == '\r'
|
|
|| pwOld[ichStart] == '\n'
|
|
|| pwOld[ichStart] == '\t'
|
|
)
|
|
)
|
|
{
|
|
ichStart--;
|
|
}
|
|
ichStart++; // the current char is not one of the above, so increment
|
|
if (ichStart == ichEnd) // we didn't have anyspace, eol, tab between </BODY> & previous token
|
|
{
|
|
cchPreEndBody = 0;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(ichEnd - ichStart > 0);
|
|
cchPreEndBody = ichEnd - ichStart;
|
|
}
|
|
}
|
|
|
|
// get cchBeforeBody if pre-BODY part was saved, and adjust pFtr for saving
|
|
memcpy((BYTE *)&cchBeforeBody, (BYTE *)pFtr, sizeof(INT));
|
|
pFtr += cchBeforeBody + sizeof(INT)/sizeof(WCHAR);
|
|
|
|
// realloc if needed
|
|
if ((cchPreEndBody+cchAfterBody+cchBeforeBody)*sizeof(WCHAR)+3*sizeof(int) > GlobalSize(ptep->m_hgDocRestore))
|
|
{
|
|
HGLOBAL hgDocRestore;
|
|
GlobalUnlock(ptep->m_hgDocRestore);
|
|
hgDocRestore = ptep->m_hgDocRestore;
|
|
#pragma prefast(suppress:308, "noise")
|
|
ptep->m_hgDocRestore = GlobalReAlloc(ptep->m_hgDocRestore, (cchPreEndBody+cchAfterBody+cchBeforeBody)*sizeof(WCHAR)+3*sizeof(int), GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
// if this alloc failed, we may still want to continue
|
|
if (ptep->m_hgDocRestore == NULL)
|
|
{
|
|
GlobalFree(hgDocRestore);
|
|
goto LRet;
|
|
}
|
|
else
|
|
{
|
|
pFtr = (WCHAR *)GlobalLock(ptep->m_hgDocRestore); // do we need to unlock this first?
|
|
ASSERT(pFtr != NULL);
|
|
// remember to set pFtr to be after cchBeforeBody
|
|
pFtr += cchBeforeBody + sizeof(INT)/sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
// copy from pwOld
|
|
memcpy( (BYTE *)pFtr,
|
|
(BYTE *)&cchAfterBody,
|
|
sizeof(INT));
|
|
memcpy( (BYTE *)(pFtr)+sizeof(INT),
|
|
(BYTE *)(pwOld+pTokArray[iArray].token.ibTokMac),
|
|
cchAfterBody*sizeof(WCHAR));
|
|
pFtr += cchAfterBody + sizeof(INT)/sizeof(WCHAR);
|
|
|
|
memcpy( (BYTE *)pFtr,
|
|
(BYTE *)&cchPreEndBody,
|
|
sizeof(INT));
|
|
memcpy( (BYTE *)(pFtr)+sizeof(INT),
|
|
(BYTE *)&(pwOld[ichStart]),
|
|
cchPreEndBody*sizeof(WCHAR));
|
|
|
|
// the very next token from TokElem_BODY will be TokTag_CLOSE in most cases, but just in case...
|
|
while (iArray < ptep->m_cMaxToken)
|
|
{
|
|
if (pTokArray[iArray].token.tok == TokTag_CLOSE && pTokArray[iArray].token.tokClass == tokTag)
|
|
break;
|
|
iArray++;
|
|
}
|
|
if (iArray >= ptep->m_cMaxToken)
|
|
{
|
|
iArray = iArraySav+1; // atleast copy till that point
|
|
goto LRet;
|
|
}
|
|
|
|
// copy till '>' of </BODY> from pwOld into pwNew
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
|
|
cbNeed = (ichNewCur+pTokArray[iArray].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
memcpy( (BYTE *)&(pwNew[ichNewCur]),
|
|
(BYTE *)&(pwOld[ichBeginCopy]),
|
|
(pTokArray[iArray].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iArray].token.ibTokMac-ichBeginCopy;
|
|
ichBeginCopy = pTokArray[iArray].token.ibTokMac;
|
|
|
|
iArray = ptep->m_cMaxToken - 1;
|
|
ichBeginCopy = pTokArray[ptep->m_cMaxToken-1].token.ibTokMac; // we don't want to copy anything after this
|
|
|
|
LRet:
|
|
// unlock
|
|
GlobalUnlock(ptep->m_hgDocRestore);
|
|
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
LRetOnly:
|
|
return;
|
|
|
|
} /* fnSaveFtr() */
|
|
|
|
void CTriEditParse::fnRestoreFtr(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy, DWORD dwFlags)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
INT cchAfterBody = 0;
|
|
INT cchBeforeBody = 0;
|
|
WCHAR *pFtr;
|
|
INT ichBodyEnd;
|
|
UINT i, iFound;
|
|
INT ichInsEOL = -1; // initilize
|
|
UINT cbNeed;
|
|
|
|
if (ptep->m_hgDocRestore == NULL)
|
|
goto LRetOnly;
|
|
|
|
// lock, copy, unlock
|
|
pFtr = (WCHAR *)GlobalLock(ptep->m_hgDocRestore);
|
|
ASSERT(pFtr != NULL);
|
|
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_BODY);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
|
|
// HACK to fix a TRIDENT misbehaviour
|
|
// If we had any text before <BODY> tag going into Trident, it will add 2nd <BODY>
|
|
// tag before this text comming out of Trident without looking forward and
|
|
// recognizing that a <BODY> tag already exists. Ideally, Trident should move teh
|
|
// <BODY> tag at appropriate place rather than inserting a 2nd one.
|
|
// Lets assume that Trident will insert only one extra <\BODY> tag.
|
|
i = iArray + 1; // we know iArray is the 1st <\BODY> tag
|
|
iFound = iArray;
|
|
while (i < ptep->m_cMaxToken)
|
|
{
|
|
if ( (pTokArray[i].token.tok == ft.tokBegin2) /*TokElem_BODY*/
|
|
&& (pTokArray[i-1].token.tok == TokTag_END)
|
|
)
|
|
{
|
|
iFound = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (iFound > iArray) // this means that we found the last <BODY> tag Trident inserted
|
|
iArray = iFound;
|
|
|
|
memcpy((BYTE *)&cchBeforeBody, (BYTE *)pFtr, sizeof(INT));
|
|
pFtr += cchBeforeBody + sizeof(INT)/sizeof(WCHAR);
|
|
memcpy((BYTE *)&cchAfterBody, (BYTE *)pFtr, sizeof(INT));
|
|
pFtr += sizeof(INT)/sizeof(WCHAR);
|
|
ichBodyEnd = pTokArray[iArray].token.ibTokMac;
|
|
// if (cchAfterBody == 0) // get the size of our own header
|
|
|
|
// realloc if needed
|
|
cbNeed = (ichNewCur+cchAfterBody+(ichBodyEnd-ichBeginCopy)+2/* for EOL*/)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
|
|
if (cchAfterBody > 0)
|
|
{
|
|
LPCWSTR rgSpaceTags[] = {L"DESIGNTIMESP"};
|
|
int cchTag, index, indexDSP;
|
|
|
|
// ichBeginCopy is a position in pwOld and
|
|
// ichNewCur is a position in pwNew
|
|
// copy from ichBeginCopy to end of HTML document
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichBodyEnd-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichBodyEnd-ichBeginCopy);
|
|
ichBeginCopy = ichBodyEnd;
|
|
|
|
// now that we have copied 'BODY' of </BODY> tag, lets make sure its of correct case (bug 18248)
|
|
indexDSP = -1;
|
|
index = pTokArray[iArray].iNextprev;
|
|
cchTag = wcslen(rgSpaceTags[0]);
|
|
if (index != -1 && index < (int)iArray) // we have matching <BODY> tag prior to this one
|
|
{
|
|
// get the designtimesp attribute
|
|
while (index < (int)iArray) // we will never come this far, but thats the only known position at this point
|
|
{
|
|
if (pTokArray[index].token.tok == TokTag_CLOSE)
|
|
break;
|
|
if ( (pTokArray[index].token.tok == 0)
|
|
&& (pTokArray[index].token.tokClass == tokSpace)
|
|
&& (0 == _wcsnicmp(rgSpaceTags[0], &pwOld[pTokArray[index].token.ibTokMin], cchTag))
|
|
)
|
|
{
|
|
indexDSP = index;
|
|
break;
|
|
}
|
|
index++;
|
|
} // while
|
|
if (indexDSP != -1) // we found DESIGNTIMESP attribute
|
|
{
|
|
// look for the case of designtimesp
|
|
if (iswupper(pwOld[pTokArray[indexDSP].token.ibTokMin]) != 0) // DESIGNTIMESP is upper case
|
|
_wcsupr(&pwNew[ichNewCur-4]); // length of BODY tag name
|
|
else
|
|
_wcslwr(&pwNew[ichNewCur-4]); // length of BODY tag name
|
|
}
|
|
}
|
|
|
|
// we know that the following condition will be met most of the times, but just to cover
|
|
// incomplete HTML cases...
|
|
if ( (pTokArray[iArray].token.tok == ft.tokBegin2) /*TokElem_BODY*/
|
|
&& (pTokArray[iArray-1].token.tok == TokTag_END)
|
|
)
|
|
{
|
|
ichInsEOL = ichNewCur - (pTokArray[iArray].token.ibTokMac - pTokArray[iArray-1].token.ibTokMin);
|
|
}
|
|
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)pFtr,
|
|
(cchAfterBody)*sizeof(WCHAR));
|
|
ichNewCur += (cchAfterBody);
|
|
|
|
// we had saved spacing info before </BODY>
|
|
if (ichInsEOL != -1)
|
|
{
|
|
INT cchPreEndBody = 0;
|
|
|
|
pFtr += cchAfterBody;
|
|
cchPreEndBody = *(int *)pFtr;
|
|
if (cchPreEndBody > 0)
|
|
{
|
|
INT ichT = ichInsEOL-1;
|
|
WCHAR *pw = NULL;
|
|
INT cchSubStr = 0;
|
|
WCHAR *pwStr = NULL;
|
|
WCHAR *pwSubStr = NULL;
|
|
|
|
pFtr += sizeof(INT)/sizeof(WCHAR); // pFtr now points to Pre </BODY> stuff
|
|
// This is kind of hacky - but I don't see a way out, atleast
|
|
// If the contents in pFtr at cchPreEndBody are subset of the
|
|
// contents before </BODY> and after any previous text/tokens,
|
|
// then we shouldn't do the following memcpy()
|
|
while ( ichT >= 0 /* validation */
|
|
&& ( pwNew[ichT] == ' '
|
|
|| pwNew[ichT] == '\n'
|
|
|| pwNew[ichT] == '\r'
|
|
|| pwNew[ichT] == '\t'
|
|
)
|
|
)
|
|
{
|
|
ichT--;
|
|
cchSubStr++;
|
|
}
|
|
ichT++; // compensate the last decrement
|
|
if (cchSubStr > 0)
|
|
{
|
|
ASSERT(ichT >= 0);
|
|
pwStr = new WCHAR [cchSubStr+1];
|
|
memcpy((BYTE *)pwStr, (BYTE *)(&pwNew[ichT]), cchSubStr*sizeof(WCHAR));
|
|
pwStr[cchSubStr] = '\0';
|
|
pwSubStr = new WCHAR [cchPreEndBody+1];
|
|
memcpy((BYTE *)pwSubStr, (BYTE *)pFtr, cchPreEndBody*sizeof(WCHAR));
|
|
pwSubStr[cchPreEndBody] = '\0';
|
|
pw = wcsstr(pwStr, pwSubStr);
|
|
}
|
|
if (pw == NULL) // means that the substring wasn't found
|
|
{
|
|
// allocate more memory if needed
|
|
cbNeed = (ichNewCur+cchPreEndBody)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
|
|
|
|
memmove((BYTE *)(&pwNew[ichInsEOL+cchPreEndBody]),
|
|
(BYTE *)(&pwNew[ichInsEOL]),
|
|
(ichNewCur-ichInsEOL)*sizeof(WCHAR));
|
|
memcpy( (BYTE *)(&pwNew[ichInsEOL]),
|
|
(BYTE *)(pFtr),
|
|
(cchPreEndBody)*sizeof(WCHAR));
|
|
ichNewCur += cchPreEndBody;
|
|
}
|
|
if (pwStr != NULL)
|
|
delete pwStr;
|
|
if (pwSubStr != NULL)
|
|
delete pwSubStr;
|
|
} // if (cchPreEndBody > 0)
|
|
} // if (ichInsEOL != -1)
|
|
|
|
ichBeginCopy = pTokArray[ptep->m_cMaxToken-1].token.ibTokMac; // we don't want to copy anything after this
|
|
iArray = ptep->m_cMaxToken - 1;
|
|
|
|
// WISH LIST Item for space preservation
|
|
// we know that ptep->m_ispInfoBlock was the last spacing block that was recovered.
|
|
// This block (like all others) has 4 parts (1)pre '<' (2)between '<>' & order info
|
|
// (3)post '>' (4)pre matching '</'
|
|
// At this point we care about (3) & (4)
|
|
// first of all, get ichBeginNext (ich past '>') & ichBeginMatch (ich before '</')
|
|
// apply the saved spacing info to the contents of pwNew
|
|
|
|
// The difficult part is to get these ich's without parsing pwNew.
|
|
}
|
|
else
|
|
{
|
|
// copy our own Footer
|
|
if (dwFlags & dwFilterSourceCode)
|
|
{
|
|
int ichBodyStart, index, ichBodyTagEnd;
|
|
|
|
// get the '</' of </body>
|
|
index = iArray;
|
|
while (index >= 0) // we won't go this far, but just in case we have invalid html
|
|
{
|
|
if ( pTokArray[index].token.tok == TokTag_END
|
|
&& pTokArray[index].token.tokClass == tokTag
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
index--;
|
|
}
|
|
if (index >= 0)
|
|
{
|
|
ichBodyStart = pTokArray[index].token.ibTokMin;
|
|
// copy till the current token's begining, see if we have enough space
|
|
if (ichBodyStart > (int)ichBeginCopy)
|
|
{
|
|
cbNeed = (ichNewCur+ichBodyStart-ichBeginCopy+1/*for null at the end*/)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichBodyStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichBodyStart-ichBeginCopy);
|
|
ichBeginCopy = ichBodyStart; // setting this is redundant, but it makes the code readable.
|
|
}
|
|
else if (ichBodyEnd > (int)ichBeginCopy)
|
|
{
|
|
index = iArray;
|
|
while (index <= (int)ptep->m_cMaxToken) // we won't go this far, but just in case we have invalid html
|
|
{
|
|
if ( pTokArray[index].token.tok == TokTag_CLOSE
|
|
&& pTokArray[index].token.tokClass == tokTag
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
if (index < (int)ptep->m_cMaxToken)
|
|
{
|
|
ichBodyTagEnd = pTokArray[index].token.ibTokMac;
|
|
cbNeed = (ichNewCur+ichBodyTagEnd-ichBeginCopy+1/*for null at the end*/)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichBodyTagEnd-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichBodyTagEnd-ichBeginCopy);
|
|
ichBeginCopy = ichBodyTagEnd; // setting this is redundant, but it makes the code readable.
|
|
}
|
|
}
|
|
|
|
// add a null at the end
|
|
// to keep the code in ssync with the if (cchAfterBody > 0) case
|
|
pwNew[ichNewCur++] = '\0';
|
|
|
|
ichBeginCopy = pTokArray[ptep->m_cMaxToken-1].token.ibTokMac; // we don't want to copy anything after this
|
|
iArray = ptep->m_cMaxToken - 1;
|
|
} // if (index >= 0)
|
|
} // if (dwFlags & dwFilterSourceCode)
|
|
}
|
|
|
|
|
|
if (ptep->m_cchPTDTC != 0)
|
|
{
|
|
// this means that we didn't encounter the DTC on way out from Trident
|
|
// but they were there when we went to Trident. The user must have deleted
|
|
// the DTCs while in Design view
|
|
ASSERT(ptep->m_ichPTDTC != 0);
|
|
// remove m_cchPTDTC WCHARS from m_ichPTDTC
|
|
memset( (BYTE *)&pwNew[ptep->m_ichPTDTC],
|
|
0,
|
|
ptep->m_cchPTDTC*sizeof(WCHAR)
|
|
);
|
|
memmove((BYTE *)&pwNew[ptep->m_ichPTDTC],
|
|
(BYTE *)&pwNew[ptep->m_ichPTDTC+ptep->m_cchPTDTC],
|
|
(ichNewCur-(ptep->m_ichPTDTC+ptep->m_cchPTDTC))*sizeof(WCHAR)
|
|
);
|
|
ichNewCur -= ptep->m_cchPTDTC;
|
|
ptep->m_cchPTDTC = 0;
|
|
}
|
|
|
|
LErrorRet:
|
|
// unlock
|
|
GlobalUnlock(ptep->m_hgDocRestore);
|
|
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
LRetOnly:
|
|
return;
|
|
|
|
} /* fnRestoreFtr() */
|
|
|
|
|
|
void CTriEditParse::fnSaveObject(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy, DWORD /*dwFlags*/)
|
|
{
|
|
// scan till the end of the object.
|
|
// If we find '<% %>' blocks inside, put a comment with a special tag around it,
|
|
// else simply copy that object as is and exit
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
INT ichObjectStart, ichObjectEnd, iObjectStart, iObjectEnd, i;
|
|
BOOL fSSSFound = FALSE;
|
|
UINT iArraySav = iArray;
|
|
UINT cbNeed;
|
|
|
|
ichObjectStart = ichObjectEnd = iObjectStart = iObjectEnd = 0;
|
|
|
|
if ( pTokArray[iArray-1].token.tok == TokTag_END
|
|
&& pTokArray[iArray-1].token.tokClass == tokTag
|
|
)
|
|
{
|
|
iArray++;
|
|
goto LRet;
|
|
}
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_OBJECT); // we should be at the object tag
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
iObjectStart = iArray;
|
|
|
|
if (pTokArray[iArray].iNextprev != -1)
|
|
{
|
|
// NOTE that this will give us topmost nested level of the OBJECT, if we had nested objects
|
|
iObjectEnd = pTokArray[iArray].iNextprev;
|
|
ASSERT(iObjectEnd < (INT)ptep->m_cMaxToken);
|
|
ASSERT((iObjectEnd-1 >= 0) && pTokArray[iObjectEnd-1].token.tok == TokTag_END);
|
|
|
|
// this will be a wierd case where the iNextprev is incorrectly pointing to another token
|
|
// but lets handle that case.
|
|
if (pTokArray[iObjectEnd].token.tok != TokElem_OBJECT)
|
|
goto LFindObjectClose; // find it by looking at each token
|
|
}
|
|
else // actually, this is an error case, but rather than just giving assert, try to find the token
|
|
{
|
|
LFindObjectClose:
|
|
i = iObjectStart+1;
|
|
while (i < (INT)ptep->m_cMaxToken)
|
|
{
|
|
// this may not give us the correct matching </OBJECT> if we had nested objects.
|
|
// but we don't have that knowledge at this point any way.
|
|
if ( pTokArray[i].token.tok == TokElem_OBJECT
|
|
&& pTokArray[i].token.tokClass == tokElem
|
|
&& (i-1 >= 0) /* validation */
|
|
&& pTokArray[i-1].token.tok == TokTag_END
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i < (INT)ptep->m_cMaxToken) // found TokElem_OBJECT token
|
|
iObjectEnd = i;
|
|
else // error case
|
|
goto LRet; // didn't find OBJECT, but exhausted the token array
|
|
}
|
|
// at this point iObjectStart & iObjectEnd point to OBJECT of <OBJECT> and iObjectEnd respectively
|
|
// look for '<' in <OBJECT> & and '>' in </OBJECT>
|
|
i = iObjectStart;
|
|
while (i >= 0)
|
|
{
|
|
if ( pTokArray[i].token.tok == TokTag_START
|
|
&& pTokArray[i].token.tokClass == tokTag
|
|
)
|
|
break;
|
|
i--;
|
|
}
|
|
if (i < 0) // error case
|
|
goto LRet;
|
|
iObjectStart = i;
|
|
ichObjectStart = pTokArray[iObjectStart].token.ibTokMin;
|
|
|
|
i = iObjectEnd;
|
|
while (i <= (INT)ptep->m_cMaxToken)
|
|
{
|
|
if ( pTokArray[i].token.tok == TokTag_CLOSE
|
|
&& pTokArray[i].token.tokClass == tokTag
|
|
)
|
|
break;
|
|
i++;
|
|
}
|
|
if (i >= (INT)ptep->m_cMaxToken) // error case
|
|
goto LRet;
|
|
iObjectEnd = i;
|
|
ichObjectEnd = pTokArray[iObjectEnd].token.ibTokMac;
|
|
ASSERT(ichObjectEnd > ichObjectStart);
|
|
|
|
// look for <% %> between iObjectStart & iObjectEnd
|
|
for (i = iObjectStart; i <= iObjectEnd; i++)
|
|
{
|
|
if ( pTokArray[i].token.tok == TokTag_SSSOPEN
|
|
&& pTokArray[i].token.tokClass == tokSSS
|
|
)
|
|
{
|
|
fSSSFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (fSSSFound) // this object can't be displayed in Trident, so convert it
|
|
{
|
|
LPCWSTR rgComment[] =
|
|
{
|
|
L"<!--ERROROBJECT ",
|
|
L" ERROROBJECT-->",
|
|
};
|
|
|
|
//if (dwFlags & dwPreserveSourceCode)
|
|
//{
|
|
// in this case, we would have already copied <OBJECT ... DESIGNTIMESP=x>
|
|
// and ichNewCur is adjusted accordingly
|
|
// get ich that points after <OBJECT> in pwOld
|
|
|
|
// I don't like this, but don't see a way out...
|
|
// look back in pwNew and get ich that points to '<' of <OBJECT ... DESIGNTIMESP=x>
|
|
// insert the comment there
|
|
//}
|
|
//else
|
|
//{
|
|
ASSERT((INT)(ichObjectStart-ichBeginCopy) > 0);
|
|
cbNeed = (ichNewCur+ichObjectEnd-ichBeginCopy+wcslen(rgComment[0])+wcslen(rgComment[1]))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LNoCopy;
|
|
|
|
// copy till begining of <OBJECT>
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichObjectStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += ichObjectStart-ichBeginCopy;
|
|
|
|
// copy the comment begining
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(rgComment[0]),
|
|
wcslen(rgComment[0])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgComment[0]);
|
|
|
|
// copy from <OBJECT> to </OBJECT>
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichObjectStart]),
|
|
(ichObjectEnd-ichObjectStart)*sizeof(WCHAR));
|
|
ichNewCur += ichObjectEnd-ichObjectStart;
|
|
|
|
// copy the comment end
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(rgComment[1]),
|
|
wcslen(rgComment[1])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgComment[1]);
|
|
//}
|
|
}
|
|
else
|
|
{
|
|
// We always save its contents into our buffer and replace it on the way back if need be
|
|
// save cchClsId, clsId, cchParam, PARAM_Tags
|
|
INT cchParam, ichParam, iParamStart, iParamEnd;
|
|
INT ichObjStartEnd; // ich at the end of <OBJECT .....>
|
|
LPCWSTR rgComment[] =
|
|
{
|
|
L"<!--ERRORPARAM ",
|
|
L" ERRORPARAM-->",
|
|
};
|
|
INT iObjTagEnd = -1;
|
|
|
|
iParamStart = iObjectStart;
|
|
while (iParamStart < iObjectEnd)
|
|
{
|
|
//if ( pTokArray[iParamStart].token.tok == TokAttrib_CLASSID
|
|
// && pTokArray[iParamStart].token.tokClass == tokAttr)
|
|
// iClsId = iParamStart;
|
|
if ( pTokArray[iParamStart].token.tok == TokElem_PARAM
|
|
&& pTokArray[iParamStart].token.tokClass == tokElem)
|
|
break;
|
|
iParamStart++;
|
|
}
|
|
if (iParamStart >= iObjectEnd) // don't see any <PARAM> tags, so don't save
|
|
goto LSkipSave;
|
|
|
|
while (iParamStart > iObjectStart) // generally this will the previous token, but cover all cases
|
|
{
|
|
if ( pTokArray[iParamStart].token.tok == TokTag_START
|
|
&& pTokArray[iParamStart].token.tokClass == tokTag)
|
|
break;
|
|
iParamStart--;
|
|
}
|
|
if (iParamStart <= iObjectStart) // error
|
|
goto LSkipSave;
|
|
ichParam = pTokArray[iParamStart].token.ibTokMin;
|
|
|
|
iParamEnd = iObjectEnd;
|
|
while (iParamEnd > iObjectStart)
|
|
{
|
|
if ( pTokArray[iParamEnd].token.tok == TokElem_PARAM
|
|
&& pTokArray[iParamEnd].token.tokClass == tokElem)
|
|
break;
|
|
iParamEnd--;
|
|
}
|
|
while (iParamEnd < iObjectEnd) // generally this will the previous token, but cover all cases
|
|
{
|
|
if ( pTokArray[iParamEnd].token.tok == TokTag_CLOSE
|
|
&& pTokArray[iParamEnd].token.tokClass == tokTag)
|
|
break;
|
|
iParamEnd++;
|
|
}
|
|
if (iParamEnd >= iObjectEnd) // error
|
|
goto LSkipSave;
|
|
cchParam = pTokArray[iParamEnd].token.ibTokMac - ichParam;
|
|
ASSERT(cchParam > 0);
|
|
|
|
// calculate ichObjStartEnd
|
|
iObjTagEnd = iObjectStart;
|
|
while (iObjTagEnd < iParamStart)
|
|
{
|
|
if ( pTokArray[iObjTagEnd].token.tok == TokTag_CLOSE
|
|
&& pTokArray[iObjTagEnd].token.tokClass == tokTag)
|
|
break;
|
|
iObjTagEnd++;
|
|
}
|
|
if (iObjTagEnd >= iParamStart) // error case
|
|
goto LSkipSave;
|
|
ichObjStartEnd = pTokArray[iObjTagEnd].token.ibTokMac;
|
|
|
|
// realloc if needed
|
|
cbNeed = (ichNewCur+cchParam+(ichObjStartEnd-ichBeginCopy)+wcslen(rgComment[0])+wcslen(rgComment[1]))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LSkipSave;
|
|
|
|
// 1. copy <OBJECT ...> tag into pwNew
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichObjStartEnd-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichObjStartEnd-ichBeginCopy);
|
|
ichBeginCopy = ichObjStartEnd;
|
|
#ifdef ERROR_PARAM
|
|
// 2. now insert the <PARAM> tags as a comment at pwNew[ichNewCur]
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(rgComment[0]),
|
|
wcslen(rgComment[0])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgComment[0]);
|
|
|
|
// we should copy <PARAM> tags ONLY. We may have things other than the tags
|
|
// in between. e.g. comments
|
|
// Look for TokElem_PARAM between iParamStart & iParamEnd
|
|
ASSERT(pTokArray[iParamStart].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[iParamEnd].token.tok == TokTag_CLOSE);
|
|
// Find PARAM tag, get the '<' & '>' for that PARAM and copy that to pwNew
|
|
// repeat
|
|
index = iParamStart;
|
|
iPrev = iParamStart;
|
|
while (index <= iParamEnd)
|
|
{
|
|
INT iStart, iEnd;
|
|
|
|
iStart = iEnd = -1; // that way, its easy to make sure that this is initilized
|
|
// get PARAM
|
|
while ( ( pTokArray[index].token.tok != TokElem_PARAM
|
|
|| pTokArray[index].token.tokClass != tokElem)
|
|
&& (index <= iParamEnd)
|
|
)
|
|
index++;
|
|
if (index > iParamEnd)
|
|
goto LDoneCopy;
|
|
// get '<' before the PARAM
|
|
while ( ( pTokArray[index].token.tok != TokTag_START
|
|
|| pTokArray[index].token.tokClass != tokTag)
|
|
&& (index >= iPrev)
|
|
)
|
|
index--;
|
|
if (index < iPrev)
|
|
goto LDoneCopy;
|
|
iStart = index;
|
|
|
|
// get matching '>'
|
|
while ( ( pTokArray[index].token.tok != TokTag_CLOSE
|
|
|| pTokArray[index].token.tokClass != tokTag)
|
|
&& (index <= iParamEnd)
|
|
)
|
|
index++;
|
|
|
|
if (index > iParamEnd)
|
|
goto LDoneCopy;
|
|
iEnd = index;
|
|
ASSERT(iEnd > iStart);
|
|
ASSERT(iStart != -1);
|
|
ASSERT(iEnd != -1);
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[pTokArray[iStart].token.ibTokMin]),
|
|
(pTokArray[iEnd].token.ibTokMac-pTokArray[iStart].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[iEnd].token.ibTokMac-pTokArray[iStart].token.ibTokMin);
|
|
iPrev = iEnd + 1;
|
|
}
|
|
LDoneCopy:
|
|
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(rgComment[1]),
|
|
wcslen(rgComment[1])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgComment[1]);
|
|
#endif //ERROR_PARAM
|
|
|
|
// fake iArraySav to be iObjTagEnd, that way we will st iArray correctly before we leave
|
|
ASSERT(iObjTagEnd != -1);
|
|
iArraySav = (UINT)iObjTagEnd;
|
|
|
|
LSkipSave:
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
LNoCopy:
|
|
ichBeginCopy = ichObjectEnd; // set it for next copy
|
|
iArray = iObjectEnd+1; // set it after </OBJECT>
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
//LRetOnly:
|
|
return;
|
|
|
|
} /* fnSaveObject() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreObject(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy, DWORD /*dwFlags*/)
|
|
{
|
|
// look for the special tag after the '<!--'
|
|
// if we find it, this was an object, remove the comments around it
|
|
// else simply copy the comment and return
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
INT iArraySav = iArray;
|
|
INT ichCommentStart, ichCommentEnd, iCommentStart, iCommentEnd, cchComment1, cchComment2;
|
|
INT ichObjectStart;
|
|
LPCWSTR rgComment[] =
|
|
{
|
|
L"ERROROBJECT",
|
|
L"--ERROROBJECT ",
|
|
L" ERROROBJECT--",
|
|
L"TRIEDITCOMMENT-",
|
|
L"TRIEDITCOMMENTEND-",
|
|
L"TRIEDITPRECOMMENT-",
|
|
};
|
|
BOOL fSimpleComment = FALSE;
|
|
UINT cbNeed;
|
|
|
|
ichCommentStart = ichCommentEnd = iCommentStart = iCommentEnd = 0;
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_BANG); // we should be at the comment
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
|
|
// ASSUMPTION - that Trident doesn't muck with the contents inside a comment block
|
|
|
|
// if rgComment[0] matches and rgComment[1] does not, Trident may have mucked with the
|
|
// comment contents. This invalidates our original assumption.
|
|
// NOTE - In this version, we can get away by assuming that trident doesn't muck with the comments
|
|
|
|
// early return cases
|
|
// 1. see if this is a comment or not. It could be anything that starts with '<!'
|
|
// e.g. <!DOCTYPE
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken)
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin] == '-')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin+1] == '-')
|
|
&& (0 == _wcsnicmp(rgComment[0], &pwOld[pTokArray[iArray+1].token.ibTokMin+2], wcslen(rgComment[0])))
|
|
)
|
|
{
|
|
iCommentStart = iArray; // this is a comment we are interested in
|
|
}
|
|
else if ( (iArray+1 < (INT)ptep->m_cMaxToken)
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin] == '-')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin+1] == '-')
|
|
&& (0 == _wcsnicmp(rgComment[3], &pwOld[pTokArray[iArray+1].token.ibTokMin+2], wcslen(rgComment[3])))
|
|
)
|
|
{
|
|
fSimpleComment = TRUE; // BUG 14056 - Instead of going to LRet, process the comment for space preservation. We will save 3 strings that look similar to text run
|
|
}
|
|
else
|
|
{
|
|
iArray = iArraySav + 1; // not this one
|
|
goto LRet;
|
|
}
|
|
// The first part matched, look at the end of the comment
|
|
if ( (pwOld[pTokArray[iArray+1].token.ibTokMac-1] == '-')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMac-2] == '-')
|
|
&& (0 == _wcsnicmp( rgComment[0],
|
|
&pwOld[pTokArray[iArray+1].token.ibTokMac-(wcslen(rgComment[0])+2)],
|
|
wcslen(rgComment[0])
|
|
)
|
|
)
|
|
)
|
|
{
|
|
iCommentEnd = iArray + 2;
|
|
ASSERT(iCommentEnd < (INT)ptep->m_cMaxToken);
|
|
}
|
|
else // error case (our assumption was not valid). ignore and return with iArraySav+1
|
|
{
|
|
if (!fSimpleComment)
|
|
{
|
|
iArray = iArraySav + 1; // not this one
|
|
goto LRet;
|
|
}
|
|
}
|
|
|
|
if (!fSimpleComment)
|
|
{
|
|
// found the correct one
|
|
cchComment1 = wcslen(rgComment[1]);
|
|
cchComment2 = wcslen(rgComment[2]);
|
|
// remove cchComment1 chars from begining of pwOld[pTokArray[iArray+1].token.ibTokMin
|
|
// remove cchComment2 chars from the end of pwOld[pTokArray[iArray+1].token.ibTokMac
|
|
// and copy the rest into pwNew
|
|
|
|
// copy till begining of the comment
|
|
ichCommentStart = pTokArray[iCommentStart].token.ibTokMin;
|
|
ichObjectStart = pTokArray[iCommentStart+1].token.ibTokMin+cchComment1;
|
|
ASSERT((INT)ichCommentStart-ichBeginCopy >= 0);
|
|
|
|
cbNeed = (ichNewCur+(ichCommentStart-ichBeginCopy)+(pTokArray[iArray+1].token.ibTokMac-pTokArray[iArray+1].token.ibTokMin))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+ichBeginCopy),
|
|
(ichCommentStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += ichCommentStart-ichBeginCopy;
|
|
ichBeginCopy = pTokArray[iCommentEnd].token.ibTokMac;
|
|
|
|
ASSERT((INT)(pTokArray[iArray+1].token.ibTokMac-pTokArray[iArray+1].token.ibTokMin-cchComment1-cchComment2) >= 0);
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)&(pwOld[ichObjectStart]),
|
|
(pTokArray[iArray+1].token.ibTokMac-pTokArray[iArray+1].token.ibTokMin-cchComment1-cchComment2)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iArray+1].token.ibTokMac-pTokArray[iArray+1].token.ibTokMin-cchComment1-cchComment2;
|
|
iArray = iCommentEnd + 1;
|
|
}
|
|
else
|
|
{
|
|
int ichspBegin, ichspEnd, ichCopy;
|
|
WCHAR *pwstr = NULL;
|
|
|
|
// part 1 - copy till begining of the comment & apply spacing
|
|
iCommentStart = iArraySav;
|
|
ASSERT(pTokArray[iArraySav].token.tok == TokTag_BANG);
|
|
ASSERT(pTokArray[iArraySav].token.tokClass == tokTag);
|
|
|
|
iCommentEnd = iCommentStart + 2;
|
|
ASSERT(pTokArray[iCommentEnd].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iCommentEnd].token.tokClass == tokTag);
|
|
|
|
ichCommentStart = pTokArray[iCommentStart].token.ibTokMin;
|
|
ASSERT((INT)ichCommentStart-ichBeginCopy >= 0);
|
|
cbNeed = (ichNewCur+ichCommentStart-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichBeginCopy],
|
|
(ichCommentStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += ichCommentStart-ichBeginCopy;
|
|
|
|
// make sure that we have enough space
|
|
// to make this calculation simple, we assume the extreme case where every
|
|
// character in the comment had end of line after it. i.e. we will insert
|
|
// 2 characters ('\r\n') after each character in the comment when we restore
|
|
// the spacing. That means, as long as we have enough space for
|
|
// (pTokArray[iCommentEnd].token.ibTokMac-pTokArray[iCommentStart].token.ibTokMin)*3
|
|
// we are fine
|
|
cbNeed = (ichNewCur+3*(pTokArray[iCommentEnd].token.ibTokMac-pTokArray[iCommentStart].token.ibTokMin))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
|
|
// apply spacing for pre comment part
|
|
// remove extsting spacing before the comment & add the saved spacing
|
|
// note that we already have copied till the begining of the comment
|
|
ichNewCur--;
|
|
while ( ( pwNew[ichNewCur] == ' ' || pwNew[ichNewCur] == '\t'
|
|
|| pwNew[ichNewCur] == '\r' || pwNew[ichNewCur] == '\n'
|
|
)
|
|
)
|
|
{
|
|
ichNewCur--;
|
|
}
|
|
ichNewCur++; // compensate, ichNewCur points to non-white space characher
|
|
// now, start writing out the saved spacing
|
|
// look for rgComment[4] & rgComment[5]
|
|
ichspBegin = pTokArray[iCommentStart+1].token.ibTokMin + 2/*for --*/ + wcslen(rgComment[3]);
|
|
pwstr = wcsstr(&pwOld[ichspBegin], rgComment[4]);// pwstr points just after the spacing info block
|
|
if (pwstr == NULL) // didn't find the substring
|
|
{
|
|
// copy the entire comment as is
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[iCommentStart+1].token.ibTokMin],
|
|
(pTokArray[iCommentStart+1].token.ibTokMac-pTokArray[iCommentStart+1].token.ibTokMin-2)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iCommentStart+1].token.ibTokMac-pTokArray[iCommentStart+1].token.ibTokMin-2;
|
|
goto LCommentEnd;
|
|
}
|
|
ichspBegin = SAFE_PTR_DIFF_TO_INT(pwstr+wcslen(rgComment[4])-pwOld);
|
|
pwstr = wcsstr(&pwOld[ichspBegin], rgComment[5]);// pwstr points just after the spacing info block
|
|
if (pwstr == NULL) // didn't find the substring
|
|
{
|
|
// copy the entire comment as is
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[iCommentStart+1].token.ibTokMin],
|
|
(pTokArray[iCommentStart+1].token.ibTokMac-pTokArray[iCommentStart+1].token.ibTokMin-2)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iCommentStart+1].token.ibTokMac-pTokArray[iCommentStart+1].token.ibTokMin-2;
|
|
goto LCommentEnd;
|
|
}
|
|
ichCopy = SAFE_PTR_DIFF_TO_INT(pwstr-pwOld) + wcslen(rgComment[5]); // actual comment begins at ichCopy
|
|
ichspEnd = SAFE_PTR_DIFF_TO_INT(pwstr-pwOld);
|
|
ASSERT(ichspEnd >= ichspBegin);
|
|
while (ichspBegin < ichspEnd)
|
|
{
|
|
switch(pwOld[ichspBegin])
|
|
{
|
|
case chCommentSp:
|
|
pwNew[ichNewCur++] = ' ';
|
|
break;
|
|
case chCommentTab:
|
|
pwNew[ichNewCur++] = '\t';
|
|
break;
|
|
case chCommentEOL:
|
|
pwNew[ichNewCur++] = '\r';
|
|
pwNew[ichNewCur++] = '\n';
|
|
break;
|
|
case ',':
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
ichspBegin++;
|
|
}
|
|
// now pre comment spacing is restored
|
|
|
|
|
|
pwNew[ichNewCur++] = '<';
|
|
pwNew[ichNewCur++] = '!';
|
|
pwNew[ichNewCur++] = '-';
|
|
pwNew[ichNewCur++] = '-';
|
|
|
|
// part 2 - copy the comment and apply spacing
|
|
// from pTokArray[iCommentStart+1].token,ibTokMIn, look for rgComment[4]
|
|
// thats where we keep our spacing info. Exclude this stuff while copying the comment
|
|
ichspBegin = pTokArray[iCommentStart+1].token.ibTokMin + 2/*for --*/ + wcslen(rgComment[3]);
|
|
// locate rgComment[4] that will be somewhere in iCommentStart'th token
|
|
pwstr = wcsstr(&pwOld[ichspBegin], rgComment[4]);// pwstr points just after the spacing info block
|
|
if (pwstr == NULL) // didn't find the substring
|
|
{
|
|
// copy the entire comment as is
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[iCommentStart+1].token.ibTokMin],
|
|
(pTokArray[iCommentStart+1].token.ibTokMac-pTokArray[iCommentStart+1].token.ibTokMin-2)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iCommentStart+1].token.ibTokMac-pTokArray[iCommentStart+1].token.ibTokMin-2;
|
|
goto LCommentEnd;
|
|
}
|
|
ichspEnd = SAFE_PTR_DIFF_TO_INT(pwstr - pwOld);
|
|
ASSERT(ichspEnd >= ichspBegin);
|
|
|
|
while (ichspBegin < ichspEnd)
|
|
{
|
|
switch(pwOld[ichspBegin])
|
|
{
|
|
case chCommentSp:
|
|
pwNew[ichNewCur++] = ' ';
|
|
break;
|
|
case chCommentTab:
|
|
pwNew[ichNewCur++] = '\t';
|
|
break;
|
|
case chCommentEOL:
|
|
pwNew[ichNewCur++] = '\r';
|
|
pwNew[ichNewCur++] = '\n';
|
|
break;
|
|
case ',':
|
|
while ( pwOld[ichCopy] == ' ' || pwOld[ichCopy] == '\t'
|
|
|| pwOld[ichCopy] == '\r' || pwOld[ichCopy] == '\n'
|
|
)
|
|
{
|
|
if (ichCopy >= (int)(pTokArray[iCommentStart+1].token.ibTokMac-2)) // we are done with copying
|
|
goto LCommentEnd;
|
|
ichCopy++;
|
|
}
|
|
while ( pwOld[ichCopy] != ' ' && pwOld[ichCopy] != '\t'
|
|
&& pwOld[ichCopy] != '\r' && pwOld[ichCopy] != '\n'
|
|
)
|
|
{
|
|
if (ichCopy >= (int)(pTokArray[iCommentStart+1].token.ibTokMac-2)) // we are done with copying
|
|
goto LCommentEnd;
|
|
pwNew[ichNewCur++] = pwOld[ichCopy++];
|
|
}
|
|
break;
|
|
}
|
|
ichspBegin++;
|
|
}
|
|
|
|
LCommentEnd:
|
|
// part 3 - copy the end of comment
|
|
pwNew[ichNewCur++] = '-';
|
|
pwNew[ichNewCur++] = '-';
|
|
pwNew[ichNewCur++] = '>';
|
|
|
|
// set iArray & ichBeginCopy for next run
|
|
ichBeginCopy = pTokArray[iCommentEnd].token.ibTokMac;
|
|
iArray = iCommentEnd + 1;
|
|
}
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
//LRetOnly:
|
|
return;
|
|
|
|
} /* fnRestoreObject()*/
|
|
|
|
|
|
void
|
|
CTriEditParse::fnSaveSpace(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy, DWORD /*dwFlags*/)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
INT iArray = (INT)*piArrayStart;
|
|
INT ichEnd, ichBegin;
|
|
LPWSTR pwNew = *ppwNew;
|
|
INT iArraySav = iArray;
|
|
LPCWSTR rgSpaceTags[] =
|
|
{
|
|
L" DESIGNTIMESP=",
|
|
L" DESIGNTIMESP1=",
|
|
L" designtimesp=",
|
|
};
|
|
INT iArrayElem = -1;
|
|
INT iArrayMatch, iArrayPrevTag;
|
|
INT ichEndMatch, ichBeginMatch, ichEndPrev, ichBeginPrev, ichEndNext, ichBeginNext, ichEndTag, ichBeginTag;
|
|
WCHAR szIndex[cchspBlockMax]; // will we have more than 20 digit numbers as number of DESIGNTIMESPx?
|
|
UINT cbNeed;
|
|
int cchURL = 0;
|
|
int ichURL = 0;
|
|
|
|
// {-1, TokTag_START, tokTag, TokTag_CLOSE, -1, tokClsIgnore, fnSaveSpace},
|
|
|
|
ASSERT(dwFlags &dwPreserveSourceCode);
|
|
|
|
// special cases where we don't need to save spacing, because Trident doesn't muck with
|
|
// the spacing in these cases. If this changes in future, remove these cases.
|
|
// If this case is removed, then make sure that fnSaveObject() changes accordingly
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken) /* validation */
|
|
&& (pTokArray[iArray+1].token.tok == TokElem_OBJECT)
|
|
&& (pTokArray[iArray+1].token.tokClass == tokElem)
|
|
)
|
|
{
|
|
// (iArray+1)th token is an OBJECT tag
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// trident munges custom attributes inside STYLE tag, so DESIGNTIMESP gets out of place
|
|
// so lets not save any spacing info for TokElem_STYLE
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken) /* validation */
|
|
&& (pTokArray[iArray+1].token.tok == TokElem_STYLE)
|
|
&& (pTokArray[iArray+1].token.tokClass == tokElem)
|
|
)
|
|
{
|
|
// (iArray+1)th token is an STYLE tag
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// trident overwrites PARAM tags, so we can skip saving spacing info
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken) /* validation */
|
|
&& (pTokArray[iArray+1].token.tok == TokElem_PARAM)
|
|
&& (pTokArray[iArray+1].token.tokClass == tokElem)
|
|
)
|
|
{
|
|
// (iArray+1)th token is an PARAM tag
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// we should skip saving for <applet>
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken) /* validation */
|
|
&& ( pTokArray[iArray+1].token.tok == TokElem_APPLET
|
|
)
|
|
&& (pTokArray[iArray+1].token.tokClass == tokElem)
|
|
)
|
|
{
|
|
// (iArray+1)th token is an APPLET tag
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// we special case textarea tags, so we should skip saving spacing info
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken) /* validation */
|
|
&& (pTokArray[iArray+1].token.tok == TokElem_TEXTAREA)
|
|
&& (pTokArray[iArray+1].token.tokClass == tokElem)
|
|
)
|
|
{
|
|
// (iArray+1)th token is TEXTAREA tag
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// we special case A/IMG/LINK tags with Relative URLs ONLY, so we should skip saving spacing info
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken) /* validation */
|
|
&& ( pTokArray[iArray+1].token.tok == TokElem_A
|
|
|| pTokArray[iArray+1].token.tok == TokElem_IMG
|
|
|| pTokArray[iArray+1].token.tok == TokElem_LINK
|
|
)
|
|
&& (pTokArray[iArray+1].token.tokClass == tokElem)
|
|
&& (FURLNeedSpecialHandling(pTokArray, iArray, pwOld, (int)ptep->m_cMaxToken, &ichURL, &cchURL))
|
|
)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// step 1
|
|
// look for > that matches with <. we already are at ft.tokBegin2 i.e. <
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
ichBeginTag = pTokArray[iArray].token.ibTokMac;
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
if (pTokArray[iArray].token.tok == ft.tokEnd && pTokArray[iArray].token.tokClass == tokTag) // ft.tokEnd2 is -1
|
|
break;
|
|
if (pTokArray[iArray].token.tokClass == tokElem)
|
|
iArrayElem = iArray;
|
|
iArray++;
|
|
}
|
|
if (iArray >= (int)ptep->m_cMaxToken) // didn't find >
|
|
{
|
|
goto LRet;
|
|
}
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE); // found >
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag); // found >
|
|
ichEndTag = ichBegin = pTokArray[iArray].token.ibTokMin;
|
|
ichEnd = pTokArray[iArray].token.ibTokMac;
|
|
|
|
// step 2
|
|
// look for > before iArraySav. Boundary case will be for the first < in the document
|
|
// save the spacing info
|
|
ASSERT(pTokArray[iArraySav].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[iArraySav].token.tokClass == tokTag);
|
|
ichEndPrev = pTokArray[iArraySav].token.ibTokMin;
|
|
ichBeginPrev = ichEndPrev-1;
|
|
// look for previous TokTag_CLOSE
|
|
// if the tag ending tag, ichBeginPrev becomes ibTokMac of '>' tag
|
|
// if the tag is starting tag, ichBeginPrev becomes ibTokMac+(white space just after that tag)
|
|
iArrayPrevTag = iArraySav; // this is TokTag_START
|
|
while (iArrayPrevTag >= 0)
|
|
{
|
|
if ( ( pTokArray[iArrayPrevTag].token.tokClass == tokTag
|
|
&& pTokArray[iArrayPrevTag].token.tok == TokTag_CLOSE
|
|
)
|
|
|| ( pTokArray[iArrayPrevTag].token.tokClass == tokSSS
|
|
&& pTokArray[iArrayPrevTag].token.tok == TokTag_SSSCLOSE
|
|
)/* VID6 - bug 22787 */
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
iArrayPrevTag--;
|
|
}
|
|
if (iArrayPrevTag < 0) // handle error case
|
|
{
|
|
// leave the old behaviour as is for V1
|
|
while (ichBeginPrev >= 0)
|
|
{
|
|
if ( pwOld[ichBeginPrev] != ' '
|
|
&& pwOld[ichBeginPrev] != '\r'
|
|
&& pwOld[ichBeginPrev] != '\n'
|
|
&& pwOld[ichBeginPrev] != '\t'
|
|
)
|
|
break;
|
|
ichBeginPrev--;
|
|
}
|
|
goto LGotEndNext;
|
|
}
|
|
ichBeginPrev = pTokArray[iArrayPrevTag].token.ibTokMac - 1;
|
|
|
|
LGotEndNext:
|
|
if (ichBeginPrev < 0)
|
|
ichBeginPrev = 0;
|
|
else
|
|
ichBeginPrev++;
|
|
|
|
|
|
// step 3
|
|
// look for TokTag_START after iArray(which currently is TokTag_CLOSE)
|
|
// save spacing info
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
//iArrayNextStart = iArray;
|
|
ichBeginNext = pTokArray[iArray].token.ibTokMac;
|
|
ASSERT(ichBeginNext == ichEnd);
|
|
ichEndNext = ichBeginNext;
|
|
while (ichEndNext < (INT)pTokArray[ptep->m_cMaxToken-1].token.ibTokMac)
|
|
{
|
|
if ( pwOld[ichEndNext] != ' '
|
|
&& pwOld[ichEndNext] != '\r'
|
|
&& pwOld[ichEndNext] != '\n'
|
|
&& pwOld[ichEndNext] != '\t'
|
|
)
|
|
break;
|
|
ichEndNext++;
|
|
}
|
|
|
|
if (ichEndNext >= (INT)pTokArray[ptep->m_cMaxToken-1].token.ibTokMac)
|
|
ichEndNext = pTokArray[ptep->m_cMaxToken-1].token.ibTokMac;
|
|
|
|
// step 4
|
|
// if iArrayElem != -1, look for pTokArray[iArrayElem].iNextprev. If its not -1, set iArrayMatch
|
|
// look for previous TokTag_START/TokTag_END. look for previous TokTag_CLOSE
|
|
// save spacing info
|
|
if (iArrayElem == -1) // this can happen if we have incomplete HTML
|
|
{
|
|
ichEndMatch = ichBeginMatch = 0;
|
|
goto LSkipMatchCalc;
|
|
}
|
|
iArrayMatch = pTokArray[iArrayElem].iNextprev;
|
|
if (iArrayMatch != -1) // match was set while tokenizing
|
|
{
|
|
ichBeginMatch = ichEndMatch = 0; //init
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
while (iArrayMatch >= iArray) // iArray is TokTag_CLOSE of the current tag (i.e. '>')
|
|
{
|
|
if ( pTokArray[iArrayMatch].token.tokClass == tokTag
|
|
&& ( pTokArray[iArrayMatch].token.tok == TokTag_START
|
|
|| pTokArray[iArrayMatch].token.tok == TokTag_END
|
|
)
|
|
)
|
|
break;
|
|
iArrayMatch--;
|
|
}
|
|
if (iArrayMatch > iArray) // did find '</' or '<' after the current tag
|
|
{
|
|
ichEndMatch = pTokArray[iArrayMatch].token.ibTokMin;
|
|
ichBeginMatch = ichEndMatch; // init
|
|
// look for '>' and set ichBeginMatch
|
|
while (iArrayMatch >= iArray) // iArray is TokTag_CLOSE of the current tag (i.e. '>')
|
|
{
|
|
if ( ( pTokArray[iArrayMatch].token.tokClass == tokTag
|
|
&& pTokArray[iArrayMatch].token.tok == TokTag_CLOSE
|
|
)
|
|
|| ( pTokArray[iArrayMatch].token.tokClass == tokSSS
|
|
&& pTokArray[iArrayMatch].token.tok == TokTag_SSSCLOSE
|
|
)/* VID6 - bug 22787 */
|
|
)
|
|
break;
|
|
iArrayMatch--;
|
|
}
|
|
if (iArrayMatch >= iArray) // they may very well be the same
|
|
{
|
|
ichBeginMatch = pTokArray[iArrayMatch].token.ibTokMac;
|
|
ASSERT(ichBeginMatch <= ichEndMatch);
|
|
ASSERT(ichBeginMatch >= ichEnd);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// don't bother saving any info from here
|
|
ichEndMatch = ichBeginMatch = 0;
|
|
}
|
|
LSkipMatchCalc:
|
|
if (ichEndPrev > ichBeginPrev)
|
|
ptep->hrMarkSpacing(pwOld, ichEndPrev, &ichBeginPrev);
|
|
else
|
|
ptep->hrMarkSpacing(pwOld, ichEndPrev, &ichEndPrev);
|
|
|
|
if (ichEndTag > ichBeginTag)
|
|
{
|
|
INT ichBeginTagSav = ichBeginTag;
|
|
|
|
ptep->hrMarkSpacing(pwOld, ichEndTag, &ichBeginTag);
|
|
// iArray'th token is TokTag_CLOSE & iArraySav is TokTag_START
|
|
ptep->hrMarkOrdering(pwOld, pTokArray, iArraySav, iArray, ichEndTag, &ichBeginTagSav);
|
|
}
|
|
else
|
|
{
|
|
INT ichEndTagSav = ichEndTag;
|
|
|
|
ptep->hrMarkSpacing(pwOld, ichEndTag, &ichEndTag);
|
|
// iArray'th token is TokTag_CLOSE & iArraySav is TokTag_START
|
|
ptep->hrMarkOrdering(pwOld, pTokArray, iArraySav, iArray, ichEndTagSav, &ichEndTagSav);
|
|
}
|
|
|
|
if (ichEndNext > ichBeginNext)
|
|
ptep->hrMarkSpacing(pwOld, ichEndNext, &ichBeginNext);
|
|
else
|
|
ptep->hrMarkSpacing(pwOld, ichEndNext, &ichEndNext);
|
|
|
|
if (ichEndMatch > ichBeginMatch)
|
|
ptep->hrMarkSpacing(pwOld, ichEndMatch, &ichBeginMatch);
|
|
else
|
|
ptep->hrMarkSpacing(pwOld, ichEndMatch, &ichEndMatch);
|
|
|
|
|
|
|
|
// realloc if needed
|
|
cbNeed = (ichNewCur+ichBegin-ichBeginCopy+3*wcslen(rgSpaceTags[0])+(ichEnd-ichBegin))*sizeof(WCHAR);
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
// ichBeginCopy is a position in pwOld and
|
|
// ichNewCur is a position in pwNew
|
|
// copy from ichBeginCopy to >
|
|
ASSERT((INT)(ichBegin-ichBeginCopy) >= 0);
|
|
if ((INT)(ichBegin-ichBeginCopy) > 0)
|
|
{
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+ichBeginCopy),
|
|
(ichBegin-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichBegin-ichBeginCopy);
|
|
}
|
|
ichBeginCopy = ichEnd; // make it ready for next copy
|
|
|
|
// BUG 15389 - Ideal fix will be to save the exact tag and restore it when we switch back,
|
|
// but it will be a bigger change at this point, So we simply look at first character of the tag.
|
|
// If it is uppercase, write DESIGNTIMESP, else write designtimesp
|
|
// ASSUMPTION is that Trident doesn't change the case of unknown attribute & so far its TRUE.
|
|
// ASSUMPTION is that we don't have extra spaces between '<' & the tag name.
|
|
ASSERT(wcslen(rgSpaceTags[0]) == wcslen(rgSpaceTags[2]));
|
|
if (iswupper(pwOld[pTokArray[iArraySav+1].token.ibTokMin]) != 0) // upper case
|
|
{
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(rgSpaceTags[0]),
|
|
(wcslen(rgSpaceTags[0]))*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgSpaceTags[0]);
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(rgSpaceTags[2]),
|
|
(wcslen(rgSpaceTags[2]))*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgSpaceTags[2]);
|
|
}
|
|
|
|
(WCHAR)_itow(ptep->m_ispInfoBlock+ptep->m_ispInfoBase, szIndex, 10);
|
|
ptep->m_ispInfoBlock++;
|
|
|
|
ASSERT(wcslen(szIndex) < sizeof(szIndex));
|
|
ASSERT(sizeof(szIndex) == cchspBlockMax*sizeof(WCHAR));
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(szIndex),
|
|
wcslen(szIndex)*sizeof(WCHAR));
|
|
ichNewCur += wcslen(szIndex);
|
|
|
|
|
|
// if (m_ispInfoIn == 0), then we have the last block of SPINFO, lets save it here
|
|
if (ptep->m_ispInfoIn == 0)
|
|
{
|
|
ASSERT(FALSE);
|
|
// realloc if needed
|
|
cbNeed = (ichNewCur+ichBegin-ichBeginCopy+2*wcslen(rgSpaceTags[1]))*sizeof(WCHAR);
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LErrorRet;
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(rgSpaceTags[1]),
|
|
(wcslen(rgSpaceTags[1]))*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgSpaceTags[1]);
|
|
|
|
*(WCHAR *)(pwNew+ichNewCur) = 'Z'; // ptep->m_ispInfoIn;
|
|
ichNewCur++;
|
|
}
|
|
|
|
ASSERT((INT)(ichEnd-ichBegin) > 0);
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+ichBegin),
|
|
(ichEnd-ichBegin)*sizeof(WCHAR));
|
|
ichNewCur += (ichEnd-ichBegin);
|
|
|
|
// restore iArray
|
|
iArray = iArraySav+1;
|
|
|
|
LErrorRet:
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = (UINT)iArray;
|
|
} /* fnSaveSpace() */
|
|
|
|
|
|
void
|
|
CTriEditParse::fnRestoreSpace(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT *pcHtml, UINT *pichNewCur, UINT *pichBeginCopy, DWORD dwFlags)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
INT iArray = (INT)*piArrayStart;
|
|
UINT ichBegin, ichspInfoEndtagEnd;
|
|
LPWSTR pwNew = *ppwNew;
|
|
LPCWSTR rgSpaceTags[] =
|
|
{
|
|
L"DESIGNTIMESP",
|
|
L"DESIGNTIMESP1",
|
|
};
|
|
INT iArraySav = iArray;
|
|
WORD *pspInfoEnd, *pspInfoOrder;
|
|
INT cchwspInfo; // spInfo block size in wide chars
|
|
INT cchRange; // number of char for which this spInfo was saved
|
|
BOOL fMatch = FALSE;
|
|
BOOL fMatchLast = FALSE;
|
|
INT cchtok, cchtag, itoktagStart, ichtoktagStart, iArrayValue, index;
|
|
WCHAR szIndex[cchspBlockMax];
|
|
INT cwOrderInfo = 0;
|
|
UINT cbNeed;
|
|
INT ichNewCurSav = -1; // init to -1 so that we will know when its set.
|
|
int ichNewCurAtIndex0 = -1; // we need to adjust the saved ichNewCur because it gets invalidated
|
|
// as soon as the tag moves as a result of restoring pre-tag spaces.
|
|
|
|
ASSERT(dwFlags & dwPreserveSourceCode);
|
|
|
|
// take care of the matching end token's spacing
|
|
if ( pTokArray[iArray].token.tok == ft.tokBegin2
|
|
&& pTokArray[iArray].token.tokClass == tokTag
|
|
)
|
|
{
|
|
ASSERT(ft.tokBegin2 == TokTag_END);
|
|
fnRestoreSpaceEnd( ptep, pwOld, ppwNew, pcchNew, phgNew, pTokArray, piArrayStart,
|
|
ft, pcHtml, pichNewCur, pichBeginCopy, dwFlags);
|
|
goto LRetOnly;
|
|
|
|
}
|
|
|
|
// we already are at (token.tok == tokSpace), which may be DESIGNTIMESPx
|
|
ASSERT(pTokArray[iArray].token.tok == 0);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokSpace);
|
|
cchtok = pTokArray[iArray].token.ibTokMac - pTokArray[iArray].token.ibTokMin;
|
|
cchtag = wcslen(rgSpaceTags[0]);
|
|
if (cchtag == cchtok)
|
|
{
|
|
if (0 == _wcsnicmp(rgSpaceTags[0], &pwOld[pTokArray[iArray].token.ibTokMin], cchtag))
|
|
{
|
|
fMatch = TRUE;// match
|
|
}
|
|
else
|
|
goto LNoMatch;
|
|
}
|
|
else if (cchtag+1 == cchtok)
|
|
{
|
|
if (0 == _wcsnicmp(rgSpaceTags[1], &pwOld[pTokArray[iArray].token.ibTokMin], cchtag+1))
|
|
{
|
|
fMatchLast = TRUE;// match
|
|
}
|
|
else
|
|
goto LNoMatch;
|
|
}
|
|
else
|
|
{
|
|
LNoMatch:
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
ASSERT(fMatch || fMatchLast); // one of them has to be TRUE
|
|
// found DESIGNTIMESPx. Now, go backwords and look for ft.tokBegin
|
|
itoktagStart = iArray;
|
|
ASSERT(ft.tokBegin == TokTag_START);
|
|
while (itoktagStart >= 0)
|
|
{
|
|
if ( pTokArray[itoktagStart].token.tok == ft.tokBegin
|
|
&& pTokArray[itoktagStart].token.tokClass == tokTag
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
itoktagStart--;
|
|
}
|
|
if (itoktagStart < 0) // didn't find '<' before DESIGNTIMESPx
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// found '<' before DESIGNTIMESPx
|
|
// the spacing info saved was for the portion of the document before the '<'
|
|
ASSERT(pTokArray[itoktagStart].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[itoktagStart].token.tokClass == tokTag);
|
|
// we already know that iArray'th token is DESIGNTIMESPx, so get past the '=' that follows it
|
|
// ASSUMPTION - the value of attribute DESIGNTIMESPx will NOT get munged by Trident.
|
|
// NOTE - the above assumption is correct for this release of Trident
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
if (*(WORD *)(pwOld+pTokArray[iArray].token.ibTokMin) == '=')
|
|
{
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokOp);
|
|
break;
|
|
}
|
|
else if (*(WORD *)(pwOld+pTokArray[iArray].token.ibTokMin) == '>') // gone too far
|
|
goto LSkip1;
|
|
iArray++;
|
|
}
|
|
if (iArray >= (int)ptep->m_cMaxToken) // didn't find = after DESIGNTIMESPx
|
|
{
|
|
LSkip1:
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
iArrayValue = -1;
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( (iArrayValue == -1)
|
|
&& ( (pTokArray[iArray].token.tokClass == tokValue)
|
|
|| (pTokArray[iArray].token.tokClass == tokString)
|
|
)
|
|
)
|
|
iArrayValue = iArray;
|
|
else if ( pTokArray[iArray].token.tok == TokTag_CLOSE
|
|
&& pTokArray[iArray].token.tokClass == tokTag
|
|
)
|
|
{
|
|
ASSERT(*(WORD *)(pwOld+pTokArray[iArray].token.ibTokMin) == '>');
|
|
break;
|
|
}
|
|
iArray++;
|
|
}
|
|
if (iArrayValue == -1 || iArray >= (int)ptep->m_cMaxToken) // didn't find tokValue after DESIGNTIMESPx
|
|
{
|
|
// BUG 9040
|
|
//if (iArray >= (int)ptep->m_cMaxToken && iArrayValue != -1)
|
|
//{
|
|
// SOLUTION 1
|
|
// overwrite the stuff from pwOld[pTokArray[iArraySav].token.ibTokMin]
|
|
// to pwOld[pTokArray[iArrayValue].token.ibTokMac - 1]
|
|
// SOLUTION 2
|
|
// look for DESIGNTIMESP from pwOld[pTokArray[itokTagStart].token.ibTokMac - 1]
|
|
// to pwOld[pTokArray[iArray].token.ibTokMac - 1] and overwrite all of those
|
|
// strings with spaces. We could NULL those and do the blts, but why bother
|
|
// when the html isn't valid!
|
|
|
|
// make sure that all DESIGNTIMESPs are stripped off if we encountered this error case
|
|
//}
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// we know that 4 blocks of info was saved for each DESIGNTIMESPx attribute
|
|
// before tag, within tag, after tag, before matching end-tag
|
|
// even if no info was saved, the block will still exist with 2 words (size,# of char)
|
|
ichspInfoEndtagEnd = pTokArray[iArray].token.ibTokMac;
|
|
|
|
// first copy the document till DESIGNTIMESPx
|
|
// skip DESIGNTIMESPx and its value and set ichBeginCopy to be after that
|
|
|
|
// NOTE - token before iArraySav'th one should be tokSpace with lenght 1
|
|
// and with a value of chSpace (unless Trident has modified it). If thats TRUE,
|
|
// we should skip that too, because we added it when we put in DESIGNTIMESPx.
|
|
|
|
// fix Trident's behaviour - If Trident sees unknown tag(s) it puts it(them) at the end
|
|
// and inserts EOL before those. In this case, we would have inserted a space before DESIGNTIMESP
|
|
// and Trident would have inserted EOL. If thats not the case, we will ignore it.
|
|
if ( (iArraySav-1 > 0) /* validation */
|
|
&& ( ( (pTokArray[iArraySav-1].token.ibTokMac - pTokArray[iArraySav-1].token.ibTokMin == 1)
|
|
&& (pwOld[pTokArray[iArraySav-1].token.ibTokMin] == ' ')
|
|
)
|
|
|| ( (pTokArray[iArraySav-1].token.ibTokMac - pTokArray[iArraySav-1].token.ibTokMin == 3)
|
|
&& (pwOld[pTokArray[iArraySav-1].token.ibTokMin] == ' ')
|
|
&& (pwOld[pTokArray[iArraySav-1].token.ibTokMin+1] == '\r')
|
|
&& (pwOld[pTokArray[iArraySav-1].token.ibTokMin+2] == '\n')
|
|
)
|
|
)
|
|
)
|
|
{
|
|
ichBegin = pTokArray[iArraySav-1].token.ibTokMin;
|
|
}
|
|
else
|
|
ichBegin = pTokArray[iArraySav].token.ibTokMin;
|
|
ASSERT(ichBegin >= ichBeginCopy);
|
|
|
|
cbNeed = (ichNewCur+(ichBegin-ichBeginCopy))*sizeof(WCHAR) + cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// BUG 15389 - look at the case of DESIGNTIMESP & convert the tag into upper/lower case...
|
|
//memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
// (BYTE *)(pwOld+ichBeginCopy),
|
|
// (ichBegin-ichBeginCopy)*sizeof(WCHAR));
|
|
//ichNewCur += (ichBegin-ichBeginCopy);
|
|
if (ichBegin >= ichBeginCopy )
|
|
{
|
|
// step 1 - copy from ichBeginCopy to '<' of the current tag
|
|
if ((int)(pTokArray[itoktagStart].token.ibTokMac-ichBeginCopy) > 0)
|
|
{
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+ichBeginCopy),
|
|
(pTokArray[itoktagStart].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[itoktagStart].token.ibTokMac-ichBeginCopy);
|
|
ichNewCurSav = ichNewCur+1; // used as a peg to get preceding tokTag_START i.e. '<'
|
|
}
|
|
// step 2 - convert current tag into upper/lower case & copy it
|
|
if (ichBeginCopy < pTokArray[itoktagStart+1].token.ibTokMin)
|
|
{
|
|
ASSERT((int)(pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin) > 0);
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+pTokArray[itoktagStart+1].token.ibTokMin),
|
|
(pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin)*sizeof(WCHAR));
|
|
if (iswupper(pwOld[pTokArray[iArraySav].token.ibTokMin]) != 0) // DESIGNTIMESP is upper case
|
|
{
|
|
// convert the tag into upper case. ASSUME that the tag is at itoktagStart+1
|
|
_wcsupr(&pwNew[ichNewCur]);
|
|
}
|
|
else
|
|
{
|
|
// convert the tag into lower case. ASSUME that the tag is at itoktagStart+1
|
|
_wcslwr(&pwNew[ichNewCur]);
|
|
}
|
|
ichNewCur += (pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin);
|
|
}
|
|
else // this tag is alreay been copied
|
|
{
|
|
// hack
|
|
if (pTokArray[itoktagStart+1].token.ibTokMac == ichBeginCopy) // means we are just past the current tag
|
|
{
|
|
if (iswupper(pwOld[pTokArray[iArraySav].token.ibTokMin]) != 0) // DESIGNTIMESP is upper case
|
|
{
|
|
ASSERT(ichNewCur >= (pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin));
|
|
// convert the tag into upper case. ASSUME that the tag is at itoktagStart+1
|
|
_wcsupr(&pwNew[ichNewCur-(pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin)]);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(ichNewCur >= (pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin));
|
|
// convert the tag into lower case. ASSUME that the tag is at itoktagStart+1
|
|
_wcslwr(&pwNew[ichNewCur-(pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin)]);
|
|
}
|
|
}
|
|
}
|
|
// step 3 - copy from after the tag (which is at ichtoktagStart+1) to ichBegin
|
|
if ((int)(ichBegin-pTokArray[itoktagStart+1].token.ibTokMac) > 0)
|
|
{
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+pTokArray[itoktagStart+1].token.ibTokMac),
|
|
(ichBegin-pTokArray[itoktagStart+1].token.ibTokMac)*sizeof(WCHAR));
|
|
ichNewCur += (ichBegin-pTokArray[itoktagStart+1].token.ibTokMac);
|
|
}
|
|
}
|
|
// set ichBeginCopy
|
|
ichBeginCopy = ichspInfoEndtagEnd; // make it ready for next copy
|
|
|
|
// copy the rest of the tag (skipping DESIGNTIMESPx = value)
|
|
ASSERT((INT)(ichspInfoEndtagEnd-pTokArray[iArrayValue].token.ibTokMac) >= 0);
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+pTokArray[iArrayValue].token.ibTokMac),
|
|
(ichspInfoEndtagEnd-pTokArray[iArrayValue].token.ibTokMac)*sizeof(WCHAR));
|
|
ichNewCur += (ichspInfoEndtagEnd-pTokArray[iArrayValue].token.ibTokMac);
|
|
|
|
memset((BYTE *)szIndex, 0, sizeof(szIndex));
|
|
// check if the value has quotes around it and don't copy them to szIndex
|
|
if ( pwOld[pTokArray[iArrayValue].token.ibTokMin] == '"'
|
|
&& pwOld[pTokArray[iArrayValue].token.ibTokMac-1] == '"'
|
|
)
|
|
{
|
|
memcpy( (BYTE *)szIndex,
|
|
(BYTE *)(pwOld+pTokArray[iArrayValue].token.ibTokMin+1),
|
|
(pTokArray[iArrayValue].token.ibTokMac-pTokArray[iArrayValue].token.ibTokMin-2)*sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)szIndex,
|
|
(BYTE *)(pwOld+pTokArray[iArrayValue].token.ibTokMin),
|
|
(pTokArray[iArrayValue].token.ibTokMac-pTokArray[iArrayValue].token.ibTokMin)*sizeof(WCHAR));
|
|
}
|
|
ptep->m_ispInfoBlock = _wtoi(szIndex);
|
|
ptep->m_ispInfoBlock -= ptep->m_ispInfoBase;
|
|
if (ptep->m_ispInfoBlock < 0)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// NOTE - we can cache this info in a link list at the begining
|
|
// get to the ptep->m_ispInfoBlock'th block from ptep->m_pspInfoOutStart
|
|
ASSERT(ptep->m_cchspInfoTotal >= 0);
|
|
pspInfoEnd = ptep->m_pspInfoOutStart + ptep->m_cchspInfoTotal;
|
|
ptep->m_pspInfoOut = ptep->m_pspInfoOutStart;
|
|
for (index = 0; index < ptep->m_ispInfoBlock; index++)
|
|
{
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // before <
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // between <>
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // Order Info
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // after >
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // before matching </
|
|
|
|
// we somehow have gone beyond the data that was saved for spacing
|
|
if (ptep->m_pspInfoOut >= pspInfoEnd)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
}
|
|
|
|
// get the Order Info
|
|
pspInfoOrder = ptep->m_pspInfoOut;
|
|
pspInfoOrder += *(WORD *)pspInfoOrder; // skip info saved for spacing before '<'
|
|
pspInfoOrder += *(WORD *)pspInfoOrder; // skip info saved for spacing between '<>'
|
|
// now pspInfoOrder is at correct place
|
|
cwOrderInfo = *(WORD *)pspInfoOrder++;
|
|
ASSERT(cwOrderInfo >= 1);
|
|
// process this info
|
|
if (cwOrderInfo > 1) // means that we saved some info
|
|
{
|
|
INT cchNewCopy;
|
|
|
|
cchNewCopy = (ichBegin-pTokArray[itoktagStart].token.ibTokMin) + (ichspInfoEndtagEnd-pTokArray[iArrayValue].token.ibTokMac);
|
|
ptep->FRestoreOrder(pwNew, pwOld, pspInfoOrder, &ichNewCur, cwOrderInfo, pTokArray, itoktagStart, iArray, iArraySav, iArrayValue, cchNewCopy, phgNew);
|
|
}
|
|
ichtoktagStart = ichNewCur; // init
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
for (index = 0; index < 4; index++)
|
|
{
|
|
BOOL fLookback = FALSE;
|
|
|
|
cchwspInfo = *(WORD *)ptep->m_pspInfoOut++;
|
|
cchRange = *(WORD *)ptep->m_pspInfoOut++;
|
|
if (cchwspInfo == 2) // we didn't save any spacing info
|
|
{
|
|
if (index == 0) // special case BUG 8741
|
|
{
|
|
// Note that we didn't save anything before this tag. which means that
|
|
// we had '>' or some text immediately before the < tag.
|
|
ichtoktagStart = ichNewCur;
|
|
while (ichtoktagStart >= 0)
|
|
{
|
|
if (pwNew[ichtoktagStart] == '<')
|
|
{
|
|
ichtoktagStart--;
|
|
break;
|
|
}
|
|
ichtoktagStart--;
|
|
}
|
|
if (ichtoktagStart >= 0)
|
|
{
|
|
int cws = 0;
|
|
int ichtagStart = ichtoktagStart;
|
|
|
|
// remove any such white space trident inserts.
|
|
while ( pwNew[ichtoktagStart] == ' '
|
|
|| pwNew[ichtoktagStart] == '\r'
|
|
|| pwNew[ichtoktagStart] == '\n'
|
|
|| pwNew[ichtoktagStart] == '\t')
|
|
{
|
|
cws++;
|
|
ichtoktagStart--;
|
|
}
|
|
if (cws > 0)
|
|
{
|
|
ASSERT((int)(ichNewCur-ichtagStart-1) >= 0);
|
|
//ichtokTagStart now points to either '>' or a non-whitespace char
|
|
memmove((BYTE*)&pwNew[ichtoktagStart+1],
|
|
(BYTE*)&pwNew[ichtoktagStart+1+cws],
|
|
(ichNewCur-ichtagStart-1)*sizeof(WCHAR));
|
|
ichNewCur -= cws;
|
|
}
|
|
} // if (ichtoktagStart >= 0)
|
|
} // if (index == 0)
|
|
goto LNext;
|
|
}
|
|
|
|
// note that ichtoktagStart is a position in pwNew
|
|
switch (index)
|
|
{
|
|
case 0: // before < of the tag
|
|
fLookback = TRUE;
|
|
ichtoktagStart = (ichNewCurSav == -1)?ichNewCur:ichNewCurSav;// handle < ... <%..%>...> case correctly
|
|
ichNewCurAtIndex0 = ichNewCur; // lets save the ichNewCur before we restore pre-tag spacing
|
|
while (ichtoktagStart >= 0)
|
|
{
|
|
if (pwNew[ichtoktagStart] == '<' && pwNew[ichtoktagStart+1] != '%')
|
|
{
|
|
ichtoktagStart--;
|
|
break;
|
|
}
|
|
ichtoktagStart--;
|
|
}
|
|
if (ichtoktagStart < 0) // looks to be an error, don't try to restore the spacing
|
|
{
|
|
ptep->m_pspInfoOut += cchwspInfo-2;
|
|
continue;
|
|
}
|
|
break;
|
|
case 1: // between <> of the tag
|
|
fLookback = FALSE;
|
|
// NOTE - we can assume that in 'case 0' we had put ichtoktagStart is just before '<'
|
|
// so that we can avoid this while loop. but what if we skipped case '0'?
|
|
|
|
// adjust ichNewCurSav to reflect the pre-tag spacing so that it doesn't become invalid
|
|
// we may need to adjust it in ichNewCur-ichNewCurAtIndex0 < 0 case as well, but lets not
|
|
// add code at this stage that we don't have to. (4/30/98)
|
|
if (ichNewCurAtIndex0 != -1 && ichNewCurSav != -1 && ichNewCur-ichNewCurAtIndex0 > 0)
|
|
ichNewCurSav = ichNewCurSav + (ichNewCur-ichNewCurAtIndex0);
|
|
ichtoktagStart = (ichNewCurSav == -1)?ichNewCur:ichNewCurSav;// handle < ... <%..%>...> case correctly
|
|
while (ichtoktagStart >= 0)
|
|
{
|
|
if (pwNew[ichtoktagStart] == '<' && pwNew[ichtoktagStart+1] != '%')
|
|
{
|
|
ichtoktagStart++;
|
|
break;
|
|
}
|
|
ichtoktagStart--;
|
|
}
|
|
if (ichtoktagStart < 0) // looks to be an error, don't try to restore the spacing
|
|
{
|
|
ptep->m_pspInfoOut += cchwspInfo-2; // for spacing info
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // for Order Info
|
|
continue;
|
|
}
|
|
break;
|
|
case 2: // after > of the tag
|
|
// Observation - Trident messes up the document in following way -
|
|
// If we had an EOL after '>' which is followed by HTML text,
|
|
// trident eats that EOL
|
|
// BUT
|
|
// If we had a space/tab before that EOL trident doesn't eat it!!!
|
|
// so I have added the conditions
|
|
// && (pwOld[pTokArray[iArray+1].token.ibTokMin] != ' ')
|
|
// && (pwOld[pTokArray[iArray+1].token.ibTokMin] != '\t')
|
|
|
|
// here is the deal - If the next tone happens to be plain text, there is no danger
|
|
// of applying the same format twice.( i.e. once for after '>' and the next time for
|
|
// before the next '<')
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken) /*validation*/
|
|
&& pTokArray[iArray+1].token.tok == 0
|
|
&& pTokArray[iArray+1].token.tokClass == tokIDENTIFIER
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin] != '\r')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin] != ' ')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin] != '\t')
|
|
)
|
|
{
|
|
fLookback = FALSE;
|
|
ichtoktagStart = ichNewCur;
|
|
while (ichtoktagStart >= 0)
|
|
{
|
|
if (pwNew[ichtoktagStart] == '>')
|
|
{
|
|
ichtoktagStart++;
|
|
break;
|
|
}
|
|
ichtoktagStart--;
|
|
}
|
|
if (ichtoktagStart < 0) // looks to be an error, don't try to restore the spacing
|
|
{
|
|
ptep->m_pspInfoOut += cchwspInfo-2;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptep->m_pspInfoOut += cchwspInfo-2; // we ignore this info
|
|
continue;
|
|
}
|
|
break;
|
|
case 3: // before matching end tag
|
|
ptep->m_pspInfoOut += cchwspInfo-2; // we ignore this info
|
|
continue;
|
|
//fLookback = TRUE;
|
|
//ichtoktagStart = 0; // we ignore this info
|
|
break;
|
|
}
|
|
|
|
if (index == 3) // skip this info, because we have not reached matching end tag yet
|
|
ptep->m_pspInfoOut += cchwspInfo-2;
|
|
//else if (index == 0)
|
|
// ptep->FRestoreSpacingInHTML(pwNew, pwOld, &ichNewCur, &cchwspInfo, cchRange, ichtoktagStart, fLookback, index);
|
|
else
|
|
ptep->FRestoreSpacing(pwNew, pwOld, &ichNewCur, &cchwspInfo, cchRange, ichtoktagStart, fLookback, index);
|
|
|
|
LNext:
|
|
if (index == 1) // we have already processed this info, just move the pointer ahead
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut;
|
|
|
|
} // for ()
|
|
|
|
iArray++; // go part > of this tag for the next round
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = (UINT)iArray;
|
|
|
|
LRetOnly:
|
|
return;
|
|
|
|
} /* fnRestoreSpace() */
|
|
|
|
|
|
|
|
|
|
void
|
|
CTriEditParse::fnRestoreSpaceEnd(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok ft,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy, DWORD /*dwFlags*/)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
INT iArray = (INT)*piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
LPCWSTR rgSpaceTags[] =
|
|
{
|
|
L"DESIGNTIMESP",
|
|
};
|
|
INT iArraySav = iArray;
|
|
INT iArrayMatch, i, itoktagStart;
|
|
BOOL fMatch = FALSE;
|
|
INT cchtag;
|
|
WORD *pspInfoEnd;
|
|
INT cchwspInfo; // spInfo block size in wide chars
|
|
INT cchRange; // number of char for which this spInfo was saved
|
|
INT ichtoktagStart, iArrayValue, index;
|
|
WCHAR szIndex[cchspBlockMax];
|
|
int iDSP = -1;
|
|
UINT cbNeed;
|
|
|
|
ASSERT(dwFlags & dwPreserveSourceCode);
|
|
|
|
// take care of the matching end token's spacing
|
|
ASSERT(pTokArray[iArray].token.tok == ft.tokBegin2);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
ASSERT(ft.tokBegin2 == TokTag_END);
|
|
|
|
// We already are at (token.tok == TokTag_END)
|
|
// Get the tokElem after the current token and find its matching begin token
|
|
// If we don't find the begin token, we don't have spacing for this end token, return
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
if (pTokArray[iArray].token.tokClass == tokElem) // generally this will be the next token
|
|
break;
|
|
iArray++;
|
|
}
|
|
if (iArray >= (int)ptep->m_cMaxToken) // error case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
if (pTokArray[iArray].iNextprev == -1)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
iArrayMatch = pTokArray[iArray].iNextprev;
|
|
// look for 'DESIGNTIMESP' from iArrayMatch till the next '>'
|
|
// If we don't find 'DESIGNTIMESP', this is an error case, return.
|
|
i = iArrayMatch;
|
|
cchtag = wcslen(rgSpaceTags[0]);
|
|
while ( i < iArraySav /* boundary case */
|
|
&& ( pTokArray[i].token.tokClass != tokTag
|
|
|| pTokArray[i].token.tok != TokTag_CLOSE
|
|
)
|
|
)
|
|
{
|
|
|
|
if ( pTokArray[i].token.tokClass == tokSpace
|
|
&& cchtag == (int)(pTokArray[i].token.ibTokMac - pTokArray[i].token.ibTokMin)
|
|
&& (0 == _wcsnicmp(rgSpaceTags[0], &pwOld[pTokArray[i].token.ibTokMin], cchtag))
|
|
)
|
|
{
|
|
fMatch = TRUE;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (!fMatch)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// at this point pTokArray[i] is 'DESIGNTIMESP'
|
|
iDSP = i; // save for later use when we convert the tokElem to upper/lower case
|
|
itoktagStart = i;
|
|
while (itoktagStart >= 0)
|
|
{
|
|
if ( pTokArray[itoktagStart].token.tok == ft.tokBegin
|
|
&& pTokArray[itoktagStart].token.tokClass == tokTag
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
itoktagStart--;
|
|
}
|
|
if (itoktagStart < 0) // didn't find '<' before DESIGNTIMESPx
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// found '<' before DESIGNTIMESPx
|
|
ASSERT(pTokArray[itoktagStart].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[itoktagStart].token.tokClass == tokTag);
|
|
// we already know that i'th token is DESIGNTIMESPx, so get past the '=' that follows it
|
|
// ASSUMPTION - the value of attribute DESIGNTIMESPx will NOT get munged by Trident.
|
|
// NOTE - The above assumption is correct for this Trident release.
|
|
while (i < iArraySav)
|
|
{
|
|
if (*(WORD *)(pwOld+pTokArray[i].token.ibTokMin) == '=')
|
|
{
|
|
ASSERT(pTokArray[i].token.tokClass == tokOp);
|
|
break;
|
|
}
|
|
else if (*(WORD *)(pwOld+pTokArray[i].token.ibTokMin) == '>') // gone too far
|
|
goto LSkip1;
|
|
i++;
|
|
}
|
|
if (i >= iArraySav) // didn't find = after DESIGNTIMESPx
|
|
{
|
|
LSkip1:
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
iArrayValue = -1;
|
|
while (i < iArraySav)
|
|
{
|
|
if ( (iArrayValue == -1)
|
|
&& ( pTokArray[i].token.tokClass == tokValue
|
|
|| pTokArray[i].token.tokClass == tokString)
|
|
)
|
|
iArrayValue = i;
|
|
else if ( pTokArray[i].token.tok == TokTag_CLOSE
|
|
&& pTokArray[i].token.tokClass == tokTag
|
|
)
|
|
{
|
|
ASSERT(*(WORD *)(pwOld+pTokArray[i].token.ibTokMin) == '>');
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (iArrayValue == -1)/*BUG 7951 || i >= iArraySav)*/ // didn't find tokValue after DESIGNTIMESPx
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// we know that iArraySav'th token is '</', copy till that token and apply spacing
|
|
cbNeed = (ichNewCur+pTokArray[iArraySav].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
ASSERT(pTokArray[iArraySav].token.ibTokMin >= ichBeginCopy);
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+ichBeginCopy),
|
|
(pTokArray[iArraySav].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[iArraySav].token.ibTokMin-ichBeginCopy);
|
|
ichtoktagStart = ichNewCur-1;
|
|
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+pTokArray[iArraySav].token.ibTokMin),
|
|
(pTokArray[iArraySav].token.ibTokMac-pTokArray[iArraySav].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[iArraySav].token.ibTokMac-pTokArray[iArraySav].token.ibTokMin);
|
|
ichBeginCopy = pTokArray[iArraySav].token.ibTokMac; // make it ready for next copy
|
|
|
|
// we know that 4 blocks of info was saved for each DESIGNTIMESPx attribute
|
|
// before tag, within tag, after tag, before matching end-tag
|
|
// even if no info was saved, the block will still exist with 2 words (size,# of char)
|
|
memset((BYTE *)szIndex, 0, sizeof(szIndex));
|
|
// check if the value has quotes around it and don't copy them to szIndex
|
|
if ( pwOld[pTokArray[iArrayValue].token.ibTokMin] == '"'
|
|
&& pwOld[pTokArray[iArrayValue].token.ibTokMac-1] == '"'
|
|
)
|
|
{
|
|
memcpy( (BYTE *)szIndex,
|
|
(BYTE *)(pwOld+pTokArray[iArrayValue].token.ibTokMin+1),
|
|
(pTokArray[iArrayValue].token.ibTokMac-pTokArray[iArrayValue].token.ibTokMin-2)*sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)szIndex,
|
|
(BYTE *)(pwOld+pTokArray[iArrayValue].token.ibTokMin),
|
|
(pTokArray[iArrayValue].token.ibTokMac-pTokArray[iArrayValue].token.ibTokMin)*sizeof(WCHAR));
|
|
}
|
|
ptep->m_ispInfoBlock = _wtoi(szIndex);
|
|
ptep->m_ispInfoBlock -= ptep->m_ispInfoBase;
|
|
if (ptep->m_ispInfoBlock < 0)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// NOTE - we can cache this info in a link list at the begining
|
|
// get to the ptep->m_ispInfoBlock'th block from ptep->m_pspInfoOutStart
|
|
ASSERT(ptep->m_cchspInfoTotal >= 0);
|
|
pspInfoEnd = ptep->m_pspInfoOutStart + ptep->m_cchspInfoTotal;
|
|
ptep->m_pspInfoOut = ptep->m_pspInfoOutStart;
|
|
for (index = 0; index < ptep->m_ispInfoBlock; index++)
|
|
{
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // before <
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // between <>
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // Order Info
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // after >
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // before matching </
|
|
|
|
// we somehow have gone beyond the data that was saved for spacing
|
|
if (ptep->m_pspInfoOut >= pspInfoEnd)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
}
|
|
|
|
// skip pre '<' data
|
|
cchwspInfo = *(WORD *)ptep->m_pspInfoOut++;
|
|
cchRange = *(WORD *)ptep->m_pspInfoOut++;
|
|
ptep->m_pspInfoOut += cchwspInfo - 2;
|
|
// skip '<...>' data
|
|
cchwspInfo = *(WORD *)ptep->m_pspInfoOut++;
|
|
cchRange = *(WORD *)ptep->m_pspInfoOut++;
|
|
ptep->m_pspInfoOut += cchwspInfo - 2;
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // for Order Info
|
|
// skip post '>' data
|
|
cchwspInfo = *(WORD *)ptep->m_pspInfoOut++;
|
|
cchRange = *(WORD *)ptep->m_pspInfoOut++;
|
|
ptep->m_pspInfoOut += cchwspInfo - 2;
|
|
// now we are at matching </...> of the token
|
|
cchwspInfo = *(WORD *)ptep->m_pspInfoOut++;
|
|
cchRange = *(WORD *)ptep->m_pspInfoOut++;
|
|
if (cchwspInfo == 2) // we didn't save any spacing info
|
|
{
|
|
// here is a little story. If we didn't save any spacing information for this end
|
|
// tag, that means we didn't have any white-space before it. Lets go back from
|
|
// pwNew[ichNewCur-1] and remove the white-space.
|
|
// NOTE - Ideally, this needs to get folded into FRestoreSpacing, but
|
|
// FRestorespacing gets called from other places too so this is late in
|
|
// the game to that kind of change.
|
|
// we know that pwNew[ichNewCur-1] is '/' & pwNew[ichNewCur-2] is '<'
|
|
if ((int)(ichNewCur-2) >= 0 && pwNew[ichNewCur-1] == '/' && pwNew[ichNewCur-2] == '<')
|
|
{
|
|
ichNewCur = ichNewCur - 3;
|
|
while ( ( pwNew[ichNewCur] == ' ' || pwNew[ichNewCur] == '\t'
|
|
|| pwNew[ichNewCur] == '\r' || pwNew[ichNewCur] == '\n'
|
|
)
|
|
)
|
|
{
|
|
ichNewCur--;
|
|
}
|
|
ichNewCur++; // compensate, ichNewCur points to non-white space characher
|
|
pwNew[ichNewCur++] = '<';
|
|
pwNew[ichNewCur++] = '/';
|
|
}
|
|
|
|
iArray = iArraySav + 1;
|
|
goto LRestoreCaseAndRet;
|
|
}
|
|
ptep->FRestoreSpacing(pwNew, pwOld, &ichNewCur, &cchwspInfo, cchRange, ichtoktagStart, /*fLookback*/TRUE, /*index*/3);
|
|
|
|
iArray = iArraySav + 1; // go past '</', we have already copied the doc till this point
|
|
|
|
LRestoreCaseAndRet:
|
|
// BUG 15389 - we need to start copying the tokElem as well with proper upper/lower case
|
|
// we should combine this memcpy with the above ones, but I want to keep the
|
|
// code separate
|
|
if (pTokArray[iArray].token.tokClass == tokElem && iDSP != -1)
|
|
{
|
|
// except for </BODY> tag because we need to restore post-end-BODY stuff in fnRestoreFtr()
|
|
if (pTokArray[iArray].token.tok != TokElem_BODY && pTokArray[iArray].token.tok != tokElem)
|
|
{
|
|
cbNeed = (ichNewCur+pTokArray[iArray].token.ibTokMac-pTokArray[iArray].token.ibTokMin)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+pTokArray[iArray].token.ibTokMin),
|
|
(pTokArray[iArray].token.ibTokMac-pTokArray[iArray].token.ibTokMin)*sizeof(WCHAR));
|
|
// convert into upper/lower case appropriately to match the opening tag's case
|
|
if (iswupper(pwOld[pTokArray[iDSP].token.ibTokMin]) != 0) // DESIGNTIMESP is upper case
|
|
{
|
|
_wcsupr(&pwNew[ichNewCur]);
|
|
}
|
|
else
|
|
{
|
|
_wcslwr(&pwNew[ichNewCur]);
|
|
}
|
|
ichNewCur += (pTokArray[iArray].token.ibTokMac-pTokArray[iArray].token.ibTokMin);
|
|
|
|
// set ichBeginCopy & iArray for next run
|
|
ichBeginCopy = pTokArray[iArray].token.ibTokMac;
|
|
iArray++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = (UINT)iArray;
|
|
|
|
//LRetOnly:
|
|
return;
|
|
|
|
} /* fnRestoreSpaceEnd() */
|
|
|
|
|
|
|
|
void
|
|
CTriEditParse::fnSaveTbody(CTriEditParse* /*ptep*/,
|
|
LPWSTR /*pwOld*/, LPWSTR* /*ppwNew*/, UINT* /*pcchNew*/, HGLOBAL* /*phgNew*/,
|
|
TOKSTRUCT* /*pTokArray*/, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT* /*pichNewCur*/, UINT* /*hBeginCopy*/,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
UINT iArray = *piArrayStart;
|
|
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_TBODY);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
iArray++;
|
|
|
|
*piArrayStart = iArray;
|
|
return;
|
|
|
|
} /* fnSaveTbody() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreTbody(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
// see if we have DESIGNTIMESP as an attribute for <TBODY>. If we do, ignore this one because
|
|
// we know it existed before going to trident. Else, remove this one because trident inserted
|
|
// it.
|
|
// NOTE - If Trident inserted it, we also have to remove the matching </TBODY>
|
|
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
INT iArray = (INT)*piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
INT ichTBodyStart, ichTBodyEnd;
|
|
BOOL fFoundDSP = FALSE;
|
|
INT iArraySav = iArray;
|
|
INT cchtag;
|
|
LPCWSTR rgSpaceTags[] =
|
|
{
|
|
L"DESIGNTIMESP",
|
|
};
|
|
BOOL fBeginTBody = FALSE;
|
|
UINT cbNeed;
|
|
|
|
ichTBodyStart = pTokArray[iArray].token.ibTokMin; // init
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_TBODY);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
// look for '<' or '</' before TBODY
|
|
while (iArray >= 0) // generally, it will be the previous token, but just in case...
|
|
{
|
|
if ( (pTokArray[iArray].token.tok == TokTag_START)
|
|
&& (pTokArray[iArray].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
fBeginTBody = TRUE;
|
|
ichTBodyStart = pTokArray[iArray].token.ibTokMin;
|
|
break;
|
|
}
|
|
else if ( (pTokArray[iArray].token.tok == TokTag_END)
|
|
&& (pTokArray[iArray].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
if (ptep->m_iTBodyMax > 0) // we have atleast one saved <TBODY>
|
|
{
|
|
ASSERT(ptep->m_pTBodyStack != NULL);
|
|
if (ptep->m_pTBodyStack[ptep->m_iTBodyMax-1] == (UINT)iArraySav) // this was the matching </TBODY>
|
|
{
|
|
// we want to remove it
|
|
ichTBodyStart = pTokArray[iArray].token.ibTokMin;
|
|
break;
|
|
}
|
|
else // this one doesn't match with the saved one, so quit
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
}
|
|
else // we don't have any saved <TBODY>, so quit
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
}
|
|
iArray--;
|
|
} // while ()
|
|
if (iArray < 0) // this can happen only if we have incomplete HTML. Handle error case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
ichTBodyEnd = pTokArray[iArraySav].token.ibTokMac; // init
|
|
iArray = iArraySav;
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_TBODY);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
cchtag = wcslen(rgSpaceTags[0]);
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( (pTokArray[iArray].token.tok == TokTag_CLOSE) /* > */
|
|
&& (pTokArray[iArray].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
ichTBodyEnd = pTokArray[iArray].token.ibTokMac;
|
|
break;
|
|
}
|
|
// look for DESIGNTIMESP
|
|
if ( (pTokArray[iArray].token.tok == 0)
|
|
&& (pTokArray[iArray].token.tokClass == tokSpace)
|
|
&& (cchtag == (INT)(pTokArray[iArray].token.ibTokMac - pTokArray[iArray].token.ibTokMin))
|
|
&& (0 == _wcsnicmp(rgSpaceTags[0], &pwOld[pTokArray[iArray].token.ibTokMin], cchtag))
|
|
)
|
|
{
|
|
fFoundDSP = TRUE;
|
|
break;
|
|
}
|
|
else if (pTokArray[iArray].token.tokClass == tokAttr)
|
|
{
|
|
// look for any attribute before '>'
|
|
// Even if Trident inserted this <TBODY>, the user may have set some TBODY properties
|
|
// If thats the case, we don't want to remove this <TBODY>
|
|
fFoundDSP = TRUE; // fake it to be fFoundDSP
|
|
break;
|
|
}
|
|
|
|
iArray++;
|
|
}
|
|
if (iArray >= (int)ptep->m_cMaxToken) // error case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
if (fFoundDSP)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// we found '>', but didn't find DESIGNTIMESP
|
|
// At this point we are sure that this was added by trident
|
|
ASSERT(iArray < (int)ptep->m_cMaxToken);
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
ASSERT(!fFoundDSP);
|
|
|
|
if (fBeginTBody)
|
|
{
|
|
// copy till ichTBodyStart, skip from ichTBodyStart till ichTBodyEnd, set ichBeginCopy accordingly
|
|
// get the iArray for the matching </TBODY> and save it on stack
|
|
|
|
if (ptep->m_pTBodyStack == NULL) // first time, so allocate it
|
|
{
|
|
ASSERT(ptep->m_hgTBodyStack == NULL);
|
|
ptep->m_hgTBodyStack = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, cTBodyInit*sizeof(UINT));
|
|
if (ptep->m_hgTBodyStack == NULL)
|
|
{
|
|
// not enough memory, so lets keep all <TBODY> elements
|
|
goto LRet;
|
|
}
|
|
ptep->m_pTBodyStack = (UINT *)GlobalLock(ptep->m_hgTBodyStack);
|
|
ASSERT(ptep->m_pTBodyStack != NULL);
|
|
ptep->m_iMaxTBody = cTBodyInit;
|
|
ptep->m_iTBodyMax = 0;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(ptep->m_hgTBodyStack != NULL);
|
|
// see if we need to realloc it
|
|
if (ptep->m_iTBodyMax+1 >= ptep->m_iMaxTBody)
|
|
{
|
|
HRESULT hrRet;
|
|
|
|
hrRet = ReallocBuffer( &ptep->m_hgTBodyStack,
|
|
(ptep->m_iMaxTBody+cTBodyInit)*sizeof(UINT),
|
|
GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
if (hrRet == E_OUTOFMEMORY)
|
|
goto LRet;
|
|
ptep->m_iMaxTBody += cTBodyInit;
|
|
ptep->m_pTBodyStack = (UINT *)GlobalLock(ptep->m_hgTBodyStack);
|
|
ASSERT(ptep->m_pTBodyStack != NULL);
|
|
}
|
|
}
|
|
if (pTokArray[iArraySav].iNextprev != -1) // handle error case
|
|
{
|
|
ptep->m_pTBodyStack[ptep->m_iTBodyMax] = pTokArray[iArraySav].iNextprev;
|
|
ptep->m_iTBodyMax++;
|
|
}
|
|
else
|
|
{
|
|
// don't delete this <TBODY> and its matching </TBODY>
|
|
goto LRet;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if this was a matching </TBODY> for the one trident inserted, we don't copy it to pwNew
|
|
ASSERT(ptep->m_iTBodyMax > 0);
|
|
// look in ptep->m_pTBodyStack and see if you find this iArray
|
|
ASSERT(ptep->m_pTBodyStack[ptep->m_iTBodyMax-1] == (UINT)iArraySav);
|
|
// assume that we never can have tangled TBODY's
|
|
ptep->m_pTBodyStack[ptep->m_iTBodyMax-1] = 0;
|
|
ptep->m_iTBodyMax--;
|
|
}
|
|
// now do the actual skipping
|
|
cbNeed = (ichNewCur+ichTBodyStart-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
if ((INT)(ichTBodyStart-ichBeginCopy) > 0)
|
|
{
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichTBodyStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichTBodyStart-ichBeginCopy);
|
|
}
|
|
ichBeginCopy = ichTBodyEnd;
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
iArray++; // iArray was at '>' of TBODY, so set it to be the next one.
|
|
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
return;
|
|
|
|
} /* fnRestoreTbody() */
|
|
|
|
void
|
|
CTriEditParse::fnSaveApplet(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD dwFlags)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
UINT iArraySav = iArray;
|
|
int indexAppletEnd, ichAppletEnd, indexAppletTagClose, index;
|
|
UINT cbNeed;
|
|
int cchURL = 0;
|
|
int ichURL = 0;
|
|
LPCWSTR rgDspURL[] =
|
|
{
|
|
L" DESIGNTIMEURL=",
|
|
L" DESIGNTIMEURL2=",
|
|
};
|
|
|
|
indexAppletTagClose = -1;
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_APPLET);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
|
|
// get the ending '>' of the </applet>
|
|
indexAppletEnd = pTokArray[iArraySav].iNextprev;
|
|
if (indexAppletEnd == -1) // error case, we don't have matching </applet> tag
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// validity check - the matching tag is not '</applet>'
|
|
if (indexAppletEnd-1 >= 0 && pTokArray[indexAppletEnd-1].token.tok != TokTag_END)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// get ending '>' of the <applet ...>
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( (pTokArray[iArray].token.tok == TokTag_CLOSE) /* > */
|
|
&& (pTokArray[iArray].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
indexAppletTagClose = iArray;
|
|
break;
|
|
}
|
|
iArray++;
|
|
}
|
|
if (iArray >= (int)ptep->m_cMaxToken) // invalid case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
iArray = indexAppletEnd;
|
|
while (iArray < (int)ptep->m_cMaxToken) // generally, it will be the next token, but just in case...
|
|
{
|
|
if ( (pTokArray[iArray].token.tok == TokTag_CLOSE) /* > */
|
|
&& (pTokArray[iArray].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
iArray++;
|
|
}
|
|
indexAppletEnd = iArray;
|
|
ichAppletEnd = pTokArray[indexAppletEnd].token.ibTokMac;
|
|
|
|
// step 1 - if the applet needs special URL processing, act on it.
|
|
if (!FURLNeedSpecialHandling(pTokArray, iArraySav, pwOld, (int)ptep->m_cMaxToken, &ichURL, &cchURL))
|
|
goto LStep2;
|
|
else // save the URL as an attribute value of DESIGNTIMEURL
|
|
{
|
|
// make sure we have enough space in pwNew.
|
|
// copy from ichBeginCopy till current token's ending '>'.
|
|
// index points to APPLET
|
|
index = indexAppletTagClose;
|
|
cbNeed = (ichNewCur+pTokArray[index].token.ibTokMin-ichBeginCopy+wcslen(rgDspURL[0])+cchURL+3/*eq,quotes*/)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// index points to '>'
|
|
if ((int) (pTokArray[index].token.ibTokMin-ichBeginCopy) > 0)
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichBeginCopy],
|
|
(pTokArray[index].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[index].token.ibTokMin-ichBeginCopy);
|
|
}
|
|
|
|
if (cchURL != 0)
|
|
{
|
|
// add 'DESIGNTIMEURL=' followed by the current URL as quoted value
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)rgDspURL[0],
|
|
wcslen(rgDspURL[0])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgDspURL[0]);
|
|
|
|
pwNew[ichNewCur++] = '"';
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichURL],
|
|
cchURL*sizeof(WCHAR));
|
|
ichNewCur += cchURL;
|
|
pwNew[ichNewCur++] = '"';
|
|
}
|
|
|
|
if (dwFlags & dwPreserveSourceCode)
|
|
ptep->SaveSpacingSpecial(ptep, pwOld, &pwNew, phgNew, pTokArray, iArraySav-1, &ichNewCur);
|
|
|
|
// add ending '>' and set ichBeginCopy, iArray, ichNewCur appropriately
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[index].token.ibTokMin],
|
|
(pTokArray[index].token.ibTokMac-pTokArray[index].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[index].token.ibTokMac-pTokArray[index].token.ibTokMin);
|
|
|
|
iArray = index+1; // redundant, but makes code more understandable
|
|
ichBeginCopy = pTokArray[index].token.ibTokMac;
|
|
}
|
|
|
|
// step2 - copy the applet
|
|
LStep2:
|
|
cbNeed = (ichNewCur+ichAppletEnd-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichAppletEnd-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichAppletEnd-ichBeginCopy);
|
|
ichBeginCopy = ichAppletEnd;
|
|
iArray = indexAppletEnd;
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
return;
|
|
|
|
} /* fnSaveApplet() */
|
|
|
|
|
|
void
|
|
CTriEditParse::fnRestoreApplet(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD dwFlags)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
UINT iArraySav = iArray;
|
|
LPCWSTR rgSpaceTags[] =
|
|
{
|
|
L"DESIGNTIMESP",
|
|
L"DESIGNTIMEURL",
|
|
};
|
|
int indexAppletStart, ichAppletStart, indexAppletEnd, i, indexAppletTagClose;
|
|
UINT cchtag, cbNeed, cchURL;
|
|
int indexDSU = -1; // init
|
|
int indexDSUEnd = -1; // init
|
|
int indexDSP = -1; // init
|
|
int indexDSPEnd = -1; // init
|
|
int indexCB = -1; // init (CODEBASE index)
|
|
int indexCBEnd = -1; // init (CODEBASE index)
|
|
BOOL fCodeBaseFound = FALSE;
|
|
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_APPLET);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
indexAppletTagClose = iArraySav;
|
|
// get the matching </applet> tag
|
|
indexAppletEnd = pTokArray[iArraySav].iNextprev;
|
|
if (indexAppletEnd == -1) // error case, we don't have matching </applet> tag
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// get ending '>' of the <applet ...>
|
|
i = iArraySav;
|
|
while (i < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( (pTokArray[i].token.tok == TokTag_CLOSE) /* > */
|
|
&& (pTokArray[i].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
indexAppletTagClose = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i >= (int)ptep->m_cMaxToken) // invalid case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// look for DESIGNTIMESP & DESIGNTIMEURL inside the <applet> tag
|
|
cchtag = wcslen(rgSpaceTags[0]);
|
|
cchURL = wcslen(rgSpaceTags[1]);
|
|
for (i = iArraySav; i < indexAppletTagClose; i++)
|
|
{
|
|
if ( pTokArray[i].token.tok == 0
|
|
&& pTokArray[i].token.tokClass == tokSpace
|
|
&& cchtag == pTokArray[i].token.ibTokMac - pTokArray[i].token.ibTokMin
|
|
&& (0 == _wcsnicmp(rgSpaceTags[0], &pwOld[pTokArray[i].token.ibTokMin], cchtag))
|
|
)
|
|
{
|
|
indexDSP = i;
|
|
}
|
|
else if ( pTokArray[i].token.tok == 0
|
|
&& pTokArray[i].token.tokClass == tokSpace
|
|
&& cchURL == pTokArray[i].token.ibTokMac - pTokArray[i].token.ibTokMin
|
|
&& (0 == _wcsnicmp(rgSpaceTags[1], &pwOld[pTokArray[i].token.ibTokMin], cchURL))
|
|
)
|
|
{
|
|
indexDSU = i;
|
|
}
|
|
else if ( pTokArray[i].token.tok == TokAttrib_CODEBASE
|
|
&& pTokArray[i].token.tokClass == tokAttr
|
|
)
|
|
{
|
|
indexCB = i;
|
|
}
|
|
} // for ()
|
|
|
|
// look for '<' before APPLET
|
|
i = iArraySav;
|
|
while (i >= 0) // generally, it will be the previous token, but just in case...
|
|
{
|
|
if ( (pTokArray[i].token.tok == TokTag_START)
|
|
&& (pTokArray[i].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
i--;
|
|
} // while ()
|
|
if (i < 0) // this can happen only if we have incomplete HTML. Handle error case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
indexAppletStart = i;
|
|
ichAppletStart = pTokArray[indexAppletStart].token.ibTokMin;
|
|
|
|
// look for '>' of </applet>
|
|
i = indexAppletEnd;
|
|
while (i < (int)ptep->m_cMaxToken) // generally, it will be the next token, but just in case...
|
|
{
|
|
if ( (pTokArray[i].token.tok == TokTag_CLOSE) /* > */
|
|
&& (pTokArray[i].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (i >= (int)ptep->m_cMaxToken) // this can happen only if we have incomplete HTML. Handle error case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
indexAppletEnd = i;
|
|
|
|
// step 1 - copy till indexAppletStart
|
|
cbNeed = (ichNewCur+ichAppletStart-ichBeginCopy+3*(indexAppletEnd-indexAppletStart))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[ichBeginCopy]),
|
|
(ichAppletStart-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (ichAppletStart-ichBeginCopy);
|
|
|
|
// step 2 - if (indexDSU != -1), we need to go and restore the CODEBASE atrtribute
|
|
// if (indexDSU == -1), we need to remove CODEBASE attribute
|
|
ASSERT(indexAppletTagClose != -1);
|
|
|
|
// get indexDSUEnd
|
|
if (indexDSU != -1)
|
|
{
|
|
i = indexDSU;
|
|
while (i < indexAppletTagClose)
|
|
{
|
|
if ( pTokArray[i].token.tok == 0
|
|
&& (pTokArray[i].token.tokClass == tokValue || pTokArray[i].token.tokClass == tokString)
|
|
)
|
|
{
|
|
indexDSUEnd = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (indexDSUEnd == -1) // we have malformed html
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
} /* if (indexDSU != -1)*/
|
|
|
|
// get indexDSPEnd
|
|
if (indexDSP != -1)
|
|
{
|
|
i = indexDSP;
|
|
indexDSPEnd = -1;
|
|
while (i < indexAppletTagClose)
|
|
{
|
|
if ( pTokArray[i].token.tok == 0
|
|
&& (pTokArray[i].token.tokClass == tokValue || pTokArray[i].token.tokClass == tokString)
|
|
)
|
|
{
|
|
indexDSPEnd = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (indexDSPEnd == -1) // we have malformed html
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
} /* if (indexDSP != -1) */
|
|
|
|
// get indexCBEnd
|
|
if (indexCB != -1)
|
|
{
|
|
i = indexCB;
|
|
while (i < indexAppletTagClose)
|
|
{
|
|
if ( pTokArray[i].token.tok == 0
|
|
&& (pTokArray[i].token.tokClass == tokValue || pTokArray[i].token.tokClass == tokString)
|
|
)
|
|
{
|
|
indexCBEnd = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (indexCBEnd == -1) // we have malformed html
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
} /* if (indexCB != -1) */
|
|
|
|
// if we didn't find DESIGNTIMEURL attribute, that means CODEBASE attribute
|
|
// should be removed because it didn't exist in source view
|
|
i = indexAppletStart;
|
|
while (i <= indexAppletTagClose)
|
|
{
|
|
if ( (indexDSU != -1)
|
|
&& (i >= indexDSU && i <= indexDSUEnd)
|
|
)
|
|
{
|
|
i++; // don't copy this token
|
|
}
|
|
else if ( (indexDSP != -1)
|
|
&& (i >= indexDSP && i <= indexDSPEnd)
|
|
)
|
|
{
|
|
i++; // don't copy this token
|
|
}
|
|
else if ( pTokArray[i].token.tok == TokAttrib_CODEBASE
|
|
&& pTokArray[i].token.tokClass == tokAttr
|
|
&& !fCodeBaseFound
|
|
)
|
|
{
|
|
if (indexDSU == -1) // DESIGNTIMEURL not found, so skip CODEBASE
|
|
{
|
|
ASSERT(i == indexCB);
|
|
i = indexCBEnd+1;
|
|
}
|
|
else
|
|
{
|
|
fCodeBaseFound = TRUE;
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
i++;
|
|
}
|
|
}
|
|
else if ( pTokArray[i].token.tok == 0
|
|
&& pTokArray[i].token.tokClass == tokString || pTokArray[i].token.tokClass == tokValue
|
|
&& fCodeBaseFound
|
|
)
|
|
{
|
|
int ichURL, ichURLEnd, ichDSURL, ichDSURLEnd;
|
|
// if the url is now absloute and is just an absolute version of
|
|
// the one at indexDSUEnd, we need to replace it.
|
|
ichURL = (pwOld[pTokArray[i].token.ibTokMin] == '"')
|
|
? pTokArray[i].token.ibTokMin+1
|
|
: pTokArray[i].token.ibTokMin;
|
|
ichURLEnd = (pwOld[pTokArray[i].token.ibTokMac-1] == '"')
|
|
? pTokArray[i].token.ibTokMac-1
|
|
: pTokArray[i].token.ibTokMac;
|
|
if (FIsAbsURL((LPOLESTR)&pwOld[ichURL]))
|
|
{
|
|
WCHAR *pszURL1 = NULL;
|
|
WCHAR *pszURL2 = NULL;
|
|
int ich;
|
|
|
|
ichDSURL = (pwOld[pTokArray[indexDSUEnd].token.ibTokMin] == '"')
|
|
? pTokArray[indexDSUEnd].token.ibTokMin+1
|
|
: pTokArray[indexDSUEnd].token.ibTokMin;
|
|
ichDSURLEnd = (pwOld[pTokArray[indexDSUEnd].token.ibTokMac-1] == '"')
|
|
? pTokArray[indexDSUEnd].token.ibTokMac-1
|
|
: pTokArray[indexDSUEnd].token.ibTokMac;
|
|
|
|
// just for comparison purposes, don't look at '/' or '\' separators
|
|
// between filenames & directories...
|
|
pszURL1 = new WCHAR[ichDSURLEnd-ichDSURL + 1];
|
|
pszURL2 = new WCHAR[ichDSURLEnd-ichDSURL + 1];
|
|
if (pszURL1 == NULL || pszURL2 == NULL)
|
|
goto LResumeCopy;
|
|
memcpy((BYTE *)pszURL1, (BYTE *)&pwOld[ichDSURL], (ichDSURLEnd-ichDSURL)*sizeof(WCHAR));
|
|
memcpy((BYTE *)pszURL2, (BYTE *)&pwOld[ichURLEnd-(ichDSURLEnd-ichDSURL)], (ichDSURLEnd-ichDSURL)*sizeof(WCHAR));
|
|
pszURL1[ichDSURLEnd-ichDSURL] = '\0';
|
|
pszURL2[ichDSURLEnd-ichDSURL] = '\0';
|
|
for (ich = 0; ich < ichDSURLEnd-ichDSURL; ich++)
|
|
{
|
|
if (pszURL1[ich] == '/')
|
|
pszURL1[ich] = '\\';
|
|
if (pszURL2[ich] == '/')
|
|
pszURL2[ich] = '\\';
|
|
}
|
|
|
|
if (0 == _wcsnicmp(pszURL1, pszURL2, ichDSURLEnd-ichDSURL))
|
|
{
|
|
pwNew[ichNewCur++] = '"';
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichDSURL],
|
|
(ichDSURLEnd-ichDSURL)*sizeof(WCHAR));
|
|
ichNewCur += (ichDSURLEnd-ichDSURL);
|
|
pwNew[ichNewCur++] = '"';
|
|
}
|
|
else // copy it as it is
|
|
{
|
|
LResumeCopy:
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
if (pszURL1 != NULL)
|
|
delete pszURL1;
|
|
if (pszURL2 != NULL)
|
|
delete pszURL2;
|
|
}
|
|
else // its realtive, simply copy it
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
i++;
|
|
}
|
|
else // all other tokens
|
|
{
|
|
// ****NOTE - we can actually do pretty printing here
|
|
// instead of fixing the special cases****
|
|
|
|
// fix Trident's behaviour - If Trident sees unknown tag(s) it puts it(them) at the end
|
|
// and inserts EOL before those. In this case, we would have inserted a space before DESIGNTIMESP
|
|
// and Trident would have inserted EOL. If thats not the case, we will ignore it.
|
|
if ( (pTokArray[i].token.tokClass == tokSpace)
|
|
&& (pTokArray[i].token.tok == 0)
|
|
&& (FIsWhiteSpaceToken(pwOld, pTokArray[i].token.ibTokMin, pTokArray[i].token.ibTokMac))
|
|
)
|
|
{
|
|
if (i != indexDSU-1) // else skip the copy
|
|
pwNew[ichNewCur++] = ' '; // convert space+\r+\n into space
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
i++;
|
|
}
|
|
}
|
|
} // while ()
|
|
|
|
// we have spacing save dfor this tag, lets restore it
|
|
if ( (indexDSP != -1)
|
|
&& (dwFlags & dwPreserveSourceCode)
|
|
)
|
|
ptep->RestoreSpacingSpecial(ptep, pwOld, &pwNew, phgNew, pTokArray, indexDSP, &ichNewCur);
|
|
|
|
// step 3 - format all stuff between <applet> ... </applet>
|
|
pwNew[ichNewCur] = '\r';
|
|
ichNewCur++;
|
|
pwNew[ichNewCur] = '\n';
|
|
ichNewCur++;
|
|
pwNew[ichNewCur] = '\t'; // replace this with appropriate alignment
|
|
ichNewCur++;
|
|
for (i = indexAppletTagClose+1; i <= indexAppletEnd; i++)
|
|
{
|
|
// copy the tag
|
|
memcpy( (BYTE *)(&pwNew[ichNewCur]),
|
|
(BYTE *)(&pwOld[pTokArray[i].token.ibTokMin]),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
// if its was TokTag_CLOSE, insert EOL
|
|
if ( pTokArray[i].token.tok == TokTag_CLOSE
|
|
&& pTokArray[i].token.tokClass == tokTag)
|
|
{
|
|
pwNew[ichNewCur] = '\r';
|
|
ichNewCur++;
|
|
pwNew[ichNewCur] = '\n';
|
|
ichNewCur++;
|
|
pwNew[ichNewCur] = '\t'; // replace this with appropriate alignment
|
|
ichNewCur++;
|
|
}
|
|
} // for ()
|
|
|
|
// remember to set iArray appropriately
|
|
iArray = indexAppletEnd + 1;
|
|
ichBeginCopy = pTokArray[indexAppletEnd].token.ibTokMac;
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
return;
|
|
|
|
} /* fnRestoreApplet() */
|
|
|
|
void
|
|
CTriEditParse::RestoreSpacingSpecial(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR *ppwNew, HGLOBAL* /*phgNew*/,
|
|
TOKSTRUCT *pTokArray, UINT iArray, UINT *pichNewCur)
|
|
{
|
|
LPWSTR pwNew = *ppwNew;
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT iArraySav = iArray;
|
|
UINT ichspInfoEndtagEnd, ichBegin;
|
|
WCHAR szIndex[cchspBlockMax]; // will we have more than 20 digit numbers as number of DESIGNTIMESPx?
|
|
WORD *pspInfoEnd, *pspInfoOrder;
|
|
INT cwOrderInfo = 0;
|
|
UINT ichNewCurSav = 0xFFFFFFFF;
|
|
INT cchwspInfo; // spInfo block size in wide chars
|
|
INT cchRange; // number of char for which this spInfo was saved
|
|
INT ichtoktagStart, iArrayValue, index, itoktagStart;
|
|
int ichNewCurAtIndex0 = -1; // we need to adjust the saved ichNewCur because it gets invalidated
|
|
// as soon as the tag moves as a result of restoring pre-tag spaces.
|
|
|
|
itoktagStart = iArray; // init
|
|
// found DESIGNTIMESPx. Now, go backwords and look for TokTag_START
|
|
while (itoktagStart >= 0)
|
|
{
|
|
if ( pTokArray[itoktagStart].token.tok == TokTag_START
|
|
&& pTokArray[itoktagStart].token.tokClass == tokTag
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
itoktagStart--;
|
|
}
|
|
if (itoktagStart < 0) // didn't find '<' before DESIGNTIMESPx
|
|
goto LRet;
|
|
|
|
// found '<' before DESIGNTIMESPx
|
|
// the spacing info saved was for the portion of the document before the '<'
|
|
ASSERT(pTokArray[itoktagStart].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[itoktagStart].token.tokClass == tokTag);
|
|
// we already know that iArray'th token is DESIGNTIMESPx, so get past the '=' that follows it
|
|
// ASSUMPTION - the value of attribute DESIGNTIMESPx will NOT get munged by Trident.
|
|
// NOTE - the above assumption is correct for this release of Trident
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
if (*(WORD *)(pwOld+pTokArray[iArray].token.ibTokMin) == '=')
|
|
{
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokOp);
|
|
break;
|
|
}
|
|
else if (*(WORD *)(pwOld+pTokArray[iArray].token.ibTokMin) == '>') // gone too far
|
|
goto LSkip1;
|
|
iArray++;
|
|
}
|
|
if (iArray >= (int)ptep->m_cMaxToken) // didn't find = after DESIGNTIMESPx
|
|
{
|
|
LSkip1:
|
|
goto LRet;
|
|
}
|
|
iArrayValue = -1; // init
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( (iArrayValue == -1)
|
|
&& ( (pTokArray[iArray].token.tokClass == tokValue)
|
|
|| (pTokArray[iArray].token.tokClass == tokString)
|
|
)
|
|
)
|
|
iArrayValue = iArray;
|
|
else if ( pTokArray[iArray].token.tok == TokTag_CLOSE
|
|
&& pTokArray[iArray].token.tokClass == tokTag
|
|
)
|
|
{
|
|
ASSERT(*(WORD *)(pwOld+pTokArray[iArray].token.ibTokMin) == '>');
|
|
break;
|
|
}
|
|
iArray++;
|
|
}
|
|
if (iArrayValue == -1 || iArray >= (int)ptep->m_cMaxToken) // didn't find tokValue after DESIGNTIMESPx
|
|
{
|
|
// BUG 9040
|
|
//if (iArray >= (int)ptep->m_cMaxToken && iArrayValue != -1)
|
|
//{
|
|
// SOLUTION 1
|
|
// overwrite the stuff from pwOld[pTokArray[iArraySav].token.ibTokMin]
|
|
// to pwOld[pTokArray[iArrayValue].token.ibTokMac - 1]
|
|
// SOLUTION 2
|
|
// look for DESIGNTIMESP from pwOld[pTokArray[itokTagStart].token.ibTokMac - 1]
|
|
// to pwOld[pTokArray[iArray].token.ibTokMac - 1] and overwrite all of those
|
|
// strings with spaces. We could NULL those and do the blts, but why bother
|
|
// when the html isn't valid!
|
|
|
|
// make sure that all DESIGNTIMESPs are stripped off if we encountered this error case
|
|
//}
|
|
goto LRet;
|
|
}
|
|
|
|
// we know that 4 blocks of info was saved for each DESIGNTIMESPx attribute
|
|
// before tag, within tag, after tag, before matching end-tag
|
|
// even if no info was saved, the block will still exist with 2 words (size,# of char)
|
|
ichspInfoEndtagEnd = pTokArray[iArray].token.ibTokMac;
|
|
|
|
// first copy the document till DESIGNTIMESPx
|
|
// skip DESIGNTIMESPx and its value and set ichBeginCopy to be after that
|
|
|
|
// NOTE - token before iArraySav'th one should be tokSpace with lenght 1
|
|
// and with a value of chSpace (unless Trident has modified it). If thats TRUE,
|
|
// we should skip that too, because we added it when we put in DESIGNTIMESPx.
|
|
|
|
// fix Trident's behaviour - If Trident sees unknown tag(s) it puts it(them) at the end
|
|
// and inserts EOL before those. In this case, we would have inserted a space before DESIGNTIMESP
|
|
// and Trident would have inserted EOL. If thats not the case, we will ignore it.
|
|
if ( (iArraySav-1 > 0) /* validation */
|
|
&& ( ( (pTokArray[iArraySav-1].token.ibTokMac - pTokArray[iArraySav-1].token.ibTokMin == 1)
|
|
&& (pwOld[pTokArray[iArraySav-1].token.ibTokMin] == ' ')
|
|
)
|
|
|| ( (pTokArray[iArraySav-1].token.ibTokMac - pTokArray[iArraySav-1].token.ibTokMin == 3)
|
|
&& (pwOld[pTokArray[iArraySav-1].token.ibTokMin] == ' ')
|
|
&& (pwOld[pTokArray[iArraySav-1].token.ibTokMin+1] == '\r')
|
|
&& (pwOld[pTokArray[iArraySav-1].token.ibTokMin+2] == '\n')
|
|
)
|
|
)
|
|
)
|
|
{
|
|
ichBegin = pTokArray[iArraySav-1].token.ibTokMin;
|
|
}
|
|
else
|
|
ichBegin = pTokArray[iArraySav].token.ibTokMin;
|
|
|
|
#ifdef NEEDED
|
|
ASSERT(ichBegin >= ichBeginCopy);
|
|
|
|
cbNeed = (ichNewCur+(ichBegin-ichBeginCopy))*sizeof(WCHAR) + cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
// BUG 15389 - look at the case of DESIGNTIMESP & convert the tag into upper/lower case...
|
|
//memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
// (BYTE *)(pwOld+ichBeginCopy),
|
|
// (ichBegin-ichBeginCopy)*sizeof(WCHAR));
|
|
//ichNewCur += (ichBegin-ichBeginCopy);
|
|
if (ichBegin-ichBeginCopy >= 0)
|
|
{
|
|
// step 1 - copy from ichBeginCopy to '<' of the current tag
|
|
if ((int)(pTokArray[itoktagStart].token.ibTokMac-ichBeginCopy) > 0)
|
|
{
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+ichBeginCopy),
|
|
(pTokArray[itoktagStart].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[itoktagStart].token.ibTokMac-ichBeginCopy);
|
|
ichNewCurSav = ichNewCur+1; // used as a peg to get preceding tokTag_START i.e. '<'
|
|
}
|
|
// step 2 - convert current tag into upper/lower case & copy it
|
|
if (ichBeginCopy < pTokArray[itoktagStart+1].token.ibTokMin)
|
|
{
|
|
ASSERT((int)(pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin) > 0);
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+pTokArray[itoktagStart+1].token.ibTokMin),
|
|
(pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin)*sizeof(WCHAR));
|
|
if (iswupper(pwOld[pTokArray[iArraySav].token.ibTokMin]) != 0) // DESIGNTIMESP is upper case
|
|
{
|
|
// convert the tag into upper case. ASSUME that the tag is at itoktagStart+1
|
|
_wcsupr(&pwNew[ichNewCur]);
|
|
}
|
|
else
|
|
{
|
|
// convert the tag into lower case. ASSUME that the tag is at itoktagStart+1
|
|
_wcslwr(&pwNew[ichNewCur]);
|
|
}
|
|
ichNewCur += (pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin);
|
|
}
|
|
else // this tag is alreay been copied
|
|
{
|
|
// hack
|
|
if (pTokArray[itoktagStart+1].token.ibTokMac == ichBeginCopy) // means we are just past the current tag
|
|
{
|
|
if (iswupper(pwOld[pTokArray[iArraySav].token.ibTokMin]) != 0) // DESIGNTIMESP is upper case
|
|
{
|
|
ASSERT(ichNewCur >= (pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin));
|
|
// convert the tag into upper case. ASSUME that the tag is at itoktagStart+1
|
|
_wcsupr(&pwNew[ichNewCur-(pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin)]);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(ichNewCur >= (pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin));
|
|
// convert the tag into lower case. ASSUME that the tag is at itoktagStart+1
|
|
_wcslwr(&pwNew[ichNewCur-(pTokArray[itoktagStart+1].token.ibTokMac-pTokArray[itoktagStart+1].token.ibTokMin)]);
|
|
}
|
|
}
|
|
}
|
|
// step 3 - copy from after the tag (which is at ichtoktagStart+1) to ichBegin
|
|
if ((int)(ichBegin-pTokArray[itoktagStart+1].token.ibTokMac) > 0)
|
|
{
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+pTokArray[itoktagStart+1].token.ibTokMac),
|
|
(ichBegin-pTokArray[itoktagStart+1].token.ibTokMac)*sizeof(WCHAR));
|
|
ichNewCur += (ichBegin-pTokArray[itoktagStart+1].token.ibTokMac);
|
|
}
|
|
}
|
|
// set ichBeginCopy
|
|
ichBeginCopy = ichspInfoEndtagEnd; // make it ready for next copy
|
|
|
|
// copy the rest of the tag (skipping DESIGNTIMESPx = value)
|
|
ASSERT((INT)(ichspInfoEndtagEnd-pTokArray[iArrayValue].token.ibTokMac) >= 0);
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(pwOld+pTokArray[iArrayValue].token.ibTokMac),
|
|
(ichspInfoEndtagEnd-pTokArray[iArrayValue].token.ibTokMac)*sizeof(WCHAR));
|
|
ichNewCur += (ichspInfoEndtagEnd-pTokArray[iArrayValue].token.ibTokMac);
|
|
#endif //NEEDED
|
|
|
|
memset((BYTE *)szIndex, 0, sizeof(szIndex));
|
|
// check if the value has quotes around it and don't copy them to szIndex
|
|
if ( pwOld[pTokArray[iArrayValue].token.ibTokMin] == '"'
|
|
&& pwOld[pTokArray[iArrayValue].token.ibTokMac-1] == '"'
|
|
)
|
|
{
|
|
memcpy( (BYTE *)szIndex,
|
|
(BYTE *)(pwOld+pTokArray[iArrayValue].token.ibTokMin+1),
|
|
(pTokArray[iArrayValue].token.ibTokMac-pTokArray[iArrayValue].token.ibTokMin-2)*sizeof(WCHAR));
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)szIndex,
|
|
(BYTE *)(pwOld+pTokArray[iArrayValue].token.ibTokMin),
|
|
(pTokArray[iArrayValue].token.ibTokMac-pTokArray[iArrayValue].token.ibTokMin)*sizeof(WCHAR));
|
|
}
|
|
ptep->m_ispInfoBlock = _wtoi(szIndex);
|
|
ptep->m_ispInfoBlock -= ptep->m_ispInfoBase;
|
|
if (ptep->m_ispInfoBlock < 0)
|
|
goto LRet;
|
|
|
|
// NOTE - we can cache this info in a link list at the begining
|
|
// get to the ptep->m_ispInfoBlock'th block from ptep->m_pspInfoOutStart
|
|
ASSERT(ptep->m_cchspInfoTotal >= 0);
|
|
pspInfoEnd = ptep->m_pspInfoOutStart + ptep->m_cchspInfoTotal;
|
|
ptep->m_pspInfoOut = ptep->m_pspInfoOutStart;
|
|
for (index = 0; index < ptep->m_ispInfoBlock; index++)
|
|
{
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // before <
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // between <>
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // Order Info
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // after >
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // before matching </
|
|
|
|
// we somehow have gone beyond the data that was saved for spacing
|
|
if (ptep->m_pspInfoOut >= pspInfoEnd)
|
|
{
|
|
goto LRet;
|
|
}
|
|
}
|
|
|
|
// get the Order Info
|
|
pspInfoOrder = ptep->m_pspInfoOut;
|
|
pspInfoOrder += *(WORD *)pspInfoOrder; // skip info saved for spacing before '<'
|
|
pspInfoOrder += *(WORD *)pspInfoOrder; // skip info saved for spacing between '<>'
|
|
// now pspInfoOrder is at correct place
|
|
cwOrderInfo = *(WORD *)pspInfoOrder++;
|
|
ASSERT(cwOrderInfo >= 1);
|
|
// process this info
|
|
#ifdef NEEDED
|
|
if (cwOrderInfo > 1) // means that we saved some info
|
|
{
|
|
INT cchNewCopy;
|
|
|
|
cchNewCopy = (ichBegin-pTokArray[itoktagStart].token.ibTokMin) + (ichspInfoEndtagEnd-pTokArray[iArrayValue].token.ibTokMac);
|
|
ptep->FRestoreOrder(pwNew, pwOld, pspInfoOrder, &ichNewCur, cwOrderInfo, pTokArray, itoktagStart, iArray, iArraySav, iArrayValue, cchNewCopy, phgNew);
|
|
}
|
|
#endif //NEEDED
|
|
ichtoktagStart = ichNewCur; // init
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
for (index = 0; index < 4; index++)
|
|
{
|
|
BOOL fLookback = FALSE;
|
|
|
|
cchwspInfo = *(WORD *)ptep->m_pspInfoOut++;
|
|
cchRange = *(WORD *)ptep->m_pspInfoOut++;
|
|
if (cchwspInfo == 2) // we didn't save any spacing info
|
|
{
|
|
if (index == 0) // special case BUG 8741
|
|
{
|
|
// Note that we didn't save anything before this tag. which means that
|
|
// we had '>' or some text immediately before the < tag.
|
|
ichtoktagStart = ichNewCur;
|
|
while (ichtoktagStart >= 0)
|
|
{
|
|
if (pwNew[ichtoktagStart] == '<')
|
|
{
|
|
ichtoktagStart--;
|
|
break;
|
|
}
|
|
ichtoktagStart--;
|
|
}
|
|
if (ichtoktagStart >= 0)
|
|
{
|
|
int cws = 0;
|
|
int ichtagStart = ichtoktagStart;
|
|
|
|
// remove any such white space trident inserts.
|
|
while ( pwNew[ichtoktagStart] == ' '
|
|
|| pwNew[ichtoktagStart] == '\r'
|
|
|| pwNew[ichtoktagStart] == '\n'
|
|
|| pwNew[ichtoktagStart] == '\t')
|
|
{
|
|
cws++;
|
|
ichtoktagStart--;
|
|
}
|
|
if (cws > 0)
|
|
{
|
|
ASSERT((int)(ichNewCur-ichtagStart-1) >= 0);
|
|
//ichtokTagStart now points to either '>' or a non-whitespace char
|
|
memmove((BYTE*)&pwNew[ichtoktagStart+1],
|
|
(BYTE*)&pwNew[ichtoktagStart+1+cws],
|
|
(ichNewCur-ichtagStart-1)*sizeof(WCHAR));
|
|
ichNewCur -= cws;
|
|
}
|
|
} // if (ichtoktagStart >= 0)
|
|
} // if (index == 0)
|
|
goto LNext;
|
|
}
|
|
|
|
// note that ichtoktagStart is a position in pwNew
|
|
switch (index)
|
|
{
|
|
case 0: // before < of the tag
|
|
fLookback = TRUE;
|
|
ichtoktagStart = (ichNewCurSav == -1)?ichNewCur:ichNewCurSav;// handle < ... <%..%>...> case correctly
|
|
ichNewCurAtIndex0 = ichNewCur; // lets save the ichNewCur before we restore pre-tag spacing
|
|
while (ichtoktagStart >= 0)
|
|
{
|
|
if (pwNew[ichtoktagStart] == '<' && pwNew[ichtoktagStart+1] != '%')
|
|
{
|
|
ichtoktagStart--;
|
|
break;
|
|
}
|
|
ichtoktagStart--;
|
|
}
|
|
if (ichtoktagStart < 0) // looks to be an error, don't try to restore the spacing
|
|
{
|
|
ptep->m_pspInfoOut += cchwspInfo-2;
|
|
continue;
|
|
}
|
|
break;
|
|
case 1: // between <> of the tag
|
|
fLookback = FALSE;
|
|
// NOTE - we can assume that in 'case 0' we had put ichtoktagStart is just before '<'
|
|
// so that we can avoid this while loop. but what if we skipped case '0'?
|
|
|
|
// adjust ichNewCurSav to reflect the pre-tag spacing so that it doesn't become invalid
|
|
// we may need to adjust it in ichNewCur-ichNewCurAtIndex0 < 0 case as well, but lets not
|
|
// add code at this stage that we don't have to. (4/30/98)
|
|
if (ichNewCurAtIndex0 != -1 && ichNewCurSav != -1 && ichNewCur-ichNewCurAtIndex0 > 0)
|
|
ichNewCurSav = ichNewCurSav + (ichNewCur-ichNewCurAtIndex0);
|
|
ichtoktagStart = (ichNewCurSav == -1)?ichNewCur:ichNewCurSav;// handle < ... <%..%>...> case correctly
|
|
while (ichtoktagStart >= 0)
|
|
{
|
|
if (pwNew[ichtoktagStart] == '<' && pwNew[ichtoktagStart+1] != '%')
|
|
{
|
|
ichtoktagStart++;
|
|
break;
|
|
}
|
|
ichtoktagStart--;
|
|
}
|
|
if (ichtoktagStart < 0) // looks to be an error, don't try to restore the spacing
|
|
{
|
|
ptep->m_pspInfoOut += cchwspInfo-2; // for spacing info
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut; // for Order Info
|
|
continue;
|
|
}
|
|
break;
|
|
case 2: // after > of the tag
|
|
// Observation - Trident messes up the document in following way -
|
|
// If we had an EOL after '>' which is followed by HTML text,
|
|
// trident eats that EOL
|
|
// BUT
|
|
// If we had a space/tab before that EOL trident doesn't eat it!!!
|
|
// so I have added the conditions
|
|
// && (pwOld[pTokArray[iArray+1].token.ibTokMin] != ' ')
|
|
// && (pwOld[pTokArray[iArray+1].token.ibTokMin] != '\t')
|
|
|
|
// here is the deal - If the next tone happens to be plain text, there is no danger
|
|
// of applying the same format twice.( i.e. once for after '>' and the next time for
|
|
// before the next '<')
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken) /*validation*/
|
|
&& pTokArray[iArray+1].token.tok == 0
|
|
&& pTokArray[iArray+1].token.tokClass == tokIDENTIFIER
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin] != '\r')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin] != ' ')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin] != '\t')
|
|
)
|
|
{
|
|
fLookback = FALSE;
|
|
ichtoktagStart = ichNewCur;
|
|
while (ichtoktagStart >= 0)
|
|
{
|
|
if (pwNew[ichtoktagStart] == '>')
|
|
{
|
|
ichtoktagStart++;
|
|
break;
|
|
}
|
|
ichtoktagStart--;
|
|
}
|
|
if (ichtoktagStart < 0) // looks to be an error, don't try to restore the spacing
|
|
{
|
|
ptep->m_pspInfoOut += cchwspInfo-2;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptep->m_pspInfoOut += cchwspInfo-2; // we ignore this info
|
|
continue;
|
|
}
|
|
break;
|
|
case 3: // before matching end tag
|
|
ptep->m_pspInfoOut += cchwspInfo-2; // we ignore this info
|
|
continue;
|
|
//fLookback = TRUE;
|
|
//ichtoktagStart = 0; // we ignore this info
|
|
break;
|
|
}
|
|
|
|
if (index == 3) // skip this info, because we have not reached matching end tag yet
|
|
ptep->m_pspInfoOut += cchwspInfo-2;
|
|
//else if (index == 0)
|
|
// ptep->FRestoreSpacingInHTML(pwNew, pwOld, &ichNewCur, &cchwspInfo, cchRange, ichtoktagStart, fLookback, index);
|
|
else
|
|
ptep->FRestoreSpacing(pwNew, pwOld, &ichNewCur, &cchwspInfo, cchRange, ichtoktagStart, fLookback, index);
|
|
|
|
LNext:
|
|
if (index == 1) // we have already processed this info, just move the pointer ahead
|
|
ptep->m_pspInfoOut += *(WORD *)ptep->m_pspInfoOut;
|
|
|
|
} // for ()
|
|
|
|
LRet:
|
|
*ppwNew = pwNew; // in case this changed
|
|
*pichNewCur = ichNewCur;
|
|
|
|
} /* RestoreSpacingSpecial() */
|
|
|
|
void
|
|
CTriEditParse::SaveSpacingSpecial(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR *ppwNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, INT iArray, UINT *pichNewCur)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
LPWSTR pwNew = *ppwNew;
|
|
int iArrayPrevTag, iArrayMatch;
|
|
UINT iArrayElem, iArrayTagStart;
|
|
INT ichEndMatch, ichBeginMatch, ichEndPrev, ichBeginPrev, ichEndNext, ichBeginNext, ichEndTag, ichBeginTag, ichBegin, ichEnd;
|
|
UINT cbNeed;
|
|
WCHAR szIndex[cchspBlockMax]; // will we have more than 20 digit numbers as number of DESIGNTIMESPx?
|
|
LPCWSTR rgSpaceTags[] =
|
|
{
|
|
L" DESIGNTIMESP=",
|
|
L" DESIGNTIMESP1=",
|
|
L" designtimesp=",
|
|
};
|
|
|
|
iArrayElem = 0xFFFFFFFF; // init
|
|
//
|
|
// look for TokTag_START
|
|
while (iArray >= 0)
|
|
{
|
|
if ( pTokArray[iArray].token.tokClass == tokTag
|
|
&& pTokArray[iArray].token.tok == TokTag_START
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
iArray--;
|
|
}
|
|
if (iArray < 0) // error case
|
|
goto LRet;
|
|
iArrayTagStart = iArray;
|
|
//
|
|
|
|
// step 1
|
|
// look for > that matches with <. we already are at ft.tokBegin2 i.e. <
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
ichBeginTag = pTokArray[iArray].token.ibTokMac;
|
|
while (iArray < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( pTokArray[iArray].token.tok == TokTag_CLOSE
|
|
&& pTokArray[iArray].token.tokClass == tokTag) // ft.tokEnd2 is -1
|
|
break;
|
|
if (pTokArray[iArray].token.tokClass == tokElem)
|
|
iArrayElem = iArray;
|
|
iArray++;
|
|
}
|
|
if (iArray >= (int)ptep->m_cMaxToken) // didn't find >
|
|
{
|
|
goto LRet;
|
|
}
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE); // found >
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag); // found >
|
|
ichEndTag = ichBegin = pTokArray[iArray].token.ibTokMin;
|
|
ichEnd = pTokArray[iArray].token.ibTokMac;
|
|
|
|
// step 2
|
|
// look for > before iArrayTagStart. Boundary case will be for the first < in the document
|
|
// save the spacing info
|
|
ASSERT(pTokArray[iArrayTagStart].token.tok == TokTag_START);
|
|
ASSERT(pTokArray[iArrayTagStart].token.tokClass == tokTag);
|
|
ichEndPrev = pTokArray[iArrayTagStart].token.ibTokMin;
|
|
ichBeginPrev = ichEndPrev-1;
|
|
// look for previous TokTag_CLOSE
|
|
// if the tag ending tag, ichBeginPrev becomes ibTokMac of '>' tag
|
|
// if the tag is starting tag, ichBeginPrev becomes ibTokMac+(white space just after that tag)
|
|
iArrayPrevTag = iArrayTagStart; // this is TokTag_START
|
|
while (iArrayPrevTag >= 0)
|
|
{
|
|
if ( ( pTokArray[iArrayPrevTag].token.tokClass == tokTag
|
|
&& pTokArray[iArrayPrevTag].token.tok == TokTag_CLOSE
|
|
)
|
|
|| ( pTokArray[iArrayPrevTag].token.tokClass == tokSSS
|
|
&& pTokArray[iArrayPrevTag].token.tok == TokTag_SSSCLOSE
|
|
)/* VID6 - bug 22787 */
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
iArrayPrevTag--;
|
|
}
|
|
if (iArrayPrevTag < 0) // handle error case
|
|
{
|
|
// leave the old behaviour as is for V1
|
|
while (ichBeginPrev >= 0)
|
|
{
|
|
if ( pwOld[ichBeginPrev] != ' '
|
|
&& pwOld[ichBeginPrev] != '\r'
|
|
&& pwOld[ichBeginPrev] != '\n'
|
|
&& pwOld[ichBeginPrev] != '\t'
|
|
)
|
|
break;
|
|
ichBeginPrev--;
|
|
}
|
|
goto LGotEndNext;
|
|
}
|
|
ichBeginPrev = pTokArray[iArrayPrevTag].token.ibTokMac - 1;
|
|
|
|
LGotEndNext:
|
|
if (ichBeginPrev < 0)
|
|
ichBeginPrev = 0;
|
|
else
|
|
ichBeginPrev++;
|
|
|
|
|
|
// step 3
|
|
// look for TokTag_START after iArray(which currently is TokTag_CLOSE)
|
|
// save spacing info
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
//iArrayNextStart = iArray;
|
|
ichBeginNext = pTokArray[iArray].token.ibTokMac;
|
|
ASSERT(ichBeginNext == ichEnd);
|
|
ichEndNext = ichBeginNext;
|
|
while (ichEndNext < (INT)pTokArray[ptep->m_cMaxToken-1].token.ibTokMac)
|
|
{
|
|
if ( pwOld[ichEndNext] != ' '
|
|
&& pwOld[ichEndNext] != '\r'
|
|
&& pwOld[ichEndNext] != '\n'
|
|
&& pwOld[ichEndNext] != '\t'
|
|
)
|
|
break;
|
|
ichEndNext++;
|
|
}
|
|
|
|
if (ichEndNext >= (INT)pTokArray[ptep->m_cMaxToken-1].token.ibTokMac)
|
|
ichEndNext = pTokArray[ptep->m_cMaxToken-1].token.ibTokMac;
|
|
|
|
// step 4
|
|
// if iArrayElem != -1, look for pTokArray[iArrayElem].iNextprev. If its not -1, set iArrayMatch
|
|
// look for previous TokTag_START/TokTag_END. look for previous TokTag_CLOSE
|
|
// save spacing info
|
|
if (iArrayElem == -1) // this can happen if we have incomplete HTML
|
|
{
|
|
ichEndMatch = ichBeginMatch = 0;
|
|
goto LSkipMatchCalc;
|
|
}
|
|
iArrayMatch = pTokArray[iArrayElem].iNextprev;
|
|
if (iArrayMatch != -1) // match was set while tokenizing
|
|
{
|
|
ichBeginMatch = ichEndMatch = 0; //init
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_CLOSE);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
while (iArrayMatch >= iArray) // iArray is TokTag_CLOSE of the current tag (i.e. '>')
|
|
{
|
|
if ( pTokArray[iArrayMatch].token.tokClass == tokTag
|
|
&& ( pTokArray[iArrayMatch].token.tok == TokTag_START
|
|
|| pTokArray[iArrayMatch].token.tok == TokTag_END
|
|
)
|
|
)
|
|
break;
|
|
iArrayMatch--;
|
|
}
|
|
if (iArrayMatch > iArray) // did find '</' or '<' after the current tag
|
|
{
|
|
ichEndMatch = pTokArray[iArrayMatch].token.ibTokMin;
|
|
ichBeginMatch = ichEndMatch; // init
|
|
// look for '>' and set ichBeginMatch
|
|
while (iArrayMatch >= iArray) // iArray is TokTag_CLOSE of the current tag (i.e. '>')
|
|
{
|
|
if ( ( pTokArray[iArrayMatch].token.tokClass == tokTag
|
|
&& pTokArray[iArrayMatch].token.tok == TokTag_CLOSE
|
|
)
|
|
|| ( pTokArray[iArrayMatch].token.tokClass == tokSSS
|
|
&& pTokArray[iArrayMatch].token.tok == TokTag_SSSCLOSE
|
|
)/* VID6 - bug 22787 */
|
|
)
|
|
break;
|
|
iArrayMatch--;
|
|
}
|
|
if (iArrayMatch >= iArray) // they may very well be the same
|
|
{
|
|
ichBeginMatch = pTokArray[iArrayMatch].token.ibTokMac;
|
|
ASSERT(ichBeginMatch <= ichEndMatch);
|
|
ASSERT(ichBeginMatch >= ichEnd);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// don't bother saving any info from here
|
|
ichEndMatch = ichBeginMatch = 0;
|
|
}
|
|
LSkipMatchCalc:
|
|
if (ichEndPrev > ichBeginPrev)
|
|
ptep->hrMarkSpacing(pwOld, ichEndPrev, &ichBeginPrev);
|
|
else
|
|
ptep->hrMarkSpacing(pwOld, ichEndPrev, &ichEndPrev);
|
|
|
|
if (ichEndTag > ichBeginTag)
|
|
{
|
|
INT ichBeginTagSav = ichBeginTag;
|
|
|
|
ptep->hrMarkSpacing(pwOld, ichEndTag, &ichBeginTag);
|
|
// iArray'th token is TokTag_CLOSE & iArrayTagStart is TokTag_START
|
|
ptep->hrMarkOrdering(pwOld, pTokArray, iArrayTagStart, iArray, ichEndTag, &ichBeginTagSav);
|
|
}
|
|
else
|
|
{
|
|
INT ichEndTagSav = ichEndTag;
|
|
|
|
ptep->hrMarkSpacing(pwOld, ichEndTag, &ichEndTag);
|
|
// iArray'th token is TokTag_CLOSE & iArrayTagStart is TokTag_START
|
|
ptep->hrMarkOrdering(pwOld, pTokArray, iArrayTagStart, iArray, ichEndTagSav, &ichEndTagSav);
|
|
}
|
|
|
|
if (ichEndNext > ichBeginNext)
|
|
ptep->hrMarkSpacing(pwOld, ichEndNext, &ichBeginNext);
|
|
else
|
|
ptep->hrMarkSpacing(pwOld, ichEndNext, &ichEndNext);
|
|
|
|
if (ichEndMatch > ichBeginMatch)
|
|
ptep->hrMarkSpacing(pwOld, ichEndMatch, &ichBeginMatch);
|
|
else
|
|
ptep->hrMarkSpacing(pwOld, ichEndMatch, &ichEndMatch);
|
|
|
|
// realloc if needed
|
|
cbNeed = (ichNewCur+3*wcslen(rgSpaceTags[0])+(ichEnd-ichBegin))*sizeof(WCHAR);
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
if (iswupper(pwOld[pTokArray[iArrayTagStart+1].token.ibTokMin]) != 0) // upper case
|
|
{
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(rgSpaceTags[0]),
|
|
(wcslen(rgSpaceTags[0]))*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgSpaceTags[0]);
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(rgSpaceTags[2]),
|
|
(wcslen(rgSpaceTags[2]))*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgSpaceTags[2]);
|
|
}
|
|
|
|
(WCHAR)_itow(ptep->m_ispInfoBlock+ptep->m_ispInfoBase, szIndex, 10);
|
|
ptep->m_ispInfoBlock++;
|
|
|
|
ASSERT(wcslen(szIndex) < sizeof(szIndex));
|
|
ASSERT(sizeof(szIndex) == cchspBlockMax*sizeof(WCHAR));
|
|
memcpy( (BYTE *)(pwNew+ichNewCur),
|
|
(BYTE *)(szIndex),
|
|
wcslen(szIndex)*sizeof(WCHAR));
|
|
ichNewCur += wcslen(szIndex);
|
|
|
|
|
|
|
|
LRet:
|
|
//*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
*pichNewCur = ichNewCur;
|
|
|
|
return;
|
|
} /* SaveSpacingSpecial() */
|
|
|
|
|
|
void
|
|
CTriEditParse::fnSaveAImgLink(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD dwFlags)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
UINT cbNeed;
|
|
|
|
int cchURL = 0;
|
|
int ichURL = 0;
|
|
int index = iArray;
|
|
LPCWSTR rgDspURL[] =
|
|
{
|
|
L" DESIGNTIMEURL=",
|
|
};
|
|
|
|
ASSERT( pTokArray[iArray].token.tok == TokElem_A
|
|
|| pTokArray[iArray].token.tok == TokElem_IMG
|
|
|| pTokArray[iArray].token.tok == TokElem_LINK);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
|
|
if (!FURLNeedSpecialHandling(pTokArray, iArray, pwOld, (int)ptep->m_cMaxToken, &ichURL, &cchURL))
|
|
iArray++;
|
|
else // save the URL as an attribute value of DESIGNTIMEURL
|
|
{
|
|
// make sure we have enough space in pwNew.
|
|
// copy from ichBeginCopy till current token's ending '>'.
|
|
// index points to A/IMG/LINK
|
|
while (index < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( pTokArray[index].token.tok == TokTag_CLOSE
|
|
&& pTokArray[index].token.tokClass == tokTag
|
|
)
|
|
break;
|
|
index++;
|
|
}
|
|
if (index >= (int)ptep->m_cMaxToken) // invalid HTML, we didn't find '>'
|
|
{
|
|
iArray++;
|
|
goto LRet;
|
|
}
|
|
cbNeed = (ichNewCur+pTokArray[index].token.ibTokMin-ichBeginCopy+wcslen(rgDspURL[0])+cchURL+3/*eq,quotes*/)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
{
|
|
iArray++;
|
|
goto LRet;
|
|
}
|
|
// index points to '>'
|
|
if ((int) (pTokArray[index].token.ibTokMin-ichBeginCopy) > 0)
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichBeginCopy],
|
|
(pTokArray[index].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[index].token.ibTokMin-ichBeginCopy);
|
|
}
|
|
|
|
if (cchURL != 0)
|
|
{
|
|
// add 'DESIGNTIMEURL=' followed by the current URL as quoted value
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)rgDspURL[0],
|
|
wcslen(rgDspURL[0])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgDspURL[0]);
|
|
|
|
pwNew[ichNewCur++] = '"';
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichURL],
|
|
cchURL*sizeof(WCHAR));
|
|
ichNewCur += cchURL;
|
|
pwNew[ichNewCur++] = '"';
|
|
}
|
|
|
|
if (dwFlags & dwPreserveSourceCode)
|
|
ptep->SaveSpacingSpecial(ptep, pwOld, &pwNew, phgNew, pTokArray, iArray-1, &ichNewCur);
|
|
|
|
// add ending '>' and set ichBeginCopy, iArray, ichNewCur appropriately
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[index].token.ibTokMin],
|
|
(pTokArray[index].token.ibTokMac-pTokArray[index].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[index].token.ibTokMac-pTokArray[index].token.ibTokMin);
|
|
|
|
iArray = index+1;
|
|
ichBeginCopy = pTokArray[index].token.ibTokMac;
|
|
}
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
return;
|
|
|
|
} /* fnSaveAImgLink() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreAImgLink(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD dwFlags)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
UINT iArraySav = iArray;
|
|
LPCWSTR rgTags[] =
|
|
{
|
|
L"DESIGNTIMESP",
|
|
L"DESIGNTIMEREF",
|
|
L"DESIGNTIMEURL",
|
|
};
|
|
int indexStart, indexEnd, i, indexDSR, indexDSP, indexDSU;
|
|
UINT cchsptag, cchhreftag, cchdsurltag;
|
|
CComBSTR bstrRelativeURL;
|
|
BOOL fHrefSrcFound = FALSE;
|
|
UINT cbNeed;
|
|
|
|
// we know that DESIGNTIMESP is not saved for these tags, but check it just to be sure.
|
|
// if we find DESIGNTIMEREF, it means that the HREF was dragged on the page while in design view.
|
|
ASSERT( pTokArray[iArray].token.tok == TokElem_A
|
|
|| pTokArray[iArray].token.tok == TokElem_IMG
|
|
|| pTokArray[iArray].token.tok == TokElem_LINK);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
|
|
indexDSP = indexDSR = indexDSU = -1;
|
|
//get the start tag
|
|
indexStart = iArray;
|
|
while (indexStart >= 0) // generally, it will be the previous token, but just in case...
|
|
{
|
|
if ( (pTokArray[indexStart].token.tok == TokTag_START)
|
|
&& (pTokArray[indexStart].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
indexStart--;
|
|
} // while ()
|
|
if (indexStart < 0) // this can happen only if we have incomplete HTML. Handle error case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
indexEnd = iArray;
|
|
while (indexEnd < (int)ptep->m_cMaxToken) // generally, it will be the next token, but just in case...
|
|
{
|
|
if ( (pTokArray[indexEnd].token.tok == TokTag_CLOSE) /* > */
|
|
&& (pTokArray[indexEnd].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
indexEnd++;
|
|
}
|
|
if (indexEnd >= (int)ptep->m_cMaxToken) // error case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// look for DESIGNTIMEREF inside the tags
|
|
cchsptag = wcslen(rgTags[0]);
|
|
cchhreftag = wcslen(rgTags[1]);
|
|
cchdsurltag = wcslen(rgTags[2]);
|
|
for (i = iArray; i < indexEnd; i++)
|
|
{
|
|
if ( pTokArray[i].token.tok == 0
|
|
&& pTokArray[i].token.tokClass == tokSpace
|
|
&& cchsptag == pTokArray[i].token.ibTokMac - pTokArray[i].token.ibTokMin
|
|
&& (0 == _wcsnicmp(rgTags[0], &pwOld[pTokArray[i].token.ibTokMin], cchsptag))
|
|
)
|
|
{
|
|
indexDSP = i;
|
|
if (indexDSR != -1 && indexDSU != -1) // already initilized
|
|
break;
|
|
}
|
|
else if ( pTokArray[i].token.tok == 0
|
|
&& pTokArray[i].token.tokClass == tokSpace
|
|
&& cchhreftag == pTokArray[i].token.ibTokMac - pTokArray[i].token.ibTokMin
|
|
&& (0 == _wcsnicmp(rgTags[1], &pwOld[pTokArray[i].token.ibTokMin], cchhreftag))
|
|
)
|
|
{
|
|
indexDSR = i;
|
|
if (indexDSP != -1 && indexDSU != -1) // already initilized
|
|
break;
|
|
}
|
|
else if ( pTokArray[i].token.tok == 0
|
|
&& pTokArray[i].token.tokClass == tokSpace
|
|
&& cchhreftag == pTokArray[i].token.ibTokMac - pTokArray[i].token.ibTokMin
|
|
&& (0 == _wcsnicmp(rgTags[2], &pwOld[pTokArray[i].token.ibTokMin], cchdsurltag))
|
|
)
|
|
{
|
|
indexDSU = i;
|
|
if (indexDSP != -1 && indexDSR != -1) // already initilized
|
|
break;
|
|
}
|
|
} // for ()
|
|
|
|
// Here is the deal - If we found DESIGNTIMESP, it means that this A/Img/Link existed
|
|
// while in source view. And in that case, we shouldn't find DESIGNTIMEREF. With the
|
|
// same token, if we found DESINTIMEREF, it means that this A/Img/Link was dropped
|
|
// while in design view, so DESIGNTIMESP shouldn't be there. They are mutually exclusive.
|
|
|
|
// Also, DESIGNTIMEURL can exist only if the href was there while in source view
|
|
// and its value was relative. This can coexist with DESIGNTIMESP,
|
|
// but not with DESIGNTIMEREF.
|
|
if (indexDSP != -1 && indexDSU == -1) // we found DESIGNTIMESP, but not DESIGNTIMEURL
|
|
{
|
|
ASSERT(indexDSR == -1); // based on above statement, this better be true
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
if (indexDSR == -1 && indexDSU == -1)
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
if (indexDSR != -1)
|
|
{
|
|
ASSERT(indexDSU == -1); // this better be TRUE, because the 2 are mutually exclusive
|
|
// at this point we know that we have DESIGNTIMEREF (that was put in as part
|
|
// of drag-drop operation while in design view)
|
|
// modify the href and copy the tag.
|
|
if ((int) (pTokArray[indexStart].token.ibTokMin-ichBeginCopy) > 0)
|
|
{
|
|
cbNeed = (ichNewCur+pTokArray[indexStart].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichBeginCopy],
|
|
(pTokArray[indexStart].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[indexStart].token.ibTokMin-ichBeginCopy);
|
|
}
|
|
|
|
cbNeed = (ichNewCur+pTokArray[indexEnd].token.ibTokMac-pTokArray[indexStart].token.ibTokMin)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
// trident mucks with the spacing of these tags and we didn't save any spacing info
|
|
// soput endofline at the end of the tag.
|
|
//pwNew[ichNewCur++] = '\r';
|
|
//pwNew[ichNewCur++] = '\n';
|
|
i = indexStart;
|
|
|
|
while (i <= indexEnd)
|
|
{
|
|
if (i == indexDSR)
|
|
i++; // don't copy this token
|
|
else if ( ( pTokArray[i].token.tok == TokAttrib_HREF
|
|
|| pTokArray[i].token.tok == TokAttrib_SRC
|
|
)
|
|
&& pTokArray[i].token.tokClass == tokAttr
|
|
&& !fHrefSrcFound
|
|
)
|
|
{
|
|
fHrefSrcFound = TRUE;
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
i++;
|
|
}
|
|
else if ( pTokArray[i].token.tok == 0
|
|
&& pTokArray[i].token.tokClass == tokString
|
|
&& fHrefSrcFound
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
int cchURL;
|
|
WCHAR *pszURL;
|
|
BOOL fQuote = (pwOld[pTokArray[i].token.ibTokMin] == '"');
|
|
|
|
cchURL = (fQuote)
|
|
? pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin-2
|
|
: pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin;
|
|
pszURL = new WCHAR [cchURL+1];
|
|
|
|
fHrefSrcFound = FALSE;
|
|
if (ptep->m_bstrBaseURL != NULL) // get the relative URL
|
|
{
|
|
// get the URL string from pwOld and pass it in to relativise
|
|
memcpy( (BYTE *)pszURL,
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin + ((fQuote)? 1 : 0)],
|
|
(cchURL)*sizeof(WCHAR));
|
|
pszURL[cchURL] = '\0';
|
|
hr = UtilConvertToRelativeURL((LPOLESTR)pszURL, ptep->m_bstrBaseURL, NULL, &bstrRelativeURL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// can we assume that bstrRelativeURL is NULL terminated?
|
|
LPWSTR pszRelativeURL = bstrRelativeURL;
|
|
if (wcslen(pszRelativeURL) == 0)
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
else
|
|
{
|
|
pwNew[ichNewCur++] = '"';
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)pszRelativeURL,
|
|
wcslen(pszRelativeURL)*sizeof(WCHAR));
|
|
ichNewCur += wcslen(pszRelativeURL);
|
|
pwNew[ichNewCur++] = '"';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
delete pszURL;
|
|
i++;
|
|
}
|
|
else // all other tokens
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
i++;
|
|
}
|
|
}
|
|
// trident mucks with the spacing of these tags and we didn't save any spacing info
|
|
// so put endofline at the end of the tag.
|
|
//pwNew[ichNewCur++] = '\r';
|
|
//pwNew[ichNewCur++] = '\n';
|
|
}
|
|
else // DESIGNTIMEURL case
|
|
{
|
|
int indexDSUEnd, indexDSPEnd;
|
|
// we found DESIGNTIMEURL. It means, we had this URL while in source view and it was
|
|
// a relative URL then.
|
|
// Check if trident has made it absolute. If it has and the filename is same,
|
|
// we need to restore it. In all other cases, simply copy the URL and return.
|
|
ASSERT(indexDSR == -1); // this better be TRUE, because the 2 are mutually exclusive
|
|
if ((int) (pTokArray[indexStart].token.ibTokMin-ichBeginCopy) > 0)
|
|
{
|
|
cbNeed = (ichNewCur+pTokArray[indexStart].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichBeginCopy],
|
|
(pTokArray[indexStart].token.ibTokMin-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[indexStart].token.ibTokMin-ichBeginCopy);
|
|
}
|
|
|
|
cbNeed = (ichNewCur+pTokArray[indexEnd].token.ibTokMac-pTokArray[indexStart].token.ibTokMin)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
// get indexDSUEnd
|
|
i = indexDSU;
|
|
indexDSUEnd = -1;
|
|
while (i < indexEnd)
|
|
{
|
|
if ( pTokArray[i].token.tok == 0
|
|
&& (pTokArray[i].token.tokClass == tokValue || pTokArray[i].token.tokClass == tokString)
|
|
)
|
|
{
|
|
indexDSUEnd = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (indexDSUEnd == -1) // we have malformed html
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// get indexDSPEnd
|
|
i = indexDSP;
|
|
indexDSPEnd = -1;
|
|
while (i < indexEnd)
|
|
{
|
|
if ( pTokArray[i].token.tok == 0
|
|
&& (pTokArray[i].token.tokClass == tokValue || pTokArray[i].token.tokClass == tokString)
|
|
)
|
|
{
|
|
indexDSPEnd = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
if (indexDSPEnd == -1) // we have malformed html
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
i = indexStart;
|
|
while (i <= indexEnd)
|
|
{
|
|
if ( (i >= indexDSU && i <= indexDSUEnd)
|
|
|| (i >= indexDSP && i <= indexDSPEnd)
|
|
)
|
|
i++; // don't copy this token
|
|
else if ( ( pTokArray[i].token.tok == TokAttrib_HREF
|
|
|| pTokArray[i].token.tok == TokAttrib_SRC
|
|
)
|
|
&& pTokArray[i].token.tokClass == tokAttr
|
|
&& !fHrefSrcFound
|
|
)
|
|
{
|
|
fHrefSrcFound = TRUE;
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
i++;
|
|
}
|
|
else if ( pTokArray[i].token.tok == 0
|
|
&& pTokArray[i].token.tokClass == tokString
|
|
&& fHrefSrcFound
|
|
)
|
|
{
|
|
int ichURL, ichURLEnd, ichDSURL, ichDSURLEnd;
|
|
// if the url is now absloute and is just an absolute version of
|
|
// the one at indexDSUEnd, we need to replace it.
|
|
ichURL = (pwOld[pTokArray[i].token.ibTokMin] == '"')
|
|
? pTokArray[i].token.ibTokMin+1
|
|
: pTokArray[i].token.ibTokMin;
|
|
ichURLEnd = (pwOld[pTokArray[i].token.ibTokMac-1] == '"')
|
|
? pTokArray[i].token.ibTokMac-1
|
|
: pTokArray[i].token.ibTokMac;
|
|
if (FIsAbsURL((LPOLESTR)&pwOld[ichURL]))
|
|
{
|
|
WCHAR *pszURL1 = NULL;
|
|
WCHAR *pszURL2 = NULL;
|
|
int ich;
|
|
|
|
ichDSURL = (pwOld[pTokArray[indexDSUEnd].token.ibTokMin] == '"')
|
|
? pTokArray[indexDSUEnd].token.ibTokMin+1
|
|
: pTokArray[indexDSUEnd].token.ibTokMin;
|
|
ichDSURLEnd = (pwOld[pTokArray[indexDSUEnd].token.ibTokMac-1] == '"')
|
|
? pTokArray[indexDSUEnd].token.ibTokMac-1
|
|
: pTokArray[indexDSUEnd].token.ibTokMac;
|
|
|
|
// just for comparison purposes, don't look at '/' or '\' separators
|
|
// between filenames & directories...
|
|
pszURL1 = new WCHAR[ichDSURLEnd-ichDSURL + 1];
|
|
pszURL2 = new WCHAR[ichDSURLEnd-ichDSURL + 1];
|
|
if (pszURL1 == NULL || pszURL2 == NULL)
|
|
goto LResumeCopy;
|
|
memcpy((BYTE *)pszURL1, (BYTE *)&pwOld[ichDSURL], (ichDSURLEnd-ichDSURL)*sizeof(WCHAR));
|
|
memcpy((BYTE *)pszURL2, (BYTE *)&pwOld[ichURLEnd-(ichDSURLEnd-ichDSURL)], (ichDSURLEnd-ichDSURL)*sizeof(WCHAR));
|
|
pszURL1[ichDSURLEnd-ichDSURL] = '\0';
|
|
pszURL2[ichDSURLEnd-ichDSURL] = '\0';
|
|
for (ich = 0; ich < ichDSURLEnd-ichDSURL; ich++)
|
|
{
|
|
if (pszURL1[ich] == '/')
|
|
pszURL1[ich] = '\\';
|
|
if (pszURL2[ich] == '/')
|
|
pszURL2[ich] = '\\';
|
|
}
|
|
|
|
if (0 == _wcsnicmp(pszURL1, pszURL2, ichDSURLEnd-ichDSURL))
|
|
{
|
|
pwNew[ichNewCur++] = '"';
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichDSURL],
|
|
(ichDSURLEnd-ichDSURL)*sizeof(WCHAR));
|
|
ichNewCur += (ichDSURLEnd-ichDSURL);
|
|
pwNew[ichNewCur++] = '"';
|
|
}
|
|
else // copy it as it is
|
|
{
|
|
LResumeCopy:
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
if (pszURL1 != NULL)
|
|
delete pszURL1;
|
|
if (pszURL2 != NULL)
|
|
delete pszURL2;
|
|
}
|
|
else // its realtive, simply copy it
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
i++;
|
|
}
|
|
else // all other tokens
|
|
{
|
|
// ****NOTE - we can actually do pretty printing here
|
|
// instead of fixing the special cases****
|
|
|
|
// fix Trident's behaviour - If Trident sees unknown tag(s) it puts it(them) at the end
|
|
// and inserts EOL before those. In this case, we would have inserted a space before DESIGNTIMESP
|
|
// and Trident would have inserted EOL. If thats not the case, we will ignore it.
|
|
if ( (pTokArray[i].token.tokClass == tokSpace)
|
|
&& (pTokArray[i].token.tok == 0)
|
|
&& (FIsWhiteSpaceToken(pwOld, pTokArray[i].token.ibTokMin, pTokArray[i].token.ibTokMac))
|
|
)
|
|
{
|
|
if (i != indexDSU-1) // else skip the copy
|
|
pwNew[ichNewCur++] = ' '; // convert space+\r+\n into space
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[i].token.ibTokMin],
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
i++;
|
|
}
|
|
}
|
|
} // while (i <= indexEnd)
|
|
} // end of DESIGNTIMEURL case
|
|
|
|
// we have spacing save dfor this tag, lets restore it
|
|
if ( (indexDSP != -1)
|
|
&& (dwFlags & dwPreserveSourceCode)
|
|
)
|
|
ptep->RestoreSpacingSpecial(ptep, pwOld, &pwNew, phgNew, pTokArray, indexDSP, &ichNewCur);
|
|
|
|
|
|
// remember to set iArray appropriately
|
|
iArray = indexEnd + 1;
|
|
ichBeginCopy = pTokArray[indexEnd].token.ibTokMac;
|
|
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
return;
|
|
|
|
} /* fnRestoreAImgLink() */
|
|
|
|
|
|
|
|
void
|
|
CTriEditParse::fnSaveComment(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
UINT iArraySav = iArray;
|
|
UINT iCommentStart, iCommentEnd;
|
|
LPCWSTR rgComment[] =
|
|
{
|
|
L"TRIEDITCOMMENT-",
|
|
L"TRIEDITCOMMENTEND-",
|
|
L"TRIEDITPRECOMMENT-",
|
|
};
|
|
int ichSp, cchComment;
|
|
UINT cbNeed;
|
|
|
|
// REMOVE METADATA from here, we don't need it because we are checking for end
|
|
// of comment too.
|
|
|
|
ASSERT(pTokArray[iArray].token.tok == TokTag_BANG);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokTag);
|
|
// early return cases
|
|
// 1. see if this is a comment or not. It could be anything that starts with '<!'
|
|
// e.g. <!DOCTYPE
|
|
if ( (iArray+1 < (INT)ptep->m_cMaxToken)
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin] == '-')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin+1] == '-')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin+2] == '[')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin+3] == 'i')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin+3] == 'I')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin+4] == 'f')
|
|
&& (pwOld[pTokArray[iArray+1].token.ibTokMin+4] == 'F')
|
|
)
|
|
{
|
|
iCommentStart = iArray; // this is a comment we are interested in
|
|
}
|
|
else
|
|
{
|
|
iArray = iArraySav + 1; // not this one
|
|
goto LRet;
|
|
}
|
|
iCommentEnd = iArray + 2;
|
|
ASSERT(iCommentEnd < (INT)ptep->m_cMaxToken);
|
|
if ( pTokArray[iCommentEnd].token.tok != TokTag_CLOSE
|
|
&& pTokArray[iCommentEnd].token.tokClass != tokTag)
|
|
{
|
|
// we have found something that looks like a comment to begin with, but its
|
|
// something else like a DTC, webbot stuff or some thing else...
|
|
iArray = iArraySav + 1; // not this one
|
|
goto LRet;
|
|
}
|
|
|
|
// write the spacing info, reallocate pwNew if needed
|
|
cchComment = pTokArray[iCommentStart+1].token.ibTokMac-pTokArray[iCommentStart+1].token.ibTokMin;
|
|
cbNeed = (ichNewCur+2*cchComment+wcslen(rgComment[0])+wcslen(rgComment[1])+(pTokArray[iCommentStart].token.ibTokMac-ichBeginCopy+2))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
// write till '<!--' part of the comment
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichBeginCopy],
|
|
(pTokArray[iCommentStart].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iCommentStart].token.ibTokMac-ichBeginCopy;
|
|
pwNew[ichNewCur++] = '-';
|
|
pwNew[ichNewCur++] = '-';
|
|
|
|
// write the spacing info keyword
|
|
memcpy((BYTE *)&pwNew[ichNewCur], (BYTE *)rgComment[0], wcslen(rgComment[0])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgComment[0]);
|
|
//write spacing block
|
|
ichSp = pTokArray[iCommentStart+1].token.ibTokMin+2; // exclude -- from <!--comment
|
|
while (ichSp < (int)(pTokArray[iCommentStart+1].token.ibTokMac-2))// exclude -- from comment-->
|
|
{
|
|
switch (pwOld[ichSp++])
|
|
{
|
|
case ' ':
|
|
pwNew[ichNewCur++] = chCommentSp;
|
|
break;
|
|
case '\t':
|
|
pwNew[ichNewCur++] = chCommentTab;
|
|
break;
|
|
case '\r':
|
|
pwNew[ichNewCur++] = chCommentEOL;
|
|
break;
|
|
case '\n':
|
|
break;
|
|
default:
|
|
if (pwNew[ichNewCur-1] != ',')
|
|
pwNew[ichNewCur++] = ',';
|
|
break;
|
|
} // switch()
|
|
}
|
|
|
|
// write the spacing info keyword
|
|
memcpy((BYTE *)&pwNew[ichNewCur], (BYTE *)rgComment[1], wcslen(rgComment[1])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgComment[1]);
|
|
|
|
//write spacing block for pre comment
|
|
// go back from pwOld[ichSp] and see where we have the last non-white space
|
|
ichSp = pTokArray[iCommentStart].token.ibTokMin-1;
|
|
while ( (ichSp >= 0)
|
|
&& ( pwOld[ichSp] == ' ' || pwOld[ichSp] == '\t'
|
|
|| pwOld[ichSp] == '\r' || pwOld[ichSp] == '\n'
|
|
)
|
|
)
|
|
{
|
|
ichSp--;
|
|
}
|
|
ichSp++; // compensate because ichSp points to non-white space character at this point
|
|
ASSERT(pTokArray[iCommentStart].token.ibTokMin >= (UINT)ichSp);
|
|
cbNeed = (ichNewCur+2*(pTokArray[iCommentStart].token.ibTokMin-ichSp)+wcslen(rgComment[2]))*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
while (ichSp < (int)(pTokArray[iCommentStart].token.ibTokMin))
|
|
{
|
|
switch (pwOld[ichSp++])
|
|
{
|
|
case ' ':
|
|
pwNew[ichNewCur++] = chCommentSp;
|
|
break;
|
|
case '\t':
|
|
pwNew[ichNewCur++] = chCommentTab;
|
|
break;
|
|
case '\r':
|
|
pwNew[ichNewCur++] = chCommentEOL;
|
|
break;
|
|
case '\n':
|
|
break;
|
|
default:
|
|
if (pwNew[ichNewCur-1] != ',')
|
|
pwNew[ichNewCur++] = ',';
|
|
break;
|
|
} // switch()
|
|
}
|
|
// write the spacing info keyword
|
|
memcpy((BYTE *)&pwNew[ichNewCur], (BYTE *)rgComment[2], wcslen(rgComment[2])*sizeof(WCHAR));
|
|
ichNewCur += wcslen(rgComment[2]);
|
|
|
|
// write the comment
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[pTokArray[iCommentStart+1].token.ibTokMin+2],
|
|
(pTokArray[iCommentStart+1].token.ibTokMac-pTokArray[iCommentStart+1].token.ibTokMin-2)*sizeof(WCHAR));
|
|
ichNewCur += pTokArray[iCommentStart+1].token.ibTokMac-pTokArray[iCommentStart+1].token.ibTokMin-2;
|
|
|
|
// write the ending '>'
|
|
pwNew[ichNewCur++] = '>'; // alternatively, we could write iCommentEnd'th token
|
|
|
|
// set iArray & ichBeginCopy
|
|
iArray = iCommentEnd+1;
|
|
ichBeginCopy = pTokArray[iCommentEnd].token.ibTokMac;
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
return;
|
|
|
|
} /* fnSaveComment() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreComment(CTriEditParse* /*ptep*/,
|
|
LPWSTR /*pwOld*/, LPWSTR* /*ppwNew*/, UINT* /*pcchNew*/, HGLOBAL* /*phgNew*/,
|
|
TOKSTRUCT* /*pTokArray*/, UINT* /*piArrayStart*/, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT* /*pichNewCur*/, UINT* /*pichBeginCopy*/,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
ASSERT(FALSE); // this case is handled by fnRestoreObject(), so we shouldn't reach here
|
|
return;
|
|
|
|
} /* fnRestoreComment() */
|
|
|
|
void
|
|
CTriEditParse::fnSaveTextArea(CTriEditParse *ptep, LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew, HGLOBAL *phgNew,
|
|
TOKSTRUCT *pTokArray, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT *pichNewCur, UINT *pichBeginCopy,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
|
|
UINT ichNewCur = *pichNewCur;
|
|
UINT ichBeginCopy = *pichBeginCopy;
|
|
UINT iArray = *piArrayStart;
|
|
LPWSTR pwNew = *ppwNew;
|
|
UINT iArraySav = iArray;
|
|
UINT cbNeed;
|
|
UINT iTextAreaEnd;
|
|
|
|
// look for TEXTAREA block and simply copy it into pwNew. Thereby avoiding the
|
|
// space preservation & stuff.
|
|
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_TEXTAREA);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
iTextAreaEnd = pTokArray[iArray].iNextprev;
|
|
if (iTextAreaEnd == -1) // we don't have matching </textarea>
|
|
{
|
|
// ignore this case
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// NOTE that we don't even need to get get the '<' before the textarea here because we are
|
|
// not doing anything special with them. We simply are going to copy everything inside the
|
|
// textarea to pwNew. So, we start copying from ichBeginCopy and copy till end of the
|
|
// textarea block.
|
|
|
|
// get the '>' after the matching end textarea, generally this will be right after iTextAreaEnd
|
|
while (iTextAreaEnd < (int)ptep->m_cMaxToken)
|
|
{
|
|
if ( (pTokArray[iTextAreaEnd].token.tok == TokTag_CLOSE) /* > */
|
|
&& (pTokArray[iTextAreaEnd].token.tokClass == tokTag)
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
iTextAreaEnd++;
|
|
}
|
|
if (iTextAreaEnd >= (int)ptep->m_cMaxToken) // error case
|
|
{
|
|
iArray = iArraySav + 1;
|
|
goto LRet;
|
|
}
|
|
|
|
// copy the textarea block into pwNew. Make sure that we have enough space in pwNew
|
|
// NOTE - pTokArray[iTextAreaEnd].token.ibTokMac should be larger than ichBeginCopy,
|
|
// but at this point in the game the assert is of no use, because no one is using
|
|
// debug builds (6/10/98)
|
|
if ((int) (pTokArray[iTextAreaEnd].token.ibTokMac-ichBeginCopy) > 0)
|
|
{
|
|
cbNeed = (ichNewCur+pTokArray[iTextAreaEnd].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR)+cbBufPadding;
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
goto LRet;
|
|
|
|
memcpy( (BYTE *)&pwNew[ichNewCur],
|
|
(BYTE *)&pwOld[ichBeginCopy],
|
|
(pTokArray[iTextAreaEnd].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[iTextAreaEnd].token.ibTokMac-ichBeginCopy);
|
|
}
|
|
|
|
// set iArray & ichBeginCopy
|
|
iArray = iTextAreaEnd+1;
|
|
ichBeginCopy = pTokArray[iTextAreaEnd].token.ibTokMac;
|
|
LRet:
|
|
*pcchNew = ichNewCur;
|
|
*ppwNew = pwNew;
|
|
|
|
*pichNewCur = ichNewCur;
|
|
*pichBeginCopy = ichBeginCopy;
|
|
*piArrayStart = iArray;
|
|
|
|
return;
|
|
|
|
} /* fnSaveTextArea() */
|
|
|
|
void
|
|
CTriEditParse::fnRestoreTextArea(CTriEditParse* /*ptep*/,
|
|
LPWSTR /*pwOld*/, LPWSTR* /*ppwNew*/, UINT* /*pcchNew*/, HGLOBAL* /*phgNew*/,
|
|
TOKSTRUCT* /*pTokArray*/, UINT *piArrayStart, FilterTok /*ft*/,
|
|
INT* /*pcHtml*/, UINT* /*pichNewCur*/, UINT* /*pichBeginCopy*/,
|
|
DWORD /*dwFlags*/)
|
|
{
|
|
UINT iArray = *piArrayStart;
|
|
|
|
// ideally, (for next version) we should restore the trident-converted >'s & stuff
|
|
// for now, we are simply going to ignore this tag on the way back from trident
|
|
// NOTE that we never put in designtimesp's in this block, so we souldn't have to look
|
|
// for them here.
|
|
|
|
ASSERT(pTokArray[iArray].token.tok == TokElem_TEXTAREA);
|
|
ASSERT(pTokArray[iArray].token.tokClass == tokElem);
|
|
|
|
iArray++; // skip this textarea tag
|
|
|
|
*piArrayStart = iArray;
|
|
return;
|
|
|
|
} /* fnRestoreTextArea() */
|
|
|
|
void
|
|
CTriEditParse::FilterHtml(LPWSTR pwOld, LPWSTR* ppwNew, UINT *pcchNew,
|
|
HGLOBAL *phgNew, TOKSTRUCT *pTokArray,
|
|
FilterMode mode, DWORD dwFlags)
|
|
{
|
|
UINT iArray = 0;
|
|
UINT ichNewCur = 0;
|
|
UINT ichBeginCopy = 0;
|
|
HRESULT hr;
|
|
INT index = 0;
|
|
INT iItem;
|
|
INT cItems = 0;
|
|
INT cRuleMid = cRuleMax / 2; // ASSUME that cRuleMax is an even number
|
|
|
|
FilterRule fr[cRuleMax] =
|
|
{
|
|
// make sure that modeInput and modeOutput have the matching entries.
|
|
// modeInput entries
|
|
{TokTag_BANG, TokAttrib_STARTSPAN, tokClsIgnore, TokTag_CLOSE, TokAttrib_ENDSPAN, tokClsIgnore, fnSaveDTC},
|
|
{TokTag_SSSOPEN, -1, tokClsIgnore, TokTag_SSSCLOSE, -1, tokClsIgnore, fnSaveSSS},
|
|
{TokTag_START, TokElem_HTML, tokClsIgnore, TokTag_CLOSE, TokElem_HTML, tokClsIgnore, fnSaveHtmlTag},
|
|
{-1, -1, tokEntity, -1, -1, tokEntity, fnSaveNBSP},
|
|
{-1, TokElem_BODY, tokElem, -1, -1, tokClsIgnore, fnSaveHdr},
|
|
{TokTag_END, TokElem_BODY, tokElem, -1, -1, tokClsIgnore, fnSaveFtr},
|
|
{-1, TokTag_START, tokTag, TokTag_CLOSE, -1, tokClsIgnore, fnSaveSpace},
|
|
{TokTag_START, TokElem_OBJECT, tokElem, TokTag_CLOSE, TokElem_OBJECT, tokElem, fnSaveObject},
|
|
{TokTag_START, TokElem_TBODY, tokElem, TokTag_CLOSE, -1, tokTag, fnSaveTbody},
|
|
{-1, TokElem_APPLET, tokElem, -1, -1, -1, fnSaveApplet},
|
|
{TokTag_START, TokElem_A, tokElem, TokTag_CLOSE, TokAttrib_HREF, tokTag, fnSaveAImgLink},
|
|
{-1, TokTag_BANG, tokTag, -1, -1, tokClsIgnore, fnSaveComment},
|
|
{TokTag_START, TokElem_TEXTAREA, tokElem, TokTag_CLOSE, TokElem_TEXTAREA, tokClsIgnore, fnSaveTextArea},
|
|
|
|
// modeOutput entries
|
|
{TokTag_START, TokElem_OBJECT, tokClsIgnore, TokTag_CLOSE, TokElem_OBJECT, tokClsIgnore, fnRestoreDTC},
|
|
{TokTag_START, TokElem_SCRIPT, tokClsIgnore, TokTag_CLOSE, TokElem_SCRIPT, tokClsIgnore, fnRestoreSSS},
|
|
{-1, -1, tokClsIgnore, -1, -1, tokClsIgnore, fnRestoreHtmlTag},
|
|
{-1, -1, tokEntity, -1, -1, tokEntity, fnRestoreNBSP},
|
|
{-1, TokElem_BODY, tokElem, -1, -1, tokClsIgnore, fnRestoreHdr},
|
|
{TokTag_END, TokElem_BODY, tokElem, -1, -1, tokClsIgnore, fnRestoreFtr},
|
|
{TokTag_START, TokTag_END, tokSpace, TokTag_CLOSE, -1, tokClsIgnore, fnRestoreSpace},
|
|
{-1, TokTag_BANG, tokTag, TokTag_CLOSE, -1, tokTag, fnRestoreObject},
|
|
{TokTag_START, TokElem_TBODY, tokElem, TokTag_CLOSE, -1, tokTag, fnRestoreTbody},
|
|
{TokTag_START, TokElem_APPLET, tokElem, TokTag_CLOSE, -1, tokTag, fnRestoreApplet},
|
|
{TokTag_START, TokElem_A, tokElem, TokTag_CLOSE, TokAttrib_HREF, tokTag, fnRestoreAImgLink},
|
|
{-1, TokTag_BANG, tokTag, TokTag_CLOSE, -1, tokTag, fnRestoreObject},
|
|
{TokTag_START, TokElem_TEXTAREA, tokElem, TokTag_CLOSE, TokElem_TEXTAREA, tokClsIgnore, fnRestoreTextArea},
|
|
};
|
|
|
|
memcpy(m_FilterRule, fr, sizeof(FilterRule)*cRuleMax);
|
|
ASSERT(pwOld != NULL);
|
|
ASSERT(*ppwNew != NULL);
|
|
|
|
if (mode == modeInput)
|
|
{
|
|
cItems = m_cDTC + m_cSSSIn + m_cHtml + m_cNbsp + m_cHdr + m_cFtr + m_cObjIn + m_ispInfoIn + m_cAppletIn + m_cAImgLink;
|
|
while (cItems > 0)
|
|
{
|
|
if (iArray >= m_cMaxToken) // this will catch error cases
|
|
break;
|
|
|
|
while (iArray < m_cMaxToken)
|
|
{
|
|
// its OK to enumerate the comparison rules, but once we have
|
|
// a lot of rules, this needs to be made into a function
|
|
if (pTokArray[iArray].token.tok == m_FilterRule[0].ft.tokBegin2 && m_cDTC > 0)
|
|
{
|
|
m_cDTC--;
|
|
iItem = 1;
|
|
index = 0;
|
|
break;
|
|
}
|
|
else if ( (m_FilterRule[1].ft.tokBegin2 != -1)
|
|
? (pTokArray[iArray].token.tok == m_FilterRule[1].ft.tokBegin2 && m_cSSSIn > 0)
|
|
: (pTokArray[iArray].token.tok == m_FilterRule[1].ft.tokBegin && m_cSSSIn > 0)
|
|
)
|
|
{
|
|
m_cSSSIn--;
|
|
iItem = 1;
|
|
index = 1;
|
|
break;
|
|
}
|
|
else if (pTokArray[iArray].token.tok == m_FilterRule[2].ft.tokBegin2 && m_cHtml > 0)
|
|
{
|
|
m_cHtml--;
|
|
iItem = 1;
|
|
index = 2;
|
|
break;
|
|
}
|
|
else if ( m_FilterRule[3].ft.tokBegin == -1
|
|
&& m_FilterRule[3].ft.tokBegin2 == -1
|
|
&& m_FilterRule[3].ft.tokClsBegin == pTokArray[iArray].token.tokClass
|
|
&& m_cNbsp > 0)
|
|
{
|
|
m_cNbsp--;
|
|
iItem = 1;
|
|
index = 3;
|
|
break;
|
|
}
|
|
else if (pTokArray[iArray].token.tok == m_FilterRule[4].ft.tokBegin2 && m_cHdr > 0)
|
|
{
|
|
m_cHdr--;
|
|
iItem = 1;
|
|
index = 4;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[5].ft.tokBegin2
|
|
&& pTokArray[iArray-1].token.tok == m_FilterRule[5].ft.tokBegin
|
|
&& m_cFtr > 0
|
|
)
|
|
{
|
|
m_cFtr--;
|
|
iItem = 1;
|
|
index = 5;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[6].ft.tokBegin2
|
|
&& m_FilterRule[6].ft.tokClsBegin == pTokArray[iArray].token.tokClass
|
|
&& m_ispInfoIn > 0
|
|
&& (dwFlags & dwPreserveSourceCode)
|
|
)
|
|
{
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
index = 6;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[7].ft.tokBegin2
|
|
&& pTokArray[iArray].token.tokClass == m_FilterRule[7].ft.tokClsBegin
|
|
&& pTokArray[iArray-1].token.tok == TokTag_START
|
|
&& pTokArray[iArray-1].token.tokClass == tokTag
|
|
&& m_cObjIn > 0
|
|
)
|
|
{
|
|
m_cObjIn--;
|
|
iItem = 1;
|
|
index = 7;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[8].ft.tokBegin2
|
|
&& pTokArray[iArray].token.tokClass == m_FilterRule[8].ft.tokClsBegin
|
|
&& pTokArray[iArray-1].token.tok == TokTag_START
|
|
&& pTokArray[iArray-1].token.tokClass == tokTag
|
|
&& (dwFlags & dwPreserveSourceCode)
|
|
)
|
|
{
|
|
cItems++; //to compensate for cItems-- after the pfn() call
|
|
iItem = 1;
|
|
index = 8;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[9].ft.tokBegin2
|
|
&& m_FilterRule[9].ft.tokClsBegin == pTokArray[iArray].token.tokClass
|
|
&& m_cAppletIn > 0
|
|
)
|
|
{
|
|
cItems++; //to compensate for cItems-- after the pfn() call
|
|
m_cAppletIn--;
|
|
index = 9;
|
|
break;
|
|
}
|
|
else if ( ( pTokArray[iArray].token.tok == m_FilterRule[10].ft.tokBegin2
|
|
|| pTokArray[iArray].token.tok == TokElem_IMG
|
|
|| pTokArray[iArray].token.tok == TokElem_LINK)
|
|
&& m_FilterRule[10].ft.tokClsBegin == pTokArray[iArray].token.tokClass
|
|
&& m_cAImgLink > 0
|
|
&& (pTokArray[iArray-1].token.tok == m_FilterRule[10].ft.tokBegin)
|
|
)
|
|
{
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
index = 10;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[11].ft.tokBegin2
|
|
&& m_FilterRule[11].ft.tokClsBegin == pTokArray[iArray].token.tokClass
|
|
)
|
|
{
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
index = 11;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[12].ft.tokBegin2
|
|
&& m_FilterRule[12].ft.tokClsBegin == pTokArray[iArray].token.tokClass
|
|
&& pTokArray[iArray-1].token.tok == m_FilterRule[12].ft.tokBegin
|
|
&& pTokArray[iArray-1].token.tokClass == tokTag
|
|
)
|
|
{
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
index = 12;
|
|
break;
|
|
}
|
|
|
|
iArray++;
|
|
}
|
|
if (iArray < m_cMaxToken) // we found a match
|
|
{
|
|
// call that function
|
|
m_FilterRule[index].pfn( this, pwOld, ppwNew, pcchNew, phgNew, pTokArray,
|
|
&iArray, m_FilterRule[index].ft, &iItem,
|
|
&ichNewCur, &ichBeginCopy,
|
|
dwFlags);
|
|
}
|
|
|
|
cItems--;
|
|
} // while (cItems > 0)
|
|
}
|
|
else if (mode == modeOutput)
|
|
{
|
|
cItems = m_cObj + m_cSSSOut + m_cHtml + m_cNbsp + m_cHdr + m_cFtr + m_cComment + m_ispInfoOut + m_cAppletOut + m_cAImgLink;
|
|
while (cItems > 0)
|
|
{
|
|
if (iArray >= m_cMaxToken) // this will catch error cases
|
|
break;
|
|
|
|
while (iArray < m_cMaxToken)
|
|
{
|
|
// its OK to enumerate the comparison rules, but once we have
|
|
// a lot of rules, this needs to be made into a function
|
|
if ( pTokArray[iArray].token.tok == m_FilterRule[cRuleMid].ft.tokBegin2
|
|
&& pTokArray[iArray-1].token.tok == TokTag_START
|
|
&& m_cObj > 0
|
|
)
|
|
{
|
|
m_cObj--;
|
|
index = cRuleMid;
|
|
iItem = m_iControl;
|
|
break;
|
|
}
|
|
else if (pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+1].ft.tokBegin2 && m_cSSSOut > 0)
|
|
{
|
|
m_cSSSOut--;
|
|
iItem = 1;
|
|
index = cRuleMid+1;
|
|
break;
|
|
}
|
|
else if (pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+2].ft.tokBegin2 && m_cHtml > 0)
|
|
{
|
|
m_cHtml--;
|
|
iItem = 1;
|
|
index = cRuleMid+2;
|
|
break;
|
|
}
|
|
else if ( m_FilterRule[cRuleMid+3].ft.tokBegin == -1
|
|
&& m_FilterRule[cRuleMid+3].ft.tokBegin2 == -1
|
|
&& m_FilterRule[cRuleMid+3].ft.tokClsBegin == tokEntity
|
|
&& m_cNbsp > 0)
|
|
{
|
|
m_cNbsp--;
|
|
iItem = 1;
|
|
index = cRuleMid+3;
|
|
break;
|
|
}
|
|
else if (pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+4].ft.tokBegin2 && m_cHdr > 0)
|
|
{
|
|
m_cHdr--;
|
|
iItem = 1;
|
|
index = cRuleMid+4;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+5].ft.tokBegin2
|
|
&& pTokArray[iArray-1].token.tok == m_FilterRule[cRuleMid+5].ft.tokBegin
|
|
&& m_cFtr > 0)
|
|
{
|
|
m_cFtr--;
|
|
iItem = 1;
|
|
index = cRuleMid+5;
|
|
break;
|
|
}
|
|
else if ( ( pTokArray[iArray].token.tokClass == m_FilterRule[cRuleMid+6].ft.tokClsBegin
|
|
|| ( pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+6].ft.tokBegin2
|
|
&& pTokArray[iArray].token.tokClass == tokTag
|
|
)
|
|
)
|
|
&& (dwFlags & dwPreserveSourceCode)
|
|
)
|
|
{
|
|
index = cRuleMid+6;
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+7].ft.tokBegin2
|
|
&& pTokArray[iArray].token.tokClass == m_FilterRule[cRuleMid+7].ft.tokClsBegin
|
|
&& m_cComment > 0
|
|
)
|
|
{
|
|
m_cComment--;
|
|
iItem = 1;
|
|
index = cRuleMid+7;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+8].ft.tokBegin2
|
|
&& pTokArray[iArray].token.tokClass == m_FilterRule[cRuleMid+8].ft.tokClsBegin
|
|
&& (dwFlags & dwPreserveSourceCode)
|
|
)
|
|
{
|
|
// Note that TBody filtering is tied in with space preservation.
|
|
// In ideal world it shouldn't be, but thats acceptable to the most.
|
|
// If this view changes, we need to add some other designtime attribute
|
|
// along with spacing attributes. This will be somewhat big change than
|
|
// simply adding an attribute because then we need to change the code to
|
|
// start going backwards in the token array in the main loop.
|
|
iItem = 1;
|
|
index = cRuleMid+8;
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+9].ft.tokBegin2
|
|
&& pTokArray[iArray].token.tokClass == m_FilterRule[cRuleMid+9].ft.tokClsBegin
|
|
&& pTokArray[iArray-1].token.tok == m_FilterRule[cRuleMid+9].ft.tokBegin
|
|
&& m_cAppletOut > 0
|
|
)
|
|
{
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
m_cAppletOut--;
|
|
index = cRuleMid+9;
|
|
break;
|
|
}
|
|
else if ( ( pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+10].ft.tokBegin2
|
|
|| pTokArray[iArray].token.tok == TokElem_IMG
|
|
|| pTokArray[iArray].token.tok == TokElem_LINK)
|
|
&& m_FilterRule[cRuleMid+10].ft.tokClsBegin == pTokArray[iArray].token.tokClass
|
|
&& m_cAImgLink > 0
|
|
&& (pTokArray[iArray-1].token.tok == m_FilterRule[cRuleMid+10].ft.tokBegin)
|
|
)
|
|
{
|
|
index = cRuleMid+10;
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+11].ft.tokBegin2
|
|
&& pTokArray[iArray].token.tokClass == m_FilterRule[cRuleMid+11].ft.tokClsBegin
|
|
)
|
|
{
|
|
// actually, we won't reach here - just a dummy
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
index = cRuleMid+11;
|
|
break;
|
|
}
|
|
else if ( pTokArray[iArray].token.tok == m_FilterRule[cRuleMid+12].ft.tokBegin2
|
|
&& m_FilterRule[cRuleMid+12].ft.tokClsBegin == pTokArray[iArray].token.tokClass
|
|
&& pTokArray[iArray-1].token.tok == m_FilterRule[cRuleMid+12].ft.tokBegin
|
|
&& pTokArray[iArray-1].token.tokClass == tokTag
|
|
)
|
|
{
|
|
cItems++; // to compensate for cItems-- after the pfn() call
|
|
index = cRuleMid+12;
|
|
break;
|
|
}
|
|
|
|
|
|
iArray++;
|
|
}
|
|
if (iArray < m_cMaxToken) // we found a match
|
|
{
|
|
// call that function
|
|
m_FilterRule[index].pfn( this, pwOld, ppwNew, pcchNew, phgNew, pTokArray,
|
|
&iArray, m_FilterRule[index].ft, &iItem,
|
|
&ichNewCur, &ichBeginCopy,
|
|
dwFlags);
|
|
}
|
|
|
|
if (m_fDontDeccItem) // we can do things differently next time
|
|
{
|
|
m_fDontDeccItem = FALSE;
|
|
cItems++;
|
|
}
|
|
cItems--;
|
|
} // while (cItems > 0)
|
|
}
|
|
else
|
|
ASSERT(FALSE);
|
|
|
|
|
|
if (cItems == 0) // everything ok, copy rest of the doc
|
|
{
|
|
LIncorrectcItems:
|
|
// copy rest of the stuff into pwNew
|
|
/* REALLOCATE pwNew IF NEEDED here use cache value for GlobalSize(*phgNew) and don't forget to update it too */
|
|
if (GlobalSize(*phgNew) < (ichNewCur+pTokArray[m_cMaxToken-1].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR))
|
|
{
|
|
hr = ReallocBuffer( phgNew,
|
|
(ichNewCur+pTokArray[m_cMaxToken-1].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR),
|
|
GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
if (hr == E_OUTOFMEMORY)
|
|
goto LCopyAndRet;
|
|
ASSERT(*phgNew != NULL);
|
|
*ppwNew = (WCHAR *)GlobalLock(*phgNew);
|
|
}
|
|
memcpy( (BYTE *)(*ppwNew+ichNewCur),
|
|
(BYTE *)(pwOld+ichBeginCopy),
|
|
(pTokArray[m_cMaxToken-1].token.ibTokMac-ichBeginCopy)*sizeof(WCHAR));
|
|
ichNewCur += (pTokArray[m_cMaxToken-1].token.ibTokMac-ichBeginCopy);
|
|
*pcchNew = ichNewCur;
|
|
}
|
|
else
|
|
{
|
|
// this means that we calculated one of m_c's incorrectly. We need to fix that
|
|
// case in M4
|
|
goto LIncorrectcItems;
|
|
|
|
LCopyAndRet:
|
|
memcpy( (BYTE *)*ppwNew,
|
|
(BYTE *)pwOld,
|
|
(pTokArray[m_cMaxToken-1].token.ibTokMac)*sizeof(WCHAR));
|
|
*pcchNew = pTokArray[m_cMaxToken-1].token.ibTokMac;
|
|
}
|
|
|
|
} /* CTriEditParse::FilterHtml() */
|
|
|
|
int
|
|
CTriEditParse::ValidateTag(LPWSTR pszText)
|
|
{
|
|
int len = 0;
|
|
|
|
if (pszText == NULL)
|
|
return(0);
|
|
// check for the first non Alpha in the pszText and return it. Add '\0' at the end
|
|
while ( (*(pszText+len) >= _T('A') && *(pszText+len) <= _T('Z'))
|
|
|| (*(pszText+len) >= _T('a') && *(pszText+len) <= _T('z'))
|
|
|| (*(pszText+len) >= _T('0') && *(pszText+len) <= _T('9'))
|
|
)
|
|
{
|
|
len++;
|
|
}
|
|
|
|
return(len);
|
|
}
|
|
|
|
INT
|
|
CTriEditParse::GetTagID(LPWSTR pszText, TXTB token)
|
|
{
|
|
WCHAR szTag[MAX_TOKIDLEN+1];
|
|
int len;
|
|
int tagID;
|
|
|
|
len = ValidateTag(pszText+token.ibTokMin);
|
|
if (len == 0 || len != (int)(token.ibTokMac-token.ibTokMin))
|
|
tagID = -1;
|
|
else
|
|
{
|
|
if (token.tok == 0 && token.tokClass == tokIDENTIFIER)
|
|
tagID = -1;
|
|
else
|
|
{
|
|
memcpy((BYTE *)szTag, (BYTE *)(pszText+token.ibTokMin), (min(len, MAX_TOKIDLEN))*sizeof(WCHAR));
|
|
szTag[min(len, MAX_TOKIDLEN)] = '\0';
|
|
tagID = IndexFromElementName((LPCTSTR) szTag);
|
|
}
|
|
}
|
|
return(tagID);
|
|
}
|
|
void
|
|
CTriEditParse::PreProcessToken(TOKSTRUCT *pTokArray, INT *pitokCur, LPWSTR /*pszText*/,
|
|
UINT /*cbCur*/, TXTB token, DWORD lxs, INT tagID, FilterMode mode)
|
|
{
|
|
TOKSTRUCT *pTokT = pTokArray + *pitokCur;
|
|
|
|
if (*pitokCur == -1) // the buffer reallocation must have failed
|
|
goto LSkipArrayOp;
|
|
|
|
// if (lxs & inTag) then we can ASSERT(token.tok == TokTag_START)
|
|
//put the new token into pTokArray at *pitokCur position
|
|
pTokT->token = token;
|
|
pTokT->fStart = (lxs & inEndTag)?FALSE:TRUE;
|
|
pTokT->ichStart = token.ibTokMin;
|
|
pTokT->iNextprev = 0xFFFFFFFF; // init value
|
|
pTokT->iNextPrevAlternate = 0xFFFFFFFF; // init value
|
|
pTokT->tagID = tagID;
|
|
|
|
if (mode == modeInput)
|
|
{
|
|
if ( pTokT->token.tok == TokTag_SSSOPEN
|
|
&& pTokT->token.tokClass == tokSSS
|
|
&& ((lxs & inSCRIPT) || (lxs & inAttribute))
|
|
)
|
|
{
|
|
pTokT->token.tok = TokTag_SSSOPEN_TRIEDIT;
|
|
}
|
|
if ( pTokT->token.tok == TokTag_SSSCLOSE
|
|
&& pTokT->token.tokClass == tokSSS
|
|
&& ((lxs & inSCRIPT) || (lxs & inAttribute))
|
|
)
|
|
{
|
|
pTokT->token.tok = TokTag_SSSCLOSE_TRIEDIT;
|
|
}
|
|
}
|
|
|
|
*pitokCur += 1;
|
|
|
|
LSkipArrayOp:
|
|
return;
|
|
|
|
} /* CTriEditParse::PreProcessToken() */
|
|
|
|
|
|
// Handle special cases of replacing things and saving the replaced contents
|
|
void
|
|
CTriEditParse::PostProcessToken(OLECHAR* /*pwOld*/, OLECHAR* /*pwNew*/, UINT* /*pcbNew*/,
|
|
UINT /*cbCur*/, UINT /*cbCurSav*/, TXTB token,
|
|
FilterMode mode, DWORD lxs, DWORD dwFlags)
|
|
{
|
|
// handle special cases of replacing the DTCs, ServerSideScripts etc.
|
|
// save the contents into a buffer if (mode == modeInput)
|
|
// put the contents back into buffer if (mode == modeOutput)
|
|
|
|
if (mode == modeInput)
|
|
{
|
|
if ( token.tok == TokAttrib_ENDSPAN
|
|
&& token.tokClass == tokAttr
|
|
&& (dwFlags & (dwFilterDTCs | dwFilterDTCsWithoutMetaTags))
|
|
)
|
|
{
|
|
m_cDTC++;
|
|
}
|
|
if ( token.tok == TokTag_SSSCLOSE
|
|
&& token.tokClass == tokSSS
|
|
&& !(lxs & inAttribute) // !(lxs & inValue && lxs & inTag)
|
|
&& !(lxs & inSCRIPT)
|
|
&& (dwFlags & dwFilterServerSideScripts)
|
|
)
|
|
{
|
|
m_cSSSIn++;
|
|
}
|
|
if ( token.tokClass == tokEntity
|
|
&& dwFlags != dwFilterNone
|
|
)
|
|
{
|
|
m_cNbsp++;
|
|
}
|
|
if ( (token.tok == TokElem_OBJECT)
|
|
&& (token.tokClass == tokElem)
|
|
&& (lxs & inEndTag)
|
|
&& (dwFlags != dwFilterNone)
|
|
)
|
|
{
|
|
m_cObjIn++;
|
|
}
|
|
if ( token.tok == TokElem_APPLET
|
|
&& token.tokClass == tokElem
|
|
&& (lxs & inEndTag)
|
|
&& (dwFlags != dwFilterNone)
|
|
)
|
|
{
|
|
m_cAppletIn++;
|
|
}
|
|
}
|
|
else if (mode == modeOutput)
|
|
{
|
|
if ( token.tok == TokElem_OBJECT
|
|
&& token.tokClass == tokElem
|
|
&& (lxs & inTag && !(lxs & inEndTag))
|
|
&& (dwFlags & (dwFilterDTCs | dwFilterDTCsWithoutMetaTags))
|
|
)
|
|
{
|
|
m_cObj++;
|
|
}
|
|
if ( token.tok == TokElem_SCRIPT
|
|
&& token.tokClass == tokElem
|
|
&& (lxs & inEndTag)
|
|
&& (dwFlags & dwFilterServerSideScripts)
|
|
)
|
|
{
|
|
m_cSSSOut++;
|
|
}
|
|
if ( token.tok == TokTag_BANG
|
|
&& token.tokClass == tokTag
|
|
)
|
|
{
|
|
m_cComment++;
|
|
}
|
|
if ( token.tok == TokElem_APPLET
|
|
&& token.tokClass == tokElem
|
|
&& (lxs & inEndTag)
|
|
&& (dwFlags != dwFilterNone)
|
|
)
|
|
{
|
|
m_cAppletOut++;
|
|
}
|
|
}
|
|
|
|
} /* CTriEditParse::PostProcessToken() */
|
|
|
|
HRESULT
|
|
CTriEditParse::ProcessToken(DWORD &lxs, TXTB &tok, LPWSTR pszText,
|
|
UINT /*cbCur*/, TOKSTACK *pTokStack, INT *pitokTop,
|
|
TOKSTRUCT *pTokArray, INT iArrayPos, INT tagID)
|
|
{
|
|
TXTB token = tok;
|
|
|
|
if (*pitokTop == -1) // the buffer reallocation must have failed
|
|
goto LSkipStackOp;
|
|
|
|
if (lxs & inEndTag) // end tag begins, set m_fEndTagFound
|
|
m_fEndTagFound = TRUE;
|
|
|
|
if (tagID == -1) // we need to put only the IDENTIFIERS on the stack
|
|
{
|
|
// special cases (1)<%, (2)%>, (3)startspan, (4)endspan
|
|
if (token.tok == TokTag_SSSOPEN && token.tokClass == tokSSS /*&& !(lxs & inAttribute)*/) // <%
|
|
{
|
|
token.tok = TokTag_SSSCLOSE; // fake it so that we can use the same code for matching %>
|
|
goto LSpecialCase;
|
|
}
|
|
else if (token.tok == TokTag_SSSCLOSE && token.tokClass == tokSSS /*&& !(lxs & inAttribute)*/) // %>
|
|
{
|
|
m_fEndTagFound = TRUE; // lxs is not inEndTag when we get TokTag_SSSCLOSE
|
|
goto LSpecialCase;
|
|
}
|
|
else if (token.tok == TokAttrib_STARTSPAN && token.tokClass == tokAttr) // startspan
|
|
{
|
|
token.tok = TokAttrib_ENDSPAN; // fake it so that we can use the same code for matching endspan
|
|
goto LSpecialCase;
|
|
}
|
|
else if (token.tok == TokAttrib_ENDSPAN && token.tokClass == tokAttr) // endspan
|
|
{
|
|
LPCWSTR szDesignerControl[] =
|
|
{
|
|
L"\"DesignerControl\"",
|
|
L"DesignerControl",
|
|
};
|
|
|
|
// HACK to fix FrontPage BUG - DaVinci puts a dummy endspan & startspan between
|
|
// the "DESIGNERCONTROL" startspan-endspan pair. We want to make sure that
|
|
// our pTokArray has correct matching iNextprev for the TokAttrib_STARTSPAN
|
|
// Refer VID bug 3991
|
|
if ( (iArrayPos-3 >= 0) /* validation */
|
|
&& ( 0 == _wcsnicmp(szDesignerControl[0], &pszText[pTokArray[iArrayPos-3].token.ibTokMin], wcslen(szDesignerControl[0]))
|
|
|| 0 == _wcsnicmp(szDesignerControl[1], &pszText[pTokArray[iArrayPos-3].token.ibTokMin], wcslen(szDesignerControl[1]))
|
|
)
|
|
)
|
|
{
|
|
m_fEndTagFound = TRUE; // lxs is not inEndTag when we get TokAttrib_ENDSPAN
|
|
goto LSpecialCase;
|
|
}
|
|
else
|
|
goto LSkipStackOp;
|
|
}
|
|
else
|
|
{
|
|
if (m_fEndTagFound)
|
|
m_fEndTagFound = FALSE;
|
|
goto LSkipStackOp;
|
|
}
|
|
}
|
|
|
|
LSpecialCase:
|
|
if (m_fEndTagFound) // end tag was found previously, means pop from the stack
|
|
{
|
|
TOKSTACK *pTokT;
|
|
|
|
if (*pitokTop == 0) // we don't have anything on stack, we can't delete it
|
|
goto LSkipStackOp;
|
|
|
|
pTokT = pTokStack + *pitokTop - 1;
|
|
m_fEndTagFound = FALSE; // reset
|
|
|
|
// if we get an end tag, in ideal case, the top of the stack should
|
|
// match with what we got
|
|
if (tagID == pTokT->tagID)
|
|
{
|
|
if (tagID == -1) // special case, match token.tok & token.tokClass
|
|
{
|
|
if ( (pTokT->token.tok == TokTag_SSSCLOSE) /* faked token for <% */
|
|
&& (pTokT->token.tokClass == tokSSS)
|
|
)
|
|
{
|
|
ASSERT(token.tok == TokTag_SSSCLOSE);
|
|
goto LMatch;
|
|
}
|
|
else if ( (pTokT->token.tok == TokAttrib_ENDSPAN) /* faked token for startspan */
|
|
&& (pTokT->token.tokClass == tokAttr)
|
|
)
|
|
{
|
|
ASSERT(token.tok == TokAttrib_ENDSPAN);
|
|
goto LMatch;
|
|
}
|
|
else // we may have found another special case
|
|
{
|
|
goto LNoMatch;
|
|
}
|
|
}
|
|
LMatch:
|
|
ASSERT(iArrayPos - 1 >= 0);
|
|
// put iNextPrev or INextPrevAlternate for the matching start token in pTokArray
|
|
pTokArray[pTokT->iMatch].iNextprev = iArrayPos - 1;
|
|
ASSERT(pTokArray[pTokT->iMatch].fStart == TRUE);
|
|
ASSERT(pTokT->ichStart == pTokArray[pTokT->iMatch].token.ibTokMin);
|
|
pTokArray[iArrayPos-1].iNextprev = pTokT->iMatch;
|
|
|
|
ASSERT(*pitokTop >= 0);
|
|
*pitokTop -= 1; // pop the stack
|
|
}
|
|
else
|
|
{
|
|
LNoMatch:
|
|
int index;
|
|
|
|
// look for the first entry down the array that matches
|
|
index = *pitokTop - 1;
|
|
while (index >= 0)
|
|
{
|
|
if (tagID == (pTokStack+index)->tagID)
|
|
{
|
|
if (tagID == -1) // special case
|
|
{
|
|
if ( ( ((pTokStack+index)->token.tok == TokTag_SSSCLOSE) /* faked token for <% */
|
|
&& ((pTokStack+index)->token.tokClass == tokSSS)
|
|
&& (token.tok == TokTag_SSSCLOSE)
|
|
&& (token.tokClass == tokSSS)
|
|
)
|
|
|| ( ((pTokStack+index)->token.tok == TokAttrib_ENDSPAN) /* faked token for startspan */
|
|
&& ((pTokStack+index)->token.tokClass == tokAttr)
|
|
&& (token.tok == TokAttrib_ENDSPAN)
|
|
&& (token.tokClass == tokAttr)
|
|
)
|
|
)
|
|
break;
|
|
//else actually, this means error case.
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
index--;
|
|
}
|
|
|
|
if (index != -1) // match was found at index'th position on the stack
|
|
{
|
|
int i;
|
|
TOKSTACK *pTokIndex = pTokStack + index;
|
|
|
|
ASSERT(index >= 0);
|
|
ASSERT(iArrayPos - 1 >= 0);
|
|
|
|
if (tagID == -1) // special case, match token.tok & token.tokClass
|
|
{
|
|
ASSERT( ( (pTokIndex->token.tok == TokTag_SSSCLOSE) /* faked token for <% */
|
|
&& (pTokIndex->token.tokClass == tokSSS)
|
|
&& (token.tok == TokTag_SSSCLOSE)
|
|
&& (token.tokClass == tokSSS)
|
|
)
|
|
|| ( ((pTokStack+index)->token.tok == TokAttrib_ENDSPAN) /* faked token for startspan */
|
|
&& ((pTokStack+index)->token.tokClass == tokAttr)
|
|
&& (token.tok == TokAttrib_ENDSPAN)
|
|
&& (token.tokClass == tokAttr)
|
|
)
|
|
);
|
|
}
|
|
// first of all fill in appropriate iNextprev
|
|
pTokArray[pTokIndex->iMatch].iNextprev = iArrayPos - 1;
|
|
ASSERT(pTokArray[pTokIndex->iMatch].fStart == TRUE);
|
|
pTokArray[iArrayPos-1].iNextprev = pTokIndex->iMatch;
|
|
|
|
// now fill in iNextPrevAlternate for all elements from index to *pitokTop - 1
|
|
for (i = index+1; i <= *pitokTop - 1; i++)
|
|
{
|
|
TOKSTACK *pTokSkip = pTokStack + i;
|
|
|
|
pTokArray[pTokSkip->iMatch].iNextPrevAlternate = iArrayPos - 1;
|
|
ASSERT(pTokArray[pTokSkip->iMatch].fStart == TRUE);
|
|
ASSERT(pTokArray[pTokSkip->iMatch].iNextprev == -1);
|
|
} // for ()
|
|
// decrement the stack appropriately
|
|
*pitokTop = index;
|
|
} // else
|
|
|
|
} // of if (tagID == pTokT->tagID)
|
|
} // end of if (lxs & inEndTag)
|
|
else // push the token info on the stack
|
|
{
|
|
TOKSTACK *pTokT = pTokStack + *pitokTop;
|
|
|
|
ASSERT(iArrayPos - 1 >= 0);
|
|
//push the new token into pTokArray at *pitokCur position
|
|
pTokT->iMatch = iArrayPos - 1;
|
|
pTokT->tagID = tagID;
|
|
pTokT->ichStart = token.ibTokMin;
|
|
pTokT->token = token; // note that this isused ONLY in special cases where tagID is -1
|
|
|
|
*pitokTop += 1;
|
|
} //end of else case of if (lxs & inEndTag)
|
|
|
|
LSkipStackOp:
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
// This function does following
|
|
// (a) reads the stream
|
|
// (b) generates tokens
|
|
// (c) allocates a buffer that holds replaced elements like DTCs
|
|
// (d) does the parsing of the tokens to build a not-so-tree tree of tokens
|
|
// (e) returns the not-so-tree tree of tokens
|
|
// VK 5/19/99: Replaced dwReserved with dwSpecialize.
|
|
// This can currently take PARSE_SPECIAL_HEAD_ONLY to terminate parsing at the <BODY>
|
|
HRESULT CTriEditParse::hrTokenizeAndParse(HGLOBAL hOld, HGLOBAL *phNew, IStream *pStmNew,
|
|
DWORD dwFlags, FilterMode mode,
|
|
int cbSizeIn, UINT *pcbSizeOut, IUnknown *pUnkTrident,
|
|
HGLOBAL *phgTokArray, UINT *pcMaxToken,
|
|
HGLOBAL *phgDocRestore, BSTR bstrBaseURL, DWORD dwSpecialize)
|
|
{
|
|
// FilterRule structure initilization - move this at apporpriate place
|
|
LPSTR pOld, pNew;
|
|
UINT cbOld = 0;
|
|
UINT cbwOld, cchwOld; // number of bytes & chars in the converted unicode string
|
|
UINT cchNew = 0; // number of unicode chars in the new (after filtering) buffer
|
|
HRESULT hrRet = S_OK;
|
|
HGLOBAL hgNew, hgOld, hgTokStack;
|
|
WCHAR *pwOld, *pwNew;
|
|
UINT cbCur = 0; // This is actually the current character position
|
|
TOKSTRUCT *pTokArray;
|
|
TOKSTACK *pTokStack;
|
|
INT itokTop = 0;
|
|
INT itokCur = 0;
|
|
TXTB token;
|
|
INT cStackMax, cArrayMax;
|
|
DWORD lxs = 0;
|
|
INT tagID;
|
|
BOOL fAllocDocRestore = FALSE; // did we allocate *phgDocRestore locally? (Y/N)
|
|
BOOL fUsePstmNew = (dwFlags & dwFilterUsePstmNew);
|
|
HGLOBAL hgPstm = NULL;
|
|
ULARGE_INTEGER li;
|
|
UINT cbT = 0;
|
|
BOOL fBeginTokSelect; // used by special case code that detects server side scripts inside a SELECT block
|
|
BOOL fBeginTokTextarea; // used by special case code that detects server side scripts inside a TEXTAREA block
|
|
BOOL fBeginTokLabel; // used by special case code that detects server side scripts inside a LABEL block
|
|
BOOL fBeginTokListing; // used by special case code that detects server side scripts inside a LISTING block
|
|
BOOL fInDTCOutput, fInDTC;
|
|
|
|
#ifdef DEBUG
|
|
DWORD dwErr;
|
|
#endif // DEBUG
|
|
|
|
ASSERT((PARSE_SPECIAL_NONE == dwSpecialize) || (PARSE_SPECIAL_HEAD_ONLY == dwSpecialize));
|
|
|
|
if ( PARSE_SPECIAL_HEAD_ONLY & dwSpecialize )
|
|
ASSERT ( dwFlags == dwFilterNone );
|
|
|
|
// NOTE
|
|
// this could be done another way. We can make m_pUnkTrident public member and set its value
|
|
// at the point where the CTriEditParse object is created. But this looks fine too.
|
|
m_pUnkTrident = pUnkTrident; // we cache this for our use.
|
|
m_fUnicodeFile = FALSE;
|
|
m_bstrBaseURL = bstrBaseURL;
|
|
li.LowPart = li.HighPart = 0;
|
|
// Initialize PTDTC related members
|
|
if (mode == modeInput)
|
|
{
|
|
m_fInHdrIn = TRUE;
|
|
}
|
|
|
|
if (fUsePstmNew)
|
|
li.LowPart = li.HighPart = 0;
|
|
|
|
// initialize <TBODY> related members
|
|
m_hgTBodyStack = NULL;
|
|
m_pTBodyStack = NULL;
|
|
m_iMaxTBody = m_iTBodyMax = 0;
|
|
|
|
// initilize members used by PageTransitionDTC
|
|
if (mode == modeInput)
|
|
{
|
|
m_ichPTDTC = m_cchPTDTCObj = m_cchPTDTC = 0;
|
|
m_indexBeginBody = m_indexEndBody = 0;
|
|
m_hgPTDTC = m_pPTDTC = NULL;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(m_hgPTDTC == NULL); // make sure that it was freed (if we allocated it in modeInput case)
|
|
}
|
|
|
|
if (mode == modeInput)
|
|
{
|
|
m_fHasTitleIn = FALSE;
|
|
m_indexTitleIn = -1;
|
|
m_ichTitleIn = -1;
|
|
m_cchTitleIn = -1;
|
|
m_ichBeginBodyTagIn = -1;
|
|
m_ichBeginHeadTagIn = -1;
|
|
m_indexHttpEquivIn = -1;
|
|
}
|
|
//initilize fBeginTokSelect (used by special case code that
|
|
// detects server side scripts inside a SELECT block)
|
|
fBeginTokSelect = fBeginTokTextarea = fBeginTokLabel = fBeginTokListing = FALSE;
|
|
fInDTCOutput = fInDTC = FALSE;
|
|
|
|
pOld = (LPSTR) GlobalLock(hOld);
|
|
if (cbSizeIn == -1)
|
|
cbOld = SAFE_INT64_TO_DWORD(GlobalSize(hOld));
|
|
else
|
|
cbOld = cbSizeIn;
|
|
if (cbOld == 0) // zero sized file
|
|
{
|
|
if (pcbSizeOut)
|
|
*pcbSizeOut = 0;
|
|
hrRet = E_OUTOFMEMORY;
|
|
*pcMaxToken = 0;
|
|
if (fUsePstmNew)
|
|
pStmNew->SetSize(li);
|
|
else
|
|
*phNew = NULL;
|
|
*phgTokArray = NULL;
|
|
goto LRetOnly;
|
|
}
|
|
hgNew = hgOld = hgTokStack = NULL;
|
|
if (*((BYTE *)pOld) == 0xff && *((BYTE *)pOld+1) == 0xfe)
|
|
{
|
|
m_fUnicodeFile = TRUE;
|
|
if (dwFlags & dwFilterMultiByteStream)
|
|
dwFlags &= ~dwFilterMultiByteStream;
|
|
}
|
|
|
|
// allocate a buffer that will hold token structs. This is returned
|
|
*phgTokArray = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, MIN_TOK*sizeof(TOKSTRUCT)); // stack
|
|
if (*phgTokArray == NULL)
|
|
{
|
|
hrRet = E_OUTOFMEMORY;
|
|
goto LOOM;
|
|
}
|
|
pTokArray = (TOKSTRUCT *) GlobalLock(*phgTokArray);
|
|
ASSERT(pTokArray != NULL);
|
|
cArrayMax = MIN_TOK;
|
|
|
|
// allocate temporary buffers that for the current & filtered html documents
|
|
hgTokStack = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, MIN_TOK*sizeof(TOKSTRUCT)); // stack
|
|
if (hgTokStack == NULL)
|
|
{
|
|
hrRet = E_OUTOFMEMORY;
|
|
goto LOOM;
|
|
}
|
|
pTokStack = (TOKSTACK *) GlobalLock(hgTokStack);
|
|
ASSERT(pTokStack != NULL);
|
|
cStackMax = MIN_TOK;
|
|
|
|
// In most cases for NON-UNICODE streams,
|
|
// (cbOld+1/*for NULL*/)*sizeof(WCHAR) will endup being lot more than what we need
|
|
hgOld = GlobalAlloc(GMEM_ZEROINIT, (dwFlags & dwFilterMultiByteStream)
|
|
? (cbOld+1/*for NULL*/)*sizeof(WCHAR)
|
|
: (cbOld+2/*for NULL*/));
|
|
if (hgOld == NULL)
|
|
{
|
|
hrRet = E_OUTOFMEMORY;
|
|
goto LOOM;
|
|
}
|
|
pwOld = (WCHAR *) GlobalLock(hgOld);
|
|
ASSERT(pwOld != NULL);
|
|
|
|
// we could just allocate cbOld bytes in modeInput and modeOutput.
|
|
// But reallocs are expensive and in both cases, we will grow by some bytes
|
|
// if we have DTCs and/or SSSs.
|
|
if (dwFlags & dwFilterNone) // the caller has called this function only for tokenizing
|
|
{
|
|
if (dwFlags & dwFilterMultiByteStream)
|
|
cbT = (cbOld+1/*for NULL*/)*sizeof(WCHAR); // this will be bigger than what we need.
|
|
else
|
|
cbT = cbOld + sizeof(WCHAR); // for NULL
|
|
}
|
|
else
|
|
{
|
|
if (dwFlags & dwFilterMultiByteStream)
|
|
cbT = (cbOld+1)*sizeof(WCHAR) + cbBufPadding;
|
|
else
|
|
cbT = cbOld + cbBufPadding; // no need to add +2
|
|
}
|
|
hgNew = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, cbT);
|
|
if (hgNew == NULL)
|
|
{
|
|
hrRet = E_OUTOFMEMORY;
|
|
goto LOOM;
|
|
}
|
|
pwNew = (WCHAR *) GlobalLock(hgNew);
|
|
ASSERT(pwNew != NULL);
|
|
|
|
// buffer to save all contents before/after <BODY> tag
|
|
m_hgDocRestore = phgDocRestore ? *phgDocRestore : NULL;
|
|
if (m_hgDocRestore == NULL)
|
|
{
|
|
fAllocDocRestore = TRUE;
|
|
m_hgDocRestore = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, cbHeader);
|
|
if (m_hgDocRestore == NULL)
|
|
{
|
|
hrRet = E_OUTOFMEMORY;
|
|
goto LOOM;
|
|
}
|
|
}
|
|
// at this point we know that m_hgDocRestore is not going to be null, but lets be cautious
|
|
// we call FilterIn only once when we load the document. (bug 15393)
|
|
if (m_hgDocRestore != NULL && mode == modeInput)
|
|
{
|
|
WCHAR *pwDocRestore;
|
|
DWORD cbDocRestore;
|
|
|
|
// lock
|
|
pwDocRestore = (WCHAR *) GlobalLock(m_hgDocRestore);
|
|
// fill with zeros
|
|
cbDocRestore = SAFE_INT64_TO_DWORD(GlobalSize(m_hgDocRestore));
|
|
memset((BYTE *)pwDocRestore, 0, cbDocRestore);
|
|
// unlock
|
|
GlobalUnlock(m_hgDocRestore);
|
|
}
|
|
|
|
m_fEndTagFound = FALSE; // initialize
|
|
|
|
m_cMaxToken = m_cDTC = m_cObj = m_cSSSIn = m_cSSSOut = m_cNbsp = m_iControl = m_cComment = m_cObjIn = 0;
|
|
m_cAppletIn = m_cAppletOut = 0;
|
|
m_fSpecialSSS = FALSE;
|
|
m_cHtml = (mode == modeInput)? 0 : 0; // assume that we atleast have one <HTML> tag in modeInput case
|
|
m_cHdr = m_cFtr = m_cAImgLink = 1;
|
|
m_pspInfoCur = m_pspInfo = m_pspInfoOut = m_pspInfoOutStart = NULL;
|
|
m_hgspInfo = NULL;
|
|
m_ichStartSP = 0;
|
|
if (dwFlags & dwPreserveSourceCode)
|
|
{
|
|
m_ispInfoIn = (mode == modeInput)? 1 : 0;
|
|
m_ispInfoOut = (mode == modeOutput)? 1 : 0;
|
|
if (mode == modeInput)
|
|
{
|
|
srand((unsigned)time(NULL));
|
|
m_ispInfoBase = rand();
|
|
if (0x0fffffff-m_ispInfoBase < 0x000fffff)
|
|
m_ispInfoBase = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_ispInfoIn = 0;
|
|
m_ispInfoOut = 0;
|
|
}
|
|
|
|
m_iArrayspLast = 0;
|
|
m_ispInfoBlock = 0; // index of the block. stored as value of DESIGNTIMESPx tag
|
|
m_cchspInfoTotal = 0;
|
|
m_fDontDeccItem = FALSE; // we can do this differently next time
|
|
|
|
// if we have multiple of these tags, we need to warn the user before going to design view
|
|
// and not let the user switch views (bug 18474)
|
|
m_cBodyTags = m_cHtmlTags = m_cTitleTags = m_cHeadTags = 0;
|
|
|
|
if (dwFlags & dwFilterMultiByteStream)
|
|
{
|
|
// note that cbOld is actually number of characters in single byte world
|
|
cchwOld = MultiByteToWideChar(CP_ACP, 0, pOld, (cbSizeIn==-1)?-1:cbOld, NULL, 0);
|
|
MultiByteToWideChar(CP_ACP, 0, pOld, (cbSizeIn==-1)?-1:cbOld, pwOld, cchwOld);
|
|
}
|
|
else
|
|
{
|
|
memcpy((BYTE *)pwOld, (BYTE *)pOld, cbOld); // we are already UNICODE
|
|
// Assume that in UNICODE world we can simply divide cbOld by sizeof(WCHAR)
|
|
cchwOld = cbOld/sizeof(WCHAR);
|
|
}
|
|
*(pwOld+cchwOld) = '\0';
|
|
|
|
// get the token & save it into a buffer
|
|
cbwOld = cchwOld * sizeof(WCHAR);
|
|
while (cbCur < cchwOld)
|
|
{
|
|
UINT cbCurSav = cbCur;
|
|
|
|
NextToken(pwOld, cchwOld, &cbCur, &lxs, &token);
|
|
tagID = GetTagID(pwOld, token); // only if inAttribute & inTag ????
|
|
|
|
// if we have more of any of these tags, Trident removes them, so lets warn the user and
|
|
// not the user go to design view (bug 18474)
|
|
if ( (mode == modeInput)
|
|
&& (token.tokClass == tokElem)
|
|
&& (lxs & inTag)
|
|
&& !(lxs & inEndTag) /* this may be redundant, but having it does no harm */
|
|
)
|
|
{
|
|
switch (token.tok)
|
|
{
|
|
case TokElem_BODY:
|
|
m_cBodyTags++;
|
|
break;
|
|
case TokElem_HTML:
|
|
m_cHtmlTags++;
|
|
break;
|
|
case TokElem_TITLE:
|
|
m_cTitleTags++;
|
|
break;
|
|
case TokElem_HEAD:
|
|
m_cHeadTags++;
|
|
break;
|
|
};
|
|
if (m_cBodyTags > 1 || m_cHtmlTags > 1 || m_cTitleTags > 1 || m_cHeadTags > 1)
|
|
{
|
|
// skip tokenizing. we can't let this go to Trident
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, cchwOld*sizeof(WCHAR));
|
|
cchNew = cchwOld;
|
|
hrRet = E_FILTER_MULTIPLETAGS;
|
|
goto LSkipTokFilter;
|
|
}
|
|
}
|
|
|
|
if ( (token.tokClass == tokElem)
|
|
&& ( (token.tok == TokElem_FRAME)
|
|
|| (token.tok == TokElem_FRAMESET)
|
|
)
|
|
)
|
|
{
|
|
// skip tokenizing. we can't let this go to Trident
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, cchwOld*sizeof(WCHAR));
|
|
cchNew = cchwOld;
|
|
hrRet = E_FILTER_FRAMESET;
|
|
goto LSkipTokFilter;
|
|
}
|
|
if ( (token.tok == TokTag_SSSOPEN)
|
|
&& (token.tokClass == tokSSS)
|
|
&& (lxs & inAttribute)
|
|
&& !(lxs & inString)
|
|
&& !(lxs & inStringA)
|
|
&& !(fInDTCOutput)
|
|
&& (mode == modeInput)
|
|
)
|
|
{
|
|
// skip tokenizing. we can't let this go to Trident
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, cchwOld*sizeof(WCHAR));
|
|
cchNew = cchwOld;
|
|
hrRet = E_FILTER_SERVERSCRIPT;
|
|
goto LSkipTokFilter;
|
|
}
|
|
if ( (token.tok == 0)
|
|
&& (token.tokClass == tokSSS)
|
|
&& (lxs & inTag)
|
|
&& (lxs & inHTXTag)
|
|
&& (lxs & inAttribute)
|
|
&& (lxs & inString || lxs & inStringA)
|
|
&& (lxs & inNestedQuoteinSSS)
|
|
&& !(fInDTCOutput)
|
|
)
|
|
{
|
|
// skip tokenizing. we can't let this go to Trident
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, cchwOld*sizeof(WCHAR));
|
|
cchNew = cchwOld;
|
|
hrRet = E_FILTER_SERVERSCRIPT;
|
|
goto LSkipTokFilter;
|
|
}
|
|
|
|
// REVIEW TODO LATER - For all following special cases, we need to add !fInDTCOutput
|
|
if ( (fBeginTokSelect)
|
|
&& (token.tok == TokTag_SSSOPEN || token.tok == TokElem_SCRIPT)
|
|
)
|
|
{
|
|
// skip tokenizing. we can't let this go to Trident
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, cchwOld*sizeof(WCHAR));
|
|
cchNew = cchwOld;
|
|
hrRet = E_FILTER_SCRIPTSELECT;
|
|
goto LSkipTokFilter;
|
|
}
|
|
|
|
if ( (fBeginTokTextarea)
|
|
&& (token.tok == TokTag_SSSOPEN && token.tokClass == tokSSS)
|
|
)
|
|
{
|
|
// skip tokenizing. we can't let this go to Trident
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, cchwOld*sizeof(WCHAR));
|
|
cchNew = cchwOld;
|
|
hrRet = E_FILTER_SCRIPTTEXTAREA;
|
|
goto LSkipTokFilter;
|
|
}
|
|
if ( (fBeginTokLabel)
|
|
&& (token.tok == TokTag_SSSOPEN && token.tokClass == tokSSS)
|
|
)
|
|
{
|
|
// skip tokenizing. we can't let this go to Trident
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, cchwOld*sizeof(WCHAR));
|
|
cchNew = cchwOld;
|
|
hrRet = E_FILTER_SCRIPTLABEL;
|
|
goto LSkipTokFilter;
|
|
}
|
|
if ( (fBeginTokListing)
|
|
&& (token.tok == TokTag_SSSOPEN && token.tokClass == tokSSS)
|
|
)
|
|
{
|
|
// skip tokenizing. we can't let this go to Trident
|
|
memcpy((BYTE *)pwNew, (BYTE *)pwOld, cchwOld*sizeof(WCHAR));
|
|
cchNew = cchwOld;
|
|
hrRet = E_FILTER_SCRIPTLISTING;
|
|
goto LSkipTokFilter;
|
|
}
|
|
|
|
// Special cases Begin
|
|
|
|
// special case - check if the document has <!DOCTYPE before going to Design view.
|
|
// If it does, set m_fHasDocType flag. Trident always inserts this flag and we
|
|
// want to remove it on the way out from Design view.
|
|
if ( (token.tok == TokElem_TITLE)
|
|
&& (token.tokClass == tokElem)
|
|
)
|
|
{
|
|
if (mode == modeInput)
|
|
{
|
|
m_fHasTitleIn = TRUE;
|
|
if (m_indexTitleIn == -1)
|
|
m_indexTitleIn = itokCur;
|
|
}
|
|
}
|
|
|
|
if ( (token.tok == TokElem_BODY)
|
|
&& (token.tokClass == tokElem)
|
|
&& (m_ichBeginBodyTagIn == -1)
|
|
)
|
|
{
|
|
if ( PARSE_SPECIAL_HEAD_ONLY & dwSpecialize )
|
|
break;
|
|
if (mode == modeInput)
|
|
m_ichBeginBodyTagIn = token.ibTokMin;
|
|
}
|
|
|
|
if ( (token.tok == TokAttrib_HTTPEQUIV || token.tok == TokAttrib_HTTP_EQUIV)
|
|
&& (token.tokClass == tokAttr)
|
|
&& (mode == modeInput)
|
|
)
|
|
{
|
|
if (m_indexHttpEquivIn == -1)
|
|
m_indexHttpEquivIn = itokCur;
|
|
}
|
|
if ( (token.tok == TokElem_HEAD)
|
|
&& (token.tokClass == tokElem)
|
|
&& (m_ichBeginHeadTagIn == -1)
|
|
&& (mode == modeInput)
|
|
)
|
|
{
|
|
m_ichBeginHeadTagIn = token.ibTokMin;
|
|
}
|
|
if ( (token.tok == TokElem_SELECT)
|
|
&& (token.tokClass == tokElem)
|
|
&& (mode == modeInput)
|
|
&& !(lxs & inSCRIPT)
|
|
)
|
|
{
|
|
if ( (pTokArray[itokCur-1].token.tok == TokTag_START)
|
|
&& (pTokArray[itokCur-1].token.tokClass == tokTag)
|
|
)
|
|
fBeginTokSelect = TRUE;
|
|
else if ( (pTokArray[itokCur-1].token.tok == TokTag_END)
|
|
&& (pTokArray[itokCur-1].token.tokClass == tokTag)
|
|
)
|
|
fBeginTokSelect = FALSE;
|
|
}
|
|
if ( (token.tok == TokElem_TEXTAREA)
|
|
&& (token.tokClass == tokElem)
|
|
&& (mode == modeInput)
|
|
)
|
|
{
|
|
if ( (pTokArray[itokCur-1].token.tok == TokTag_START)
|
|
&& (pTokArray[itokCur-1].token.tokClass == tokTag)
|
|
)
|
|
fBeginTokTextarea = TRUE;
|
|
else if ( (pTokArray[itokCur-1].token.tok == TokTag_END)
|
|
&& (pTokArray[itokCur-1].token.tokClass == tokTag)
|
|
)
|
|
fBeginTokTextarea = FALSE;
|
|
}
|
|
if ( (token.tok == TokElem_LABEL)
|
|
&& (token.tokClass == tokElem)
|
|
&& (mode == modeInput)
|
|
)
|
|
{
|
|
if ( (pTokArray[itokCur-1].token.tok == TokTag_START)
|
|
&& (pTokArray[itokCur-1].token.tokClass == tokTag)
|
|
)
|
|
fBeginTokLabel = TRUE;
|
|
else if ( (pTokArray[itokCur-1].token.tok == TokTag_END)
|
|
&& (pTokArray[itokCur-1].token.tokClass == tokTag)
|
|
)
|
|
fBeginTokLabel = FALSE;
|
|
}
|
|
if ( (token.tok == TokElem_LISTING)
|
|
&& (token.tokClass == tokElem)
|
|
&& (mode == modeInput)
|
|
)
|
|
{
|
|
if ( (pTokArray[itokCur-1].token.tok == TokTag_START)
|
|
&& (pTokArray[itokCur-1].token.tokClass == tokTag)
|
|
)
|
|
fBeginTokListing = TRUE;
|
|
else if ( (pTokArray[itokCur-1].token.tok == TokTag_END)
|
|
&& (pTokArray[itokCur-1].token.tokClass == tokTag)
|
|
)
|
|
fBeginTokListing = FALSE;
|
|
}
|
|
|
|
if ( (token.tok == TokAttrib_STARTSPAN)
|
|
&& (token.tokClass == tokAttr)
|
|
&& (mode == modeInput)
|
|
)
|
|
fInDTC = TRUE;
|
|
if ( (token.tok == TokElem_OBJECT)
|
|
&& (token.tokClass == tokElem)
|
|
&& (lxs & inEndTag)
|
|
&& (fInDTC)
|
|
&& (mode == modeInput)
|
|
)
|
|
fInDTCOutput = TRUE;
|
|
if ( (token.tok == TokAttrib_ENDSPAN)
|
|
&& (token.tokClass == tokAttr)
|
|
&& (mode == modeInput)
|
|
)
|
|
{
|
|
fInDTCOutput = FALSE;
|
|
fInDTC = FALSE;
|
|
}
|
|
// Special cases End
|
|
|
|
|
|
if (itokCur == cArrayMax - 1) //allocate more memory for the array
|
|
{
|
|
HGLOBAL hgTokArray;
|
|
GlobalUnlock(*phgTokArray);
|
|
hgTokArray = *phgTokArray;
|
|
#pragma prefast(suppress:308, "noise")
|
|
*phgTokArray = GlobalReAlloc(*phgTokArray, (cArrayMax+MIN_TOK)*sizeof(TOKSTRUCT), GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
// if this alloc failed, we may still want to continue
|
|
if (*phgTokArray == NULL)
|
|
{
|
|
GlobalFree(hgTokArray);
|
|
hrRet = E_OUTOFMEMORY;
|
|
*pcMaxToken = itokCur;
|
|
if (fUsePstmNew)
|
|
pStmNew->SetSize(li);
|
|
else
|
|
*phNew = NULL;
|
|
goto LOOM;
|
|
}
|
|
else
|
|
{
|
|
pTokArray = (TOKSTRUCT *)GlobalLock(*phgTokArray); // do we need to unlock this first?
|
|
ASSERT(pTokArray != NULL);
|
|
cArrayMax += MIN_TOK;
|
|
}
|
|
}
|
|
ASSERT(itokCur < cArrayMax);
|
|
PreProcessToken(pTokArray, &itokCur, pwOld, cbCur, token, lxs, tagID, mode); //saves the token into the buffer
|
|
|
|
|
|
if (itokTop == cStackMax - 1) //allocate more memory for the stack
|
|
{
|
|
HGLOBAL hg;
|
|
GlobalUnlock(hgTokStack);
|
|
hg = hgTokStack;
|
|
#pragma prefast(suppress: 308, "noise")
|
|
hgTokStack = GlobalReAlloc(hgTokStack, (cStackMax+MIN_TOK)*sizeof(TOKSTACK), GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
// if this alloc failed, we may still want to continue
|
|
if (hgTokStack == NULL)
|
|
{
|
|
GlobalFree(hg);
|
|
hrRet = E_OUTOFMEMORY;
|
|
*pcMaxToken = itokCur;
|
|
if (fUsePstmNew)
|
|
pStmNew->SetSize(li);
|
|
else
|
|
*phNew = NULL;
|
|
goto LOOM;
|
|
}
|
|
else
|
|
{
|
|
pTokStack = (TOKSTACK *)GlobalLock(hgTokStack); // do we need to unlock this first?
|
|
ASSERT(pTokStack != NULL);
|
|
cStackMax += MIN_TOK;
|
|
}
|
|
}
|
|
ASSERT(itokTop < cStackMax);
|
|
ProcessToken(lxs, token, pwOld, cbCur, pTokStack, &itokTop, pTokArray, itokCur, tagID); //push/pop stack, determine error states
|
|
|
|
PostProcessToken(pwOld, pwNew, &cchNew, cbCur, cbCurSav, token, mode, lxs, dwFlags); // handle special cases of replacement
|
|
} // while (cbCur < cchwOld)
|
|
*pcMaxToken = m_cMaxToken = itokCur;
|
|
ASSERT(cchNew < GlobalSize(hgNew)); // or compare the cached value
|
|
|
|
ASSERT(dwFlags != dwFilterDefaults);
|
|
if ( dwFlags & dwFilterDTCs
|
|
|| dwFlags & dwFilterDTCsWithoutMetaTags
|
|
|| dwFlags & dwFilterServerSideScripts
|
|
|| dwFlags & dwPreserveSourceCode
|
|
)
|
|
{
|
|
ASSERT(!(dwFlags & dwFilterNone));
|
|
|
|
|
|
|
|
// check dwSpacing flag here
|
|
if ((mode == modeOutput) && (dwFlags & dwPreserveSourceCode))
|
|
{
|
|
INT cchBeforeBody = 0;
|
|
INT cchAfterBody = 0;
|
|
INT cchPreEndBody = 0;
|
|
|
|
ASSERT(m_pspInfoOut == NULL);
|
|
ASSERT(m_hgDocRestore != NULL);
|
|
m_pspInfoOut = (WORD *)GlobalLock(m_hgDocRestore);
|
|
cchBeforeBody = (int)*m_pspInfoOut; // we are assuming that cchBeforeBody exists in this block
|
|
m_pspInfoOut += cchBeforeBody + (sizeof(INT))/sizeof(WCHAR); // for cchBeforeBody
|
|
cchAfterBody = (int)*m_pspInfoOut;
|
|
m_pspInfoOut += cchAfterBody + (sizeof(INT))/sizeof(WCHAR); // for cchAfterBody
|
|
cchPreEndBody = (int)*m_pspInfoOut;
|
|
m_pspInfoOut += cchPreEndBody + (sizeof(INT))/sizeof(WCHAR); // for cchPreEndBody
|
|
m_cchspInfoTotal = (int)*m_pspInfoOut;
|
|
m_pspInfoOut += sizeof(INT)/sizeof(WCHAR);
|
|
m_pspInfoOutStart = m_pspInfoOut;
|
|
}
|
|
|
|
|
|
ASSERT(pTokArray != NULL);
|
|
FilterHtml( pwOld, &pwNew, &cchNew, &hgNew, pTokArray,
|
|
mode, dwFlags);
|
|
|
|
// check dwSpacing flag here
|
|
if ((mode == modeOutput) && (dwFlags & dwPreserveSourceCode))
|
|
{
|
|
if (m_pspInfoOut != NULL)
|
|
{
|
|
ASSERT(m_hgDocRestore != NULL);
|
|
GlobalUnlock(m_hgDocRestore);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
LSkipTokFilter:
|
|
|
|
if (fUsePstmNew)
|
|
{
|
|
if (dwFlags & dwFilterMultiByteStream)
|
|
li.LowPart = WideCharToMultiByte(CP_ACP, 0, pwNew, -1, NULL, 0, NULL, NULL) - 1; // to compensate for NULL character at end
|
|
else
|
|
li.LowPart = (cchNew)*sizeof(WCHAR);
|
|
li.HighPart = 0;
|
|
if (S_OK != pStmNew->SetSize(li))
|
|
{
|
|
hrRet = E_OUTOFMEMORY;
|
|
goto LOOM;
|
|
}
|
|
if (S_OK != GetHGlobalFromStream(pStmNew, &hgPstm))
|
|
{
|
|
hrRet = E_INVALIDARG;
|
|
goto LOOM;
|
|
}
|
|
pNew = (LPSTR) GlobalLock(hgPstm);
|
|
}
|
|
else
|
|
{
|
|
// cchNew is # of unicode characters in pwNew
|
|
// If we want to convert this UNICODE string into MultiByte string,
|
|
// we will need anywhere between cchNew bytes & cchNew*sizeof(WCHAR) bytes.
|
|
// and we don't know it at this point, so lets leave the max size for allocation.
|
|
*phNew = GlobalAlloc(GMEM_ZEROINIT, (cchNew+1)*sizeof(WCHAR));
|
|
if (*phNew == NULL)
|
|
{
|
|
hrRet = E_OUTOFMEMORY;
|
|
goto LOOM;
|
|
}
|
|
pNew = (LPSTR) GlobalLock(*phNew);
|
|
}
|
|
|
|
if (dwFlags & dwFilterMultiByteStream)
|
|
{
|
|
INT cbSize;
|
|
|
|
cbSize = WideCharToMultiByte(CP_ACP, 0, pwNew, -1, NULL, 0, NULL, NULL) - 1; // to compensate for NULL character at end
|
|
if (pcbSizeOut)
|
|
*pcbSizeOut = cbSize;
|
|
// we assume that number of characters will be the same in UNICODE or MBCS world
|
|
// what changes is the number of bytes they need.
|
|
WideCharToMultiByte(CP_ACP, 0, pwNew, -1, pNew, cbSize, NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
// NOTE - that we always set *pcbSizeOut to the number of BYTES in the new buffer
|
|
if (pcbSizeOut)
|
|
*pcbSizeOut = cchNew*sizeof(WCHAR);
|
|
memcpy((BYTE *)pNew, (BYTE *)pwNew, cchNew*sizeof(WCHAR)); // we want to remain UNICODE
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
dwErr = GetLastError();
|
|
#endif // DEBUG
|
|
|
|
if (fUsePstmNew)
|
|
GlobalUnlock(hgPstm);
|
|
else
|
|
GlobalUnlock(*phNew);
|
|
|
|
LOOM:
|
|
// assume that the caller will free *phgTokArray
|
|
if (*phgTokArray != NULL)
|
|
GlobalUnlock(*phgTokArray); // do we need to check if this was already Unlocked?
|
|
|
|
// assume that the caller will free *phgDocRestore if the caller allocated it
|
|
if (fAllocDocRestore && m_hgDocRestore != NULL) // we allocated it here, so the caller doesn't need it
|
|
GlobalUnlockFreeNull(&m_hgDocRestore);
|
|
|
|
if (phgDocRestore)
|
|
*phgDocRestore = m_hgDocRestore; // in case of a realloc, this may have changed.
|
|
|
|
if (hgTokStack != NULL)
|
|
GlobalUnlockFreeNull(&hgTokStack);
|
|
if (hgNew != NULL)
|
|
GlobalUnlockFreeNull(&hgNew);
|
|
if (hgOld != NULL)
|
|
GlobalUnlockFreeNull(&hgOld);
|
|
if (m_hgTBodyStack != NULL)
|
|
GlobalUnlockFreeNull(&m_hgTBodyStack);
|
|
|
|
// check dwSpacing flag here
|
|
if ((m_hgspInfo != NULL) && (dwFlags & dwPreserveSourceCode))
|
|
{
|
|
if (mode == modeInput && phgDocRestore)
|
|
{
|
|
WCHAR *pHdr, *pHdrSav;
|
|
INT cchBeforeBody, cchAfterBody, cchPreEndBody;
|
|
|
|
pHdr = (WCHAR *)GlobalLock(*phgDocRestore);
|
|
ASSERT(pHdr != NULL);
|
|
pHdrSav = pHdr;
|
|
memcpy((BYTE *)&cchBeforeBody, (BYTE *)pHdr, sizeof(INT));
|
|
pHdr += cchBeforeBody + sizeof(INT)/sizeof(WCHAR);
|
|
|
|
memcpy((BYTE *)&cchAfterBody, (BYTE *)pHdr, sizeof(INT));
|
|
pHdr += cchAfterBody + sizeof(INT)/sizeof(WCHAR);
|
|
|
|
memcpy((BYTE *)&cchPreEndBody, (BYTE *)pHdr, sizeof(INT));
|
|
pHdr += cchPreEndBody + sizeof(INT)/sizeof(WCHAR);
|
|
|
|
|
|
if (GlobalSize(*phgDocRestore) < SAFE_PTR_DIFF_TO_INT(pHdr - pHdrSav)*sizeof(WCHAR) + SAFE_PTR_DIFF_TO_INT(m_pspInfoCur-m_pspInfo)*sizeof(WORD)+sizeof(int))
|
|
{
|
|
INT cdwSize = SAFE_PTR_DIFF_TO_INT(pHdr - pHdrSav);
|
|
|
|
ASSERT(cdwSize >= 0); // validation
|
|
hrRet = ReallocBuffer( phgDocRestore,
|
|
SAFE_INT64_TO_DWORD(pHdr - pHdrSav)*sizeof(WCHAR) + SAFE_INT64_TO_DWORD(m_pspInfoCur-m_pspInfo)*sizeof(WORD)+sizeof(int),
|
|
GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
if (hrRet == E_OUTOFMEMORY)
|
|
goto LRet;
|
|
ASSERT(*phgDocRestore != NULL);
|
|
pHdr = (WORD *)GlobalLock(*phgDocRestore);
|
|
pHdr += cdwSize;
|
|
}
|
|
|
|
*(int*)pHdr = SAFE_PTR_DIFF_TO_INT(m_pspInfoCur-m_pspInfo);
|
|
pHdr += sizeof(INT)/sizeof(WCHAR);
|
|
|
|
memcpy( (BYTE *)pHdr,
|
|
(BYTE *)m_pspInfo,
|
|
SAFE_PTR_DIFF_TO_INT(m_pspInfoCur-m_pspInfo)*sizeof(WORD));
|
|
LRet:
|
|
GlobalUnlock(*phgDocRestore);
|
|
}
|
|
GlobalUnlockFreeNull(&m_hgspInfo);
|
|
}
|
|
|
|
|
|
GlobalUnlock(hOld);
|
|
LRetOnly:
|
|
return(hrRet);
|
|
|
|
}
|
|
|
|
void
|
|
CTriEditParse::SetSPInfoState(WORD inState, WORD *pdwState, WORD *pdwStatePrev, BOOL *pfSave)
|
|
{
|
|
*pfSave = TRUE;
|
|
*pdwStatePrev = *pdwState;
|
|
*pdwState = inState;
|
|
}
|
|
|
|
HRESULT
|
|
CTriEditParse::hrMarkOrdering(WCHAR *pwOld, TOKSTRUCT *pTokArray, INT iArrayStart, int iArrayEnd,
|
|
UINT cbCur, INT *pichStartOR)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
WORD *pspInfoSize;
|
|
WORD cAttr = 0;
|
|
|
|
ASSERT(m_pspInfo != NULL);
|
|
if (m_pspInfo == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto LRetOnly;
|
|
}
|
|
|
|
pspInfoSize = m_pspInfoCur; // placeholder to save run size in BYTEs, size includes this DWORD
|
|
*m_pspInfoCur++ = 0xFFFF; // placeholder to save run size in BYTEs, size includes this WORD
|
|
*m_pspInfoCur++ = 0xFFFF; // placeholder to save number of Attr
|
|
|
|
// handle the simplest case where we know that there is nothing to save
|
|
if (cbCur == (UINT)*pichStartOR)
|
|
goto LRet;
|
|
// find out the number ot attributes insize this tag
|
|
while (iArrayStart < iArrayEnd)
|
|
{
|
|
if (pTokArray[iArrayStart].token.tokClass == tokAttr)
|
|
{
|
|
INT ichStart, ichEnd;
|
|
INT iArrayQuote = iArrayStart+1;
|
|
INT iArrayEq = -1;
|
|
|
|
cAttr++;
|
|
ichStart = pTokArray[iArrayStart].token.ibTokMin;
|
|
ichEnd = pTokArray[iArrayStart].token.ibTokMac;
|
|
ASSERT(ichEnd > ichStart);
|
|
|
|
while (iArrayQuote < iArrayEnd) // handle the case of white space before the quotes
|
|
{
|
|
if (pTokArray[iArrayQuote].token.tokClass == tokAttr) // gone too far, found next attr
|
|
break;
|
|
if ( ( pTokArray[iArrayQuote].token.tokClass == tokValue
|
|
|| pTokArray[iArrayQuote].token.tokClass == tokString
|
|
)
|
|
&& ( pwOld[pTokArray[iArrayQuote].token.ibTokMin] == '"'
|
|
|| pwOld[pTokArray[iArrayQuote].token.ibTokMin] == '\''
|
|
)
|
|
)
|
|
break;
|
|
if (pwOld[pTokArray[iArrayQuote].token.ibTokMin] == '=')
|
|
iArrayEq = iArrayQuote;
|
|
iArrayQuote++;
|
|
}
|
|
|
|
if ( iArrayEq != -1
|
|
&& pTokArray[iArrayEq].token.tokClass == tokOp
|
|
&& pwOld[pTokArray[iArrayEq].token.ibTokMin] == '='
|
|
&& ( pTokArray[iArrayQuote].token.tokClass == tokValue
|
|
|| pTokArray[iArrayQuote].token.tokClass == tokString
|
|
)
|
|
&& pwOld[pTokArray[iArrayQuote].token.ibTokMin] == '"'
|
|
)
|
|
{
|
|
*m_pspInfoCur++ = 1;
|
|
}
|
|
else if ( iArrayEq != -1
|
|
&& pTokArray[iArrayEq].token.tokClass == tokOp
|
|
&& pwOld[pTokArray[iArrayEq].token.ibTokMin] == '='
|
|
&& ( pTokArray[iArrayQuote].token.tokClass == tokValue
|
|
|| pTokArray[iArrayQuote].token.tokClass == tokString
|
|
)
|
|
&& pwOld[pTokArray[iArrayQuote].token.ibTokMin] == '\''
|
|
)
|
|
{
|
|
*m_pspInfoCur++ = 2;
|
|
}
|
|
else
|
|
{
|
|
*m_pspInfoCur++ = 0;
|
|
}
|
|
*m_pspInfoCur++ = (WORD)(ichEnd-ichStart);
|
|
memcpy((BYTE *)m_pspInfoCur, (BYTE *)&(pwOld[ichStart]), (ichEnd-ichStart)*sizeof(WCHAR));
|
|
m_pspInfoCur += (ichEnd-ichStart);
|
|
}
|
|
iArrayStart++;
|
|
}
|
|
|
|
LRet:
|
|
*pspInfoSize++ = SAFE_PTR_DIFF_TO_WORD(m_pspInfoCur - pspInfoSize);
|
|
*pspInfoSize = cAttr;
|
|
|
|
*pichStartOR = cbCur; // set for next run
|
|
LRetOnly:
|
|
return(hr);
|
|
|
|
} /* hrMarkOrdering() */
|
|
|
|
BOOL
|
|
CTriEditParse::FRestoreOrder(WCHAR *pwNew, WCHAR *pwOld, WORD *pspInfoOrder, UINT *pichNewCur,
|
|
INT /*cwOrderInfo*/, TOKSTRUCT *pTokArray, INT iArrayStart, INT iArrayEnd,
|
|
INT iArrayDSPStart, INT iArrayDSPEnd, INT cchNewCopy, HGLOBAL *phgNew)
|
|
{
|
|
// iArrayStart points to '<' & iArrayEnd points to '>'. (These refer to pwOld)
|
|
// look at the attributes between iArrayStart & iArrayEnd and compare them with the attributes
|
|
// saved in pspInfoOrder (which already points to the data saved, i.e. past cwOrderInfo)
|
|
// If we find a matching attribute, move it to appropriate position.
|
|
// DON'T touch extra attributes and IGNORE missing attributes because those represent user action
|
|
|
|
HGLOBAL hgNewAttr = NULL;
|
|
HGLOBAL hgTokList = NULL;
|
|
BOOL *pTokList, *pTokListSav;
|
|
WCHAR *pNewAttr, *pNewAttrSav;
|
|
INT i, ichStart, ichEnd, iStart, iEnd, cAttr, cchTag, iStartSav, cchNew;
|
|
BOOL fRet = TRUE;
|
|
LPCWSTR rgSpaceTags[] =
|
|
{
|
|
L"DESIGNTIMESP",
|
|
};
|
|
UINT cbNeed;
|
|
|
|
ASSERT(pspInfoOrder != NULL);
|
|
cAttr = *(WORD *)pspInfoOrder++;
|
|
ASSERT(cAttr >= 0); // make sure that it was filled in
|
|
if (cAttr == 0)/* || cAttr == 1)*/
|
|
goto LRet;
|
|
|
|
hgTokList = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, (iArrayEnd-iArrayStart+1)*(sizeof(BOOL)));
|
|
if (hgTokList == NULL) // don't reorder the attributes
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
pTokList = (BOOL *) GlobalLock(hgTokList);
|
|
pTokListSav = pTokList;
|
|
|
|
ichStart = pTokArray[iArrayStart].token.ibTokMin;
|
|
ichEnd = pTokArray[iArrayEnd].token.ibTokMac;
|
|
// cAttr*2 becase we may need to add quotes around each attr value
|
|
hgNewAttr = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, (ichEnd-ichStart+cAttr*2)*(sizeof(WCHAR)));
|
|
if (hgNewAttr == NULL) // don't reorder the attributes
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
pNewAttr = (WCHAR *) GlobalLock(hgNewAttr);
|
|
pNewAttrSav = pNewAttr;
|
|
|
|
for (i = iArrayStart; i <= iArrayEnd; i++)
|
|
*pTokList++ = FALSE;
|
|
|
|
ASSERT(iArrayDSPEnd > iArrayDSPStart);
|
|
for (i = iArrayDSPStart; i <= iArrayDSPEnd; i++)
|
|
{
|
|
ASSERT(*(pTokListSav+i-iArrayStart) == FALSE);
|
|
*(pTokListSav+i-iArrayStart) = TRUE;
|
|
}
|
|
if (pwOld[pTokArray[iArrayDSPEnd+1].token.ibTokMin] == ' ')
|
|
{
|
|
ASSERT(*(pTokListSav+iArrayDSPEnd+1-iArrayStart) == FALSE);
|
|
*(pTokListSav+iArrayDSPEnd+1-iArrayStart) = TRUE;
|
|
}
|
|
// copy contents from pwOld into pNewAttr till we find the first tokAttr/tokSpace
|
|
iStart = iEnd = iArrayStart;
|
|
cchTag = wcslen(rgSpaceTags[0]);
|
|
while (iEnd < iArrayEnd)
|
|
{
|
|
if ( (pTokArray[iEnd].token.tokClass == tokAttr)
|
|
/*|| ( (pTokArray[iEnd].token.tokClass == tokSpace)
|
|
&& (0 != _wcsnicmp(rgSpaceTags[0], &pwOld[pTokArray[iEnd].token.ibTokMin], cchTag))
|
|
)*/
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
iEnd++;
|
|
}
|
|
if (iEnd >= iArrayEnd) // error
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
|
|
for (i = iStart; i < iEnd; i++)
|
|
{
|
|
if (*(pTokListSav+i-iArrayStart) != TRUE) // if not already copied
|
|
{
|
|
if ( (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin == 3)
|
|
&& pwOld[pTokArray[i].token.ibTokMin] == ' '
|
|
&& pwOld[pTokArray[i].token.ibTokMin+1] == '\r'
|
|
&& pwOld[pTokArray[i].token.ibTokMin+2] == '\n'
|
|
)
|
|
{
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)(pwOld+pTokArray[i].token.ibTokMin),
|
|
(1)*sizeof(WCHAR));
|
|
pNewAttr++;
|
|
}
|
|
else
|
|
{
|
|
if (pTokArray[i].token.tokClass == tokElem)
|
|
{
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)(pwOld+pTokArray[i].token.ibTokMin),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
// BUG 15389 - restore proper case here
|
|
if (iswupper(pwOld[pTokArray[iArrayDSPStart].token.ibTokMin]) != 0) // DESIGNTIMESP is upper case
|
|
{
|
|
_wcsupr(pNewAttr);
|
|
}
|
|
else
|
|
{
|
|
_wcslwr(pNewAttr);
|
|
}
|
|
pNewAttr += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)(pwOld+pTokArray[i].token.ibTokMin),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
pNewAttr += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
}
|
|
*(pTokListSav+i-iArrayStart) = TRUE;
|
|
}
|
|
}
|
|
|
|
iStartSav = iStart = iEnd;
|
|
while (cAttr > 0)
|
|
{
|
|
INT cchAttr;
|
|
BOOL fAddSpace;
|
|
WORD isQuote;
|
|
|
|
isQuote = *(WORD *)pspInfoOrder++;
|
|
cchAttr = *(WORD *)pspInfoOrder++;
|
|
ASSERT(cchAttr > 0); // make sure that it was filled in
|
|
|
|
while (iStart <= iArrayEnd) //for (i = iStart; i <= iArrayEnd; i++)
|
|
{
|
|
if ( (pTokArray[iStart].token.tokClass == tokAttr)
|
|
&& (pTokArray[iStart].token.ibTokMac-pTokArray[iStart].token.ibTokMin == (UINT)cchAttr)
|
|
&& (0 == _wcsnicmp(pspInfoOrder, &pwOld[pTokArray[iStart].token.ibTokMin], cchAttr))
|
|
)
|
|
{
|
|
break; // found the match, so copy from ith token to the next tokAttr
|
|
}
|
|
iStart++;
|
|
} // while ()
|
|
if (iStart >= iArrayEnd) // we know that iArrayEnd is actually '>'
|
|
goto LNoMatch;
|
|
|
|
// now from iStart go forward till we get the next tokAttr or '>'
|
|
iEnd = iStart+1;
|
|
fAddSpace = FALSE;
|
|
while (iEnd < iArrayEnd)
|
|
{
|
|
if ( (pTokArray[iEnd].token.tokClass == tokAttr)
|
|
|| ( (pTokArray[iEnd].token.tokClass == tokSpace)
|
|
&& (0 == _wcsnicmp(rgSpaceTags[0], &pwOld[pTokArray[iEnd].token.ibTokMin], cchTag))
|
|
)
|
|
)
|
|
break; // found the next attribute
|
|
iEnd++;
|
|
}
|
|
if (iEnd == iArrayEnd)
|
|
fAddSpace = TRUE;
|
|
iEnd--; // iEnd will be pointing to '>' or the next Attribute, so decrement it
|
|
|
|
for (i = iStart; i <= iEnd; i++)
|
|
{
|
|
if (*(pTokListSav+i-iArrayStart) != TRUE) // we didn't copy this token
|
|
{
|
|
if ( (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin == 3)
|
|
&& pwOld[pTokArray[i].token.ibTokMin] == ' '
|
|
&& pwOld[pTokArray[i].token.ibTokMin+1] == '\r'
|
|
&& pwOld[pTokArray[i].token.ibTokMin+2] == '\n'
|
|
)
|
|
{
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)(pwOld+pTokArray[i].token.ibTokMin),
|
|
(1)*sizeof(WCHAR));
|
|
pNewAttr++;
|
|
}
|
|
else
|
|
{
|
|
if (pTokArray[i].token.tokClass == tokAttr)
|
|
{
|
|
ASSERT(i == iStart);
|
|
ASSERT((INT)(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin) == cchAttr);
|
|
ASSERT(0 == _wcsnicmp(pspInfoOrder, &pwOld[pTokArray[i].token.ibTokMin], cchAttr));
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)pspInfoOrder,
|
|
(cchAttr)*sizeof(WCHAR));
|
|
}
|
|
else if ( (isQuote == 1)
|
|
&& ( pTokArray[i].token.tokClass == tokValue
|
|
|| pTokArray[i].token.tokClass == tokString
|
|
)
|
|
&& (pwOld[pTokArray[i-1].token.ibTokMin] != '@') /*hack alert - VID BUG 23597*/
|
|
)
|
|
{
|
|
isQuote = 0; // the quote restoring has been taken care of for this attribute's value
|
|
if (pwOld[pTokArray[i].token.ibTokMin] != '"')
|
|
*pNewAttr++ = '"';
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)(pwOld+pTokArray[i].token.ibTokMin),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
if (pwOld[pTokArray[i].token.ibTokMin] != '"')
|
|
{
|
|
*(pNewAttr+pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin) = '"';
|
|
pNewAttr++;
|
|
}
|
|
}
|
|
else if ( (isQuote == 2)
|
|
&& ( pTokArray[i].token.tokClass == tokValue
|
|
|| pTokArray[i].token.tokClass == tokString
|
|
)
|
|
&& (pwOld[pTokArray[i-1].token.ibTokMin] != '@') /*hack alert - VID BUG 23597*/
|
|
)
|
|
{
|
|
isQuote = 0; // the quote restoring has been taken care of for this attribute's value
|
|
// if we already have double quote, don't insert another single quote.
|
|
// ideally, we want to replace the double quote, but lets not do it now, because
|
|
// we believe that trident would have inserted double quotes to make it valid html!
|
|
if (pwOld[pTokArray[i].token.ibTokMin] != '\'' && pwOld[pTokArray[i].token.ibTokMin] != '"')
|
|
*pNewAttr++ = '\'';
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)(pwOld+pTokArray[i].token.ibTokMin),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
if (pwOld[pTokArray[i].token.ibTokMin] != '\'' && pwOld[pTokArray[i].token.ibTokMin] != '"')
|
|
{
|
|
*(pNewAttr+pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin) = '\'';
|
|
pNewAttr++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)(pwOld+pTokArray[i].token.ibTokMin),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
}
|
|
pNewAttr += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
*(pTokListSav+i-iArrayStart) = TRUE;
|
|
}
|
|
}
|
|
if (fAddSpace)
|
|
*pNewAttr++ = ' ';
|
|
|
|
LNoMatch:
|
|
iStart = iStartSav;
|
|
pspInfoOrder += cchAttr;
|
|
cAttr--;
|
|
} // while (cAttr > 0)
|
|
|
|
// do we want to insert an extra space into pNewAttr here?
|
|
|
|
// all the saved attributes are accounted for, lets copy remaining stuff
|
|
for (i = iStartSav; i <= iArrayEnd; i++)
|
|
{
|
|
if (*(pTokListSav+i-iArrayStart) != TRUE) // we didn't copy this token
|
|
{
|
|
if ( (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin == 3)
|
|
&& pwOld[pTokArray[i].token.ibTokMin] == ' '
|
|
&& pwOld[pTokArray[i].token.ibTokMin+1] == '\r'
|
|
&& pwOld[pTokArray[i].token.ibTokMin+2] == '\n'
|
|
)
|
|
{
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)(pwOld+pTokArray[i].token.ibTokMin),
|
|
(1)*sizeof(WCHAR));
|
|
pNewAttr++;
|
|
}
|
|
else
|
|
{
|
|
memcpy( (BYTE *)pNewAttr,
|
|
(BYTE *)(pwOld+pTokArray[i].token.ibTokMin),
|
|
(pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin)*sizeof(WCHAR));
|
|
pNewAttr += (pTokArray[i].token.ibTokMac-pTokArray[i].token.ibTokMin);
|
|
}
|
|
*(pTokListSav+i-iArrayStart) = TRUE;
|
|
}
|
|
} // for ()
|
|
cchNew = SAFE_PTR_DIFF_TO_INT(pNewAttr - pNewAttrSav);
|
|
|
|
cbNeed = *pichNewCur+cchNew-cchNewCopy;
|
|
ASSERT(cbNeed*sizeof(WCHAR) <= GlobalSize(*phgNew));
|
|
if (S_OK != ReallocIfNeeded(phgNew, &pwNew, cbNeed, GMEM_MOVEABLE|GMEM_ZEROINIT))
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
|
|
memcpy( (BYTE *)(pwNew+*pichNewCur-cchNewCopy),
|
|
(BYTE *)(pNewAttrSav),
|
|
cchNew*sizeof(WCHAR));
|
|
*pichNewCur += (cchNew-cchNewCopy);
|
|
|
|
// NOTE - Find a better way to account for the extra space added when we moved
|
|
// the attributes. We can't avoid adding space because when we move the last attribute,
|
|
// there may not be a space between that and the '>'.
|
|
if ( /*(cchNew > cchNewCopy)
|
|
&&*/ (pwNew[*pichNewCur-1] == '>' && pwNew[*pichNewCur-2] == ' ')
|
|
)
|
|
{
|
|
pwNew[*pichNewCur-2] = pwNew[*pichNewCur-1];
|
|
pwNew[*pichNewCur-1] = '\0';
|
|
*pichNewCur -= 1;
|
|
}
|
|
|
|
LRet:
|
|
if (hgNewAttr != NULL)
|
|
GlobalUnlockFreeNull(&hgNewAttr);
|
|
if (hgTokList != NULL)
|
|
GlobalUnlockFreeNull(&hgTokList);
|
|
|
|
return(fRet);
|
|
|
|
} /* FRestoreOrder() */
|
|
|
|
HRESULT
|
|
CTriEditParse::hrMarkSpacing(WCHAR *pwOld, UINT cbCur, INT *pichStartSP)
|
|
{
|
|
|
|
HRESULT hrRet = S_OK;
|
|
UINT i;
|
|
WORD cSpace, cEOL, cTab, cChar, cTagOpen, cTagClose, cTagEq;
|
|
WORD dwState = initState;
|
|
WORD dwStatePrev = initState;
|
|
BOOL fSave = FALSE;
|
|
WORD *pspInfoSize;
|
|
|
|
if (m_pspInfo == NULL) // allocate it
|
|
{
|
|
m_hgspInfo = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, cbHeader*sizeof(WORD));
|
|
if (m_hgspInfo == NULL)
|
|
{
|
|
hrRet = E_OUTOFMEMORY;
|
|
goto LRet;
|
|
}
|
|
m_pspInfo = (WORD *) GlobalLock(m_hgspInfo);
|
|
ASSERT(m_pspInfo != NULL);
|
|
m_pspInfoCur = m_pspInfo;
|
|
//ASSERT(m_ispInfoIn == 0);
|
|
}
|
|
else // reallocate if needed
|
|
{
|
|
// assumption here is that we can't have more runs than the number of characters we have to scan
|
|
// we use *2 to reduce future reallocations
|
|
if (GlobalSize(m_hgspInfo) < SAFE_PTR_DIFF_TO_INT(m_pspInfoCur-m_pspInfo)*sizeof(WORD) + (cbCur-*pichStartSP)*2*sizeof(WORD) + cbBufPadding)
|
|
{
|
|
int cdwSize = SAFE_PTR_DIFF_TO_INT(m_pspInfoCur-m_pspInfo); // size in DWORDs
|
|
|
|
hrRet = ReallocBuffer( &m_hgspInfo,
|
|
SAFE_INT64_TO_DWORD(m_pspInfoCur-m_pspInfo)*sizeof(WORD) + (cbCur-*pichStartSP)*2*sizeof(WORD) + cbBufPadding,
|
|
GMEM_MOVEABLE|GMEM_ZEROINIT);
|
|
if (hrRet == E_OUTOFMEMORY)
|
|
goto LRet;
|
|
ASSERT(m_hgspInfo != NULL);
|
|
m_pspInfo = (WORD *)GlobalLock(m_hgspInfo);
|
|
m_pspInfoCur = m_pspInfo + cdwSize;
|
|
}
|
|
}
|
|
|
|
//m_ispInfoIn++;
|
|
pspInfoSize = m_pspInfoCur; // placeholder to save run size in BYTEs, size includes this DWORD
|
|
*m_pspInfoCur++ = 0xFFFF; // placeholder to save run size in BYTEs, size includes this WORD
|
|
*m_pspInfoCur++ = SAFE_INT_DIFF_TO_WORD(cbCur-*pichStartSP);
|
|
cSpace = cEOL = cTab = cChar = cTagOpen = cTagClose = cTagEq = 0;
|
|
|
|
//scan from ichStartSP till cbCur for space, tab, eol
|
|
// NOTE - Optimization note
|
|
// part of this info is already in pTokArray. We should use it
|
|
// to reduce the time in this function
|
|
for (i = *pichStartSP; i < cbCur; i++)
|
|
{
|
|
switch (pwOld[i])
|
|
{
|
|
case ' ':
|
|
if (dwState != inSpace)
|
|
{
|
|
SetSPInfoState(inSpace, &dwState, &dwStatePrev, &fSave);
|
|
ASSERT(cSpace == 0);
|
|
}
|
|
cSpace++;
|
|
break;
|
|
case '\r':
|
|
case '\n':
|
|
if (dwState != inEOL)
|
|
{
|
|
SetSPInfoState(inEOL, &dwState, &dwStatePrev, &fSave);
|
|
ASSERT(cEOL == 0);
|
|
}
|
|
if (pwOld[i] == '\n')
|
|
cEOL++;
|
|
break;
|
|
case '\t':
|
|
if (dwState != inTab)
|
|
{
|
|
SetSPInfoState(inTab, &dwState, &dwStatePrev, &fSave);
|
|
ASSERT(cTab == 0);
|
|
}
|
|
cTab++;
|
|
break;
|
|
case '<':
|
|
if (dwState != inTagOpen)
|
|
{
|
|
SetSPInfoState(inTagOpen, &dwState, &dwStatePrev, &fSave);
|
|
ASSERT(cTagOpen == 0);
|
|
}
|
|
cTagOpen++;
|
|
break;
|
|
case '>':
|
|
if (dwState != inTagClose)
|
|
{
|
|
SetSPInfoState(inTagClose, &dwState, &dwStatePrev, &fSave);
|
|
ASSERT(cTagClose == 0);
|
|
}
|
|
cTagClose++;
|
|
break;
|
|
case '=':
|
|
if (dwState != inTagEq)
|
|
{
|
|
SetSPInfoState(inTagEq, &dwState, &dwStatePrev, &fSave);
|
|
ASSERT(cTagEq == 0);
|
|
}
|
|
cTagEq++;
|
|
break;
|
|
default:
|
|
if (dwState != inChar)
|
|
{
|
|
SetSPInfoState(inChar, &dwState, &dwStatePrev, &fSave);
|
|
ASSERT(cChar == 0);
|
|
}
|
|
cChar++;
|
|
break;
|
|
} /* switch */
|
|
|
|
if (fSave) // save previous run
|
|
{
|
|
if (dwStatePrev != initState)
|
|
{
|
|
switch (dwStatePrev)
|
|
{
|
|
case inSpace:
|
|
*m_pspInfoCur++ = inSpace;
|
|
*m_pspInfoCur++ = cSpace;
|
|
cSpace = 0;
|
|
break;
|
|
case inEOL:
|
|
*m_pspInfoCur++ = inEOL;
|
|
*m_pspInfoCur++ = cEOL;
|
|
cEOL = 0;
|
|
break;
|
|
case inTab:
|
|
*m_pspInfoCur++ = inTab;
|
|
*m_pspInfoCur++ = cTab;
|
|
cTab = 0;
|
|
break;
|
|
case inTagOpen:
|
|
*m_pspInfoCur++ = inTagOpen;
|
|
*m_pspInfoCur++ = cTagOpen;
|
|
cTagOpen = 0;
|
|
break;
|
|
case inTagClose:
|
|
*m_pspInfoCur++ = inTagClose;
|
|
*m_pspInfoCur++ = cTagClose;
|
|
cTagClose = 0;
|
|
break;
|
|
case inTagEq:
|
|
*m_pspInfoCur++ = inTagEq;
|
|
*m_pspInfoCur++ = cTagEq;
|
|
cTagEq = 0;
|
|
break;
|
|
case inChar:
|
|
*m_pspInfoCur++ = inChar;
|
|
*m_pspInfoCur++ = cChar;
|
|
cChar = 0;
|
|
break;
|
|
}
|
|
}
|
|
fSave = FALSE;
|
|
|
|
} // if (fSave)
|
|
|
|
} // for ()
|
|
|
|
*pichStartSP = cbCur; // set for next run
|
|
|
|
//if (pwOld[i] == '\0') // end of file and we wouldn't have saved the last run
|
|
//{
|
|
if (cSpace > 0)
|
|
dwStatePrev = inSpace;
|
|
else if (cEOL > 0)
|
|
dwStatePrev = inEOL;
|
|
else if (cTab > 0)
|
|
dwStatePrev = inTab;
|
|
else if (cTagOpen > 0)
|
|
dwStatePrev = inTagOpen;
|
|
else if (cTagClose > 0)
|
|
dwStatePrev = inTagClose;
|
|
else if (cTagEq > 0)
|
|
dwStatePrev = inTagEq;
|
|
else if (cChar > 0)
|
|
dwStatePrev = inChar;
|
|
else
|
|
dwStatePrev = initState; // handle error case
|
|
|
|
switch (dwStatePrev) // repeat of above, make this into a function
|
|
{
|
|
case inSpace:
|
|
*m_pspInfoCur++ = inSpace;
|
|
*m_pspInfoCur++ = cSpace;
|
|
cSpace = 0;
|
|
break;
|
|
case inEOL:
|
|
*m_pspInfoCur++ = inEOL;
|
|
*m_pspInfoCur++ = cEOL;
|
|
cEOL = 0;
|
|
break;
|
|
case inTab:
|
|
*m_pspInfoCur++ = inTab;
|
|
*m_pspInfoCur++ = cTab;
|
|
cTab = 0;
|
|
break;
|
|
case inTagOpen:
|
|
*m_pspInfoCur++ = inTagOpen;
|
|
*m_pspInfoCur++ = cTagOpen;
|
|
cTagOpen = 0;
|
|
break;
|
|
case inTagClose:
|
|
*m_pspInfoCur++ = inTagClose;
|
|
*m_pspInfoCur++ = cTagClose;
|
|
cTagClose = 0;
|
|
break;
|
|
case inTagEq:
|
|
*m_pspInfoCur++ = inTagEq;
|
|
*m_pspInfoCur++ = cTagEq;
|
|
cTagEq = 0;
|
|
break;
|
|
case inChar:
|
|
*m_pspInfoCur++ = inChar;
|
|
*m_pspInfoCur++ = cChar;
|
|
cChar = 0;
|
|
break;
|
|
} // switch()
|
|
//} // if ()
|
|
|
|
*pspInfoSize = SAFE_PTR_DIFF_TO_WORD(m_pspInfoCur - pspInfoSize);
|
|
|
|
LRet:
|
|
return(hrRet);
|
|
|
|
} /* hrMarkSpacing() */
|
|
|
|
|
|
BOOL
|
|
CTriEditParse::FRestoreSpacing(LPWSTR pwNew, LPWSTR /*pwOld*/, UINT *pichNewCur, INT *pcchwspInfo,
|
|
INT cchRange, INT ichtoktagStart, BOOL fLookback, INT index)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
INT ichNewCur = (INT)*pichNewCur;
|
|
INT cchwspInfo = *pcchwspInfo;
|
|
WORD *pspInfoCur;
|
|
INT cchwspInfoSav, cspInfopair, cchIncDec;
|
|
BOOL fInValue = FALSE;
|
|
|
|
cchwspInfo -= 2; // skip the cch & cchRange
|
|
cchwspInfoSav = cchwspInfo;
|
|
if (fLookback)
|
|
pspInfoCur = m_pspInfoOut + cchwspInfo-1; // cch is actual number of char, so its 1 based
|
|
else
|
|
pspInfoCur = m_pspInfoOut;
|
|
cspInfopair = cchwspInfo / 2; // we assume that cchwspInfo will be even number
|
|
ASSERT(cchwspInfo % 2 == 0);
|
|
cchIncDec = (fLookback)? -1 : 1;
|
|
|
|
while (cspInfopair > 0)//(pspInfoCur >= m_pspInfoOut)
|
|
{
|
|
WORD dwState, count;
|
|
|
|
cspInfopair--; // ready to get next cch & its type
|
|
if (fLookback)
|
|
{
|
|
count = *(WORD *)pspInfoCur--;
|
|
dwState = *(WORD *)pspInfoCur--;
|
|
}
|
|
else
|
|
{
|
|
dwState = *(WORD *)pspInfoCur++;
|
|
count = *(WORD *)pspInfoCur++;
|
|
}
|
|
cchwspInfo -= 2; // previous pair of cch and its type
|
|
|
|
switch (dwState)
|
|
{
|
|
case inChar:
|
|
ASSERT(index == 1 || index == 0 || index == 3);
|
|
if (index == 0 || index == 3)
|
|
{
|
|
int countws = 0; // count of white space chars
|
|
|
|
while ( pwNew[ichtoktagStart-countws] == ' '
|
|
|| pwNew[ichtoktagStart-countws] == '\t'
|
|
|| pwNew[ichtoktagStart-countws] == '\r'
|
|
|| pwNew[ichtoktagStart-countws] == '\n'
|
|
)
|
|
{
|
|
// skip these white space chars. They shouldn't be here
|
|
countws++;
|
|
if (ichtoktagStart-countws <= 0)
|
|
break;
|
|
}
|
|
if (countws > 0)
|
|
{
|
|
if (ichtoktagStart-countws >= 0)
|
|
{
|
|
memcpy((BYTE*)&pwNew[ichtoktagStart-countws+1], (BYTE *)&pwNew[ichtoktagStart+1], (ichNewCur-ichtoktagStart-1)*sizeof(WCHAR));
|
|
ichNewCur -= countws;
|
|
ichtoktagStart -= countws;
|
|
}
|
|
}
|
|
} // if (index == 0 || index == 3)
|
|
|
|
while ( pwNew[ichtoktagStart] != ' '
|
|
&& pwNew[ichtoktagStart] != '\t'
|
|
&& pwNew[ichtoktagStart] != '\n'
|
|
&& pwNew[ichtoktagStart] != '\r'
|
|
&& pwNew[ichtoktagStart] != '<'
|
|
&& pwNew[ichtoktagStart] != '>'
|
|
&& pwNew[ichtoktagStart] != '='
|
|
&& (ichNewCur > ichtoktagStart)
|
|
&& count > 0
|
|
)
|
|
{
|
|
count--;
|
|
ichtoktagStart += cchIncDec;
|
|
cchRange--;
|
|
if (ichtoktagStart < 0 || cchRange < 0) // boundary condition
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
}
|
|
if (count == 0) // we match the exact chars, we may have more contiguous chars in pwNew
|
|
{
|
|
while ( pwNew[ichtoktagStart] != ' '
|
|
&& pwNew[ichtoktagStart] != '\t'
|
|
&& pwNew[ichtoktagStart] != '\n'
|
|
&& pwNew[ichtoktagStart] != '\r'
|
|
&& pwNew[ichtoktagStart] != '<'
|
|
&& pwNew[ichtoktagStart] != '>'
|
|
&& (pwNew[ichtoktagStart] != '=' || (fInValue /*&& index == 1*/))
|
|
&& (ichNewCur > ichtoktagStart)
|
|
)
|
|
{
|
|
ichtoktagStart += cchIncDec;
|
|
cchRange--;
|
|
if (ichtoktagStart < 0 || cchRange < 0) // boundary condition
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case inTagOpen:
|
|
case inTagClose:
|
|
case inTagEq:
|
|
// make sure that we have atleast count number of spaces at
|
|
// pwNew[ichtoktagStart-count]
|
|
if (pwNew[ichtoktagStart] == '=' /* && index == 1*/)
|
|
fInValue = TRUE;
|
|
else
|
|
fInValue = FALSE;
|
|
while ( (pwNew[ichtoktagStart] == '<' || pwNew[ichtoktagStart] == '>' || pwNew[ichtoktagStart] == '=')
|
|
&& count > 0
|
|
)
|
|
{
|
|
count--;
|
|
ichtoktagStart += cchIncDec;
|
|
cchRange--;
|
|
if (ichtoktagStart < 0 || cchRange < 0) // boundary condition
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case inSpace:
|
|
// make sure that we have atleast count number of spaces at
|
|
// pwNew[ichtoktagStart-count]
|
|
fInValue = FALSE;
|
|
while (pwNew[ichtoktagStart] == ' ' && count > 0)
|
|
{
|
|
count--;
|
|
ichtoktagStart += cchIncDec;
|
|
cchRange--;
|
|
if (ichtoktagStart < 0 || cchRange < 0) // boundary condition
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
}
|
|
if (count == 0) // we matched exact spaces, we may have more spaces in pwNew
|
|
{
|
|
if (fLookback)
|
|
{
|
|
INT countT = 0;
|
|
//INT ichtoktagStartSav = ichtoktagStart;
|
|
|
|
if (cspInfopair == 0)
|
|
break;
|
|
|
|
ASSERT(index == 0 || index == 3);
|
|
// REMOVE EXTRA SPACES here.
|
|
while (pwNew[ichtoktagStart-countT] == ' ')
|
|
countT++;
|
|
if (countT > 0)
|
|
{
|
|
if (ichNewCur-(ichtoktagStart) > 0)
|
|
{
|
|
memmove((BYTE *)(pwNew+ichtoktagStart-countT+1),
|
|
(BYTE *)(pwNew+ichtoktagStart),
|
|
(ichNewCur-(ichtoktagStart))*sizeof(WCHAR));
|
|
ichNewCur -= (countT-1);
|
|
ichtoktagStart -= (countT-1);
|
|
while (countT > 1)
|
|
{
|
|
pwNew[ichNewCur+countT-2] = '\0';
|
|
countT--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!fLookback)
|
|
{
|
|
INT countT = -1;
|
|
|
|
ASSERT(index == 1 || index == 2);
|
|
// look ahead into pspInfoCur to see what the next parameters should be
|
|
if ((index == 1) && (*(WORD *)pspInfoCur == inChar))
|
|
{
|
|
while ( pwNew[ichtoktagStart] == ' '
|
|
|| pwNew[ichtoktagStart] == '\r'
|
|
|| pwNew[ichtoktagStart] == '\n'
|
|
|| pwNew[ichtoktagStart] == '\t'
|
|
)
|
|
{
|
|
countT++;
|
|
ichtoktagStart += cchIncDec;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (pwNew[ichtoktagStart] == ' ')
|
|
{
|
|
countT++;
|
|
ichtoktagStart += cchIncDec;
|
|
}
|
|
}
|
|
if (countT > 0)
|
|
{
|
|
if (ichNewCur-(ichtoktagStart+1) > 0)
|
|
{
|
|
memmove((BYTE *)(pwNew+ichtoktagStart-countT-1),
|
|
(BYTE *)(pwNew+ichtoktagStart),
|
|
(ichNewCur-ichtoktagStart)*sizeof(WCHAR));
|
|
ichNewCur -= (countT+1);
|
|
ichtoktagStart -= (countT+1);
|
|
while (countT >= 0)
|
|
{
|
|
pwNew[ichNewCur+countT] = '\0';
|
|
countT--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fLookback)
|
|
{
|
|
ASSERT(index == 0 || index == 3);
|
|
if ((int)(ichNewCur-ichtoktagStart-1) >= 0)
|
|
{
|
|
// insert spaces after ichtoktagStart
|
|
memmove((BYTE *)&pwNew[ichtoktagStart+1+count],
|
|
(BYTE *)&pwNew[ichtoktagStart+1],
|
|
(ichNewCur-ichtoktagStart-1)*sizeof(WCHAR));
|
|
ichNewCur += count;
|
|
//ichtoktagStart++;
|
|
while (count > 0)
|
|
{
|
|
pwNew[ichtoktagStart+count] = ' ';
|
|
count--;
|
|
}
|
|
//ichtoktagStart--; // compensate
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(index == 1 || index == 2);
|
|
if ((int)(ichNewCur-ichtoktagStart) >= 0)
|
|
{
|
|
int countT = count;
|
|
|
|
// insert spaces at ichtoktagStart and set ichtoktagStart after last space
|
|
memmove((BYTE *)&pwNew[ichtoktagStart+count],
|
|
(BYTE *)&pwNew[ichtoktagStart],
|
|
(ichNewCur-ichtoktagStart)*sizeof(WCHAR));
|
|
ichNewCur += count;
|
|
while (count > 0)
|
|
{
|
|
ASSERT((INT)(ichtoktagStart+count-1) >= 0);
|
|
pwNew[ichtoktagStart+count-1] = ' ';
|
|
count--;
|
|
}
|
|
ichtoktagStart += countT;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case inEOL:
|
|
// make sure that we have atleast count number of EOLs at
|
|
// pwNew[ichtoktagStart-count]
|
|
// if fLookback, then we get '\n', else we get '\r'
|
|
fInValue = FALSE;
|
|
while ((pwNew[ichtoktagStart] == '\n' || pwNew[ichtoktagStart] == '\r') && count > 0)
|
|
{
|
|
count--;
|
|
cchRange -= 2;
|
|
ichtoktagStart += cchIncDec; // assume '\r' or '\n'
|
|
ichtoktagStart += cchIncDec; // assume '\r' or '\n'
|
|
if (ichtoktagStart < 0 || cchRange < 0) // boundary condition
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
|
|
}
|
|
if (count == 0) // we matched exact EOLs, we may have more EOLs in pwNew
|
|
{
|
|
if (fLookback)
|
|
{
|
|
INT countT = 0;
|
|
|
|
ASSERT(index == 0 || index == 3);
|
|
// REMOVE EXTRA EOLs here.
|
|
while ( pwNew[ichtoktagStart-countT] == '\r'
|
|
|| pwNew[ichtoktagStart-countT] == '\n'
|
|
)
|
|
countT++;
|
|
if (countT > 0)
|
|
{
|
|
if (ichNewCur-(ichtoktagStart) > 0)
|
|
{
|
|
memmove((BYTE *)(pwNew+ichtoktagStart-countT+1),
|
|
(BYTE *)(pwNew+ichtoktagStart),
|
|
(ichNewCur-(ichtoktagStart))*sizeof(WCHAR));
|
|
ichNewCur -= (countT-1);
|
|
ichtoktagStart -= (countT-1);
|
|
while (countT > 1)
|
|
{
|
|
pwNew[ichNewCur+countT-2] = '\0';
|
|
countT--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!fLookback)
|
|
{
|
|
INT countT = 0;
|
|
|
|
ASSERT(index == 1 || index == 2);
|
|
// REMOVE EXTRA EOLS here.
|
|
|
|
// look ahead into pspInfoCur to see what the next parameters should be
|
|
if ((index == 1) && (*(WORD *)pspInfoCur == inChar))
|
|
{
|
|
while ( pwNew[ichtoktagStart] == ' '
|
|
|| pwNew[ichtoktagStart] == '\r'
|
|
|| pwNew[ichtoktagStart] == '\n'
|
|
|| pwNew[ichtoktagStart] == '\t'
|
|
)
|
|
{
|
|
countT++;
|
|
ichtoktagStart += cchIncDec;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ( pwNew[ichtoktagStart] == '\r'
|
|
|| pwNew[ichtoktagStart] == '\n'
|
|
)
|
|
{
|
|
countT++;
|
|
ichtoktagStart += cchIncDec;
|
|
}
|
|
}
|
|
|
|
//ASSERT(countT % 2 == 0); // assert that countT is an even number, because we should find \r & \n always in pair
|
|
if (countT > 0)
|
|
{
|
|
if (ichNewCur-(ichtoktagStart+1) > 0)
|
|
{
|
|
memmove((BYTE *)(pwNew+ichtoktagStart-countT),
|
|
(BYTE *)(pwNew+ichtoktagStart),
|
|
(ichNewCur-ichtoktagStart)*sizeof(WCHAR));
|
|
ichNewCur -= (countT);
|
|
ichtoktagStart -= (countT);
|
|
while (countT >= 0)
|
|
{
|
|
pwNew[ichNewCur+countT] = '\0';
|
|
countT--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fLookback)
|
|
{
|
|
INT i;
|
|
|
|
ASSERT(index == 0 || index == 3);
|
|
if ((int)(ichNewCur-ichtoktagStart-1) >= 0)
|
|
{
|
|
// insert EOLs after ichtoktagStart
|
|
memmove((BYTE *)&pwNew[ichtoktagStart+1+count*2],
|
|
(BYTE *)&pwNew[ichtoktagStart+1],
|
|
(ichNewCur-ichtoktagStart-1)*sizeof(WCHAR));
|
|
ichNewCur += count*2;
|
|
count *= 2;
|
|
ichtoktagStart++;
|
|
for (i = 0; i < count; i+=2)
|
|
{
|
|
pwNew[ichtoktagStart+i] = '\r';
|
|
pwNew[ichtoktagStart+i+1] = '\n';
|
|
}
|
|
ichtoktagStart--; // compensate for prior increment
|
|
}
|
|
}
|
|
else
|
|
{
|
|
INT i;
|
|
|
|
ASSERT(index == 1 || index == 2);
|
|
// insert spaces at ichtoktagStart and set ichtoktagStart after last space
|
|
if ((int)(ichNewCur-ichtoktagStart) >= 0)
|
|
{
|
|
memmove((BYTE *)&pwNew[ichtoktagStart+count*2],
|
|
(BYTE *)&pwNew[ichtoktagStart],
|
|
(ichNewCur-ichtoktagStart)*sizeof(WCHAR));
|
|
ichNewCur += count*2;
|
|
count *= 2;
|
|
for (i=0; i < count; i+=2)
|
|
{
|
|
pwNew[ichtoktagStart+i] = '\r';
|
|
pwNew[ichtoktagStart+i+1] = '\n';
|
|
}
|
|
ichtoktagStart += count;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
case inTab:
|
|
// make sure that we have atleast count number of spaces at
|
|
// pwNew[ichtoktagStart-count]
|
|
fInValue = FALSE;
|
|
while (pwNew[ichtoktagStart] == '\t' && count > 0)
|
|
{
|
|
count--;
|
|
ichtoktagStart += cchIncDec;
|
|
cchRange--;
|
|
if (ichtoktagStart < 0 || cchRange < 0) // boundary condition
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
}
|
|
if (count == 0) // we matched exact spaces, we may have more tabs in pwNew
|
|
{
|
|
// skip extra spaces in pwNew, if we had more spaces in pwNew than count
|
|
while (pwNew[ichtoktagStart] == '\t')
|
|
{
|
|
ichtoktagStart += cchIncDec;
|
|
cchRange--;
|
|
if (ichtoktagStart < 0 || cchRange < 0) // boundary condition
|
|
{
|
|
fRet = FALSE;
|
|
goto LRet;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
INT ichSav = ichtoktagStart;
|
|
INT i;
|
|
|
|
ASSERT(count > 0);
|
|
// insert these many extra tabs at pwNew[ichtoktagStart] and increment ichNewCur
|
|
if (fLookback)
|
|
ichtoktagStart++;
|
|
if (ichNewCur-ichtoktagStart > 0)
|
|
{
|
|
memmove((BYTE *)(pwNew+ichtoktagStart+count),
|
|
(BYTE *)(pwNew+ichtoktagStart),
|
|
(ichNewCur-ichtoktagStart)*sizeof(WCHAR));
|
|
}
|
|
for (i = 0; i < count; i++)
|
|
pwNew[ichtoktagStart+i] = '\t';
|
|
|
|
ichNewCur += count;
|
|
if (fLookback)
|
|
ichtoktagStart = ichSav;
|
|
else
|
|
ichtoktagStart += count;
|
|
}
|
|
break;
|
|
} // switch (dwState)
|
|
|
|
} // while ()
|
|
if ( cspInfopair == 0
|
|
&& pwNew[ichNewCur-1] == '>'
|
|
&& ichNewCur > ichtoktagStart
|
|
&& !fLookback
|
|
&& index == 1)
|
|
{
|
|
INT countT = 0;
|
|
|
|
ASSERT(cchIncDec == 1);
|
|
// This means that we may have extra spaces & EOLs from ichtoktagStart to '>'
|
|
// REMOVE EXTRA SPACES EOLS here.
|
|
while ( pwNew[ichtoktagStart+countT] == ' '
|
|
|| pwNew[ichtoktagStart+countT] == '\r'
|
|
|| pwNew[ichtoktagStart+countT] == '\n'
|
|
|| pwNew[ichtoktagStart+countT] == '\t'
|
|
)
|
|
{
|
|
countT++;
|
|
}
|
|
if (countT > 0 && pwNew[ichtoktagStart+countT] == '>')
|
|
{
|
|
if (ichNewCur-(ichtoktagStart+1) > 0)
|
|
{
|
|
memmove((BYTE *)(pwNew+ichtoktagStart),
|
|
(BYTE *)(pwNew+ichtoktagStart+countT),
|
|
(ichNewCur-(ichtoktagStart+countT))*sizeof(WCHAR));
|
|
ichNewCur -= (countT);
|
|
ichtoktagStart -= (countT);
|
|
while (countT > 0)
|
|
{
|
|
pwNew[ichNewCur+countT-1] = '\0';
|
|
countT--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Next time around - we can do the following...
|
|
// look back from ichtoktagStart and check if we have any spaces/eols.
|
|
// if we do, there is a likelihood that these shouldn't have been there.
|
|
// Here is how they get there - If we had spaces between the parameter and
|
|
// the '=' and its value, those spacves are removed by Trident. We then go
|
|
// in and add those spaces at the end rather than at proper place because
|
|
// we don't break up the text. e.g. "width = 23" --> "width=23".
|
|
// Now, because we don't break that text, we end up inserting these spaces
|
|
// at the end. Lets remove them.
|
|
}
|
|
else if ( cspInfopair == 0
|
|
&& fLookback
|
|
&& (index == 0 || index == 3)) /* VID6 - bug 18207 */
|
|
{
|
|
INT countT = 0;
|
|
|
|
ASSERT(cchIncDec == -1);
|
|
// This means that we may have extra spaces & EOLs before ichtoktagStart to '>'
|
|
// REMOVE EXTRA SPACES EOLS here.
|
|
while ( pwNew[ichtoktagStart-countT] == ' '
|
|
|| pwNew[ichtoktagStart-countT] == '\r'
|
|
|| pwNew[ichtoktagStart-countT] == '\n'
|
|
|| pwNew[ichtoktagStart-countT] == '\t'
|
|
)
|
|
{
|
|
countT++;
|
|
}
|
|
if (countT > 0 && pwNew[ichtoktagStart-countT] == '>')
|
|
{
|
|
if (ichNewCur-(ichtoktagStart+1) > 0)
|
|
{
|
|
memmove((BYTE *)(pwNew+ichtoktagStart-countT+1),
|
|
(BYTE *)(pwNew+ichtoktagStart+1),
|
|
(ichNewCur-(ichtoktagStart+1))*sizeof(WCHAR));
|
|
ichNewCur -= countT;
|
|
ichtoktagStart -= (countT); // this doesn't matter because we will exit after this
|
|
while (countT > 0)
|
|
{
|
|
pwNew[ichNewCur+countT-1] = '\0';
|
|
countT--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LRet:
|
|
m_pspInfoOut = m_pspInfoOut + cchwspInfoSav;
|
|
*pcchwspInfo = cchwspInfo;
|
|
*pichNewCur = ichNewCur;
|
|
return(fRet);
|
|
}
|