• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ChunkStream()20 ChunkStream::ChunkStream() {
21 }
22 
~ChunkStream()23 ChunkStream::~ChunkStream() {
24 }
25 
Clear()26 void ChunkStream::Clear() {
27   chunks_.clear();
28   data_.clear();
29 }
30 
Preallocate(size_t stream_size)31 void ChunkStream::Preallocate(size_t stream_size) {
32   data_.reserve(stream_size);
33 }
34 
GetSize()35 size_t ChunkStream::GetSize() {
36   return data_.size();
37 }
38 
WriteData(size_t offset,void * buffer,size_t size)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 
ReadData(size_t offset,size_t size,void * buffer) const78 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 
GetMissedRanges(size_t offset,size_t size,std::vector<std::pair<size_t,size_t>> * ranges) const86 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 
IsRangeAvailable(size_t offset,size_t size) const131 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 
GetFirstMissingByte() const146 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 
GetLastByteBefore(size_t offset) const153 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 
GetFirstByteAfter(size_t offset) const163 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
173