summaryrefslogtreecommitdiff
path: root/core/fxcrt/cfx_blockbuffer.cpp
blob: 6a7d98aa18840f25cc1cdb2de6cc31038bf2426a (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
123
124
// 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;
}

WideString CFX_BlockBuffer::GetTextData(size_t start, size_t length) const {
  if (m_BufferSize <= m_StartPosition + 1 || length == 0)
    return WideString();

  size_t maybeDataLength = m_BufferSize - 1 - m_StartPosition;
  if (start > maybeDataLength)
    return WideString();

  length = std::min(length, maybeDataLength);
  if (!length)
    return WideString();

  WideString wsTextData;
  {
    // Span's lifetime must end before ReleaseBuffer() below.
    pdfium::span<wchar_t> pBuf = wsTextData.GetBuffer(length);
    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};
}