| // Copyright 2017 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 "core/fxcrt/cfx_blockbuffer.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| namespace { |
| |
| const size_t kAllocStep = 1024 * 1024; |
| |
| } // namespace |
| |
| CFX_BlockBuffer::CFX_BlockBuffer() |
| : m_DataLength(0), m_BufferSize(0), m_StartPosition(0) {} |
| |
| CFX_BlockBuffer::~CFX_BlockBuffer() {} |
| |
| size_t CFX_BlockBuffer::GetAllocStep() const { |
| return kAllocStep; |
| } |
| |
| std::pair<wchar_t*, size_t> CFX_BlockBuffer::GetAvailableBlock() { |
| if (m_BlockArray.empty()) |
| return {nullptr, 0}; |
| |
| size_t realIndex = m_StartPosition + m_DataLength; |
| if (realIndex == m_BufferSize) { |
| m_BlockArray.emplace_back(FX_Alloc(wchar_t, kAllocStep)); |
| m_BufferSize += kAllocStep; |
| return {m_BlockArray.back().get(), 0}; |
| } |
| return {m_BlockArray[realIndex / kAllocStep].get(), realIndex % kAllocStep}; |
| } |
| |
| bool CFX_BlockBuffer::InitBuffer() { |
| m_BlockArray.clear(); |
| m_BlockArray.emplace_back(FX_Alloc(wchar_t, kAllocStep)); |
| m_BufferSize = kAllocStep; |
| return true; |
| } |
| |
| void CFX_BlockBuffer::SetTextChar(size_t index, wchar_t ch) { |
| size_t realIndex = m_StartPosition + index; |
| size_t blockIndex = realIndex / kAllocStep; |
| if (blockIndex >= m_BlockArray.size()) { |
| size_t newBlocks = blockIndex - m_BlockArray.size() + 1; |
| do { |
| m_BlockArray.emplace_back(FX_Alloc(wchar_t, kAllocStep)); |
| m_BufferSize += kAllocStep; |
| } while (--newBlocks); |
| } |
| wchar_t* pTextData = m_BlockArray[blockIndex].get(); |
| pTextData[realIndex % kAllocStep] = ch; |
| m_DataLength = std::max(m_DataLength, index + 1); |
| } |
| |
| void CFX_BlockBuffer::DeleteTextChars(size_t count) { |
| if (count == 0) |
| return; |
| |
| if (count >= m_DataLength) { |
| Reset(false); |
| return; |
| } |
| m_DataLength -= count; |
| } |
| |
| CFX_WideString CFX_BlockBuffer::GetTextData(size_t start, size_t length) const { |
| if (m_BufferSize <= m_StartPosition + 1 || length == 0) |
| return CFX_WideString(); |
| |
| size_t maybeDataLength = m_BufferSize - 1 - m_StartPosition; |
| if (start > maybeDataLength) |
| return CFX_WideString(); |
| length = std::min(length, maybeDataLength); |
| |
| CFX_WideString wsTextData; |
| wchar_t* pBuf = wsTextData.GetBuffer(length); |
| if (!pBuf) |
| return CFX_WideString(); |
| |
| size_t startBlock = 0; |
| size_t startInner = 0; |
| std::tie(startBlock, startInner) = TextDataIndex2BufIndex(start); |
| |
| size_t endBlock = 0; |
| size_t endInner = 0; |
| std::tie(endBlock, endInner) = TextDataIndex2BufIndex(start + length); |
| |
| size_t pointer = 0; |
| for (size_t i = startBlock; i <= endBlock; ++i) { |
| size_t bufferPointer = 0; |
| size_t copyLength = kAllocStep; |
| if (i == startBlock) { |
| copyLength -= startInner; |
| bufferPointer = startInner; |
| } |
| if (i == endBlock) |
| copyLength -= ((kAllocStep - 1) - endInner); |
| |
| wchar_t* pBlockBuf = m_BlockArray[i].get(); |
| memcpy(pBuf + pointer, pBlockBuf + bufferPointer, |
| copyLength * sizeof(wchar_t)); |
| pointer += copyLength; |
| } |
| wsTextData.ReleaseBuffer(length); |
| return wsTextData; |
| } |
| |
| std::pair<size_t, size_t> CFX_BlockBuffer::TextDataIndex2BufIndex( |
| const size_t iIndex) const { |
| ASSERT(iIndex >= 0); |
| |
| size_t realIndex = m_StartPosition + iIndex; |
| return {realIndex / kAllocStep, realIndex % kAllocStep}; |
| } |