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#include "storage/browser/fileapi/file_system_backend.h" 12 13namespace chromeos { 14namespace file_system_provider { 15 16BufferingFileStreamReader::BufferingFileStreamReader( 17 scoped_ptr<storage::FileStreamReader> file_stream_reader, 18 int preloading_buffer_length, 19 int64 max_bytes_to_read) 20 : file_stream_reader_(file_stream_reader.Pass()), 21 preloading_buffer_length_(preloading_buffer_length), 22 max_bytes_to_read_(max_bytes_to_read), 23 bytes_read_(0), 24 preloading_buffer_(new net::IOBuffer(preloading_buffer_length)), 25 preloading_buffer_offset_(0), 26 preloaded_bytes_(0), 27 weak_ptr_factory_(this) { 28} 29 30BufferingFileStreamReader::~BufferingFileStreamReader() { 31} 32 33int BufferingFileStreamReader::Read(net::IOBuffer* buffer, 34 int buffer_length, 35 const net::CompletionCallback& callback) { 36 // Return as much as available in the internal buffer. It may be less than 37 // |buffer_length|, what is valid. 38 const int bytes_read = 39 CopyFromPreloadingBuffer(make_scoped_refptr(buffer), buffer_length); 40 if (bytes_read) 41 return bytes_read; 42 43 // If the internal buffer is empty, and more bytes than the internal buffer 44 // size is requested, then call the internal file stream reader directly. 45 if (buffer_length >= preloading_buffer_length_) { 46 const int result = file_stream_reader_->Read( 47 buffer, 48 buffer_length, 49 base::Bind(&BufferingFileStreamReader::OnReadCompleted, 50 weak_ptr_factory_.GetWeakPtr(), 51 callback)); 52 DCHECK_EQ(result, net::ERR_IO_PENDING); 53 return result; 54 } 55 56 // Nothing copied, so contents have to be preloaded. 57 Preload(base::Bind(&BufferingFileStreamReader::OnReadCompleted, 58 weak_ptr_factory_.GetWeakPtr(), 59 base::Bind(&BufferingFileStreamReader::OnPreloadCompleted, 60 weak_ptr_factory_.GetWeakPtr(), 61 make_scoped_refptr(buffer), 62 buffer_length, 63 callback))); 64 65 return net::ERR_IO_PENDING; 66} 67 68int64 BufferingFileStreamReader::GetLength( 69 const net::Int64CompletionCallback& callback) { 70 const int64 result = file_stream_reader_->GetLength(callback); 71 DCHECK_EQ(net::ERR_IO_PENDING, result); 72 73 return result; 74} 75 76int BufferingFileStreamReader::CopyFromPreloadingBuffer( 77 scoped_refptr<net::IOBuffer> buffer, 78 int buffer_length) { 79 const int read_bytes = std::min(buffer_length, preloaded_bytes_); 80 81 memcpy(buffer->data(), 82 preloading_buffer_->data() + preloading_buffer_offset_, 83 read_bytes); 84 preloading_buffer_offset_ += read_bytes; 85 preloaded_bytes_ -= read_bytes; 86 87 return read_bytes; 88} 89 90void BufferingFileStreamReader::Preload( 91 const net::CompletionCallback& callback) { 92 const int preload_bytes = 93 std::min(static_cast<int64>(preloading_buffer_length_), 94 max_bytes_to_read_ - bytes_read_); 95 96 const int result = file_stream_reader_->Read( 97 preloading_buffer_.get(), preload_bytes, callback); 98 DCHECK_EQ(result, net::ERR_IO_PENDING); 99} 100 101void BufferingFileStreamReader::OnPreloadCompleted( 102 scoped_refptr<net::IOBuffer> buffer, 103 int buffer_length, 104 const net::CompletionCallback& callback, 105 int result) { 106 if (result < 0) { 107 callback.Run(result); 108 return; 109 } 110 111 preloading_buffer_offset_ = 0; 112 preloaded_bytes_ = result; 113 114 callback.Run(CopyFromPreloadingBuffer(buffer, buffer_length)); 115} 116 117void BufferingFileStreamReader::OnReadCompleted( 118 const net::CompletionCallback& callback, 119 int result) { 120 if (result < 0) { 121 callback.Run(result); 122 return; 123 } 124 125 // If more bytes than declared in |max_bytes_to_read_| was read in total, then 126 // emit an 127 // error. 128 if (result > max_bytes_to_read_ - bytes_read_) { 129 callback.Run(net::ERR_FAILED); 130 return; 131 } 132 133 bytes_read_ += result; 134 DCHECK_LE(bytes_read_, max_bytes_to_read_); 135 136 callback.Run(result); 137} 138 139} // namespace file_system_provider 140} // namespace chromeos 141