// 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 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 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