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
CFDE_TxtEdtBufIter(CFDE_TxtEdtBuf * pBuf,FX_BOOL bForDisplay)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 }
~CFDE_TxtEdtBufIter()34 CFDE_TxtEdtBufIter::~CFDE_TxtEdtBufIter() {}
Release()35 void CFDE_TxtEdtBufIter::Release() {
36 delete this;
37 }
Next(FX_BOOL bPrev)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 }
SetAt(int32_t nIndex)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 }
GetAt() const94 int32_t CFDE_TxtEdtBufIter::GetAt() const {
95 return m_nIndex;
96 }
GetChar()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 }
IsEOF(FX_BOOL bTail) const133 FX_BOOL CFDE_TxtEdtBufIter::IsEOF(FX_BOOL bTail) const {
134 return bTail ? m_nIndex == (m_pBuf->GetTextLength() - 2) : m_nIndex == 0;
135 }
Clone()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 }
CFDE_TxtEdtBuf(int32_t nDefChunkSize)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 }
Release()152 void CFDE_TxtEdtBuf::Release() {
153 delete this;
154 }
~CFDE_TxtEdtBuf()155 CFDE_TxtEdtBuf::~CFDE_TxtEdtBuf() {
156 Clear(TRUE);
157 m_pAllocator->Release();
158 m_Chunks.RemoveAll();
159 }
SetChunkSize(int32_t nChunkSize)160 FX_BOOL CFDE_TxtEdtBuf::SetChunkSize(int32_t nChunkSize) {
161 FXSYS_assert(nChunkSize);
162 ResetChunkBuffer(FDE_DEFCHUNKCOUNT, nChunkSize);
163 return TRUE;
164 }
GetChunkSize() const165 int32_t CFDE_TxtEdtBuf::GetChunkSize() const {
166 return m_nChunkSize;
167 }
GetTextLength() const168 int32_t CFDE_TxtEdtBuf::GetTextLength() const {
169 return m_nTotal;
170 }
SetText(const CFX_WideString & wsText)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 }
GetText(CFX_WideString & wsText) const201 void CFDE_TxtEdtBuf::GetText(CFX_WideString& wsText) const {
202 GetRange(wsText, 0, m_nTotal);
203 }
GetCharByIndex(int32_t nIndex) const204 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 }
GetRange(CFX_WideString & wsText,int32_t nBegin,int32_t nLength) const220 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 }
Insert(int32_t nPos,const FX_WCHAR * lpText,int32_t nLength)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 }
Delete(int32_t nIndex,int32_t nLength)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 }
Clear(FX_BOOL bRelease)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 }
Optimize(IFX_Pause * pPause)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 }
ResetChunkBuffer(int32_t nDefChunkCount,int32_t nChunkSize)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 }
CP2Index(const FDE_CHUNKPLACE & cp) const412 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 }
Index2CP(int32_t nIndex,FDE_CHUNKPLACE & cp) const420 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