Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / file_system_provider / fileapi / buffering_file_stream_reader.cc
1 // Copyright 2014 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 "chrome/browser/chromeos/file_system_provider/fileapi/buffering_file_stream_reader.h"
6
7 #include <algorithm>
8
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11
12 namespace chromeos {
13 namespace file_system_provider {
14
15 BufferingFileStreamReader::BufferingFileStreamReader(
16     scoped_ptr<webkit_blob::FileStreamReader> file_stream_reader,
17     int buffer_size)
18     : file_stream_reader_(file_stream_reader.Pass()),
19       buffer_size_(buffer_size),
20       preloading_buffer_(new net::IOBuffer(buffer_size_)),
21       preloading_buffer_offset_(0),
22       buffered_bytes_(0),
23       weak_ptr_factory_(this) {
24 }
25
26 BufferingFileStreamReader::~BufferingFileStreamReader() {
27 }
28
29 int BufferingFileStreamReader::Read(net::IOBuffer* buffer,
30                                     int buffer_length,
31                                     const net::CompletionCallback& callback) {
32   // Return as much as available in the internal buffer. It may be less than
33   // |buffer_length|, what is valid.
34   const int bytes_read =
35       CopyFromPreloadingBuffer(make_scoped_refptr(buffer), buffer_length);
36   if (bytes_read)
37     return bytes_read;
38
39   // If the internal buffer is empty, and more bytes than the internal buffer
40   // size is requested, then call the internal file stream reader directly.
41   if (buffer_length >= buffer_size_) {
42     const int result =
43         file_stream_reader_->Read(buffer, buffer_length, callback);
44     DCHECK_EQ(result, net::ERR_IO_PENDING);
45     return result;
46   }
47
48   // Nothing copied, so contents have to be preloaded.
49   Preload(base::Bind(&BufferingFileStreamReader::OnPreloadCompleted,
50                      weak_ptr_factory_.GetWeakPtr(),
51                      make_scoped_refptr(buffer),
52                      buffer_length,
53                      callback));
54
55   return net::ERR_IO_PENDING;
56 }
57
58 int64 BufferingFileStreamReader::GetLength(
59     const net::Int64CompletionCallback& callback) {
60   const int64 result = file_stream_reader_->GetLength(callback);
61   DCHECK_EQ(net::ERR_IO_PENDING, result);
62
63   return result;
64 }
65
66 int BufferingFileStreamReader::CopyFromPreloadingBuffer(
67     scoped_refptr<net::IOBuffer> buffer,
68     int buffer_length) {
69   const int read_bytes = std::min(buffer_length, buffered_bytes_);
70
71   memcpy(buffer->data(),
72          preloading_buffer_->data() + preloading_buffer_offset_,
73          read_bytes);
74   preloading_buffer_offset_ += read_bytes;
75   buffered_bytes_ -= read_bytes;
76
77   return read_bytes;
78 }
79
80 void BufferingFileStreamReader::Preload(
81     const net::CompletionCallback& callback) {
82   // TODO(mtomasz): Dynamically calculate the chunk size. Start from a small
83   // one, then increase for consecutive requests. That would improve performance
84   // when reading just small chunks, instead of the entire file.
85   const int preload_bytes = buffer_size_;
86
87   const int result =
88       file_stream_reader_->Read(preloading_buffer_, preload_bytes, callback);
89   DCHECK_EQ(result, net::ERR_IO_PENDING);
90 }
91
92 void BufferingFileStreamReader::OnPreloadCompleted(
93     scoped_refptr<net::IOBuffer> buffer,
94     int buffer_length,
95     const net::CompletionCallback& callback,
96     int result) {
97   if (result < 0) {
98     callback.Run(result);
99     return;
100   }
101
102   preloading_buffer_offset_ = 0;
103   buffered_bytes_ = result;
104
105   callback.Run(CopyFromPreloadingBuffer(buffer, buffer_length));
106 }
107
108 }  // namespace file_system_provider
109 }  // namespace chromeos