Home | History | Annotate | Download | only in fde
      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/fde/cfde_txtedtbuf.h"
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 
     12 #include "third_party/base/ptr_util.h"
     13 #include "third_party/base/stl_util.h"
     14 
     15 namespace {
     16 
     17 const int kDefaultChunkSize = 1024;
     18 
     19 }  // namespace
     20 
     21 CFDE_TxtEdtBuf::CFDE_TxtEdtBuf() : m_chunkSize(kDefaultChunkSize), m_nTotal(0) {
     22   m_chunks.push_back(NewChunk());
     23 }
     24 
     25 CFDE_TxtEdtBuf::~CFDE_TxtEdtBuf() {}
     26 
     27 int32_t CFDE_TxtEdtBuf::GetChunkSize() const {
     28   return m_chunkSize;
     29 }
     30 
     31 int32_t CFDE_TxtEdtBuf::GetTextLength() const {
     32   return m_nTotal;
     33 }
     34 
     35 void CFDE_TxtEdtBuf::SetText(const CFX_WideString& wsText) {
     36   ASSERT(!wsText.IsEmpty());
     37 
     38   Clear(false);
     39   int32_t nTextLength = wsText.GetLength();
     40   int32_t nNeedCount =
     41       ((nTextLength - 1) / GetChunkSize() + 1) - m_chunks.size();
     42   int32_t i = 0;
     43   for (i = 0; i < nNeedCount; i++)
     44     m_chunks.push_back(NewChunk());
     45 
     46   int32_t nTotalCount = m_chunks.size();
     47   const FX_WCHAR* lpSrcBuf = wsText.c_str();
     48   int32_t nLeave = nTextLength;
     49   int32_t nCopyedLength = GetChunkSize();
     50   for (i = 0; i < nTotalCount && nLeave > 0; i++) {
     51     if (nLeave < nCopyedLength) {
     52       nCopyedLength = nLeave;
     53     }
     54 
     55     ChunkHeader* chunk = m_chunks[i].get();
     56     FXSYS_memcpy(chunk->wChars.get(), lpSrcBuf,
     57                  nCopyedLength * sizeof(FX_WCHAR));
     58     nLeave -= nCopyedLength;
     59     lpSrcBuf += nCopyedLength;
     60     chunk->nUsed = nCopyedLength;
     61   }
     62   m_nTotal = nTextLength;
     63 }
     64 
     65 CFX_WideString CFDE_TxtEdtBuf::GetText() const {
     66   return GetRange(0, m_nTotal);
     67 }
     68 
     69 FX_WCHAR CFDE_TxtEdtBuf::GetCharByIndex(int32_t nIndex) const {
     70   ASSERT(nIndex >= 0 && nIndex < GetTextLength());
     71 
     72   ChunkHeader* pChunkHeader = nullptr;
     73   int32_t nTotal = 0;
     74   for (const auto& chunk : m_chunks) {
     75     pChunkHeader = chunk.get();
     76     nTotal += pChunkHeader->nUsed;
     77     if (nTotal > nIndex)
     78       break;
     79   }
     80   ASSERT(pChunkHeader);
     81 
     82   FX_WCHAR* buf = pChunkHeader->wChars.get();
     83   return buf[pChunkHeader->nUsed - (nTotal - nIndex)];
     84 }
     85 
     86 CFX_WideString CFDE_TxtEdtBuf::GetRange(int32_t nBegin, int32_t nLength) const {
     87   if (nLength == 0 || GetTextLength() == 0)
     88     return CFX_WideString();
     89 
     90   ASSERT(nBegin >= 0 && nLength > 0 && nBegin < GetTextLength() &&
     91          nBegin + nLength <= GetTextLength());
     92 
     93   int32_t chunkIndex = 0;
     94   int32_t charIndex = 0;
     95   std::tie(chunkIndex, charIndex) = Index2CP(nBegin);
     96 
     97   int32_t nLeave = nLength;
     98   int32_t nCount = m_chunks.size();
     99 
    100   CFX_WideString wsText;
    101   FX_WCHAR* lpDstBuf = wsText.GetBuffer(nLength);
    102   int32_t nChunkIndex = chunkIndex;
    103 
    104   ChunkHeader* chunkHeader = m_chunks[nChunkIndex].get();
    105   int32_t nCopyLength = chunkHeader->nUsed - charIndex;
    106   FX_WCHAR* lpSrcBuf = chunkHeader->wChars.get() + charIndex;
    107   while (nLeave > 0) {
    108     if (nLeave <= nCopyLength) {
    109       nCopyLength = nLeave;
    110     }
    111     FXSYS_memcpy(lpDstBuf, lpSrcBuf, nCopyLength * sizeof(FX_WCHAR));
    112     nChunkIndex++;
    113     if (nChunkIndex >= nCount) {
    114       break;
    115     }
    116     chunkHeader = m_chunks[nChunkIndex].get();
    117     lpSrcBuf = chunkHeader->wChars.get();
    118     nLeave -= nCopyLength;
    119     lpDstBuf += nCopyLength;
    120     nCopyLength = chunkHeader->nUsed;
    121   }
    122   wsText.ReleaseBuffer();
    123 
    124   return wsText;
    125 }
    126 
    127 void CFDE_TxtEdtBuf::Insert(int32_t nPos,
    128                             const FX_WCHAR* lpText,
    129                             int32_t nLength) {
    130   ASSERT(nPos >= 0 && nPos <= m_nTotal);
    131   ASSERT(nLength > 0);
    132 
    133   int32_t chunkIndex = 0;
    134   int32_t charIndex = 0;
    135   std::tie(chunkIndex, charIndex) = Index2CP(nPos);
    136 
    137   int32_t nLengthTemp = nLength;
    138   if (charIndex != 0) {
    139     auto newChunk = NewChunk();
    140 
    141     ChunkHeader* chunk = m_chunks[chunkIndex].get();
    142     int32_t nCopy = chunk->nUsed - charIndex;
    143 
    144     FXSYS_memcpy(newChunk->wChars.get(), chunk->wChars.get() + charIndex,
    145                  nCopy * sizeof(FX_WCHAR));
    146     chunk->nUsed -= nCopy;
    147     chunkIndex++;
    148 
    149     newChunk->nUsed = nCopy;
    150     m_chunks.insert(m_chunks.begin() + chunkIndex, std::move(newChunk));
    151     charIndex = 0;
    152   }
    153 
    154   if (chunkIndex != 0) {
    155     ChunkHeader* chunk = m_chunks[chunkIndex - 1].get();
    156     if (chunk->nUsed != GetChunkSize()) {
    157       chunkIndex--;
    158       int32_t nFree = GetChunkSize() - chunk->nUsed;
    159       int32_t nCopy = std::min(nLengthTemp, nFree);
    160       FXSYS_memcpy(chunk->wChars.get() + chunk->nUsed, lpText,
    161                    nCopy * sizeof(FX_WCHAR));
    162       lpText += nCopy;
    163       nLengthTemp -= nCopy;
    164       chunk->nUsed += nCopy;
    165       chunkIndex++;
    166     }
    167   }
    168 
    169   while (nLengthTemp > 0) {
    170     auto chunk = NewChunk();
    171 
    172     int32_t nCopy = std::min(nLengthTemp, GetChunkSize());
    173     FXSYS_memcpy(chunk->wChars.get(), lpText, nCopy * sizeof(FX_WCHAR));
    174     lpText += nCopy;
    175     nLengthTemp -= nCopy;
    176     chunk->nUsed = nCopy;
    177     m_chunks.insert(m_chunks.begin() + chunkIndex, std::move(chunk));
    178     chunkIndex++;
    179   }
    180   m_nTotal += nLength;
    181 }
    182 
    183 void CFDE_TxtEdtBuf::Delete(int32_t nIndex, int32_t nLength) {
    184   ASSERT(nLength > 0 && nIndex >= 0 && nIndex + nLength <= m_nTotal);
    185 
    186   int32_t endChunkIndex = 0;
    187   int32_t endCharIndex = 0;
    188   std::tie(endChunkIndex, endCharIndex) = Index2CP(nIndex + nLength - 1);
    189   m_nTotal -= nLength;
    190 
    191   ChunkHeader* chunk = m_chunks[endChunkIndex].get();
    192   int32_t nFirstPart = endCharIndex + 1;
    193   int32_t nMovePart = chunk->nUsed - nFirstPart;
    194   if (nMovePart != 0) {
    195     int32_t nDelete = std::min(nFirstPart, nLength);
    196     FXSYS_memmove(chunk->wChars.get() + nFirstPart - nDelete,
    197                   chunk->wChars.get() + nFirstPart,
    198                   nMovePart * sizeof(FX_WCHAR));
    199     chunk->nUsed -= nDelete;
    200     nLength -= nDelete;
    201     endChunkIndex--;
    202   }
    203 
    204   while (nLength > 0) {
    205     ChunkHeader* curChunk = m_chunks[endChunkIndex].get();
    206     int32_t nDeleted = std::min(curChunk->nUsed, nLength);
    207     curChunk->nUsed -= nDeleted;
    208     if (curChunk->nUsed == 0)
    209       m_chunks.erase(m_chunks.begin() + endChunkIndex);
    210 
    211     nLength -= nDeleted;
    212     endChunkIndex--;
    213   }
    214 }
    215 
    216 void CFDE_TxtEdtBuf::Clear(bool bRelease) {
    217   if (bRelease) {
    218     m_chunks.clear();
    219   } else {
    220     size_t i = 0;
    221     while (i < m_chunks.size())
    222       m_chunks[i++]->nUsed = 0;
    223   }
    224   m_nTotal = 0;
    225 }
    226 
    227 void CFDE_TxtEdtBuf::SetChunkSizeForTesting(size_t size) {
    228   ASSERT(size > 0);
    229 
    230   m_chunkSize = size;
    231   m_chunks.clear();
    232   m_chunks.push_back(NewChunk());
    233 }
    234 
    235 std::tuple<int32_t, int32_t> CFDE_TxtEdtBuf::Index2CP(int32_t nIndex) const {
    236   ASSERT(nIndex <= GetTextLength());
    237 
    238   if (nIndex == m_nTotal) {
    239     return std::tuple<int32_t, int32_t>(m_chunks.size() - 1,
    240                                         m_chunks.back()->nUsed);
    241   }
    242 
    243   int32_t chunkIndex = 0;
    244   int32_t nTotal = 0;
    245   for (auto& chunk : m_chunks) {
    246     nTotal += chunk->nUsed;
    247     if (nTotal > nIndex)
    248       break;
    249     chunkIndex++;
    250   }
    251 
    252   int32_t charIndex = m_chunks[chunkIndex]->nUsed - (nTotal - nIndex);
    253   return std::tuple<int32_t, int32_t>(chunkIndex, charIndex);
    254 }
    255 
    256 std::unique_ptr<CFDE_TxtEdtBuf::ChunkHeader> CFDE_TxtEdtBuf::NewChunk() {
    257   auto chunk = pdfium::MakeUnique<ChunkHeader>();
    258   chunk->wChars.reset(FX_Alloc(FX_WCHAR, GetChunkSize()));
    259   chunk->nUsed = 0;
    260   return chunk;
    261 }
    262 
    263 CFDE_TxtEdtBuf::ChunkHeader::ChunkHeader() {}
    264 
    265 CFDE_TxtEdtBuf::ChunkHeader::~ChunkHeader() {}
    266 
    267 CFDE_TxtEdtBuf::Iterator::Iterator(CFDE_TxtEdtBuf* pBuf, FX_WCHAR wcAlias)
    268     : m_pBuf(pBuf),
    269       m_nCurChunk(0),
    270       m_nCurIndex(0),
    271       m_nIndex(0),
    272       m_Alias(wcAlias) {
    273   ASSERT(m_pBuf);
    274 }
    275 
    276 CFDE_TxtEdtBuf::Iterator::~Iterator() {}
    277 
    278 bool CFDE_TxtEdtBuf::Iterator::Next(bool bPrev) {
    279   if (bPrev) {
    280     if (m_nIndex == 0)
    281       return false;
    282 
    283     ASSERT(m_nCurChunk < pdfium::CollectionSize<int32_t>(m_pBuf->m_chunks));
    284 
    285     ChunkHeader* chunk = nullptr;
    286     if (m_nCurIndex > 0) {
    287       m_nCurIndex--;
    288     } else {
    289       while (m_nCurChunk > 0) {
    290         --m_nCurChunk;
    291         chunk = m_pBuf->m_chunks[m_nCurChunk].get();
    292         if (chunk->nUsed > 0) {
    293           m_nCurIndex = chunk->nUsed - 1;
    294           break;
    295         }
    296       }
    297     }
    298     ASSERT(m_nCurChunk >= 0);
    299     m_nIndex--;
    300     return true;
    301   } else {
    302     if (m_nIndex >= (m_pBuf->m_nTotal - 1))
    303       return false;
    304 
    305     ASSERT(m_nCurChunk < pdfium::CollectionSize<int32_t>(m_pBuf->m_chunks));
    306     if (m_pBuf->m_chunks[m_nCurChunk]->nUsed != (m_nCurIndex + 1)) {
    307       m_nCurIndex++;
    308     } else {
    309       int32_t nEnd = m_pBuf->m_chunks.size() - 1;
    310       while (m_nCurChunk < nEnd) {
    311         m_nCurChunk++;
    312         ChunkHeader* chunkTemp = m_pBuf->m_chunks[m_nCurChunk].get();
    313         if (chunkTemp->nUsed > 0) {
    314           m_nCurIndex = 0;
    315           break;
    316         }
    317       }
    318     }
    319     m_nIndex++;
    320     return true;
    321   }
    322 }
    323 
    324 void CFDE_TxtEdtBuf::Iterator::SetAt(int32_t nIndex) {
    325   ASSERT(nIndex >= 0 && nIndex < m_pBuf->m_nTotal);
    326 
    327   std::tie(m_nCurChunk, m_nCurIndex) = m_pBuf->Index2CP(nIndex);
    328   m_nIndex = nIndex;
    329 }
    330 
    331 int32_t CFDE_TxtEdtBuf::Iterator::GetAt() const {
    332   return m_nIndex;
    333 }
    334 
    335 FX_WCHAR CFDE_TxtEdtBuf::Iterator::GetChar() {
    336   ASSERT(m_nIndex >= 0 && m_nIndex < m_pBuf->m_nTotal);
    337   if (m_Alias == 0 || m_nIndex == (m_pBuf->m_nTotal - 1)) {
    338     FX_WCHAR* buf = m_pBuf->m_chunks[m_nCurChunk]->wChars.get();
    339     return buf[m_nCurIndex];
    340   }
    341   return m_Alias;
    342 }
    343 
    344 bool CFDE_TxtEdtBuf::Iterator::IsEOF(bool bTail) const {
    345   return bTail ? m_nIndex == (m_pBuf->GetTextLength() - 2) : m_nIndex == 0;
    346 }
    347 
    348 IFX_CharIter* CFDE_TxtEdtBuf::Iterator::Clone() {
    349   CFDE_TxtEdtBuf::Iterator* pIter = new CFDE_TxtEdtBuf::Iterator(m_pBuf);
    350   pIter->m_nCurChunk = m_nCurChunk;
    351   pIter->m_nCurIndex = m_nCurIndex;
    352   pIter->m_nIndex = m_nIndex;
    353   pIter->m_Alias = m_Alias;
    354   return pIter;
    355 }
    356