// AttrStrA.cpp : Implementation of CMLStrAttrAStr #include "private.h" #ifdef NEWMLSTR #include "attrstra.h" #include "mlswalk.h" #include "mlsbwalk.h" ///////////////////////////////////////////////////////////////////////////// // CMLStrAttrAStr CMLStrAttrAStr::CMLStrAttrAStr(void) : m_pMLCPs(NULL), m_pMLStr(NULL) { } CMLStrAttrAStr::~CMLStrAttrAStr(void) { VERIFY(SetClient(NULL)); // Clean m_pMLStr if (m_pMLCPs) m_pMLCPs->Release(); } STDMETHODIMP CMLStrAttrAStr::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 CMLStrAttrAStr::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 CMLStrAttrAStr::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 CMLStrAttrAStr::QueryAttr(REFIID riid, LPARAM lParam, IUnknown** ppUnk, long* lConf) { return E_NOTIMPL; // CMLStrAttrAStr::QueryAttr() } STDMETHODIMP CMLStrAttrAStr::GetAttrInterface(IID* pIID, LPARAM* plParam) { return E_NOTIMPL; // CMLStrAttrAStr::GetAttrInterface() } STDMETHODIMP CMLStrAttrAStr::SetMLStr(long lDestPos, long lDestLen, IUnknown* pSrcMLStr, long lSrcPos, long lSrcLen) { return E_NOTIMPL; // CMLStrAttrAStr::SetMLStr() } STDMETHODIMP CMLStrAttrAStr::SetAStr(long lDestPos, long lDestLen, UINT uCodePage, const CHAR* 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; // Fire OnRequestEdit IEnumConnections* pEnumConn; if (SUCCEEDED(hr = EnumConnections(&pEnumConn))) { ASSERT_READ_PTR(pEnumConn); CONNECTDATA cd; while ((hr = pEnumConn->Next(1, &cd, NULL)) == S_OK) { IMLStrAttrNotifySink* pSink; if (SUCCEEDED(hr = cd.pUnk->QueryInterface(IID_IMLStrAttrNotifySink, (void**)&pSink))) { // TODO: Regularize before fire OnRequestEdit // TODO: And, calculate lNewLen, hr = pSink->OnRequestEdit(lDestPos, lDestLen, /*lNewLen*/0, IID_IMLStrAttrAStr, 0, (IMLStrAttr*)this); pSink->Release(); } } pEnumConn->Release(); } 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))) { IMLangStringBufA* const pMLStrBufA = GetMLStrBufA(); if (uCodePage == CP_ACP) uCodePage = g_uACP; if (pMLStrBufA && uCodePage == GetCodePage()) { if (cchSrc > cchDestLen) { hr = pMLStrBufA->Insert(cchDestPos, cchSrc - cchDestLen, (pcchActual || plActualLen) ? &cchSrc : NULL); cchSrc += cchDestLen; } else if (cchSrc < cchDestLen) { hr = pMLStrBufA->Delete(cchDestPos, cchDestLen - cchSrc); } CMLStrBufWalkA BufWalk(pMLStrBufA, cchDestPos, cchSrc, (pcchActual || plActualLen)); lActualLen = 0; while (BufWalk.Lock(hr)) { long lLen; if (plActualLen) hr = CalcLenA(uCodePage, pszSrc, BufWalk.GetCCh(), &lLen); if (SUCCEEDED(hr)) { lActualLen += lLen; ::memcpy(BufWalk.GetStr(), pszSrc, sizeof(CHAR) * BufWalk.GetCCh()); pszSrc += BufWalk.GetCCh(); } BufWalk.Unlock(hr); } cchActual = BufWalk.GetDoneCCh(); } else { IMLangStringWStr* pMLStrW; if (SUCCEEDED(hr = ((IMLStrAttr*)this)->QueryInterface(IID_IMLangStringWStr, (void**)&pMLStrW))) { CMLStrWalkW StrWalk(pMLStrW, lDestPos, lDestLen, MLSTR_WRITE, (pcchActual || plActualLen)); cchActual = 0; lActualLen = 0; while (StrWalk.Lock(hr)) { long cchWrittenA; long lWrittenLen; if (SUCCEEDED(hr = ConvAStrToWStr(uCodePage, pszSrc, cchSrc, StrWalk.GetStr(), StrWalk.GetCCh(), &cchWrittenA, NULL, &lWrittenLen))) { pszSrc += cchWrittenA; cchSrc -= cchWrittenA; cchActual += cchWrittenA; lActualLen += lWrittenLen; } StrWalk.Unlock(hr, lWrittenLen); } pMLStrW->Release(); } } } if (SUCCEEDED(hr)) { if (pcchActual) *pcchActual = cchActual; if (plActualLen) *plActualLen = lActualLen; } else { if (pcchActual) *pcchActual = 0; if (plActualLen) *plActualLen = 0; } return hr; } STDMETHODIMP CMLStrAttrAStr::SetStrBufA(long lDestPos, long lDestLen, UINT uCodePage, IMLangStringBufA* pSrcBuf, long* pcchActual, long* plActualLen) { ASSERT_THIS; return SetStrBufCommon(this, lDestPos, lDestLen, uCodePage, NULL, pSrcBuf, pcchActual, plActualLen); } STDMETHODIMP CMLStrAttrAStr::GetAStr(long lSrcPos, long lSrcLen, UINT uCodePageIn, UINT* puCodePageOut, CHAR* pszDest, long cchDest, long* pcchActual, long* plActualLen) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(puCodePageOut); 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))) { IMLangStringBufA* const pMLStrBufA = GetMLStrBufA(); if (pszDest) cchActual = min(cchSrcLen, cchDest); else cchActual = cchSrcLen; if (uCodePageIn == CP_ACP) uCodePageIn = g_uACP; if (pMLStrBufA && (puCodePageOut || uCodePageIn == GetCodePage())) { uCodePageIn = GetCodePage(); CMLStrBufWalkA BufWalk(pMLStrBufA, cchSrcPos, cchActual, (pcchActual || plActualLen)); lActualLen = 0; while (BufWalk.Lock(hr)) { long lLen; if (plActualLen) hr = CalcLenA(uCodePageIn, BufWalk.GetStr(), BufWalk.GetCCh(), &lLen); if (SUCCEEDED(hr)) { lActualLen += lLen; if (pszDest) { ::memcpy(pszDest, BufWalk.GetStr(), sizeof(CHAR) * BufWalk.GetCCh()); pszDest += BufWalk.GetCCh(); } } BufWalk.Unlock(hr); } cchActual = BufWalk.GetDoneCCh(); } else { IMLangStringWStr* pMLStrW; if (SUCCEEDED(hr = m_pMLStr->QueryInterface(IID_IMLangStringWStr, (void**)&pMLStrW))) { BOOL fDontHaveCodePageIn = (puCodePageOut != 0); CMLStrWalkW StrWalk(pMLStrW, lSrcPos, lSrcLen, (pcchActual || plActualLen)); cchActual = 0; while (StrWalk.Lock(hr)) { LCID locale; UINT uLocaleCodePage; DWORD dwLocaleCodePages; DWORD dwStrCodePages; long cchWritten; long lWrittenLen; if (fDontHaveCodePageIn && SUCCEEDED(hr = pMLStrW->GetLocale(lSrcPos, lSrcLen, &locale, NULL, NULL)) && SUCCEEDED(hr = ::LocaleToCodePage(locale, &uLocaleCodePage)) && SUCCEEDED(hr = PrepareMLangCodePages()) && SUCCEEDED(hr = GetMLangCodePages()->CodePageToCodePages(uLocaleCodePage, &dwLocaleCodePages)) && SUCCEEDED(hr = GetMLangCodePages()->GetStrCodePages(StrWalk.GetStr(), StrWalk.GetCCh(), dwLocaleCodePages, &dwStrCodePages, NULL))) { fDontHaveCodePageIn = FALSE; hr = GetMLangCodePages()->CodePagesToCodePage(dwStrCodePages, uLocaleCodePage, &uCodePageIn); } if (SUCCEEDED(hr) && SUCCEEDED(hr = ConvWStrToAStr(pcchActual || plActualLen, uCodePageIn, StrWalk.GetStr(), StrWalk.GetCCh(), pszDest, cchDest, &cchWritten, NULL, &lWrittenLen))) { pszDest += cchWritten; cchDest -= cchWritten; cchActual += cchWritten; } StrWalk.Unlock(hr, lWrittenLen); } lActualLen = StrWalk.GetDoneLen(); pMLStrW->Release(); } } } if (SUCCEEDED(hr)) { if (puCodePageOut) *puCodePageOut = uCodePageIn; if (pcchActual) *pcchActual = cchActual; if (plActualLen) *plActualLen = lActualLen; } else { if (puCodePageOut) *puCodePageOut = 0; if (pcchActual) *pcchActual = 0; if (plActualLen) *plActualLen = 0; } return hr; } STDMETHODIMP CMLStrAttrAStr::GetStrBufA(long lSrcPos, long lSrcMaxLen, UINT* puDestCodePage, IMLangStringBufA** ppDestBuf, long* plDestLen) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(puDestCodePage); ASSERT_WRITE_PTR_OR_NULL(ppDestBuf); ASSERT_WRITE_PTR_OR_NULL(plDestLen); HRESULT hr = CheckThread(); CLock Lock(FALSE, this, hr); IMLangStringBufA* pMLStrBufA; if (SUCCEEDED(hr) && SUCCEEDED(hr = RegularizePosLen(&lSrcPos, &lSrcMaxLen)) && lSrcMaxLen <= 0) { hr = E_INVALIDARG; } if (SUCCEEDED(hr)) { pMLStrBufA = GetMLStrBufA(); if (!pMLStrBufA) hr = MLSTR_E_STRBUFNOTAVAILABLE; } if (SUCCEEDED(hr)) { if (puDestCodePage) *puDestCodePage = GetCodePage(); if (ppDestBuf) { pMLStrBufA->AddRef(); *ppDestBuf = pMLStrBufA; } if (plDestLen) *plDestLen = lSrcMaxLen; } else { if (puDestCodePage) *puDestCodePage = 0; if (ppDestBuf) *ppDestBuf = NULL; if (plDestLen) *plDestLen = 0; } return hr; } STDMETHODIMP CMLStrAttrAStr::LockAStr(long lSrcPos, long lSrcLen, long lFlags, UINT uCodePageIn, long cchRequest, UINT* puCodePageOut, CHAR** ppszDest, long* pcchDest, long* plDestLen) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(puCodePageOut); 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; CHAR* 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))) { IMLangStringBufA* const pMLStrBufA = GetMLStrBufA(); fDirectLock = (pMLStrBufA && (puCodePageOut || uCodePageIn == GetCodePage())); if (fDirectLock) { long cchInserted; long cchLockLen = cchSrcLen; if (puCodePageOut) hr = GetAStr(lSrcPos, lSrcLen, 0, &uCodePageIn, NULL, 0, NULL, NULL); if (SUCCEEDED(hr) && cchRequest > cchSrcLen && SUCCEEDED(hr = pMLStrBufA->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 = pMLStrBufA->LockBuf(cchSrcPos, cchLockLen, &pszBuf, &cchBuf)) && !pcchDest && cchBuf < max(cchSrcLen, cchRequest)) { hr = E_OUTOFMEMORY; // Can't lock StrBuf } if (plDestLen && SUCCEEDED(hr)) hr = CalcLenA(uCodePageIn, pszBuf, cchBuf, &lLockLen); } else { long cchSize; if (SUCCEEDED(hr = CalcBufSizeA(lSrcLen, &cchSize))) { cchBuf = max(cchSize, cchRequest); hr = MemAlloc(sizeof(*pszBuf) * cchBuf, (void**)&pszBuf); } if (SUCCEEDED(hr) && ((lFlags & MLSTR_READ) || puCodePageOut)) hr = GetAStr(lSrcPos, lSrcLen, uCodePageIn, (puCodePageOut) ? &uCodePageIn : NULL, (lFlags & MLSTR_READ) ? pszBuf : NULL, cchBuf, (pcchDest) ? &cchBuf : NULL, (plDestLen) ? &lLockLen : NULL); } } if (SUCCEEDED(hr) && SUCCEEDED(hr = Lock.FallThrough())) { hr = GetLockInfo()->Lock((fDirectLock) ? UnlockAStrDirect : UnlockAStrIndirect, lFlags, uCodePageIn, pszBuf, lSrcPos, lSrcLen, cchSrcPos, cchBuf); } if (SUCCEEDED(hr)) { if (puCodePageOut) *puCodePageOut = uCodePageIn; if (ppszDest) *ppszDest = pszBuf; if (pcchDest) *pcchDest = cchBuf; if (plDestLen) *plDestLen = lLockLen; } else { if (pszBuf) { if (fDirectLock) GetMLStrBufA()->UnlockBuf(pszBuf, 0, 0); else MemFree(pszBuf); } if (puCodePageOut) *puCodePageOut = 0; if (ppszDest) *ppszDest = NULL; if (pcchDest) *pcchDest = 0; if (plDestLen) *plDestLen = 0; } return hr; } STDMETHODIMP CMLStrAttrAStr::UnlockAStr(const CHAR* 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 CMLStrAttrAStr::OnRegisterAttr(IUnknown* pUnk) { return E_NOTIMPL; // CMLStrAttrAStr::OnRegisterAttr() } STDMETHODIMP CMLStrAttrAStr::OnUnregisterAttr(IUnknown* pUnk) { return E_NOTIMPL; // CMLStrAttrAStr::OnUnregisterAttr() } STDMETHODIMP CMLStrAttrAStr::OnRequestEdit(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk) { return E_NOTIMPL; // CMLStrAttrAStr::OnRequestEdit() } STDMETHODIMP CMLStrAttrAStr::OnCanceledEdit(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk) { return E_NOTIMPL; // CMLStrAttrAStr::OnCanceledEdit() } STDMETHODIMP CMLStrAttrAStr::OnChanged(long lDestPos, long lDestLen, long lNewLen, REFIID riid, LPARAM lParam, IUnknown* pUnk) { return E_NOTIMPL; // CMLStrAttrAStr::OnChanged() } #endif // NEWMLSTR