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