| // Copyright 2014 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "xfa/fgas/crt/fgas_utils.h" |
| |
| #include <algorithm> |
| |
| #include "core/fxcrt/include/fx_basic.h" |
| |
| class FX_BASEARRAYDATA : public CFX_Target { |
| public: |
| FX_BASEARRAYDATA(int32_t growsize, int32_t blocksize) |
| : iGrowSize(growsize), |
| iBlockSize(blocksize), |
| iTotalCount(0), |
| iBlockCount(0), |
| pBuffer(nullptr) {} |
| |
| ~FX_BASEARRAYDATA() { FX_Free(pBuffer); } |
| |
| int32_t iGrowSize; |
| int32_t iBlockSize; |
| int32_t iTotalCount; |
| int32_t iBlockCount; |
| uint8_t* pBuffer; |
| }; |
| CFX_BaseArray::CFX_BaseArray(int32_t iGrowSize, int32_t iBlockSize) { |
| ASSERT(iGrowSize > 0 && iBlockSize > 0); |
| m_pData = new FX_BASEARRAYDATA(iGrowSize, iBlockSize); |
| } |
| CFX_BaseArray::~CFX_BaseArray() { |
| RemoveAll(); |
| delete m_pData; |
| } |
| int32_t CFX_BaseArray::GetSize() const { |
| return m_pData->iBlockCount; |
| } |
| int32_t CFX_BaseArray::GetBlockSize() const { |
| return m_pData->iBlockSize; |
| } |
| uint8_t* CFX_BaseArray::AddSpaceTo(int32_t index) { |
| ASSERT(index > -1); |
| uint8_t*& pBuffer = m_pData->pBuffer; |
| int32_t& iTotalCount = m_pData->iTotalCount; |
| int32_t iBlockSize = m_pData->iBlockSize; |
| if (index >= iTotalCount) { |
| int32_t iGrowSize = m_pData->iGrowSize; |
| iTotalCount = (index / iGrowSize + 1) * iGrowSize; |
| int32_t iNewSize = iTotalCount * iBlockSize; |
| if (!pBuffer) { |
| pBuffer = FX_Alloc(uint8_t, iNewSize); |
| } else { |
| pBuffer = FX_Realloc(uint8_t, pBuffer, iNewSize); |
| } |
| } |
| int32_t& iBlockCount = m_pData->iBlockCount; |
| if (index >= iBlockCount) { |
| iBlockCount = index + 1; |
| } |
| return pBuffer + index * iBlockSize; |
| } |
| uint8_t* CFX_BaseArray::GetAt(int32_t index) const { |
| ASSERT(index > -1 && index < m_pData->iBlockCount); |
| return m_pData->pBuffer + index * m_pData->iBlockSize; |
| } |
| uint8_t* CFX_BaseArray::GetBuffer() const { |
| return m_pData->pBuffer; |
| } |
| int32_t CFX_BaseArray::Append(const CFX_BaseArray& src, |
| int32_t iStart, |
| int32_t iCount) { |
| int32_t iBlockSize = m_pData->iBlockSize; |
| ASSERT(iBlockSize == src.m_pData->iBlockSize); |
| int32_t& iBlockCount = m_pData->iBlockCount; |
| int32_t iAdded = src.GetSize(); |
| ASSERT(iStart > -1 && iStart < iAdded); |
| if (iCount < 0) { |
| iCount = iAdded; |
| } |
| if (iStart + iCount > iAdded) { |
| iCount = iAdded - iStart; |
| } |
| if (iCount < 1) { |
| return 0; |
| } |
| uint8_t* pDst = m_pData->pBuffer + iBlockCount * iBlockSize; |
| AddSpaceTo(iBlockCount + iCount - 1); |
| FXSYS_memcpy(pDst, src.m_pData->pBuffer + iStart * iBlockSize, |
| iCount * iBlockSize); |
| return iCount; |
| } |
| int32_t CFX_BaseArray::Copy(const CFX_BaseArray& src, |
| int32_t iStart, |
| int32_t iCount) { |
| int32_t iBlockSize = m_pData->iBlockSize; |
| ASSERT(iBlockSize == src.m_pData->iBlockSize); |
| int32_t iCopied = src.GetSize(); |
| ASSERT(iStart > -1 && iStart < iCopied); |
| if (iCount < 0) { |
| iCount = iCopied; |
| } |
| if (iStart + iCount > iCopied) { |
| iCount = iCopied - iStart; |
| } |
| if (iCount < 1) { |
| return 0; |
| } |
| RemoveAll(TRUE); |
| AddSpaceTo(iCount - 1); |
| FXSYS_memcpy(m_pData->pBuffer, src.m_pData->pBuffer + iStart * iBlockSize, |
| iCount * iBlockSize); |
| return iCount; |
| } |
| int32_t CFX_BaseArray::RemoveLast(int32_t iCount) { |
| int32_t& iBlockCount = m_pData->iBlockCount; |
| if (iCount < 0 || iCount > iBlockCount) { |
| iCount = iBlockCount; |
| iBlockCount = 0; |
| } else { |
| iBlockCount -= iCount; |
| } |
| return iCount; |
| } |
| void CFX_BaseArray::RemoveAll(FX_BOOL bLeaveMemory) { |
| if (!bLeaveMemory) { |
| uint8_t*& pBuffer = m_pData->pBuffer; |
| if (pBuffer != NULL) { |
| FX_Free(pBuffer); |
| pBuffer = NULL; |
| } |
| m_pData->iTotalCount = 0; |
| } |
| m_pData->iBlockCount = 0; |
| } |
| |
| CFX_BaseMassArrayImp::CFX_BaseMassArrayImp(int32_t iChunkSize, |
| int32_t iBlockSize) |
| : m_iChunkSize(iChunkSize), |
| m_iBlockSize(iBlockSize), |
| m_iChunkCount(0), |
| m_iBlockCount(0), |
| m_pData(new CFX_ArrayTemplate<void*>()) { |
| ASSERT(m_iChunkSize > 0 && m_iBlockSize > 0); |
| m_pData->SetSize(16); |
| } |
| CFX_BaseMassArrayImp::~CFX_BaseMassArrayImp() { |
| RemoveAll(); |
| delete m_pData; |
| } |
| uint8_t* CFX_BaseMassArrayImp::AddSpaceTo(int32_t index) { |
| ASSERT(index > -1); |
| uint8_t* pChunk; |
| if (index < m_iBlockCount) { |
| pChunk = (uint8_t*)m_pData->GetAt(index / m_iChunkSize); |
| } else { |
| int32_t iMemSize = m_iChunkSize * m_iBlockSize; |
| while (TRUE) { |
| if (index < m_iChunkCount * m_iChunkSize) { |
| pChunk = (uint8_t*)m_pData->GetAt(index / m_iChunkSize); |
| break; |
| } else { |
| pChunk = FX_Alloc(uint8_t, iMemSize); |
| if (m_iChunkCount < m_pData->GetSize()) { |
| m_pData->SetAt(m_iChunkCount, pChunk); |
| } else { |
| m_pData->Add(pChunk); |
| } |
| m_iChunkCount++; |
| } |
| } |
| } |
| ASSERT(pChunk != NULL); |
| m_iBlockCount = index + 1; |
| return pChunk + (index % m_iChunkSize) * m_iBlockSize; |
| } |
| uint8_t* CFX_BaseMassArrayImp::GetAt(int32_t index) const { |
| ASSERT(index > -1 && index < m_iBlockCount); |
| uint8_t* pChunk = (uint8_t*)m_pData->GetAt(index / m_iChunkSize); |
| ASSERT(pChunk != NULL); |
| return pChunk + (index % m_iChunkSize) * m_iBlockSize; |
| } |
| int32_t CFX_BaseMassArrayImp::Append(const CFX_BaseMassArrayImp& src, |
| int32_t iStart, |
| int32_t iCount) { |
| ASSERT(m_iBlockSize == src.m_iBlockSize); |
| int32_t iAdded = src.m_iBlockCount; |
| ASSERT(iStart > -1 && iStart < iAdded); |
| if (iCount < 0) { |
| iCount = iAdded; |
| } |
| if (iStart + iCount > iAdded) { |
| iCount = iAdded - iStart; |
| } |
| if (iCount < 1) { |
| return m_iBlockCount; |
| } |
| int32_t iBlockCount = m_iBlockCount; |
| int32_t iTotal = m_iBlockCount + iCount; |
| AddSpaceTo(iTotal - 1); |
| Append(iBlockCount, src, iStart, iCount); |
| return m_iBlockCount; |
| } |
| int32_t CFX_BaseMassArrayImp::Copy(const CFX_BaseMassArrayImp& src, |
| int32_t iStart, |
| int32_t iCount) { |
| ASSERT(m_iBlockSize == src.m_iBlockSize); |
| int32_t iCopied = src.m_iBlockCount; |
| ASSERT(iStart > -1); |
| if (iStart >= iCopied) { |
| return 0; |
| } |
| RemoveAll(TRUE); |
| if (iCount < 0) { |
| iCount = iCopied; |
| } |
| if (iStart + iCount > iCopied) { |
| iCount = iCopied - iStart; |
| } |
| if (iCount < 1) { |
| return 0; |
| } |
| if (m_iBlockCount < iCount) { |
| AddSpaceTo(iCount - 1); |
| } |
| Append(0, src, iStart, iCount); |
| return m_iBlockCount; |
| } |
| |
| void CFX_BaseMassArrayImp::Append(int32_t iDstStart, |
| const CFX_BaseMassArrayImp& src, |
| int32_t iSrcStart, |
| int32_t iSrcCount) { |
| ASSERT(iDstStart > -1); |
| ASSERT(m_iBlockSize == src.m_iBlockSize); |
| ASSERT(src.m_iBlockCount > 0); |
| ASSERT(m_iBlockCount >= iDstStart + iSrcCount); |
| ASSERT(iSrcStart > -1); |
| ASSERT(iSrcStart < src.m_iBlockCount); |
| ASSERT(iSrcCount > 0); |
| ASSERT(iSrcStart + iSrcCount <= src.m_iBlockCount); |
| |
| int32_t iDstChunkIndex = iDstStart / m_iChunkSize; |
| int32_t iSrcChunkIndex = iSrcStart / src.m_iChunkSize; |
| uint8_t* pDstChunk = (uint8_t*)GetAt(iDstStart); |
| uint8_t* pSrcChunk = (uint8_t*)src.GetAt(iSrcStart); |
| int32_t iDstChunkSize = m_iChunkSize - (iDstStart % m_iChunkSize); |
| int32_t iSrcChunkSize = src.m_iChunkSize - (iSrcStart % src.m_iChunkSize); |
| int32_t iCopySize = |
| std::min(iSrcCount, std::min(iSrcChunkSize, iDstChunkSize)); |
| int32_t iCopyBytes = iCopySize * m_iBlockSize; |
| while (iSrcCount > 0) { |
| ASSERT(pDstChunk != NULL && pSrcChunk != NULL); |
| FXSYS_memcpy(pDstChunk, pSrcChunk, iCopyBytes); |
| iSrcCount -= iCopySize; |
| iSrcChunkSize -= iCopySize; |
| if (iSrcChunkSize < 1) { |
| iSrcChunkSize = src.m_iChunkSize; |
| iSrcChunkIndex++; |
| pSrcChunk = (uint8_t*)src.m_pData->GetAt(iSrcChunkIndex); |
| } else { |
| pSrcChunk += iCopyBytes; |
| } |
| iDstChunkSize -= iCopySize; |
| if (iDstChunkSize < 1) { |
| iDstChunkSize = m_iChunkSize; |
| iDstChunkIndex++; |
| pDstChunk = (uint8_t*)m_pData->GetAt(iDstChunkIndex); |
| } else { |
| pDstChunk += iCopyBytes; |
| } |
| iCopySize = std::min(iSrcCount, std::min(iSrcChunkSize, iDstChunkSize)); |
| iCopyBytes = iCopySize * m_iBlockSize; |
| } |
| } |
| int32_t CFX_BaseMassArrayImp::RemoveLast(int32_t iCount) { |
| if (iCount < 0 || iCount >= m_iBlockCount) { |
| m_iBlockCount = 0; |
| } else { |
| m_iBlockCount -= iCount; |
| } |
| return m_iBlockCount; |
| } |
| void CFX_BaseMassArrayImp::RemoveAll(FX_BOOL bLeaveMemory) { |
| if (bLeaveMemory) { |
| m_iBlockCount = 0; |
| return; |
| } |
| for (int32_t i = 0; i < m_iChunkCount; i++) { |
| void* p = m_pData->GetAt(i); |
| if (p == NULL) { |
| continue; |
| } |
| FX_Free(p); |
| } |
| m_pData->RemoveAll(); |
| m_iChunkCount = 0; |
| m_iBlockCount = 0; |
| } |
| CFX_BaseMassArray::CFX_BaseMassArray(int32_t iChunkSize, int32_t iBlockSize) { |
| m_pData = new CFX_BaseMassArrayImp(iChunkSize, iBlockSize); |
| } |
| CFX_BaseMassArray::~CFX_BaseMassArray() { |
| delete m_pData; |
| } |
| int32_t CFX_BaseMassArray::GetSize() const { |
| return m_pData->m_iBlockCount; |
| } |
| uint8_t* CFX_BaseMassArray::AddSpaceTo(int32_t index) { |
| return m_pData->AddSpaceTo(index); |
| } |
| uint8_t* CFX_BaseMassArray::GetAt(int32_t index) const { |
| return m_pData->GetAt(index); |
| } |
| int32_t CFX_BaseMassArray::Append(const CFX_BaseMassArray& src, |
| int32_t iStart, |
| int32_t iCount) { |
| return m_pData->Append(*(CFX_BaseMassArrayImp*)src.m_pData, iStart, iCount); |
| } |
| int32_t CFX_BaseMassArray::Copy(const CFX_BaseMassArray& src, |
| int32_t iStart, |
| int32_t iCount) { |
| return m_pData->Copy(*(CFX_BaseMassArrayImp*)src.m_pData, iStart, iCount); |
| } |
| int32_t CFX_BaseMassArray::RemoveLast(int32_t iCount) { |
| return m_pData->RemoveLast(iCount); |
| } |
| void CFX_BaseMassArray::RemoveAll(FX_BOOL bLeaveMemory) { |
| m_pData->RemoveAll(bLeaveMemory); |
| } |
| |
| struct FX_BASEDISCRETEARRAYDATA { |
| int32_t iBlockSize; |
| int32_t iChunkSize; |
| int32_t iChunkCount; |
| CFX_ArrayTemplate<uint8_t*> ChunkBuffer; |
| }; |
| |
| CFX_BaseDiscreteArray::CFX_BaseDiscreteArray(int32_t iChunkSize, |
| int32_t iBlockSize) { |
| ASSERT(iChunkSize > 0 && iBlockSize > 0); |
| FX_BASEDISCRETEARRAYDATA* pData = new FX_BASEDISCRETEARRAYDATA; |
| m_pData = pData; |
| pData->ChunkBuffer.SetSize(16); |
| pData->iChunkCount = 0; |
| pData->iChunkSize = iChunkSize; |
| pData->iBlockSize = iBlockSize; |
| } |
| CFX_BaseDiscreteArray::~CFX_BaseDiscreteArray() { |
| RemoveAll(); |
| delete static_cast<FX_BASEDISCRETEARRAYDATA*>(m_pData); |
| } |
| uint8_t* CFX_BaseDiscreteArray::AddSpaceTo(int32_t index) { |
| ASSERT(index > -1); |
| FX_BASEDISCRETEARRAYDATA* pData = (FX_BASEDISCRETEARRAYDATA*)m_pData; |
| int32_t& iChunkCount = pData->iChunkCount; |
| int32_t iChunkSize = pData->iChunkSize; |
| uint8_t* pChunk = NULL; |
| int32_t iChunk = index / iChunkSize; |
| if (iChunk < iChunkCount) { |
| pChunk = pData->ChunkBuffer.GetAt(iChunk); |
| } |
| if (!pChunk) { |
| pChunk = FX_Alloc2D(uint8_t, iChunkSize, pData->iBlockSize); |
| FXSYS_memset(pChunk, 0, iChunkSize * pData->iBlockSize); |
| pData->ChunkBuffer.SetAtGrow(iChunk, pChunk); |
| if (iChunkCount <= iChunk) { |
| iChunkCount = iChunk + 1; |
| } |
| } |
| return pChunk + (index % iChunkSize) * pData->iBlockSize; |
| } |
| uint8_t* CFX_BaseDiscreteArray::GetAt(int32_t index) const { |
| ASSERT(index >= 0); |
| FX_BASEDISCRETEARRAYDATA* pData = (FX_BASEDISCRETEARRAYDATA*)m_pData; |
| int32_t iChunkSize = pData->iChunkSize; |
| int32_t iChunk = index / iChunkSize; |
| if (iChunk >= pData->iChunkCount) |
| return nullptr; |
| |
| uint8_t* pChunk = pData->ChunkBuffer.GetAt(iChunk); |
| if (!pChunk) |
| return nullptr; |
| |
| return pChunk + (index % iChunkSize) * pData->iBlockSize; |
| } |
| void CFX_BaseDiscreteArray::RemoveAll() { |
| FX_BASEDISCRETEARRAYDATA* pData = (FX_BASEDISCRETEARRAYDATA*)m_pData; |
| CFX_ArrayTemplate<uint8_t*>& ChunkBuffer = pData->ChunkBuffer; |
| int32_t& iChunkCount = pData->iChunkCount; |
| for (int32_t i = 0; i < iChunkCount; i++) |
| FX_Free(ChunkBuffer.GetAt(i)); |
| |
| ChunkBuffer.RemoveAll(); |
| iChunkCount = 0; |
| } |
| CFX_BaseStack::CFX_BaseStack(int32_t iChunkSize, int32_t iBlockSize) { |
| m_pData = new CFX_BaseMassArrayImp(iChunkSize, iBlockSize); |
| } |
| CFX_BaseStack::~CFX_BaseStack() { |
| delete (CFX_BaseMassArrayImp*)m_pData; |
| } |
| uint8_t* CFX_BaseStack::Push() { |
| return m_pData->AddSpace(); |
| } |
| void CFX_BaseStack::Pop() { |
| int32_t& iBlockCount = m_pData->m_iBlockCount; |
| if (iBlockCount < 1) { |
| return; |
| } |
| iBlockCount--; |
| } |
| uint8_t* CFX_BaseStack::GetTopElement() const { |
| int32_t iSize = m_pData->m_iBlockCount; |
| if (iSize < 1) { |
| return NULL; |
| } |
| return m_pData->GetAt(iSize - 1); |
| } |
| int32_t CFX_BaseStack::GetSize() const { |
| return m_pData->m_iBlockCount; |
| } |
| uint8_t* CFX_BaseStack::GetAt(int32_t index) const { |
| return m_pData->GetAt(index); |
| } |
| void CFX_BaseStack::RemoveAll(FX_BOOL bLeaveMemory) { |
| m_pData->RemoveAll(bLeaveMemory); |
| } |