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
16 #include "base/basictypes.h"
18 namespace chrome_pdf
{
20 ChunkStream::ChunkStream() {
23 ChunkStream::~ChunkStream() {
26 void ChunkStream::Clear() {
31 void ChunkStream::Preallocate(size_t stream_size
) {
32 data_
.reserve(stream_size
);
35 size_t ChunkStream::GetSize() {
39 bool ChunkStream::WriteData(size_t offset
, void* buffer
, size_t size
) {
40 if (SIZE_MAX
- size
< offset
)
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
;
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
;
67 size_t new_offset
= std::min
<size_t>(start
->first
, offset
);
69 std::max
<size_t>(end
->first
+ end
->second
, offset
+ size
) - new_offset
;
71 chunks_
.erase(start
, ++end
);
73 chunks_
[new_offset
] = new_size
;
78 bool ChunkStream::ReadData(size_t offset
, size_t size
, void* buffer
) const {
79 if (!IsRangeAvailable(offset
, size
))
82 memcpy(buffer
, &data_
[offset
], size
);
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
))
93 if (chunks_
.empty()) {
94 ranges
->push_back(std::pair
<size_t, size_t>(offset
, size
));
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
));
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
;
124 if (cur_offset
< offset
+ size
)
125 ranges
->push_back(std::pair
<size_t, size_t>(cur_offset
,
126 offset
+ size
- cur_offset
));
131 bool ChunkStream::IsRangeAvailable(size_t offset
, size_t size
) const {
135 if (SIZE_MAX
- size
< offset
)
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 {
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 {
156 std::map
<size_t, size_t>::const_iterator it
= chunks_
.upper_bound(offset
);
157 if (it
== chunks_
.begin())
160 return it
->first
+ it
->second
;
163 size_t ChunkStream::GetFirstByteAfter(size_t offset
) const {
166 std::map
<size_t, size_t>::const_iterator it
= chunks_
.upper_bound(offset
);
167 if (it
== chunks_
.end())
172 } // namespace chrome_pdf