windows-nt/Source/XPSP1/NT/shell/ext/mlang/attrstr.cpp
2020-09-26 16:20:57 +08:00

624 lines
16 KiB
C++

// AttrStr.cpp : Implementation of CMLStrAttrStrCommonAttrStrCommon
#include "private.h"
#ifdef NEWMLSTR
#include "attrstr.h"
#include "mlsbwalk.h"
/////////////////////////////////////////////////////////////////////////////
// CMLStrAttrStrCommon
CMLStrAttrStrCommon::CMLStrAttrStrCommon(void) :
m_pMLStrBufW(NULL),
m_pMLStrBufA(NULL),
m_lBufFlags(0),
m_cchBuf(0),
m_locale(0),
m_LockInfo(this)
{
m_dwThreadID = ::GetCurrentThreadId();
}
CMLStrAttrStrCommon::~CMLStrAttrStrCommon(void)
{
if (m_pMLStrBufW)
m_pMLStrBufW->Release();
if (m_pMLStrBufA)
m_pMLStrBufA->Release();
}
HRESULT CMLStrAttrStrCommon::SetStrBufCommon(void* pMLStrX, long lDestPos, long lDestLen, UINT uCodePage, IMLangStringBufW* pSrcBufW, IMLangStringBufA* pSrcBufA, long* pcchActual, long* plActualLen)
{
ASSERT_THIS;
ASSERT_READ_PTR_OR_NULL(pSrcBufW);
ASSERT_READ_PTR_OR_NULL(pSrcBufA);
ASSERT(!pSrcBufW || !pSrcBufA); // Either one or both should be NULL
ASSERT_WRITE_PTR_OR_NULL(pcchActual);
ASSERT_WRITE_PTR_OR_NULL(plActualLen);
HRESULT hr = CheckThread();
CLock Lock(TRUE, this, hr);
long lBufFlags = 0; // '= 0' for in case of both of pSrcBufW and pSrcBufA are NULL
long cchBuf = 0;
long cchDestPos;
long cchDestLen;
long lActualLen = 0;
if (SUCCEEDED(hr) &&
(!pSrcBufW || SUCCEEDED(hr = pSrcBufW->GetStatus(&lBufFlags, &cchBuf))) &&
(!pSrcBufA || SUCCEEDED(hr = pSrcBufA->GetStatus(&lBufFlags, &cchBuf))) &&
SUCCEEDED(hr = RegularizePosLen(&lDestPos, &lDestLen)) &&
SUCCEEDED(hr = GetCCh(0, lDestPos, &cchDestPos)) &&
SUCCEEDED(hr = GetCCh(cchDestPos, lDestLen, &cchDestLen)))
{
if (!cchDestPos && cchDestLen == GetBufCCh()) // Replacing entire string
{
IMLangStringBufW* const pOldBufW = GetMLStrBufW();
IMLangStringBufA* const pOldBufA = GetMLStrBufA();
if (pOldBufW)
pOldBufW->Release();
else if (pOldBufA)
pOldBufA->Release();
if (pSrcBufW)
pSrcBufW->AddRef();
else if (pSrcBufA)
pSrcBufA->AddRef();
SetMLStrBufW(pSrcBufW);
SetMLStrBufA(pSrcBufA);
SetCodePage(uCodePage);
SetBufFlags(lBufFlags);
SetBufCCh(cchBuf);
if (plActualLen)
hr = GetLen(0, GetBufCCh(), &lActualLen);
}
else
{
if (pSrcBufW)
{
CMLStrBufWalkW BufWalk(pSrcBufW, 0, cchBuf, (pcchActual || plActualLen));
while (BufWalk.Lock(hr))
{
long cchSet;
long lSetLen;
hr = ((IMLangStringWStr*)pMLStrX)->SetWStr(lDestPos, lDestLen, BufWalk.GetStr(), BufWalk.GetCCh(), &cchSet, (plActualLen) ? &lSetLen : NULL);
lActualLen += lSetLen;
BufWalk.Unlock(hr, cchSet);
}
cchBuf = BufWalk.GetDoneCCh();
pSrcBufW->Release();
}
else if (pSrcBufA && pMLStrX)
{
CMLStrBufWalkA BufWalk(pSrcBufA, 0, cchBuf, (pcchActual || plActualLen));
while (BufWalk.Lock(hr))
{
long cchSet;
long lSetLen;
hr = ((IMLangStringAStr*)pMLStrX)->SetAStr(lDestPos, lDestLen, uCodePage, BufWalk.GetStr(), BufWalk.GetCCh(), &cchSet, (plActualLen) ? &lSetLen : NULL);
lActualLen += lSetLen;
BufWalk.Unlock(hr, cchSet);
}
cchBuf = BufWalk.GetDoneCCh();
pSrcBufA->Release();
}
else
{
hr = GetMLStrAttr()->SetMLStr(lDestPos, lDestLen, NULL, 0, 0);
}
}
}
if (SUCCEEDED(hr))
{
if (pcchActual)
*pcchActual = cchBuf;
if (plActualLen)
*plActualLen = lActualLen;
}
else
{
if (pcchActual)
*pcchActual = 0;
if (plActualLen)
*plActualLen = 0;
}
return hr;
}
HRESULT CMLStrAttrStrCommon::UnlockWStrDirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
{
HRESULT hr;
IMLangStringBufW* const pMLStrBufW = GetMLStrBufW();
const long cchLockLen = GetLockInfo()->GetCChLen(pKey);
if (SUCCEEDED(hr = pMLStrBufW->UnlockBuf((WCHAR*)pszSrc, 0, cchSrc)) &&
(GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE))
{
if (cchSrc < cchLockLen)
{
if (SUCCEEDED(hr = pMLStrBufW->Delete(GetLockInfo()->GetCChPos(pKey) + cchSrc, cchLockLen - cchSrc)))
SetBufCCh(GetBufCCh() - (cchLockLen - cchSrc));
}
if (SUCCEEDED(hr) && plActualLen)
hr = CalcLenW((WCHAR*)pszSrc, cchSrc, plActualLen);
if (pcchActual)
*pcchActual = cchSrc;
}
return hr;
}
HRESULT CMLStrAttrStrCommon::UnlockWStrIndirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
{
HRESULT hr = S_OK;
if (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE)
{
CComQIPtr<IMLStrAttrWStr, &IID_IMLStrAttrWStr> pAttrWStr(GetMLStrAttr());
ASSERT(pAttrWStr);
hr = pAttrWStr->SetWStr(GetLockInfo()->GetPos(pKey), GetLockInfo()->GetLen(pKey), (WCHAR*)pszSrc, cchSrc, pcchActual, plActualLen);
}
ASSIGN_IF_FAILED(hr, MemFree((void*)pszSrc));
return hr;
}
HRESULT CMLStrAttrStrCommon::UnlockAStrDirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
{
HRESULT hr;
IMLangStringBufA* const pMLStrBufA = GetMLStrBufA();
const long cchLockLen = GetLockInfo()->GetCChLen(pKey);
if (SUCCEEDED(hr = pMLStrBufA->UnlockBuf((CHAR*)pszSrc, 0, cchSrc)) &&
(GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE))
{
if (cchSrc < cchLockLen)
{
if (SUCCEEDED(hr = pMLStrBufA->Delete(GetLockInfo()->GetCChPos(pKey) + cchSrc, cchLockLen - cchSrc)))
SetBufCCh(GetBufCCh() - (cchLockLen - cchSrc));
}
if (SUCCEEDED(hr) && plActualLen)
hr = CalcLenA(GetCodePage(), (CHAR*)pszSrc, cchSrc, plActualLen);
if (pcchActual)
*pcchActual = cchSrc;
}
return hr;
}
HRESULT CMLStrAttrStrCommon::UnlockAStrIndirect(void* pKey, const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
{
HRESULT hr = S_OK;
if (GetLockInfo()->GetFlags(pKey) & MLSTR_WRITE)
{
CComQIPtr<IMLStrAttrAStr, &IID_IMLStrAttrAStr> pAttrAStr(GetMLStrAttr());
ASSERT(pAttrAStr);
hr = pAttrAStr->SetAStr(GetLockInfo()->GetPos(pKey), GetLockInfo()->GetLen(pKey), GetLockInfo()->GetCodePage(pKey), (CHAR*)pszSrc, cchSrc, pcchActual, plActualLen);
}
ASSIGN_IF_FAILED(hr, MemFree((void*)pszSrc));
return hr;
}
HRESULT CMLStrAttrStrCommon::UnlockStrCommon(const void* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
{
HRESULT hr = CheckThread();
void* pLockKey;
long lSrcLen;
if (SUCCEEDED(hr))
hr = GetLockInfo()->Find(pszSrc, cchSrc, &pLockKey);
if (SUCCEEDED(hr))
hr = GetLockInfo()->Unlock(pLockKey, pszSrc, cchSrc, (pcchActual) ? &cchSrc : NULL, (plActualLen) ? &lSrcLen : NULL);
if (SUCCEEDED(hr))
{
if (pcchActual)
*pcchActual = cchSrc;
if (plActualLen)
*plActualLen = lSrcLen;
}
else
{
if (pcchActual)
*pcchActual = 0;
if (plActualLen)
*plActualLen = 0;
}
return hr;
}
HRESULT CMLStrAttrStrCommon::PrepareMLStrBuf(void)
{
if (GetMLStrBufW() || GetMLStrBufA())
return S_OK;
IMLangStringBufW* pBuf = new CMLStrAttrStrCommon::CMLStrBufStandardW;
if (pBuf)
{
SetMLStrBufW(pBuf);
return S_OK;
}
else
{
return E_OUTOFMEMORY;
}
}
HRESULT CMLStrAttrStrCommon::RegularizePosLen(long* plPos, long* plLen)
{
HRESULT hr;
long lStrLen;
if (SUCCEEDED(hr = GetLen(0, GetBufCCh(), &lStrLen)))
hr = ::RegularizePosLen(lStrLen, plPos, plLen);
return hr;
}
HRESULT CMLStrAttrStrCommon::GetCCh(long cchOffset, long lLen, long* pcchLen)
{
if (GetMLStrBufW())
{
if (pcchLen)
*pcchLen = lLen; // The number of characters is equal to the length
return S_OK;
}
else if (GetMLStrBufA())
{
HRESULT hr = S_OK;
CMLStrBufWalkA BufWalk(GetMLStrBufA(), cchOffset, GetBufCCh() - cchOffset);
while (lLen > 0 && BufWalk.Lock(hr))
{
for (LPCSTR pszTemp = BufWalk.GetStr(); lLen > 0 && *pszTemp; lLen--)
pszTemp = ::CharNextExA((WORD)GetCodePage(), pszTemp, 0);
if (!*pszTemp)
lLen = 0; // String terminated
BufWalk.Unlock(hr);
}
if (pcchLen)
{
if (SUCCEEDED(hr))
*pcchLen = BufWalk.GetDoneCCh();
else
*pcchLen = 0;
}
return hr;
}
else
{
if (pcchLen)
*pcchLen = 0; // No string
return S_OK;
}
}
HRESULT CMLStrAttrStrCommon::GetLen(long cchOffset, long cchLen, long* plLen)
{
if (GetMLStrBufW())
{
if (plLen)
*plLen = cchLen; // The length is equal to the number of characters
return S_OK;
}
else if (GetMLStrBufA())
{
HRESULT hr = S_OK;
long lDoneLen = 0;
CMLStrBufWalkA BufWalk(GetMLStrBufA(), cchOffset, cchLen);
while (BufWalk.Lock(hr))
{
long lTempLen;
hr = CalcLenA(GetCodePage(), BufWalk.GetStr(), BufWalk.GetCCh(), &lTempLen);
if (hr == S_FALSE)
cchLen = 0; // String terminated
lDoneLen += lTempLen;
BufWalk.Unlock(hr);
}
if (plLen)
{
if (SUCCEEDED(hr))
*plLen = lDoneLen;
else
*plLen = 0;
}
return hr;
}
else
{
if (plLen)
*plLen = 0; // No string
return S_OK;
}
}
HRESULT CMLStrAttrStrCommon::CalcLenA(UINT uCodePage, const CHAR* psz, long cchLen, long* plLen)
{
long lLen = 0;
const CHAR* const pszEnd = psz + cchLen;
for (; psz < pszEnd && *psz; lLen++)
{
const CHAR* const pszNew = ::CharNextExA((WORD)uCodePage, psz, 0);
if (pszNew > pszEnd) // Overrun out of buffer
break;
psz = pszNew;
}
if (plLen)
*plLen = lLen;
if (*psz)
return S_OK;
else
return S_FALSE;
}
HRESULT CMLStrAttrStrCommon::CalcCChA(UINT uCodePage, const CHAR* psz, long lLen, long* pcchLen)
{
const CHAR* const pszStart = psz;
for (; lLen > 0 && *psz; lLen--)
psz = ::CharNextExA((WORD)uCodePage, psz, 0);
if (pcchLen)
*pcchLen = psz - pszStart;
if (*psz)
return S_OK;
else
return S_FALSE;
}
HRESULT CMLStrAttrStrCommon::ConvAStrToWStr(UINT uCodePage, const CHAR* pszSrc, long cchSrc, WCHAR* pszDest, long cchDest, long* pcchActualA, long* pcchActualW, long* plActualLen)
{
HRESULT hr = S_OK;
long lWrittenLen;
long cchWrittenA;
long cchWrittenW = ::MultiByteToWideChar(uCodePage, 0, pszSrc, cchSrc, pszDest, (pszDest) ? cchDest : 0);
if (!cchWrittenW)
hr = E_FAIL; // NLS failed
if ((pcchActualA || plActualLen) && SUCCEEDED(hr))
hr = CalcLenW(pszDest, cchWrittenW, &lWrittenLen); // BOGUS: pszDest may be NULL
if (pcchActualA && SUCCEEDED(hr))
hr = CalcCChA(uCodePage, pszSrc, lWrittenLen, &cchWrittenA);
if (SUCCEEDED(hr))
{
if (pcchActualA)
*pcchActualA = cchWrittenA;
if (pcchActualW)
*pcchActualW = cchWrittenW;
if (plActualLen)
*plActualLen = lWrittenLen;
}
else
{
if (pcchActualA)
*pcchActualA = 0;
if (pcchActualW)
*pcchActualW = 0;
if (plActualLen)
*plActualLen = 0;
}
return hr;
}
HRESULT CMLStrAttrStrCommon::ConvWStrToAStr(BOOL fCanStopAtMiddle, UINT uCodePage, const WCHAR* pszSrc, long cchSrc, CHAR* pszDest, long cchDest, long* pcchActualA, long* pcchActualW, long* plActualLen)
{
HRESULT hr = S_OK;
long lWrittenLen;
long cchWrittenW;
long cchWrittenA = ::WideCharToMultiByte(uCodePage, (fCanStopAtMiddle) ? 0 : WC_DEFAULTCHAR, pszSrc, cchSrc, pszDest, (pszDest) ? cchDest : 0, NULL, NULL);
if (!cchWrittenA)
hr = E_FAIL; // NLS failed
if ((pcchActualW || plActualLen) && SUCCEEDED(hr))
{
if (pszDest)
hr = CalcLenA(uCodePage, pszDest, cchWrittenA, &lWrittenLen);
else
hr = E_NOTIMPL; // Can't retrieve pcchActualW and plActualLen
}
if (pcchActualW && SUCCEEDED(hr))
hr = CalcCChW(pszSrc, lWrittenLen, &cchWrittenW);
if (SUCCEEDED(hr))
{
if (pcchActualA)
*pcchActualA = cchWrittenA;
if (pcchActualW)
*pcchActualW = cchWrittenW;
if (plActualLen)
*plActualLen = lWrittenLen;
}
else
{
if (pcchActualA)
*pcchActualA = 0;
if (pcchActualW)
*pcchActualW = 0;
if (plActualLen)
*plActualLen = 0;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CMLStrAttrStrCommon::CLockInfo
HRESULT CMLStrAttrStrCommon::CLockInfo::UnlockAll(void)
{
if (m_pLockArray)
{
for (int n = 0; n < MAX_LOCK_COUNT; n++)
{
if (m_pLockArray[n].m_psz)
Unlock(&m_pLockArray[n], m_pLockArray[n].m_psz, m_pLockArray[n].m_cchLen, NULL, NULL);
}
}
return S_OK;
}
HRESULT CMLStrAttrStrCommon::CLockInfo::Lock(PFNUNLOCKPROC pfnUnlockProc, long lFlags, UINT uCodePage, void* psz, long lPos, long lLen, long cchPos, long cchLen)
{
HRESULT hr = S_OK;
int nIndex;
if (!m_pLockArray)
{
m_pLockArray = new CLockInfoEntry[MAX_LOCK_COUNT];
if (m_pLockArray)
{
for (nIndex = 0; nIndex < MAX_LOCK_COUNT; nIndex++)
m_pLockArray[nIndex].m_psz = NULL;
}
else
{
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr))
{
for (nIndex = 0; nIndex < MAX_LOCK_COUNT; nIndex++)
{
if (!m_pLockArray[nIndex].m_psz)
break;
}
if (nIndex >= MAX_LOCK_COUNT)
hr = MLSTR_E_TOOMANYNESTOFLOCK;
}
if (SUCCEEDED(hr))
{
m_pLockArray[nIndex].m_psz = psz;
m_pLockArray[nIndex].m_pfnUnlockProc = pfnUnlockProc;
m_pLockArray[nIndex].m_lFlags = lFlags;
m_pLockArray[nIndex].m_uCodePage = uCodePage;
m_pLockArray[nIndex].m_lPos = lPos;
m_pLockArray[nIndex].m_lLen = lLen;
m_pLockArray[nIndex].m_cchPos = cchPos;
m_pLockArray[nIndex].m_cchLen = cchLen;
}
return hr;
}
HRESULT CMLStrAttrStrCommon::CLockInfo::Find(const void* psz, long, void** ppKey)
{
HRESULT hr = S_OK;
int nIndex;
if (m_pLockArray)
{
for (nIndex = 0; nIndex < MAX_LOCK_COUNT; nIndex++)
{
if (psz == m_pLockArray[nIndex].m_psz)
break;
}
}
if (!m_pLockArray || nIndex >= MAX_LOCK_COUNT)
hr = E_INVALIDARG;
if (ppKey)
{
if (SUCCEEDED(hr))
*ppKey = &m_pLockArray[nIndex];
else
*ppKey = NULL;
}
return hr;
}
HRESULT CMLStrAttrStrCommon::CLockInfo::Unlock(void* pKey, const void* psz, long cch, long* pcchActual, long* plActualLen)
{
CLockInfoEntry* const pEntry = (CLockInfoEntry*)pKey;
HRESULT hr;
if (!(pEntry->m_lFlags & MLSTR_WRITE))
{
cch = 0;
if (plActualLen)
*plActualLen = 0;
}
hr = (m_pCommon->*(pEntry->m_pfnUnlockProc))(pKey, psz, cch, pcchActual, plActualLen);
if (SUCCEEDED(hr))
hr = EndLock(pEntry->m_lFlags & MLSTR_WRITE);
pEntry->m_psz = NULL; // Remove from lock array anyway
if (FAILED(hr))
{
if (pcchActual)
*pcchActual = 0;
if (plActualLen)
*plActualLen = 0;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CMLStrAttrStrCommon::CMLStrBufStandardW
long CMLStrAttrStrCommon::CMLStrBufStandardW::RoundBufSize(long cchStr)
{
for (int n = 8; n < 12; n++)
{
if (cchStr < (1L << n))
break;
}
const long cchTick = (1L << (n - 4));
return (cchStr + cchTick - 1) / cchTick * cchTick;
}
#endif // NEWMLSTR