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 "mojo/common/data_pipe_utils.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <utility>
11
12 #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"
17
18 namespace mojo {
19 namespace common {
20 namespace {
21
BlockingCopyHelper(ScopedDataPipeConsumerHandle source,const base::Callback<size_t (const void *,uint32_t)> & write_bytes)22 bool 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
CopyToStringHelper(std::string * result,const void * buffer,uint32_t num_bytes)55 size_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
CopyToFileHelper(FILE * fp,const void * buffer,uint32_t num_bytes)61 size_t CopyToFileHelper(FILE* fp, const void* buffer, uint32_t num_bytes) {
62 return fwrite(buffer, 1, num_bytes, fp);
63 }
64
65 } // namespace
66
67
68 // TODO(hansmuller): Add a max_size parameter.
BlockingCopyToString(ScopedDataPipeConsumerHandle source,std::string * result)69 bool 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
BlockingCopyFromString(const std::string & source,const ScopedDataPipeProducerHandle & destination)77 bool 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
BlockingCopyToFile(ScopedDataPipeConsumerHandle source,const base::FilePath & destination)110 bool 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
CopyToFile(ScopedDataPipeConsumerHandle source,const base::FilePath & destination,base::TaskRunner * task_runner,const base::Callback<void (bool)> & callback)119 void 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
130 } // namespace common
131 } // namespace mojo
132