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