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