1 // Copyright 2018 The Chromium Authors
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 "base/fuchsia/mem_buffer_util.h"
6
7 #include <lib/fdio/io.h>
8 #include <lib/zx/vmo.h>
9
10 #include <string>
11 #include <string_view>
12 #include <utility>
13
14 #include "base/files/file.h"
15 #include "base/fuchsia/fuchsia_logging.h"
16 #include "base/numerics/safe_conversions.h"
17 #include "base/strings/utf_string_conversions.h"
18
19 namespace base {
20
ReadUTF8FromVMOAsUTF16(const fuchsia::mem::Buffer & buffer)21 std::optional<std::u16string> ReadUTF8FromVMOAsUTF16(
22 const fuchsia::mem::Buffer& buffer) {
23 std::optional<std::string> output_utf8 = StringFromMemBuffer(buffer);
24 if (!output_utf8)
25 return std::nullopt;
26 std::u16string output;
27 return UTF8ToUTF16(&output_utf8->front(), output_utf8->size(), &output)
28 ? std::optional<std::u16string>(std::move(output))
29 : std::nullopt;
30 }
31
VmoFromString(std::string_view data,std::string_view name)32 zx::vmo VmoFromString(std::string_view data, std::string_view name) {
33 zx::vmo vmo;
34
35 // The `ZX_PROP_VMO_CONTENT_SIZE` property is automatically set on VMO
36 // creation.
37 zx_status_t status = zx::vmo::create(data.size(), 0, &vmo);
38 ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create";
39 status = vmo.set_property(ZX_PROP_NAME, name.data(), name.size());
40 ZX_DCHECK(status == ZX_OK, status);
41 if (data.size() > 0) {
42 status = vmo.write(data.data(), 0, data.size());
43 ZX_CHECK(status == ZX_OK, status) << "zx_vmo_write";
44 }
45 return vmo;
46 }
47
MemBufferFromString(std::string_view data,std::string_view name)48 fuchsia::mem::Buffer MemBufferFromString(std::string_view data,
49 std::string_view name) {
50 fuchsia::mem::Buffer buffer;
51 buffer.vmo = VmoFromString(data, name);
52 buffer.size = data.size();
53 return buffer;
54 }
55
MemBufferFromString16(std::u16string_view data,std::string_view name)56 fuchsia::mem::Buffer MemBufferFromString16(std::u16string_view data,
57 std::string_view name) {
58 return MemBufferFromString(
59 std::string_view(reinterpret_cast<const char*>(data.data()),
60 data.size() * sizeof(char16_t)),
61 name);
62 }
63
StringFromVmo(const zx::vmo & vmo)64 std::optional<std::string> StringFromVmo(const zx::vmo& vmo) {
65 std::string result;
66
67 size_t size;
68 zx_status_t status = vmo.get_prop_content_size(&size);
69 if (status != ZX_OK) {
70 ZX_LOG(ERROR, status) << "zx::vmo::get_prop_content_size";
71 return std::nullopt;
72 }
73
74 if (size == 0)
75 return result;
76
77 result.resize(size);
78 status = vmo.read(&result[0], 0, size);
79 if (status == ZX_OK)
80 return result;
81
82 ZX_LOG(ERROR, status) << "zx_vmo_read";
83 return std::nullopt;
84 }
85
StringFromMemBuffer(const fuchsia::mem::Buffer & buffer)86 std::optional<std::string> StringFromMemBuffer(
87 const fuchsia::mem::Buffer& buffer) {
88 std::string result;
89
90 if (buffer.size == 0)
91 return result;
92
93 result.resize(buffer.size);
94 zx_status_t status = buffer.vmo.read(&result[0], 0, buffer.size);
95 if (status == ZX_OK)
96 return result;
97
98 ZX_LOG(ERROR, status) << "zx_vmo_read";
99 return std::nullopt;
100 }
101
StringFromMemData(const fuchsia::mem::Data & data)102 std::optional<std::string> StringFromMemData(const fuchsia::mem::Data& data) {
103 switch (data.Which()) {
104 case fuchsia::mem::Data::kBytes: {
105 const std::vector<uint8_t>& bytes = data.bytes();
106 return std::string(bytes.begin(), bytes.end());
107 }
108 case fuchsia::mem::Data::kBuffer:
109 return StringFromMemBuffer(data.buffer());
110 case fuchsia::mem::Data::kUnknown:
111 case fuchsia::mem::Data::Invalid:
112 // TODO(fxbug.dev/66155): Determine whether to use a default case instead.
113 break;
114 }
115
116 return std::nullopt;
117 }
118
MemBufferFromFile(File file)119 fuchsia::mem::Buffer MemBufferFromFile(File file) {
120 if (!file.IsValid())
121 return {};
122
123 zx::vmo vmo;
124 zx_status_t status =
125 fdio_get_vmo_copy(file.GetPlatformFile(), vmo.reset_and_get_address());
126 if (status != ZX_OK) {
127 ZX_LOG(ERROR, status) << "fdio_get_vmo_copy";
128 return {};
129 }
130
131 fuchsia::mem::Buffer output;
132 output.vmo = std::move(vmo);
133 output.size = checked_cast<uint64_t>(file.GetLength());
134 return output;
135 }
136
CloneBuffer(const fuchsia::mem::Buffer & buffer,std::string_view name)137 fuchsia::mem::Buffer CloneBuffer(const fuchsia::mem::Buffer& buffer,
138 std::string_view name) {
139 fuchsia::mem::Buffer output;
140 output.size = buffer.size;
141 zx_status_t status = buffer.vmo.create_child(
142 ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE, 0, buffer.size, &output.vmo);
143 ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create_child";
144
145 status = output.vmo.set_property(ZX_PROP_NAME, name.data(), name.size());
146 ZX_DCHECK(status == ZX_OK, status);
147
148 return output;
149 }
150
151 } // namespace base
152