Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa_test / pdf / chunk_stream.cc
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.
4
5 #include "pdf/chunk_stream.h"
6
7 #define __STDC_LIMIT_MACROS
8 #ifdef _WIN32
9 #include <limits.h>
10 #else
11 #include <stdint.h>
12 #endif
13
14 #include <algorithm>
15
16 #include "base/basictypes.h"
17
18 namespace chrome_pdf {
19
20 ChunkStream::ChunkStream() {
21 }
22
23 ChunkStream::~ChunkStream() {
24 }
25
26 void ChunkStream::Clear() {
27   chunks_.clear();
28   data_.clear();
29 }
30
31 void ChunkStream::Preallocate(size_t stream_size) {
32   data_.reserve(stream_size);
33 }
34
35 size_t ChunkStream::GetSize() {
36   return data_.size();
37 }
38
39 bool ChunkStream::WriteData(size_t offset, void* buffer, size_t size) {
40   if (SIZE_MAX - size < offset)
41     return false;
42
43   if (data_.size() < offset + size)
44     data_.resize(offset + size);
45
46   memcpy(&data_[offset], buffer, size);
47
48   if (chunks_.empty()) {
49     chunks_[offset] = size;
50     return true;
51   }
52
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.
58
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;
63   }
64
65   --end;
66
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;
70
71   chunks_.erase(start, ++end);
72
73   chunks_[new_offset] = new_size;
74
75   return true;
76 }
77
78 bool ChunkStream::ReadData(size_t offset, size_t size, void* buffer) const {
79   if (!IsRangeAvailable(offset, size))
80     return false;
81
82   memcpy(buffer, &data_[offset], size);
83   return true;
84 }
85
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;
91
92   ranges->clear();
93   if (chunks_.empty()) {
94     ranges->push_back(std::pair<size_t, size_t>(offset, size));
95     return true;
96   }
97
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.
103
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;
109   }
110
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;
120     }
121   }
122
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));
127
128   return true;
129 }
130
131 bool ChunkStream::IsRangeAvailable(size_t offset, size_t size) const {
132   if (chunks_.empty())
133     return false;
134
135   if (SIZE_MAX - size < offset)
136     return false;
137
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.
141
142   --it;  // Now it starts equal or before offset.
143   return (it->first + it->second) >= (offset + size);
144 }
145
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;
151 }
152
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;
161 }
162
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;
170 }
171
172 }  // namespace chrome_pdf