| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | |
| 6 | |
| 7 #include "xfa/src/fee/fde_txtedtbuf.h" | |
| 8 | |
| 9 #include <algorithm> | |
| 10 | |
| 11 #include "xfa/src/fee/ifde_txtedtbuf.h" | |
| 12 #include "xfa/src/fee/ifde_txtedtengine.h" | |
| 13 | |
| 14 #define FDE_DEFCHUNKCOUNT 2 | |
| 15 #define FDE_TXTEDT_FORMATBLOCK_BGN 0xFFF9 | |
| 16 #define FDE_TXTEDT_FORMATBLOCK_END 0xFFFB | |
| 17 #define FDE_TXTEDT_ZEROWIDTHSPACE 0x200B | |
| 18 | |
| 19 CFDE_TxtEdtBufIter::CFDE_TxtEdtBufIter(CFDE_TxtEdtBuf* pBuf, FX_WCHAR wcAlias) | |
| 20 : m_pBuf(pBuf), | |
| 21 m_nCurChunk(0), | |
| 22 m_nCurIndex(0), | |
| 23 m_nIndex(0), | |
| 24 m_Alias(wcAlias) { | |
| 25 FXSYS_assert(m_pBuf); | |
| 26 } | |
| 27 CFDE_TxtEdtBufIter::~CFDE_TxtEdtBufIter() {} | |
| 28 void CFDE_TxtEdtBufIter::Release() { | |
| 29 delete this; | |
| 30 } | |
| 31 FX_BOOL CFDE_TxtEdtBufIter::Next(FX_BOOL bPrev) { | |
| 32 if (bPrev) { | |
| 33 if (m_nIndex == 0) { | |
| 34 return FALSE; | |
| 35 } | |
| 36 FXSYS_assert(m_nCurChunk < m_pBuf->m_Chunks.GetSize()); | |
| 37 CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER lpChunk = NULL; | |
| 38 if (m_nCurIndex > 0) { | |
| 39 m_nCurIndex--; | |
| 40 } else { | |
| 41 while (m_nCurChunk > 0) { | |
| 42 --m_nCurChunk; | |
| 43 lpChunk = | |
| 44 (CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER)m_pBuf->m_Chunks[m_nCurChunk]; | |
| 45 if (lpChunk->nUsed > 0) { | |
| 46 m_nCurIndex = lpChunk->nUsed - 1; | |
| 47 break; | |
| 48 } | |
| 49 } | |
| 50 } | |
| 51 FXSYS_assert(m_nCurChunk >= 0); | |
| 52 m_nIndex--; | |
| 53 return TRUE; | |
| 54 } else { | |
| 55 if (m_nIndex >= (m_pBuf->m_nTotal - 1)) { | |
| 56 return FALSE; | |
| 57 } | |
| 58 FXSYS_assert(m_nCurChunk < m_pBuf->m_Chunks.GetSize()); | |
| 59 CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER lpChunk = | |
| 60 (CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER)m_pBuf->m_Chunks[m_nCurChunk]; | |
| 61 if (lpChunk->nUsed != (m_nCurIndex + 1)) { | |
| 62 m_nCurIndex++; | |
| 63 } else { | |
| 64 int32_t nEnd = m_pBuf->m_Chunks.GetSize() - 1; | |
| 65 while (m_nCurChunk < nEnd) { | |
| 66 m_nCurChunk++; | |
| 67 CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER lpChunkTemp = | |
| 68 (CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER)m_pBuf->m_Chunks[m_nCurChunk]; | |
| 69 if (lpChunkTemp->nUsed > 0) { | |
| 70 m_nCurIndex = 0; | |
| 71 break; | |
| 72 } | |
| 73 } | |
| 74 } | |
| 75 m_nIndex++; | |
| 76 return TRUE; | |
| 77 } | |
| 78 } | |
| 79 void CFDE_TxtEdtBufIter::SetAt(int32_t nIndex) { | |
| 80 FXSYS_assert(nIndex >= 0 && nIndex < m_pBuf->m_nTotal); | |
| 81 CFDE_TxtEdtBuf::FDE_CHUNKPLACE cp; | |
| 82 m_pBuf->Index2CP(nIndex, cp); | |
| 83 m_nIndex = nIndex; | |
| 84 m_nCurChunk = cp.nChunkIndex; | |
| 85 m_nCurIndex = cp.nCharIndex; | |
| 86 } | |
| 87 int32_t CFDE_TxtEdtBufIter::GetAt() const { | |
| 88 return m_nIndex; | |
| 89 } | |
| 90 FX_WCHAR CFDE_TxtEdtBufIter::GetChar() { | |
| 91 FXSYS_assert(m_nIndex >= 0 && m_nIndex < m_pBuf->m_nTotal); | |
| 92 if (m_Alias == 0 || m_nIndex == (m_pBuf->m_nTotal - 1)) { | |
| 93 return ((CFDE_TxtEdtBuf::FDE_LPCHUNKHEADER)m_pBuf->m_Chunks[m_nCurChunk]) | |
| 94 ->wChars[m_nCurIndex]; | |
| 95 } | |
| 96 return m_Alias; | |
| 97 } | |
| 98 FX_BOOL CFDE_TxtEdtBufIter::IsEOF(FX_BOOL bTail) const { | |
| 99 return bTail ? m_nIndex == (m_pBuf->GetTextLength() - 2) : m_nIndex == 0; | |
| 100 } | |
| 101 IFX_CharIter* CFDE_TxtEdtBufIter::Clone() { | |
| 102 CFDE_TxtEdtBufIter* pIter = new CFDE_TxtEdtBufIter(m_pBuf); | |
| 103 pIter->m_nCurChunk = m_nCurChunk; | |
| 104 pIter->m_nCurIndex = m_nCurIndex; | |
| 105 pIter->m_nIndex = m_nIndex; | |
| 106 pIter->m_Alias = m_Alias; | |
| 107 return pIter; | |
| 108 } | |
| 109 CFDE_TxtEdtBuf::CFDE_TxtEdtBuf(int32_t nDefChunkSize) | |
| 110 : m_nChunkSize(nDefChunkSize), | |
| 111 m_nTotal(0), | |
| 112 m_bChanged(FALSE), | |
| 113 m_pAllocator(NULL) { | |
| 114 FXSYS_assert(m_nChunkSize); | |
| 115 ResetChunkBuffer(FDE_DEFCHUNKCOUNT, m_nChunkSize); | |
| 116 } | |
| 117 void CFDE_TxtEdtBuf::Release() { | |
| 118 delete this; | |
| 119 } | |
| 120 CFDE_TxtEdtBuf::~CFDE_TxtEdtBuf() { | |
| 121 Clear(TRUE); | |
| 122 m_pAllocator->Release(); | |
| 123 m_Chunks.RemoveAll(); | |
| 124 } | |
| 125 FX_BOOL CFDE_TxtEdtBuf::SetChunkSize(int32_t nChunkSize) { | |
| 126 FXSYS_assert(nChunkSize); | |
| 127 ResetChunkBuffer(FDE_DEFCHUNKCOUNT, nChunkSize); | |
| 128 return TRUE; | |
| 129 } | |
| 130 int32_t CFDE_TxtEdtBuf::GetChunkSize() const { | |
| 131 return m_nChunkSize; | |
| 132 } | |
| 133 int32_t CFDE_TxtEdtBuf::GetTextLength() const { | |
| 134 return m_nTotal; | |
| 135 } | |
| 136 void CFDE_TxtEdtBuf::SetText(const CFX_WideString& wsText) { | |
| 137 FXSYS_assert(!wsText.IsEmpty()); | |
| 138 Clear(FALSE); | |
| 139 int32_t nTextLength = wsText.GetLength(); | |
| 140 int32_t nNeedCount = | |
| 141 ((nTextLength - 1) / m_nChunkSize + 1) - m_Chunks.GetSize(); | |
| 142 int32_t i = 0; | |
| 143 for (i = 0; i < nNeedCount; i++) { | |
| 144 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_pAllocator->Alloc( | |
| 145 sizeof(FDE_CHUNKHEADER) + (m_nChunkSize - 1) * sizeof(FX_WCHAR)); | |
| 146 lpChunk->nUsed = 0; | |
| 147 m_Chunks.Add(lpChunk); | |
| 148 } | |
| 149 int32_t nTotalCount = m_Chunks.GetSize(); | |
| 150 const FX_WCHAR* lpSrcBuf = wsText.c_str(); | |
| 151 int32_t nLeave = nTextLength; | |
| 152 int32_t nCopyedLength = m_nChunkSize; | |
| 153 for (i = 0; i < nTotalCount && nLeave > 0; i++) { | |
| 154 if (nLeave < nCopyedLength) { | |
| 155 nCopyedLength = nLeave; | |
| 156 } | |
| 157 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[i]; | |
| 158 FXSYS_memcpy(lpChunk->wChars, lpSrcBuf, nCopyedLength * sizeof(FX_WCHAR)); | |
| 159 nLeave -= nCopyedLength; | |
| 160 lpSrcBuf += nCopyedLength; | |
| 161 lpChunk->nUsed = nCopyedLength; | |
| 162 } | |
| 163 m_nTotal = nTextLength; | |
| 164 m_bChanged = TRUE; | |
| 165 } | |
| 166 void CFDE_TxtEdtBuf::GetText(CFX_WideString& wsText) const { | |
| 167 GetRange(wsText, 0, m_nTotal); | |
| 168 } | |
| 169 FX_WCHAR CFDE_TxtEdtBuf::GetCharByIndex(int32_t nIndex) const { | |
| 170 FXSYS_assert(nIndex >= 0 && nIndex < GetTextLength()); | |
| 171 FDE_LPCHUNKHEADER pChunkHeader = NULL; | |
| 172 int32_t nTotal = 0; | |
| 173 int32_t nCount = m_Chunks.GetSize(); | |
| 174 int32_t i = 0; | |
| 175 for (i = 0; i < nCount; i++) { | |
| 176 pChunkHeader = (FDE_LPCHUNKHEADER)m_Chunks[i]; | |
| 177 nTotal += pChunkHeader->nUsed; | |
| 178 if (nTotal > nIndex) { | |
| 179 break; | |
| 180 } | |
| 181 } | |
| 182 FXSYS_assert(pChunkHeader); | |
| 183 return pChunkHeader->wChars[pChunkHeader->nUsed - (nTotal - nIndex)]; | |
| 184 } | |
| 185 void CFDE_TxtEdtBuf::GetRange(CFX_WideString& wsText, | |
| 186 int32_t nBegin, | |
| 187 int32_t nLength) const { | |
| 188 FDE_CHUNKPLACE cp; | |
| 189 Index2CP(nBegin, cp); | |
| 190 int32_t nLeave = nLength; | |
| 191 int32_t nCount = m_Chunks.GetSize(); | |
| 192 FX_WCHAR* lpDstBuf = wsText.GetBuffer(nLength); | |
| 193 int32_t nChunkIndex = cp.nChunkIndex; | |
| 194 FDE_LPCHUNKHEADER lpChunkHeader = (FDE_LPCHUNKHEADER)m_Chunks[nChunkIndex]; | |
| 195 int32_t nCopyLength = lpChunkHeader->nUsed - cp.nCharIndex; | |
| 196 FX_WCHAR* lpSrcBuf = lpChunkHeader->wChars + cp.nCharIndex; | |
| 197 while (nLeave > 0) { | |
| 198 if (nLeave <= nCopyLength) { | |
| 199 nCopyLength = nLeave; | |
| 200 } | |
| 201 FXSYS_memcpy(lpDstBuf, lpSrcBuf, nCopyLength * sizeof(FX_WCHAR)); | |
| 202 nChunkIndex++; | |
| 203 if (nChunkIndex >= nCount) { | |
| 204 break; | |
| 205 } | |
| 206 lpChunkHeader = (FDE_LPCHUNKHEADER)m_Chunks[nChunkIndex]; | |
| 207 lpSrcBuf = lpChunkHeader->wChars; | |
| 208 nLeave -= nCopyLength; | |
| 209 lpDstBuf += nCopyLength; | |
| 210 nCopyLength = lpChunkHeader->nUsed; | |
| 211 } | |
| 212 wsText.ReleaseBuffer(); | |
| 213 } | |
| 214 void CFDE_TxtEdtBuf::Insert(int32_t nPos, | |
| 215 const FX_WCHAR* lpText, | |
| 216 int32_t nLength) { | |
| 217 FXSYS_assert(nPos >= 0 && nPos <= m_nTotal); | |
| 218 FDE_CHUNKPLACE cp; | |
| 219 Index2CP(nPos, cp); | |
| 220 int32_t nLengthTemp = nLength; | |
| 221 if (cp.nCharIndex != 0) { | |
| 222 FDE_LPCHUNKHEADER lpNewChunk = (FDE_LPCHUNKHEADER)m_pAllocator->Alloc( | |
| 223 sizeof(FDE_CHUNKHEADER) + (m_nChunkSize - 1) * sizeof(FX_WCHAR)); | |
| 224 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[cp.nChunkIndex]; | |
| 225 int32_t nCopy = lpChunk->nUsed - cp.nCharIndex; | |
| 226 FXSYS_memcpy(lpNewChunk->wChars, lpChunk->wChars + cp.nCharIndex, | |
| 227 nCopy * sizeof(FX_WCHAR)); | |
| 228 lpChunk->nUsed -= nCopy; | |
| 229 cp.nChunkIndex++; | |
| 230 m_Chunks.InsertAt(cp.nChunkIndex, lpNewChunk); | |
| 231 lpNewChunk->nUsed = nCopy; | |
| 232 cp.nCharIndex = 0; | |
| 233 } | |
| 234 if (cp.nChunkIndex != 0) { | |
| 235 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[cp.nChunkIndex - 1]; | |
| 236 if (lpChunk->nUsed != m_nChunkSize) { | |
| 237 cp.nChunkIndex--; | |
| 238 int32_t nFree = m_nChunkSize - lpChunk->nUsed; | |
| 239 int32_t nCopy = std::min(nLengthTemp, nFree); | |
| 240 FXSYS_memcpy(lpChunk->wChars + lpChunk->nUsed, lpText, | |
| 241 nCopy * sizeof(FX_WCHAR)); | |
| 242 lpText += nCopy; | |
| 243 nLengthTemp -= nCopy; | |
| 244 lpChunk->nUsed += nCopy; | |
| 245 cp.nChunkIndex++; | |
| 246 } | |
| 247 } | |
| 248 while (nLengthTemp > 0) { | |
| 249 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_pAllocator->Alloc( | |
| 250 sizeof(FDE_CHUNKHEADER) + (m_nChunkSize - 1) * sizeof(FX_WCHAR)); | |
| 251 FXSYS_assert(lpChunk); | |
| 252 int32_t nCopy = std::min(nLengthTemp, m_nChunkSize); | |
| 253 FXSYS_memcpy(lpChunk->wChars, lpText, nCopy * sizeof(FX_WCHAR)); | |
| 254 lpText += nCopy; | |
| 255 nLengthTemp -= nCopy; | |
| 256 lpChunk->nUsed = nCopy; | |
| 257 m_Chunks.InsertAt(cp.nChunkIndex, lpChunk); | |
| 258 cp.nChunkIndex++; | |
| 259 } | |
| 260 m_nTotal += nLength; | |
| 261 m_bChanged = TRUE; | |
| 262 } | |
| 263 void CFDE_TxtEdtBuf::Delete(int32_t nIndex, int32_t nLength) { | |
| 264 FXSYS_assert(nLength > 0 && nIndex >= 0 && nIndex + nLength <= m_nTotal); | |
| 265 FDE_CHUNKPLACE cpEnd; | |
| 266 Index2CP(nIndex + nLength - 1, cpEnd); | |
| 267 m_nTotal -= nLength; | |
| 268 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[cpEnd.nChunkIndex]; | |
| 269 int32_t nFirstPart = cpEnd.nCharIndex + 1; | |
| 270 int32_t nMovePart = lpChunk->nUsed - nFirstPart; | |
| 271 if (nMovePart != 0) { | |
| 272 int32_t nDelete = std::min(nFirstPart, nLength); | |
| 273 FXSYS_memmove(lpChunk->wChars + nFirstPart - nDelete, | |
| 274 lpChunk->wChars + nFirstPart, nMovePart * sizeof(FX_WCHAR)); | |
| 275 lpChunk->nUsed -= nDelete; | |
| 276 nLength -= nDelete; | |
| 277 cpEnd.nChunkIndex--; | |
| 278 } | |
| 279 while (nLength > 0) { | |
| 280 lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[cpEnd.nChunkIndex]; | |
| 281 int32_t nDeleted = std::min(lpChunk->nUsed, nLength); | |
| 282 lpChunk->nUsed -= nDeleted; | |
| 283 if (lpChunk->nUsed == 0) { | |
| 284 m_pAllocator->Free(lpChunk); | |
| 285 m_Chunks.RemoveAt(cpEnd.nChunkIndex); | |
| 286 lpChunk = NULL; | |
| 287 } | |
| 288 nLength -= nDeleted; | |
| 289 cpEnd.nChunkIndex--; | |
| 290 } | |
| 291 m_bChanged = TRUE; | |
| 292 } | |
| 293 void CFDE_TxtEdtBuf::Clear(FX_BOOL bRelease) { | |
| 294 int32_t i = 0; | |
| 295 int32_t nCount = m_Chunks.GetSize(); | |
| 296 if (bRelease) { | |
| 297 while (i < nCount) { | |
| 298 m_pAllocator->Free(m_Chunks[i++]); | |
| 299 } | |
| 300 m_Chunks.RemoveAll(); | |
| 301 } else { | |
| 302 while (i < nCount) { | |
| 303 ((FDE_LPCHUNKHEADER)m_Chunks[i++])->nUsed = 0; | |
| 304 } | |
| 305 } | |
| 306 m_nTotal = 0; | |
| 307 m_bChanged = TRUE; | |
| 308 } | |
| 309 FX_BOOL CFDE_TxtEdtBuf::Optimize(IFX_Pause* pPause) { | |
| 310 if (m_bChanged == FALSE) { | |
| 311 return TRUE; | |
| 312 } | |
| 313 if (m_nTotal == 0) { | |
| 314 return TRUE; | |
| 315 } | |
| 316 int32_t nCount = m_Chunks.GetSize(); | |
| 317 if (nCount == 0) { | |
| 318 return TRUE; | |
| 319 } | |
| 320 int32_t i = 0; | |
| 321 for (; i < nCount; i++) { | |
| 322 FDE_LPCHUNKHEADER lpChunk = (FDE_LPCHUNKHEADER)m_Chunks[i]; | |
| 323 if (lpChunk->nUsed == 0) { | |
| 324 m_pAllocator->Free(lpChunk); | |
| 325 m_Chunks.RemoveAt(i); | |
| 326 --i; | |
| 327 --nCount; | |
| 328 } | |
| 329 } | |
| 330 if (pPause != NULL && pPause->NeedToPauseNow()) { | |
| 331 return FALSE; | |
| 332 } | |
| 333 FDE_LPCHUNKHEADER lpPreChunk = (FDE_LPCHUNKHEADER)m_Chunks[0]; | |
| 334 FDE_LPCHUNKHEADER lpCurChunk = NULL; | |
| 335 for (i = 1; i < nCount; i++) { | |
| 336 lpCurChunk = (FDE_LPCHUNKHEADER)m_Chunks[i]; | |
| 337 if (lpPreChunk->nUsed + lpCurChunk->nUsed <= m_nChunkSize) { | |
| 338 FXSYS_memcpy(lpPreChunk->wChars + lpPreChunk->nUsed, lpCurChunk->wChars, | |
| 339 lpCurChunk->nUsed * sizeof(FX_WCHAR)); | |
| 340 lpPreChunk->nUsed += lpCurChunk->nUsed; | |
| 341 m_pAllocator->Free(lpCurChunk); | |
| 342 m_Chunks.RemoveAt(i); | |
| 343 --i; | |
| 344 --nCount; | |
| 345 } else { | |
| 346 lpPreChunk = lpCurChunk; | |
| 347 } | |
| 348 if (pPause != NULL && pPause->NeedToPauseNow()) { | |
| 349 return FALSE; | |
| 350 } | |
| 351 } | |
| 352 m_bChanged = FALSE; | |
| 353 return TRUE; | |
| 354 } | |
| 355 void CFDE_TxtEdtBuf::ResetChunkBuffer(int32_t nDefChunkCount, | |
| 356 int32_t nChunkSize) { | |
| 357 FXSYS_assert(nChunkSize); | |
| 358 FXSYS_assert(nDefChunkCount); | |
| 359 if (m_pAllocator) { | |
| 360 m_pAllocator->Release(); | |
| 361 m_pAllocator = NULL; | |
| 362 } | |
| 363 m_Chunks.RemoveAll(); | |
| 364 m_nChunkSize = nChunkSize; | |
| 365 int32_t nChunkLength = | |
| 366 sizeof(FDE_CHUNKHEADER) + (m_nChunkSize - 1) * sizeof(FX_WCHAR); | |
| 367 m_pAllocator = | |
| 368 FX_CreateAllocator(FX_ALLOCTYPE_Fixed, nDefChunkCount, nChunkLength); | |
| 369 FXSYS_assert(m_pAllocator); | |
| 370 FDE_LPCHUNKHEADER lpChunkHeader = | |
| 371 (FDE_LPCHUNKHEADER)m_pAllocator->Alloc(nChunkLength); | |
| 372 FXSYS_assert(lpChunkHeader); | |
| 373 lpChunkHeader->nUsed = 0; | |
| 374 m_Chunks.Add(lpChunkHeader); | |
| 375 m_nTotal = 0; | |
| 376 } | |
| 377 int32_t CFDE_TxtEdtBuf::CP2Index(const FDE_CHUNKPLACE& cp) const { | |
| 378 int32_t nTotal = cp.nCharIndex; | |
| 379 int32_t i = 0; | |
| 380 for (i = 0; i < cp.nChunkIndex; i++) { | |
| 381 nTotal += ((FDE_LPCHUNKHEADER)m_Chunks[i])->nUsed; | |
| 382 } | |
| 383 return nTotal; | |
| 384 } | |
| 385 void CFDE_TxtEdtBuf::Index2CP(int32_t nIndex, FDE_CHUNKPLACE& cp) const { | |
| 386 FXSYS_assert(nIndex <= GetTextLength()); | |
| 387 if (nIndex == m_nTotal) { | |
| 388 cp.nChunkIndex = m_Chunks.GetSize() - 1; | |
| 389 cp.nCharIndex = ((FDE_LPCHUNKHEADER)m_Chunks[cp.nChunkIndex])->nUsed; | |
| 390 return; | |
| 391 } | |
| 392 int32_t i = 0; | |
| 393 int32_t nTotal = 0; | |
| 394 int32_t nCount = m_Chunks.GetSize(); | |
| 395 for (; i < nCount; i++) { | |
| 396 nTotal += ((FDE_LPCHUNKHEADER)m_Chunks[i])->nUsed; | |
| 397 if (nTotal > nIndex) { | |
| 398 break; | |
| 399 } | |
| 400 } | |
| 401 cp.nChunkIndex = i; | |
| 402 cp.nCharIndex = ((FDE_LPCHUNKHEADER)m_Chunks[i])->nUsed - (nTotal - nIndex); | |
| 403 } | |
| OLD | NEW |