| Index: pdf/chunk_stream.cc | 
| =================================================================== | 
| --- pdf/chunk_stream.cc	(revision 0) | 
| +++ pdf/chunk_stream.cc	(revision 0) | 
| @@ -0,0 +1,172 @@ | 
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "pdf/chunk_stream.h" | 
| + | 
| +#define __STDC_LIMIT_MACROS | 
| +#ifdef _WIN32 | 
| +#include <limits.h> | 
| +#else | 
| +#include <stdint.h> | 
| +#endif | 
| + | 
| +#include <algorithm> | 
| + | 
| +#include "base/basictypes.h" | 
| + | 
| +namespace chrome_pdf { | 
| + | 
| +ChunkStream::ChunkStream() { | 
| +} | 
| + | 
| +ChunkStream::~ChunkStream() { | 
| +} | 
| + | 
| +void ChunkStream::Clear() { | 
| +  chunks_.clear(); | 
| +  data_.clear(); | 
| +} | 
| + | 
| +void ChunkStream::Preallocate(size_t stream_size) { | 
| +  data_.reserve(stream_size); | 
| +} | 
| + | 
| +size_t ChunkStream::GetSize() { | 
| +  return data_.size(); | 
| +} | 
| + | 
| +bool ChunkStream::WriteData(size_t offset, void* buffer, size_t size) { | 
| +  if (SIZE_MAX - size < offset) | 
| +    return false; | 
| + | 
| +  if (data_.size() < offset + size) | 
| +    data_.resize(offset + size); | 
| + | 
| +  memcpy(&data_[offset], buffer, size); | 
| + | 
| +  if (chunks_.empty()) { | 
| +    chunks_[offset] = size; | 
| +    return true; | 
| +  } | 
| + | 
| +  std::map<size_t, size_t>::iterator start = chunks_.upper_bound(offset); | 
| +  if (start != chunks_.begin()) | 
| +    --start;  // start now points to the key equal or lower than offset. | 
| +  if (start->first + start->second < offset) | 
| +    ++start;  // start element is entirely before current chunk, skip it. | 
| + | 
| +  std::map<size_t, size_t>::iterator end = chunks_.upper_bound(offset + size); | 
| +  if (start == end) {  // No chunks to merge. | 
| +    chunks_[offset] = size; | 
| +    return true; | 
| +  } | 
| + | 
| +  --end; | 
| + | 
| +  size_t new_offset = std::min<size_t>(start->first, offset); | 
| +  size_t new_size = | 
| +      std::max<size_t>(end->first + end->second, offset + size) - new_offset; | 
| + | 
| +  chunks_.erase(start, ++end); | 
| + | 
| +  chunks_[new_offset] = new_size; | 
| + | 
| +  return true; | 
| +} | 
| + | 
| +bool ChunkStream::ReadData(size_t offset, size_t size, void* buffer) const { | 
| +  if (!IsRangeAvailable(offset, size)) | 
| +    return false; | 
| + | 
| +  memcpy(buffer, &data_[offset], size); | 
| +  return true; | 
| +} | 
| + | 
| +bool ChunkStream::GetMissedRanges( | 
| +    size_t offset, size_t size, | 
| +    std::vector<std::pair<size_t, size_t> >* ranges) const { | 
| +  if (IsRangeAvailable(offset, size)) | 
| +    return false; | 
| + | 
| +  ranges->clear(); | 
| +  if (chunks_.empty()) { | 
| +    ranges->push_back(std::pair<size_t, size_t>(offset, size)); | 
| +    return true; | 
| +  } | 
| + | 
| +  std::map<size_t, size_t>::const_iterator start = chunks_.upper_bound(offset); | 
| +  if (start != chunks_.begin()) | 
| +    --start;  // start now points to the key equal or lower than offset. | 
| +  if (start->first + start->second < offset) | 
| +    ++start;  // start element is entirely before current chunk, skip it. | 
| + | 
| +  std::map<size_t, size_t>::const_iterator end = | 
| +      chunks_.upper_bound(offset + size); | 
| +  if (start == end) {  // No data in the current range available. | 
| +    ranges->push_back(std::pair<size_t, size_t>(offset, size)); | 
| +    return true; | 
| +  } | 
| + | 
| +  size_t cur_offset = offset; | 
| +  std::map<size_t, size_t>::const_iterator it; | 
| +  for (it = start; it != end; ++it) { | 
| +    if (cur_offset < it->first) { | 
| +      size_t new_size = it->first - cur_offset; | 
| +      ranges->push_back(std::pair<size_t, size_t>(cur_offset, new_size)); | 
| +      cur_offset = it->first + it->second; | 
| +    } else if (cur_offset < it->first + it->second) { | 
| +      cur_offset = it->first + it->second; | 
| +    } | 
| +  } | 
| + | 
| +  // Add last chunk. | 
| +  if (cur_offset < offset + size) | 
| +    ranges->push_back(std::pair<size_t, size_t>(cur_offset, | 
| +        offset + size - cur_offset)); | 
| + | 
| +  return true; | 
| +} | 
| + | 
| +bool ChunkStream::IsRangeAvailable(size_t offset, size_t size) const { | 
| +  if (chunks_.empty()) | 
| +    return false; | 
| + | 
| +  if (SIZE_MAX - size < offset) | 
| +    return false; | 
| + | 
| +  std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset); | 
| +  if (it == chunks_.begin()) | 
| +    return false;  // No chunks includes offset byte. | 
| + | 
| +  --it;  // Now it starts equal or before offset. | 
| +  return (it->first + it->second) >= (offset + size); | 
| +} | 
| + | 
| +size_t ChunkStream::GetFirstMissingByte() const { | 
| +  if (chunks_.empty()) | 
| +    return 0; | 
| +  std::map<size_t, size_t>::const_iterator begin = chunks_.begin(); | 
| +  return begin->first > 0 ? 0 : begin->second; | 
| +} | 
| + | 
| +size_t ChunkStream::GetLastByteBefore(size_t offset) const { | 
| +  if (chunks_.empty()) | 
| +    return 0; | 
| +  std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset); | 
| +  if (it == chunks_.begin()) | 
| +    return 0; | 
| +  --it; | 
| +  return it->first + it->second; | 
| +} | 
| + | 
| +size_t ChunkStream::GetFirstByteAfter(size_t offset) const { | 
| +  if (chunks_.empty()) | 
| +    return 0; | 
| +  std::map<size_t, size_t>::const_iterator it = chunks_.upper_bound(offset); | 
| +  if (it == chunks_.end()) | 
| +    return data_.size(); | 
| +  return it->first; | 
| +} | 
| + | 
| +}  // namespace chrome_pdf | 
|  | 
| Property changes on: pdf\chunk_stream.cc | 
| ___________________________________________________________________ | 
| Added: svn:eol-style | 
| + LF | 
|  | 
|  |