blob: 8540ac63473278bedd6d05978fe15fd34f23f206 [file] [log] [blame]
Luis Hector Chavez645501c2016-12-28 10:56:26 -08001// 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 "mojo/common/data_pipe_utils.h"
6
Luis Hector Chavez21a249e2017-07-26 17:38:05 +00007#include <stddef.h>
8#include <stdint.h>
9#include <stdio.h>
Luis Hector Chavez645501c2016-12-28 10:56:26 -080010#include <utility>
11
Luis Hector Chavez21a249e2017-07-26 17:38:05 +000012#include "base/files/file_path.h"
13#include "base/files/file_util.h"
14#include "base/files/scoped_file.h"
15#include "base/message_loop/message_loop.h"
16#include "base/task_runner_util.h"
Luis Hector Chavez645501c2016-12-28 10:56:26 -080017
18namespace mojo {
19namespace common {
20namespace {
21
22bool BlockingCopyHelper(ScopedDataPipeConsumerHandle source,
23 const base::Callback<size_t(const void*, uint32_t)>& write_bytes) {
24 for (;;) {
25 const void* buffer;
26 uint32_t num_bytes;
27 MojoResult result = BeginReadDataRaw(
28 source.get(), &buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
29 if (result == MOJO_RESULT_OK) {
30 size_t bytes_written = write_bytes.Run(buffer, num_bytes);
31 result = EndReadDataRaw(source.get(), num_bytes);
32 if (bytes_written < num_bytes || result != MOJO_RESULT_OK)
33 return false;
34 } else if (result == MOJO_RESULT_SHOULD_WAIT) {
35 result = Wait(source.get(),
36 MOJO_HANDLE_SIGNAL_READABLE,
37 MOJO_DEADLINE_INDEFINITE,
38 nullptr);
39 if (result != MOJO_RESULT_OK) {
40 // If the producer handle was closed, then treat as EOF.
41 return result == MOJO_RESULT_FAILED_PRECONDITION;
42 }
43 } else if (result == MOJO_RESULT_FAILED_PRECONDITION) {
44 // If the producer handle was closed, then treat as EOF.
45 return true;
46 } else {
47 // Some other error occurred.
48 break;
49 }
50 }
51
52 return false;
53}
54
55size_t CopyToStringHelper(
56 std::string* result, const void* buffer, uint32_t num_bytes) {
57 result->append(static_cast<const char*>(buffer), num_bytes);
58 return num_bytes;
59}
60
Luis Hector Chavez21a249e2017-07-26 17:38:05 +000061size_t CopyToFileHelper(FILE* fp, const void* buffer, uint32_t num_bytes) {
62 return fwrite(buffer, 1, num_bytes, fp);
63}
64
65} // namespace
66
Luis Hector Chavez645501c2016-12-28 10:56:26 -080067
68// TODO(hansmuller): Add a max_size parameter.
69bool BlockingCopyToString(ScopedDataPipeConsumerHandle source,
70 std::string* result) {
71 CHECK(result);
72 result->clear();
73 return BlockingCopyHelper(std::move(source),
74 base::Bind(&CopyToStringHelper, result));
75}
76
77bool MOJO_COMMON_EXPORT BlockingCopyFromString(
78 const std::string& source,
79 const ScopedDataPipeProducerHandle& destination) {
80 auto it = source.begin();
81 for (;;) {
82 void* buffer = nullptr;
83 uint32_t buffer_num_bytes = 0;
84 MojoResult result =
85 BeginWriteDataRaw(destination.get(), &buffer, &buffer_num_bytes,
86 MOJO_WRITE_DATA_FLAG_NONE);
87 if (result == MOJO_RESULT_OK) {
88 char* char_buffer = static_cast<char*>(buffer);
89 uint32_t byte_index = 0;
90 while (it != source.end() && byte_index < buffer_num_bytes) {
91 char_buffer[byte_index++] = *it++;
92 }
93 EndWriteDataRaw(destination.get(), byte_index);
94 if (it == source.end())
95 return true;
96 } else if (result == MOJO_RESULT_SHOULD_WAIT) {
97 result = Wait(destination.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
98 MOJO_DEADLINE_INDEFINITE, nullptr);
99 if (result != MOJO_RESULT_OK) {
100 // If the consumer handle was closed, then treat as EOF.
101 return result == MOJO_RESULT_FAILED_PRECONDITION;
102 }
103 } else {
104 // If the consumer handle was closed, then treat as EOF.
105 return result == MOJO_RESULT_FAILED_PRECONDITION;
106 }
107 }
108}
109
Luis Hector Chavez21a249e2017-07-26 17:38:05 +0000110bool BlockingCopyToFile(ScopedDataPipeConsumerHandle source,
111 const base::FilePath& destination) {
112 base::ScopedFILE fp(base::OpenFile(destination, "wb"));
113 if (!fp)
114 return false;
115 return BlockingCopyHelper(std::move(source),
116 base::Bind(&CopyToFileHelper, fp.get()));
117}
118
119void CopyToFile(ScopedDataPipeConsumerHandle source,
120 const base::FilePath& destination,
121 base::TaskRunner* task_runner,
122 const base::Callback<void(bool)>& callback) {
123 base::PostTaskAndReplyWithResult(
124 task_runner,
125 FROM_HERE,
126 base::Bind(&BlockingCopyToFile, base::Passed(&source), destination),
127 callback);
128}
129
Luis Hector Chavez645501c2016-12-28 10:56:26 -0800130} // namespace common
131} // namespace mojo