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