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/utility/media_galleries/ipc_data_source.h"
6
7#include "base/message_loop/message_loop_proxy.h"
8#include "chrome/common/extensions/chrome_utility_extensions_messages.h"
9#include "content/public/utility/utility_thread.h"
10
11namespace metadata {
12
13IPCDataSource::IPCDataSource(int64 total_size)
14    : total_size_(total_size),
15      utility_task_runner_(base::MessageLoopProxy::current()),
16      next_request_id_(0) {
17  data_source_thread_checker_.DetachFromThread();
18}
19
20IPCDataSource::~IPCDataSource() {
21  DCHECK(utility_thread_checker_.CalledOnValidThread());
22}
23
24void IPCDataSource::Stop() {
25  DCHECK(data_source_thread_checker_.CalledOnValidThread());
26}
27
28void IPCDataSource::Read(int64 position, int size, uint8* data,
29                         const DataSource::ReadCB& read_cb) {
30  DCHECK(data_source_thread_checker_.CalledOnValidThread());
31  utility_task_runner_->PostTask(
32      FROM_HERE,
33      base::Bind(&IPCDataSource::ReadOnUtilityThread, base::Unretained(this),
34                 position, size, data, read_cb));
35}
36
37bool IPCDataSource::GetSize(int64* size_out) {
38  DCHECK(data_source_thread_checker_.CalledOnValidThread());
39  *size_out = total_size_;
40  return true;
41}
42
43bool IPCDataSource::IsStreaming() {
44  DCHECK(data_source_thread_checker_.CalledOnValidThread());
45  return false;
46}
47
48void IPCDataSource::SetBitrate(int bitrate) {
49  DCHECK(data_source_thread_checker_.CalledOnValidThread());
50}
51
52bool IPCDataSource::OnMessageReceived(const IPC::Message& message) {
53  DCHECK(utility_thread_checker_.CalledOnValidThread());
54  bool handled = true;
55  IPC_BEGIN_MESSAGE_MAP(IPCDataSource, message)
56    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RequestBlobBytes_Finished,
57                        OnRequestBlobBytesFinished)
58    IPC_MESSAGE_UNHANDLED(handled = false)
59  IPC_END_MESSAGE_MAP()
60  return handled;
61}
62
63IPCDataSource::Request::Request()
64    : destination(NULL) {
65}
66
67IPCDataSource::Request::~Request() {
68}
69
70void IPCDataSource::ReadOnUtilityThread(int64 position, int size, uint8* data,
71                                        const DataSource::ReadCB& read_cb) {
72  DCHECK(utility_thread_checker_.CalledOnValidThread());
73  CHECK_GE(total_size_, 0);
74  CHECK_GE(position, 0);
75  CHECK_GE(size, 0);
76
77  // Cap position and size within bounds.
78  position = std::min(position, total_size_);
79  int64 clamped_size =
80      std::min(static_cast<int64>(size), total_size_ - position);
81
82  int64 request_id = ++next_request_id_;
83
84  Request request;
85  request.destination = data;
86  request.callback = read_cb;
87
88  pending_requests_[request_id] = request;
89  content::UtilityThread::Get()->Send(new ChromeUtilityHostMsg_RequestBlobBytes(
90      request_id, position, clamped_size));
91}
92
93void IPCDataSource::OnRequestBlobBytesFinished(int64 request_id,
94                                               const std::string& bytes) {
95  DCHECK(utility_thread_checker_.CalledOnValidThread());
96  std::map<int64, Request>::iterator it = pending_requests_.find(request_id);
97
98  if (it == pending_requests_.end())
99    return;
100
101  std::copy(bytes.begin(), bytes.end(), it->second.destination);
102  it->second.callback.Run(bytes.size());
103
104  pending_requests_.erase(it);
105}
106
107}  // namespace metadata
108