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

537 lines
15 KiB
C++

// AttrStrW.cpp : Implementation of CMLStrAttrWStr
#include "private.h"
#ifdef NEWMLSTR
#include "attrstrw.h"
#include "mlsbwalk.h"
/////////////////////////////////////////////////////////////////////////////
// CMLStrAttrWStr
CMLStrAttrWStr::CMLStrAttrWStr(void) :
m_pMLStr(NULL)
{
}
CMLStrAttrWStr::~CMLStrAttrWStr(void)
{
VERIFY(SetClient(NULL)); // Clean m_pMLStr
}
STDMETHODIMP CMLStrAttrWStr::SetClient(IUnknown* pUnk)
{
ASSERT_THIS;
ASSERT_READ_PTR_OR_NULL(pUnk);
HRESULT hr = S_OK;
// Release old client
IMLangString* const pMLStr = m_pMLStr;
if (pMLStr && SUCCEEDED(hr = StartEndConnectionMLStr(pMLStr, FALSE))) // End connection to MLStr
{
pMLStr->Release();
m_pMLStr = NULL;
}
// Set new client
if (SUCCEEDED(hr) && pUnk) // pUnk is given
{
ASSERT(!m_pMLStr);
if (SUCCEEDED(hr = pUnk->QueryInterface(IID_IMLangString, (void**)&m_pMLStr)))
{
ASSERT_READ_PTR(m_pMLStr);
if (FAILED(hr = StartEndConnectionMLStr(pUnk, TRUE))) // Start connection to MLStr
{
m_pMLStr->Release();
m_pMLStr = NULL;
}
}
}
return hr;
}
HRESULT CMLStrAttrWStr::StartEndConnectionMLStr(IUnknown* const pUnk, BOOL fStart)
{
ASSERT_THIS;
ASSERT_READ_PTR(pUnk);
HRESULT hr;
IConnectionPointContainer* pCPC;
if (SUCCEEDED(hr = pUnk->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC)))
{
ASSERT_READ_PTR(pCPC);
IConnectionPoint* pCP;
if (SUCCEEDED(hr = pCPC->FindConnectionPoint(IID_IMLangStringNotifySink, &pCP)))
{
ASSERT_READ_PTR(pCP);
if (fStart)
hr = pCP->Advise((IMLStrAttr*)this, &m_dwMLStrCookie);
else
hr = pCP->Unadvise(m_dwMLStrCookie);
pCP->Release();
}
pCPC->Release();
}
return hr;
}
STDMETHODIMP CMLStrAttrWStr::GetClient(IUnknown** ppUnk)
{
ASSERT_THIS;
ASSERT_WRITE_PTR_OR_NULL(ppUnk);
if (ppUnk)
{
IUnknown* const pUnk = m_pMLStr;
*ppUnk = pUnk;
if (pUnk)
pUnk->AddRef();
}
return S_OK;
}
STDMETHODIMP CMLStrAttrWStr::QueryAttr(REFIID riid, LPARAM lParam, IUnknown** ppUnk, long* lConf)
{
return E_NOTIMPL; // CMLStrAttrWStr::QueryAttr()
}
STDMETHODIMP CMLStrAttrWStr::GetAttrInterface(IID* pIID, LPARAM* plParam)
{
return E_NOTIMPL; // CMLStrAttrWStr::GetAttrInterface()
}
STDMETHODIMP CMLStrAttrWStr::SetMLStr(long lDestPos, long lDestLen, IUnknown* pSrcMLStr, long lSrcPos, long lSrcLen)
{
return E_NOTIMPL; // CMLStrAttrWStr::SetMLStr()
}
STDMETHODIMP CMLStrAttrWStr::SetWStr(long lDestPos, long lDestLen, const WCHAR* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
{
ASSERT_THIS;
ASSERT_READ_BLOCK(pszSrc, cchSrc);
ASSERT_WRITE_PTR_OR_NULL(pcchActual);
ASSERT_WRITE_PTR_OR_NULL(plActualLen);
HRESULT hr = CheckThread();
CLock Lock(TRUE, this, hr);
long cchDestPos;
long cchDestLen;
long cchActual;
long lActualLen;
if (SUCCEEDED(hr) && (GetBufFlags() & MLSTR_WRITE))
hr = E_INVALIDARG; // Not writable StrBuf; TODO: Replace StrBuf in this case if allowed
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = PrepareMLStrBuf()) &&
SUCCEEDED(hr = RegularizePosLen(&lDestPos, &lDestLen)) &&
SUCCEEDED(hr = GetCCh(0, lDestPos, &cchDestPos)) &&
SUCCEEDED(hr = GetCCh(cchDestPos, lDestLen, &cchDestLen)))
{
IMLangStringBufW* const pMLStrBufW = GetMLStrBufW();
if (pMLStrBufW)
{
if (cchSrc > cchDestLen)
{
hr = pMLStrBufW->Insert(cchDestPos, cchSrc - cchDestLen, (pcchActual || plActualLen) ? &cchSrc : NULL);
cchSrc += cchDestLen;
}
else if (cchSrc < cchDestLen)
{
hr = pMLStrBufW->Delete(cchDestPos, cchDestLen - cchSrc);
}
CMLStrBufWalkW BufWalk(pMLStrBufW, cchDestPos, cchSrc, (pcchActual || plActualLen));
lActualLen = 0;
while (BufWalk.Lock(hr))
{
long lLen;
if (plActualLen)
hr = CalcLenW(pszSrc, BufWalk.GetCCh(), &lLen);
if (SUCCEEDED(hr))
{
lActualLen += lLen;
::memcpy(BufWalk.GetStr(), pszSrc, sizeof(WCHAR) * BufWalk.GetCCh());
pszSrc += BufWalk.GetCCh();
}
BufWalk.Unlock(hr);
}
cchActual = BufWalk.GetDoneCCh();
}
else
{
IMLangStringBufA* const pMLStrBufA = GetMLStrBufA(); // Should succeed because PrepareMLStrBuf() above was succeeded
const UINT uCodePage = GetCodePage();
long cchSrcA;
if (SUCCEEDED(hr = ConvWStrToAStr(pcchActual || plActualLen, uCodePage, pszSrc, cchSrc, NULL, 0, &cchSrcA, NULL, NULL)))
{
if (cchSrcA > cchDestLen)
{
hr = pMLStrBufA->Insert(cchDestPos, cchSrcA - cchDestLen, (pcchActual || plActualLen) ? &cchSrcA : NULL);
cchSrcA += cchDestLen;
}
else if (cchSrcA < cchDestLen)
{
hr = pMLStrBufA->Delete(cchDestPos, cchDestLen - cchSrcA);
}
}
CMLStrBufWalkA BufWalk(pMLStrBufA, cchDestPos, cchSrcA, (pcchActual || plActualLen));
cchActual = 0;
lActualLen = 0;
while (BufWalk.Lock(hr))
{
long cchWrittenA;
long cchWrittenW;
long lWrittenLen;
if (SUCCEEDED(hr = ConvWStrToAStr(pcchActual || plActualLen, uCodePage, pszSrc, cchSrc, BufWalk.GetStr(), BufWalk.GetCCh(), &cchWrittenA, &cchWrittenW, &lWrittenLen)))
{
pszSrc += cchWrittenW;
cchSrc -= cchWrittenW;
cchActual += cchWrittenW;
lActualLen += lWrittenLen;
}
BufWalk.Unlock(hr, cchWrittenA);
}
}
}
if (SUCCEEDED(hr))
{
if (pcchActual)
*pcchActual = cchActual;
if (plActualLen)
*plActualLen = lActualLen;
}
else
{
if (pcchActual)
*pcchActual = 0;
if (plActualLen)
*plActualLen = 0;
}
return hr;
}
STDMETHODIMP CMLStrAttrWStr::SetStrBufW(long lDestPos, long lDestLen, IMLangStringBufW* pSrcBuf, long* pcchActual, long* plActualLen)
{
ASSERT_THIS;
return SetStrBufCommon(this, lDestPos, lDestLen, 0, pSrcBuf, NULL, pcchActual, plActualLen);
}
STDMETHODIMP CMLStrAttrWStr::GetWStr(long lSrcPos, long lSrcLen, WCHAR* pszDest, long cchDest, long* pcchActual, long* plActualLen)
{
ASSERT_THIS;
ASSERT_WRITE_BLOCK_OR_NULL(pszDest, cchDest);
ASSERT_WRITE_PTR_OR_NULL(pcchActual);
ASSERT_WRITE_PTR_OR_NULL(plActualLen);
HRESULT hr = CheckThread();
CLock Lock(FALSE, this, hr);
long cchSrcPos;
long cchSrcLen;
long cchActual;
long lActualLen;
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = RegularizePosLen(&lSrcPos, &lSrcLen)) &&
SUCCEEDED(hr = GetCCh(0, lSrcPos, &cchSrcPos)) &&
SUCCEEDED(hr = GetCCh(cchSrcPos, lSrcLen, &cchSrcLen)))
{
IMLangStringBufW* const pMLStrBufW = GetMLStrBufW();
IMLangStringBufA* const pMLStrBufA = GetMLStrBufA();
if (pszDest)
cchActual = min(cchSrcLen, cchDest);
else
cchActual = cchSrcLen;
if (pMLStrBufW)
{
CMLStrBufWalkW BufWalk(pMLStrBufW, cchSrcPos, cchActual, (pcchActual || plActualLen));
lActualLen = 0;
while (BufWalk.Lock(hr))
{
long lLen;
if (plActualLen)
hr = CalcLenW(BufWalk.GetStr(), BufWalk.GetCCh(), &lLen);
if (SUCCEEDED(hr))
{
lActualLen += lLen;
if (pszDest)
{
::memcpy(pszDest, BufWalk.GetStr(), sizeof(WCHAR) * BufWalk.GetCCh());
pszDest += BufWalk.GetCCh();
}
}
BufWalk.Unlock(hr);
}
cchActual = BufWalk.GetDoneCCh();
}
else if (pMLStrBufA)
{
CMLStrBufWalkA BufWalk(pMLStrBufA, cchSrcPos, cchActual, (pcchActual || plActualLen));
cchActual = 0;
lActualLen = 0;
while ((!pszDest || cchDest > 0) && BufWalk.Lock(hr))
{
CHAR* const pszBuf = BufWalk.GetStr();
long cchWrittenA;
long cchWrittenW;
long lWrittenLen;
if (SUCCEEDED(hr = ConvAStrToWStr(GetCodePage(), pszBuf, BufWalk.GetCCh(), pszDest, cchDest, &cchWrittenA, &cchWrittenW, &lWrittenLen)))
{
lActualLen += lWrittenLen;
cchActual += cchWrittenW;
if (pszDest)
{
pszDest += cchWrittenW;
cchDest -= cchWrittenW;
}
}
BufWalk.Unlock(hr, cchWrittenA);
}
}
else
{
ASSERT(cchActual == 0); // MLStrBuf is not available
lActualLen = 0;
}
}
if (SUCCEEDED(hr))
{
if (pcchActual)
*pcchActual = cchActual;
if (plActualLen)
*plActualLen = lActualLen;
}
else
{
if (pcchActual)
*pcchActual = 0;
if (plActualLen)
*plActualLen = 0;
}
return hr;
}
STDMETHODIMP CMLStrAttrWStr::GetStrBufW(long lSrcPos, long lSrcMaxLen, IMLangStringBufW** ppDestBuf, long* plDestLen)
{
ASSERT_THIS;
ASSERT_WRITE_PTR_OR_NULL(ppDestBuf);
ASSERT_WRITE_PTR_OR_NULL(plDestLen);
HRESULT hr = CheckThread();
CLock Lock(FALSE, this, hr);
IMLangStringBufW* pMLStrBufW;
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = RegularizePosLen(&lSrcPos, &lSrcMaxLen)) &&
lSrcMaxLen <= 0)
{
hr = E_INVALIDARG;
}
if (SUCCEEDED(hr))
{
pMLStrBufW = GetMLStrBufW();
if (!pMLStrBufW)
hr = MLSTR_E_STRBUFNOTAVAILABLE;
}
if (SUCCEEDED(hr))
{
if (ppDestBuf)
{
pMLStrBufW->AddRef();
*ppDestBuf = pMLStrBufW;
}
if (plDestLen)
*plDestLen = lSrcMaxLen;
}
else
{
if (ppDestBuf)
*ppDestBuf = NULL;
if (plDestLen)
*plDestLen = 0;
}
return hr;
}
STDMETHODIMP CMLStrAttrWStr::LockWStr(long lSrcPos, long lSrcLen, long lFlags, long cchRequest, WCHAR** ppszDest, long* pcchDest, long* plDestLen)
{
ASSERT_THIS;
ASSERT_WRITE_PTR_OR_NULL(ppszDest);
ASSERT_WRITE_PTR_OR_NULL(pcchDest);
ASSERT_WRITE_PTR_OR_NULL(plDestLen);
HRESULT hr = CheckThread();
CLock Lock(lFlags & MLSTR_WRITE, this, hr);
long cchSrcPos;
long cchSrcLen;
WCHAR* pszBuf = NULL;
long cchBuf;
long lLockLen;
BOOL fDirectLock;
if (SUCCEEDED(hr) && (!lFlags || (lFlags & ~GetBufFlags() & MLSTR_WRITE)))
hr = E_INVALIDARG; // No flags specified, or not writable StrBuf; TODO: Replace StrBuf in this case if allowed
if (!(lFlags & MLSTR_WRITE))
cchRequest = 0;
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = PrepareMLStrBuf()) &&
SUCCEEDED(hr = RegularizePosLen(&lSrcPos, &lSrcLen)) &&
SUCCEEDED(hr = GetCCh(0, lSrcPos, &cchSrcPos)) &&
SUCCEEDED(hr = GetCCh(cchSrcPos, lSrcLen, &cchSrcLen)))
{
IMLangStringBufW* const pMLStrBufW = GetMLStrBufW();
fDirectLock = (pMLStrBufW != 0);
if (fDirectLock)
{
long cchInserted;
long cchLockLen = cchSrcLen;
if (cchRequest > cchSrcLen &&
SUCCEEDED(hr = pMLStrBufW->Insert(cchSrcPos + cchSrcLen, cchRequest - cchSrcLen, &cchInserted)))
{
SetBufCCh(GetBufCCh() + cchInserted);
cchLockLen += cchInserted;
if (!pcchDest && cchLockLen < cchRequest)
hr = E_OUTOFMEMORY; // Can't insert in StrBuf
}
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = pMLStrBufW->LockBuf(cchSrcPos, cchLockLen, &pszBuf, &cchBuf)) &&
!pcchDest && cchBuf < max(cchSrcLen, cchRequest))
{
hr = E_OUTOFMEMORY; // Can't lock StrBuf
}
if (plDestLen && SUCCEEDED(hr))
hr = CalcLenW(pszBuf, cchBuf, &lLockLen);
}
else
{
long cchSize;
if (SUCCEEDED(hr = CalcBufSizeW(lSrcLen, &cchSize)))
{
cchBuf = max(cchSize, cchRequest);
hr = MemAlloc(sizeof(*pszBuf) * cchBuf, (void**)&pszBuf);
}
if (SUCCEEDED(hr) && (lFlags & MLSTR_READ))
hr = GetWStr(lSrcPos, lSrcLen, pszBuf, cchBuf, (pcchDest) ? &cchBuf : NULL, (plDestLen) ? &lLockLen : NULL);
}
}
if (SUCCEEDED(hr) &&
SUCCEEDED(hr = Lock.FallThrough()))
{
hr = GetLockInfo()->Lock((fDirectLock) ? UnlockWStrDirect : UnlockWStrIndirect, lFlags, 0, pszBuf, lSrcPos, lSrcLen, cchSrcPos, cchBuf);
}
if (SUCCEEDED(hr))
{
if (ppszDest)
*ppszDest = pszBuf;
if (pcchDest)
*pcchDest = cchBuf;
if (plDestLen)
*plDestLen = lLockLen;
}
else
{
if (pszBuf)
{
if (fDirectLock)
GetMLStrBufW()->UnlockBuf(pszBuf, 0, 0);
else
MemFree(pszBuf);
}
if (ppszDest)
*ppszDest = NULL;
if (pcchDest)
*pcchDest = 0;
if (plDestLen)
*plDestLen = 0;
}
return hr;
}
STDMETHODIMP CMLStrAttrWStr::UnlockWStr(const WCHAR* pszSrc, long cchSrc, long* pcchActual, long* plActualLen)
{
ASSERT_THIS;
ASSERT_READ_BLOCK(pszSrc, cchSrc);
ASSERT_WRITE_PTR_OR_NULL(pcchActual);
ASSERT_WRITE_PTR_OR_NULL(plActualLen);
return UnlockStrCommon(pszSrc, cchSrc, pcchActual, plActualLen);
}
STDMETHODIMP CMLStrAttrWStr::OnRegisterAttr(IUnknown* pUnk)
{
return E_NOTIMPL; // CMLStrAttrWStr::OnRegisterAttr()
}
STDMETHODIMP CMLStrAttrWStr::OnUnregisterAttr(IUnknown* pUnk)
{
return E_NOTIMPL; // CMLStrAttrWStr::OnUnregisterAttr()
}
STDMETHODIMP CMLStrAttrWStr::OnRequestEdit(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk)
{
return E_NOTIMPL; // CMLStrAttrWStr::OnRequestEdit()
}
STDMETHODIMP CMLStrAttrWStr::OnCanceledEdit(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk)
{
return E_NOTIMPL; // CMLStrAttrWStr::OnCanceledEdit()
}
STDMETHODIMP CMLStrAttrWStr::OnChanged(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk)
{
return E_NOTIMPL; // CMLStrAttrWStr::OnChanged()
}
#endif // NEWMLSTR