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 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 61size_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. 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 110bool 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 130} // namespace common 131} // namespace mojo 132