summaryrefslogtreecommitdiff
path: root/core/fxcrt/cfx_blockbuffer.cpp
blob: 7609fb9a2586c495a7631c27671d74e5321d2754 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// 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 int 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();
  if (length > maybeDataLength)
    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};
}