Improved the state machine in GuestView.
[chromium-blink-merge.git] / pdf / chunk_stream.cc
blob7ac8f974a5b8b79dd17b67658c904febb593b1b6
1 // Copyright (c) 2010 The Chromium 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.
5 #include "pdf/chunk_stream.h"
7 #define __STDC_LIMIT_MACROS
8 #ifdef _WIN32
9 #include <limits.h>
10 #else
11 #include <stdint.h>
12 #endif
14 #include <algorithm>
16 #include "base/basictypes.h"
18 namespace chrome_pdf {
20 ChunkStream::ChunkStream() {
23 ChunkStream::~ChunkStream() {
26 void ChunkStream::Clear() {
27 chunks_.clear();
28 data_.clear();
31 void ChunkStream::Preallocate(size_t stream_size) {
32 data_.reserve(stream_size);
35 size_t ChunkStream::GetSize() {
36 return data_.size();
39 bool ChunkStream::WriteData(size_t offset, void* buffer, size_t size) {
40 if (SIZE_MAX - size < offset)
41 return false;
43 if (data_.size() < offset + size)
44 data_.resize(offset + size);
46 memcpy(&data_[offset], buffer, size);
48 if (chunks_.empty()) {
49 chunks_[offset] = size;
50 return true;
53 std::map<size_t, size_t>::iterator start = chunks_.upper_bound(offset);
54 if (start != chunks_.begin())
55 --start; // start now points to the key equal or lower than offset.
56 if (start->first + start->second < offset)
57 ++start; // start element is entirely before current chunk, skip it.
59 std::map<size_t, size_t>::iterator end = chunks_.upper_bound(offset + size);
60 if (start == end) { // No chunks to merge.
61 chunks_[offset] = size;
62 return true;
65 --end;
67 size_t new_offset = std::min<size_t>(start->first, offset);
68 size_t new_size =
69 std::max<size_t>(end->first + end->second, offset + size) - new_offset;
71 chunks_.erase(start, ++end);
73 chunks_[new_offset] = new_size;
75 return true;
78 bool ChunkStream::ReadData(size_t offset, size_t size, void* buffer) const {
79 if (!IsRangeAvailable(offset, size))
80 return false;
82 memcpy(buffer, &data_[offset], size);
83 return true;
86 bool ChunkStream::GetMissedRanges(
87 size_t offset, size_t size,
88 std::vector<std::pair<size_t, size_t> >* ranges) const {
89 if (IsRangeAvailable(offset, size))
90 return false;
92 ranges->clear();
93 if (chunks_.empty()) {
94 ranges->push_back(std::pair<size_t, size_t>(offset, size));
95 return true;
98 std::map<size_t, size_t>::const_iterator start = chunks_.upper_bound(offset);
99 if (start != chunks_.begin())
100 --start; // start now points to the key equal or lower than offset.
101 if (start->first + start->second < offset)
102 ++start; // start element is entirely before current chunk, skip it.
104 std::map<size_t, size_t>::const_iterator end =
105 chunks_.upper_bound(offset + size);
106 if (start == end) { // No data in the current range available.
107 ranges->push_back(std::pair<size_t, size_t>(offset, size));
108 return true;
111 size_t cur_offset = offset;
112 std::map<size_t, size_t>::const_iterator it;
113 for (it = start; it != end; ++it) {
114 if (cur_offset < it->first) {
115 size_t new_size = it->first - cur_offset;
116 ranges->push_back(std::pair<size_t, size_t>(cur_offset, new_size));
117 cur_offset = it->first + it->second;
118 } else if (cur_offset < it->first + it->second) {
119 cur_offset = it->first + it->second;
123 // Add last chunk.
124 if (cur_offset < offset + size)
125 ranges->push_back(std::pair<size_t, size_t>(cur_offset,
126 offset + size - cur_offset));
128 return true;
131 bool ChunkStream::IsRangeAvailable(size_t offset, size_t size) const {
132 if (chunks_.empty())
133 return false;
135 if (SIZE_MAX - size < offset)
136 return false;
138 std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset);
139 if (it == chunks_.begin())
140 return false; // No chunks includes offset byte.
142 --it; // Now it starts equal or before offset.
143 return (it->first + it->second) >= (offset + size);
146 size_t ChunkStream::GetFirstMissingByte() const {
147 if (chunks_.empty())
148 return 0;
149 std::map<size_t, size_t>::const_iterator begin = chunks_.begin();
150 return begin->first > 0 ? 0 : begin->second;
153 size_t ChunkStream::GetLastByteBefore(size_t offset) const {
154 if (chunks_.empty())
155 return 0;
156 std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset);
157 if (it == chunks_.begin())
158 return 0;
159 --it;
160 return it->first + it->second;
163 size_t ChunkStream::GetFirstByteAfter(size_t offset) const {
164 if (chunks_.empty())
165 return 0;
166 std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset);
167 if (it == chunks_.end())
168 return data_.size();
169 return it->first;
172 } // namespace chrome_pdf