1 // Copyright 2017 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 "core/fxcrt/cfx_blockbuffer.h"
8
9 #include <algorithm>
10 #include <utility>
11
12 namespace {
13
14 const size_t kAllocStep = 1024 * 1024;
15
16 } // namespace
17
CFX_BlockBuffer()18 CFX_BlockBuffer::CFX_BlockBuffer()
19 : m_DataLength(0), m_BufferSize(0), m_StartPosition(0) {}
20
~CFX_BlockBuffer()21 CFX_BlockBuffer::~CFX_BlockBuffer() {}
22
GetAllocStep() const23 size_t CFX_BlockBuffer::GetAllocStep() const {
24 return kAllocStep;
25 }
26
GetAvailableBlock()27 std::pair<wchar_t*, size_t> CFX_BlockBuffer::GetAvailableBlock() {
28 if (m_BlockArray.empty())
29 return {nullptr, 0};
30
31 size_t realIndex = m_StartPosition + m_DataLength;
32 if (realIndex == m_BufferSize) {
33 m_BlockArray.emplace_back(FX_Alloc(wchar_t, kAllocStep));
34 m_BufferSize += kAllocStep;
35 return {m_BlockArray.back().get(), 0};
36 }
37 return {m_BlockArray[realIndex / kAllocStep].get(), realIndex % kAllocStep};
38 }
39
InitBuffer()40 bool CFX_BlockBuffer::InitBuffer() {
41 m_BlockArray.clear();
42 m_BlockArray.emplace_back(FX_Alloc(wchar_t, kAllocStep));
43 m_BufferSize = kAllocStep;
44 return true;
45 }
46
SetTextChar(size_t index,wchar_t ch)47 void CFX_BlockBuffer::SetTextChar(size_t index, wchar_t ch) {
48 size_t realIndex = m_StartPosition + index;
49 size_t blockIndex = realIndex / kAllocStep;
50 if (blockIndex >= m_BlockArray.size()) {
51 size_t newBlocks = blockIndex - m_BlockArray.size() + 1;
52 do {
53 m_BlockArray.emplace_back(FX_Alloc(wchar_t, kAllocStep));
54 m_BufferSize += kAllocStep;
55 } while (--newBlocks);
56 }
57 wchar_t* pTextData = m_BlockArray[blockIndex].get();
58 pTextData[realIndex % kAllocStep] = ch;
59 m_DataLength = std::max(m_DataLength, index + 1);
60 }
61
DeleteTextChars(size_t count)62 void CFX_BlockBuffer::DeleteTextChars(size_t count) {
63 if (count == 0)
64 return;
65
66 if (count >= m_DataLength) {
67 Reset(false);
68 return;
69 }
70 m_DataLength -= count;
71 }
72
GetTextData(size_t start,size_t length) const73 WideString CFX_BlockBuffer::GetTextData(size_t start, size_t length) const {
74 if (m_BufferSize <= m_StartPosition + 1 || length == 0)
75 return WideString();
76
77 size_t maybeDataLength = m_BufferSize - 1 - m_StartPosition;
78 if (start > maybeDataLength)
79 return WideString();
80 length = std::min(length, maybeDataLength);
81
82 WideString wsTextData;
83 wchar_t* pBuf = wsTextData.GetBuffer(length);
84 if (!pBuf)
85 return WideString();
86
87 size_t startBlock = 0;
88 size_t startInner = 0;
89 std::tie(startBlock, startInner) = TextDataIndex2BufIndex(start);
90
91 size_t endBlock = 0;
92 size_t endInner = 0;
93 std::tie(endBlock, endInner) = TextDataIndex2BufIndex(start + length);
94
95 size_t pointer = 0;
96 for (size_t i = startBlock; i <= endBlock; ++i) {
97 size_t bufferPointer = 0;
98 size_t copyLength = kAllocStep;
99 if (i == startBlock) {
100 copyLength -= startInner;
101 bufferPointer = startInner;
102 }
103 if (i == endBlock)
104 copyLength -= ((kAllocStep - 1) - endInner);
105
106 wchar_t* pBlockBuf = m_BlockArray[i].get();
107 memcpy(pBuf + pointer, pBlockBuf + bufferPointer,
108 copyLength * sizeof(wchar_t));
109 pointer += copyLength;
110 }
111 wsTextData.ReleaseBuffer(length);
112 return wsTextData;
113 }
114
TextDataIndex2BufIndex(const size_t iIndex) const115 std::pair<size_t, size_t> CFX_BlockBuffer::TextDataIndex2BufIndex(
116 const size_t iIndex) const {
117 ASSERT(iIndex >= 0);
118
119 size_t realIndex = m_StartPosition + iIndex;
120 return {realIndex / kAllocStep, realIndex % kAllocStep};
121 }
122