• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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