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/fgas/include/fx_utl.h"
10 #include "xfa/src/fgas/src/fgas_base.h"
11 #include "fx_utils.h"
12 
CFX_ThreadLock()13 CFX_ThreadLock::CFX_ThreadLock() {
14 }
~CFX_ThreadLock()15 CFX_ThreadLock::~CFX_ThreadLock() {}
Lock()16 void CFX_ThreadLock::Lock() {}
Unlock()17 void CFX_ThreadLock::Unlock() {}
18 class FX_BASEARRAYDATA : public CFX_Target {
19  public:
FX_BASEARRAYDATA(int32_t growsize,int32_t blocksize)20   FX_BASEARRAYDATA(int32_t growsize, int32_t blocksize)
21       : iGrowSize(growsize),
22         iBlockSize(blocksize),
23         iTotalCount(0),
24         iBlockCount(0),
25         pBuffer(nullptr) {}
26 
~FX_BASEARRAYDATA()27   ~FX_BASEARRAYDATA() { FX_Free(pBuffer); }
28 
29   int32_t iGrowSize;
30   int32_t iBlockSize;
31   int32_t iTotalCount;
32   int32_t iBlockCount;
33   uint8_t* pBuffer;
34 };
CFX_BaseArray(int32_t iGrowSize,int32_t iBlockSize)35 CFX_BaseArray::CFX_BaseArray(int32_t iGrowSize, int32_t iBlockSize) {
36   FXSYS_assert(iGrowSize > 0 && iBlockSize > 0);
37   m_pData = new FX_BASEARRAYDATA(iGrowSize, iBlockSize);
38 }
~CFX_BaseArray()39 CFX_BaseArray::~CFX_BaseArray() {
40   RemoveAll();
41   delete m_pData;
42 }
GetSize() const43 int32_t CFX_BaseArray::GetSize() const {
44   return m_pData->iBlockCount;
45 }
GetBlockSize() const46 int32_t CFX_BaseArray::GetBlockSize() const {
47   return m_pData->iBlockSize;
48 }
AddSpaceTo(int32_t index)49 uint8_t* CFX_BaseArray::AddSpaceTo(int32_t index) {
50   FXSYS_assert(index > -1);
51   uint8_t*& pBuffer = m_pData->pBuffer;
52   int32_t& iTotalCount = m_pData->iTotalCount;
53   int32_t iBlockSize = m_pData->iBlockSize;
54   if (index >= iTotalCount) {
55     int32_t iGrowSize = m_pData->iGrowSize;
56     iTotalCount = (index / iGrowSize + 1) * iGrowSize;
57     int32_t iNewSize = iTotalCount * iBlockSize;
58     if (!pBuffer) {
59       pBuffer = FX_Alloc(uint8_t, iNewSize);
60     } else {
61       pBuffer = FX_Realloc(uint8_t, pBuffer, iNewSize);
62     }
63   }
64   int32_t& iBlockCount = m_pData->iBlockCount;
65   if (index >= iBlockCount) {
66     iBlockCount = index + 1;
67   }
68   return pBuffer + index * iBlockSize;
69 }
GetAt(int32_t index) const70 uint8_t* CFX_BaseArray::GetAt(int32_t index) const {
71   FXSYS_assert(index > -1 && index < m_pData->iBlockCount);
72   return m_pData->pBuffer + index * m_pData->iBlockSize;
73 }
GetBuffer() const74 uint8_t* CFX_BaseArray::GetBuffer() const {
75   return m_pData->pBuffer;
76 }
Append(const CFX_BaseArray & src,int32_t iStart,int32_t iCount)77 int32_t CFX_BaseArray::Append(const CFX_BaseArray& src,
78                               int32_t iStart,
79                               int32_t iCount) {
80   int32_t iBlockSize = m_pData->iBlockSize;
81   FXSYS_assert(iBlockSize == src.m_pData->iBlockSize);
82   int32_t& iBlockCount = m_pData->iBlockCount;
83   int32_t iAdded = src.GetSize();
84   FXSYS_assert(iStart > -1 && iStart < iAdded);
85   if (iCount < 0) {
86     iCount = iAdded;
87   }
88   if (iStart + iCount > iAdded) {
89     iCount = iAdded - iStart;
90   }
91   if (iCount < 1) {
92     return 0;
93   }
94   uint8_t* pDst = m_pData->pBuffer + iBlockCount * iBlockSize;
95   AddSpaceTo(iBlockCount + iCount - 1);
96   FX_memcpy(pDst, src.m_pData->pBuffer + iStart * iBlockSize,
97             iCount * iBlockSize);
98   return iCount;
99 }
Copy(const CFX_BaseArray & src,int32_t iStart,int32_t iCount)100 int32_t CFX_BaseArray::Copy(const CFX_BaseArray& src,
101                             int32_t iStart,
102                             int32_t iCount) {
103   int32_t iBlockSize = m_pData->iBlockSize;
104   FXSYS_assert(iBlockSize == src.m_pData->iBlockSize);
105   int32_t iCopied = src.GetSize();
106   FXSYS_assert(iStart > -1 && iStart < iCopied);
107   if (iCount < 0) {
108     iCount = iCopied;
109   }
110   if (iStart + iCount > iCopied) {
111     iCount = iCopied - iStart;
112   }
113   if (iCount < 1) {
114     return 0;
115   }
116   RemoveAll(TRUE);
117   AddSpaceTo(iCount - 1);
118   FX_memcpy(m_pData->pBuffer, src.m_pData->pBuffer + iStart * iBlockSize,
119             iCount * iBlockSize);
120   return iCount;
121 }
RemoveLast(int32_t iCount)122 int32_t CFX_BaseArray::RemoveLast(int32_t iCount) {
123   int32_t& iBlockCount = m_pData->iBlockCount;
124   if (iCount < 0 || iCount > iBlockCount) {
125     iCount = iBlockCount;
126     iBlockCount = 0;
127   } else {
128     iBlockCount -= iCount;
129   }
130   return iCount;
131 }
RemoveAll(FX_BOOL bLeaveMemory)132 void CFX_BaseArray::RemoveAll(FX_BOOL bLeaveMemory) {
133   if (!bLeaveMemory) {
134     uint8_t*& pBuffer = m_pData->pBuffer;
135     if (pBuffer != NULL) {
136       FX_Free(pBuffer);
137       pBuffer = NULL;
138     }
139     m_pData->iTotalCount = 0;
140   }
141   m_pData->iBlockCount = 0;
142 }
CFX_BaseMassArrayImp(int32_t iChunkSize,int32_t iBlockSize)143 CFX_BaseMassArrayImp::CFX_BaseMassArrayImp(int32_t iChunkSize,
144                                            int32_t iBlockSize)
145     : m_iChunkSize(iChunkSize),
146       m_iBlockSize(iBlockSize),
147       m_iChunkCount(0),
148       m_iBlockCount(0) {
149   FXSYS_assert(m_iChunkSize > 0 && m_iBlockSize > 0);
150   m_pData = new CFX_PtrArray;
151   m_pData->SetSize(16);
152 }
~CFX_BaseMassArrayImp()153 CFX_BaseMassArrayImp::~CFX_BaseMassArrayImp() {
154   RemoveAll();
155   delete m_pData;
156 }
AddSpaceTo(int32_t index)157 uint8_t* CFX_BaseMassArrayImp::AddSpaceTo(int32_t index) {
158   FXSYS_assert(index > -1);
159   uint8_t* pChunk;
160   if (index < m_iBlockCount) {
161     pChunk = (uint8_t*)m_pData->GetAt(index / m_iChunkSize);
162   } else {
163     int32_t iMemSize = m_iChunkSize * m_iBlockSize;
164     while (TRUE) {
165       if (index < m_iChunkCount * m_iChunkSize) {
166         pChunk = (uint8_t*)m_pData->GetAt(index / m_iChunkSize);
167         break;
168       } else {
169         pChunk = FX_Alloc(uint8_t, iMemSize);
170         if (m_iChunkCount < m_pData->GetSize()) {
171           m_pData->SetAt(m_iChunkCount, pChunk);
172         } else {
173           m_pData->Add(pChunk);
174         }
175         m_iChunkCount++;
176       }
177     }
178   }
179   FXSYS_assert(pChunk != NULL);
180   m_iBlockCount = index + 1;
181   return pChunk + (index % m_iChunkSize) * m_iBlockSize;
182 }
GetAt(int32_t index) const183 uint8_t* CFX_BaseMassArrayImp::GetAt(int32_t index) const {
184   FXSYS_assert(index > -1 && index < m_iBlockCount);
185   uint8_t* pChunk = (uint8_t*)m_pData->GetAt(index / m_iChunkSize);
186   FXSYS_assert(pChunk != NULL);
187   return pChunk + (index % m_iChunkSize) * m_iBlockSize;
188 }
Append(const CFX_BaseMassArrayImp & src,int32_t iStart,int32_t iCount)189 int32_t CFX_BaseMassArrayImp::Append(const CFX_BaseMassArrayImp& src,
190                                      int32_t iStart,
191                                      int32_t iCount) {
192   FXSYS_assert(m_iBlockSize == src.m_iBlockSize);
193   int32_t iAdded = src.m_iBlockCount;
194   FXSYS_assert(iStart > -1 && iStart < iAdded);
195   if (iCount < 0) {
196     iCount = iAdded;
197   }
198   if (iStart + iCount > iAdded) {
199     iCount = iAdded - iStart;
200   }
201   if (iCount < 1) {
202     return m_iBlockCount;
203   }
204   int32_t iBlockCount = m_iBlockCount;
205   int32_t iTotal = m_iBlockCount + iCount;
206   AddSpaceTo(iTotal - 1);
207   Append(iBlockCount, src, iStart, iCount);
208   return m_iBlockCount;
209 }
Copy(const CFX_BaseMassArrayImp & src,int32_t iStart,int32_t iCount)210 int32_t CFX_BaseMassArrayImp::Copy(const CFX_BaseMassArrayImp& src,
211                                    int32_t iStart,
212                                    int32_t iCount) {
213   FXSYS_assert(m_iBlockSize == src.m_iBlockSize);
214   int32_t iCopied = src.m_iBlockCount;
215   FXSYS_assert(iStart > -1);
216   if (iStart >= iCopied) {
217     return 0;
218   }
219   RemoveAll(TRUE);
220   if (iCount < 0) {
221     iCount = iCopied;
222   }
223   if (iStart + iCount > iCopied) {
224     iCount = iCopied - iStart;
225   }
226   if (iCount < 1) {
227     return 0;
228   }
229   if (m_iBlockCount < iCount) {
230     AddSpaceTo(iCount - 1);
231   }
232   Append(0, src, iStart, iCount);
233   return m_iBlockCount;
234 }
Append(int32_t iDstStart,const CFX_BaseMassArrayImp & src,int32_t iSrcStart,int32_t iSrcCount)235 void CFX_BaseMassArrayImp::Append(int32_t iDstStart,
236                                   const CFX_BaseMassArrayImp& src,
237                                   int32_t iSrcStart,
238                                   int32_t iSrcCount) {
239   FXSYS_assert(iDstStart > -1 && m_iBlockSize == src.m_iBlockSize);
240   int32_t iSrcTotal = src.m_iBlockCount;
241   FXSYS_assert(iSrcTotal > 0 && m_iBlockCount >= iDstStart + iSrcCount);
242   FXSYS_assert(iSrcStart > -1 && iSrcStart < iSrcTotal && iSrcCount > 0 &&
243                iSrcStart + iSrcCount <= iSrcTotal);
244   int32_t iDstChunkIndex = iDstStart / m_iChunkSize;
245   int32_t iSrcChunkIndex = iSrcStart / src.m_iChunkSize;
246   uint8_t* pDstChunk = (uint8_t*)GetAt(iDstStart);
247   uint8_t* pSrcChunk = (uint8_t*)src.GetAt(iSrcStart);
248   int32_t iDstChunkSize = m_iChunkSize - (iDstStart % m_iChunkSize);
249   int32_t iSrcChunkSize = src.m_iChunkSize - (iSrcStart % src.m_iChunkSize);
250   int32_t iCopySize =
251       std::min(iSrcCount, std::min(iSrcChunkSize, iDstChunkSize));
252   int32_t iCopyBytes = iCopySize * m_iBlockSize;
253   while (iSrcCount > 0) {
254     FXSYS_assert(pDstChunk != NULL && pSrcChunk != NULL);
255     FXSYS_memcpy(pDstChunk, pSrcChunk, iCopyBytes);
256     iSrcCount -= iCopySize;
257     iSrcChunkSize -= iCopySize;
258     if (iSrcChunkSize < 1) {
259       iSrcChunkSize = src.m_iChunkSize;
260       iSrcChunkIndex++;
261       pSrcChunk = (uint8_t*)src.m_pData->GetAt(iSrcChunkIndex);
262     } else {
263       pSrcChunk += iCopyBytes;
264     }
265     iDstChunkSize -= iCopySize;
266     if (iDstChunkSize < 1) {
267       iDstChunkSize = m_iChunkSize;
268       iDstChunkIndex++;
269       pDstChunk = (uint8_t*)m_pData->GetAt(iDstChunkIndex);
270     } else {
271       pDstChunk += iCopyBytes;
272     }
273     iCopySize = std::min(iSrcCount, std::min(iSrcChunkSize, iDstChunkSize));
274     iCopyBytes = iCopySize * m_iBlockSize;
275   }
276 }
RemoveLast(int32_t iCount)277 int32_t CFX_BaseMassArrayImp::RemoveLast(int32_t iCount) {
278   if (iCount < 0 || iCount >= m_iBlockCount) {
279     m_iBlockCount = 0;
280   } else {
281     m_iBlockCount -= iCount;
282   }
283   return m_iBlockCount;
284 }
RemoveAll(FX_BOOL bLeaveMemory)285 void CFX_BaseMassArrayImp::RemoveAll(FX_BOOL bLeaveMemory) {
286   if (bLeaveMemory) {
287     m_iBlockCount = 0;
288     return;
289   }
290   for (int32_t i = 0; i < m_iChunkCount; i++) {
291     void* p = m_pData->GetAt(i);
292     if (p == NULL) {
293       continue;
294     }
295     FX_Free(p);
296   }
297   m_pData->RemoveAll();
298   m_iChunkCount = 0;
299   m_iBlockCount = 0;
300 }
CFX_BaseMassArray(int32_t iChunkSize,int32_t iBlockSize)301 CFX_BaseMassArray::CFX_BaseMassArray(int32_t iChunkSize, int32_t iBlockSize) {
302   m_pData = new CFX_BaseMassArrayImp(iChunkSize, iBlockSize);
303 }
~CFX_BaseMassArray()304 CFX_BaseMassArray::~CFX_BaseMassArray() {
305   delete m_pData;
306 }
GetSize() const307 int32_t CFX_BaseMassArray::GetSize() const {
308   return m_pData->m_iBlockCount;
309 }
AddSpaceTo(int32_t index)310 uint8_t* CFX_BaseMassArray::AddSpaceTo(int32_t index) {
311   return m_pData->AddSpaceTo(index);
312 }
GetAt(int32_t index) const313 uint8_t* CFX_BaseMassArray::GetAt(int32_t index) const {
314   return m_pData->GetAt(index);
315 }
Append(const CFX_BaseMassArray & src,int32_t iStart,int32_t iCount)316 int32_t CFX_BaseMassArray::Append(const CFX_BaseMassArray& src,
317                                   int32_t iStart,
318                                   int32_t iCount) {
319   return m_pData->Append(*(CFX_BaseMassArrayImp*)src.m_pData, iStart, iCount);
320 }
Copy(const CFX_BaseMassArray & src,int32_t iStart,int32_t iCount)321 int32_t CFX_BaseMassArray::Copy(const CFX_BaseMassArray& src,
322                                 int32_t iStart,
323                                 int32_t iCount) {
324   return m_pData->Copy(*(CFX_BaseMassArrayImp*)src.m_pData, iStart, iCount);
325 }
RemoveLast(int32_t iCount)326 int32_t CFX_BaseMassArray::RemoveLast(int32_t iCount) {
327   return m_pData->RemoveLast(iCount);
328 }
RemoveAll(FX_BOOL bLeaveMemory)329 void CFX_BaseMassArray::RemoveAll(FX_BOOL bLeaveMemory) {
330   m_pData->RemoveAll(bLeaveMemory);
331 }
332 typedef struct _FX_BASEDISCRETEARRAYDATA {
333   int32_t iBlockSize;
334   int32_t iChunkSize;
335   int32_t iChunkCount;
336   CFX_PtrArray ChunkBuffer;
337 } FX_BASEDISCRETEARRAYDATA, *FX_LPBASEDISCRETEARRAYDATA;
338 typedef FX_BASEDISCRETEARRAYDATA const* FX_LPCBASEDISCRETEARRAYDATA;
CFX_BaseDiscreteArray(int32_t iChunkSize,int32_t iBlockSize)339 CFX_BaseDiscreteArray::CFX_BaseDiscreteArray(int32_t iChunkSize,
340                                              int32_t iBlockSize) {
341   FXSYS_assert(iChunkSize > 0 && iBlockSize > 0);
342   FX_LPBASEDISCRETEARRAYDATA pData;
343   m_pData = pData = new FX_BASEDISCRETEARRAYDATA;
344   pData->ChunkBuffer.SetSize(16);
345   pData->iChunkCount = 0;
346   pData->iChunkSize = iChunkSize;
347   pData->iBlockSize = iBlockSize;
348 }
~CFX_BaseDiscreteArray()349 CFX_BaseDiscreteArray::~CFX_BaseDiscreteArray() {
350   RemoveAll();
351   delete (FX_LPBASEDISCRETEARRAYDATA) m_pData;
352 }
AddSpaceTo(int32_t index)353 uint8_t* CFX_BaseDiscreteArray::AddSpaceTo(int32_t index) {
354   FXSYS_assert(index > -1);
355   FX_LPBASEDISCRETEARRAYDATA pData = (FX_LPBASEDISCRETEARRAYDATA)m_pData;
356   int32_t& iChunkCount = pData->iChunkCount;
357   int32_t iChunkSize = pData->iChunkSize;
358   uint8_t* pChunk = NULL;
359   int32_t iChunk = index / iChunkSize;
360   if (iChunk < iChunkCount) {
361     pChunk = (uint8_t*)pData->ChunkBuffer.GetAt(iChunk);
362   }
363   if (!pChunk) {
364     pChunk = FX_Alloc2D(uint8_t, iChunkSize, pData->iBlockSize);
365     FXSYS_memset(pChunk, 0, iChunkSize * pData->iBlockSize);
366     pData->ChunkBuffer.SetAtGrow(iChunk, pChunk);
367     if (iChunkCount <= iChunk) {
368       iChunkCount = iChunk + 1;
369     }
370   }
371   return pChunk + (index % iChunkSize) * pData->iBlockSize;
372 }
GetAt(int32_t index) const373 uint8_t* CFX_BaseDiscreteArray::GetAt(int32_t index) const {
374   FXSYS_assert(index > -1);
375   FX_LPBASEDISCRETEARRAYDATA pData = (FX_LPBASEDISCRETEARRAYDATA)m_pData;
376   int32_t iChunkSize = pData->iChunkSize;
377   int32_t iChunk = index / iChunkSize;
378   if (iChunk >= pData->iChunkCount) {
379     return NULL;
380   }
381   uint8_t* pChunk = (uint8_t*)pData->ChunkBuffer.GetAt(iChunk);
382   if (pChunk == NULL) {
383     return NULL;
384   }
385   return pChunk + (index % iChunkSize) * pData->iBlockSize;
386 }
RemoveAll()387 void CFX_BaseDiscreteArray::RemoveAll() {
388   FX_LPBASEDISCRETEARRAYDATA pData = (FX_LPBASEDISCRETEARRAYDATA)m_pData;
389   CFX_PtrArray& ChunkBuffer = pData->ChunkBuffer;
390   int32_t& iChunkCount = pData->iChunkCount;
391   for (int32_t i = 0; i < iChunkCount; i++) {
392     void* p = ChunkBuffer.GetAt(i);
393     if (p == NULL) {
394       continue;
395     }
396     FX_Free(p);
397   }
398   ChunkBuffer.RemoveAll();
399   iChunkCount = 0;
400 }
CFX_BaseStack(int32_t iChunkSize,int32_t iBlockSize)401 CFX_BaseStack::CFX_BaseStack(int32_t iChunkSize, int32_t iBlockSize) {
402   m_pData = new CFX_BaseMassArrayImp(iChunkSize, iBlockSize);
403 }
~CFX_BaseStack()404 CFX_BaseStack::~CFX_BaseStack() {
405   delete (CFX_BaseMassArrayImp*)m_pData;
406 }
Push()407 uint8_t* CFX_BaseStack::Push() {
408   return m_pData->AddSpace();
409 }
Pop()410 void CFX_BaseStack::Pop() {
411   int32_t& iBlockCount = m_pData->m_iBlockCount;
412   if (iBlockCount < 1) {
413     return;
414   }
415   iBlockCount--;
416 }
GetTopElement() const417 uint8_t* CFX_BaseStack::GetTopElement() const {
418   int32_t iSize = m_pData->m_iBlockCount;
419   if (iSize < 1) {
420     return NULL;
421   }
422   return m_pData->GetAt(iSize - 1);
423 }
GetSize() const424 int32_t CFX_BaseStack::GetSize() const {
425   return m_pData->m_iBlockCount;
426 }
GetAt(int32_t index) const427 uint8_t* CFX_BaseStack::GetAt(int32_t index) const {
428   return m_pData->GetAt(index);
429 }
RemoveAll(FX_BOOL bLeaveMemory)430 void CFX_BaseStack::RemoveAll(FX_BOOL bLeaveMemory) {
431   m_pData->RemoveAll(bLeaveMemory);
432 }
433