summaryrefslogtreecommitdiff
path: root/src/base/istream_data_source.cc
blob: d1d66f0c595b7c9e301d77dbca9e2f4f1953c17c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include "image_io/base/istream_data_source.h"

#include "image_io/base/data_destination.h"
#include "image_io/base/data_segment.h"

namespace photos_editing_formats {
namespace image_io {

void IStreamDataSource::Reset() {
  istream_->clear();
  istream_->seekg(0);
  current_data_segment_.reset();
}

std::shared_ptr<DataSegment> IStreamDataSource::GetDataSegment(
    size_t begin, size_t min_size) {
  if (current_data_segment_ && current_data_segment_->Contains(begin)) {
    return current_data_segment_;
  }
  current_data_segment_ = Read(begin, min_size);
  return current_data_segment_;
}

DataSource::TransferDataResult IStreamDataSource::TransferData(
    const DataRange &data_range, size_t best_size,
    DataDestination *data_destination) {
  bool data_transferred = false;
  DataDestination::TransferStatus status = DataDestination::kTransferDone;
  if (data_destination && data_range.IsValid()) {
    size_t min_size = std::min(data_range.GetLength(), best_size);
    if (current_data_segment_ &&
        current_data_segment_->GetLength() >= min_size &&
        current_data_segment_->GetDataRange().Contains(data_range)) {
      status = data_destination->Transfer(data_range, *current_data_segment_);
      data_transferred = true;
    } else {
      istream_->clear();
      size_t chunk_size = min_size;
      for (size_t begin = data_range.GetBegin(); begin < data_range.GetEnd();
           begin += chunk_size) {
        size_t segment_length = 0;
        size_t end = std::min(data_range.GetEnd(), begin + chunk_size);
        std::shared_ptr<DataSegment> data_segment = Read(begin, end - begin);
        if (data_segment) {
          segment_length = data_segment->GetLength();
          if (segment_length) {
            status = data_destination->Transfer(data_segment->GetDataRange(),
                                                *data_segment);
            data_transferred = true;
          }
        }
        if (status != DataDestination::kTransferOk || segment_length == 0) {
          break;
        }
      }
    }
  }
  if (data_transferred) {
    return status == DataDestination::kTransferError ? kTransferDataError
                                                     : kTransferDataSuccess;
  } else {
    return data_destination ? kTransferDataNone : kTransferDataError;
  }
}

std::shared_ptr<DataSegment> IStreamDataSource::Read(size_t begin,
                                                     size_t count) {
  std::shared_ptr<DataSegment> shared_data_segment;
  istream_->seekg(begin);
  if (istream_->rdstate() == std::ios_base::goodbit) {
    Byte *buffer = new Byte[count];
    istream_->read(reinterpret_cast<char *>(buffer), count);
    size_t bytes_read = istream_->gcount();
    shared_data_segment =
        DataSegment::Create(DataRange(begin, begin + bytes_read), buffer);
  }
  return shared_data_segment;
}

}  // namespace image_io
}  // namespace photos_editing_formats