Change PDFDataDecodeResult to use DataVector
Change PDFDataDecode() to return a struct that has a DataVector. Then
change RunLengthDecode(), A85Decode() and HexDecode() to return
DataVector as well. Now most temporary data copies are gone and
DataVector is being passed straight through the call stack.
Bug: pdfium:1872
Change-Id: I019c8425c438fed88b313a85d29a14ce61ca04d7
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/119323
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_stream_acc.cpp b/core/fpdfapi/parser/cpdf_stream_acc.cpp
index 5fa511d..896f36e 100644
--- a/core/fpdfapi/parser/cpdf_stream_acc.cpp
+++ b/core/fpdfapi/parser/cpdf_stream_acc.cpp
@@ -153,16 +153,12 @@
m_ImageDecoder = std::move(result.value().image_encoding);
m_pImageParam = std::move(result.value().image_params);
- if (!result.value().data) {
+ if (result.value().data.empty()) {
m_Data = std::move(src_data);
return;
}
- DCHECK_NE(result.value().data.get(), src_span.data());
- // TODO(crbug.com/pdfium/1872): Avoid copying.
- m_Data = DataVector<uint8_t>(
- result.value().data.get(),
- UNSAFE_TODO(result.value().data.get() + result.value().size));
+ m_Data = std::move(result.value().data);
}
DataVector<uint8_t> CPDF_StreamAcc::ReadRawStream() const {
diff --git a/core/fpdfapi/parser/fpdf_parser_decode.cpp b/core/fpdfapi/parser/fpdf_parser_decode.cpp
index 38b9a1f..ea10bde 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode.cpp
@@ -114,9 +114,9 @@
return true;
}
-DataAndBytesConsumed A85Decode(pdfium::span<const uint8_t> src_span) {
+DataVectorAndBytesConsumed A85Decode(pdfium::span<const uint8_t> src_span) {
if (src_span.empty()) {
- return {nullptr, 0u, 0u};
+ return {DataVector<uint8_t>(), 0u};
}
// Count legal characters and zeros.
@@ -134,7 +134,7 @@
}
// No content to decode.
if (pos == 0) {
- return {nullptr, 0u, 0u};
+ return {DataVector<uint8_t>(), 0u};
}
// Count the space needed to contain non-zero characters. The encoding ratio
@@ -144,13 +144,11 @@
size *= 4;
size += space_for_non_zeroes;
if (!size.IsValid()) {
- return {nullptr, 0u, FX_INVALID_OFFSET};
+ return {DataVector<uint8_t>(), FX_INVALID_OFFSET};
}
- std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
- FX_Alloc(uint8_t, size.ValueOrDie()));
- uint8_t* dest_buf_ptr = dest_buf.get();
- uint32_t dest_size = 0;
+ DataVector<uint8_t> dest_buf(size.ValueOrDie());
+ pdfium::span<uint8_t> dest_span(dest_buf);
size_t state = 0;
uint32_t res = 0;
pos = 0;
@@ -161,10 +159,10 @@
}
if (ch == 'z') {
- UNSAFE_TODO(FXSYS_memset(dest_buf_ptr + dest_size, 0, 4));
+ fxcrt::spanset(dest_span.first(4), 0);
+ dest_span = dest_span.subspan(4);
state = 0;
res = 0;
- dest_size += 4;
continue;
}
@@ -180,7 +178,8 @@
}
for (size_t i = 0; i < 4; ++i) {
- UNSAFE_TODO(dest_buf_ptr[dest_size++] = GetA85Result(res, i));
+ dest_span.front() = GetA85Result(res, i);
+ dest_span = dest_span.subspan(1);
}
state = 0;
res = 0;
@@ -191,18 +190,20 @@
res = res * 85 + 84;
}
for (size_t i = 0; i < state - 1; ++i) {
- UNSAFE_TODO(dest_buf_ptr[dest_size++] = GetA85Result(res, i));
+ dest_span.front() = GetA85Result(res, i);
+ dest_span = dest_span.subspan(1);
}
}
if (pos < src_span.size() && src_span[pos] == '>') {
++pos;
}
- return {std::move(dest_buf), dest_size, pos};
+ dest_buf.resize(dest_buf.size() - dest_span.size());
+ return {std::move(dest_buf), pos};
}
-DataAndBytesConsumed HexDecode(pdfium::span<const uint8_t> src_span) {
+DataVectorAndBytesConsumed HexDecode(pdfium::span<const uint8_t> src_span) {
if (src_span.empty()) {
- return {nullptr, 0u, 0u};
+ return {DataVector<uint8_t>(), 0u};
}
uint32_t i = 0;
@@ -211,11 +212,9 @@
++i;
}
- std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
- FX_Alloc(uint8_t, i / 2 + 1));
- uint8_t* dest_buf_ptr = dest_buf.get();
- uint32_t dest_size = 0;
- bool bFirst = true;
+ DataVector<uint8_t> dest_buf(i / 2 + 1);
+ pdfium::span<uint8_t> dest_span(dest_buf);
+ bool is_first = true;
for (i = 0; i < src_span.size(); ++i) {
uint8_t ch = src_span[i];
if (PDFCharIsLineEnding(ch) || ch == ' ' || ch == '\t') {
@@ -231,20 +230,24 @@
}
int digit = FXSYS_HexCharToInt(ch);
- if (bFirst) {
- UNSAFE_TODO(dest_buf_ptr[dest_size] = digit * 16);
+ if (is_first) {
+ dest_span.front() = digit * 16;
} else {
- UNSAFE_TODO(dest_buf_ptr[dest_size++] += digit);
+ dest_span.front() += digit;
+ dest_span = dest_span.subspan(1);
}
- bFirst = !bFirst;
+ is_first = !is_first;
}
- if (!bFirst) {
+ size_t dest_size = dest_buf.size() - dest_span.size();
+ if (!is_first) {
++dest_size;
}
- return {std::move(dest_buf), dest_size, i};
+ dest_buf.resize(dest_size);
+ return {std::move(dest_buf), i};
}
-DataAndBytesConsumed RunLengthDecode(pdfium::span<const uint8_t> src_span) {
+DataVectorAndBytesConsumed RunLengthDecode(
+ pdfium::span<const uint8_t> src_span) {
uint32_t dest_size = 0;
size_t i = 0;
while (i < src_span.size()) {
@@ -255,25 +258,23 @@
if (src_span[i] < 128) {
dest_size += src_span[i] + 1;
if (dest_size < old) {
- return {nullptr, 0, FX_INVALID_OFFSET};
+ return {DataVector<uint8_t>(), FX_INVALID_OFFSET};
}
i += src_span[i] + 2;
} else {
dest_size += 257 - src_span[i];
if (dest_size < old) {
- return {nullptr, 0, FX_INVALID_OFFSET};
+ return {DataVector<uint8_t>(), FX_INVALID_OFFSET};
}
i += 2;
}
}
if (dest_size >= kMaxStreamSize) {
- return {nullptr, 0, FX_INVALID_OFFSET};
+ return {DataVector<uint8_t>(), FX_INVALID_OFFSET};
}
- std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
- FX_Alloc(uint8_t, dest_size));
- // SAFETY: allocation of `*dest_size` above.
- auto dest_span = UNSAFE_BUFFERS(pdfium::make_span(dest_buf.get(), dest_size));
+ DataVector<uint8_t> dest_buf(dest_size);
+ auto dest_span = pdfium::make_span(dest_buf);
i = 0;
int dest_count = 0;
while (i < src_span.size()) {
@@ -300,7 +301,7 @@
i += 2;
}
}
- return {std::move(dest_buf), dest_size,
+ return {std::move(dest_buf),
pdfium::checked_cast<uint32_t>(std::min(i + 1, src_span.size()))};
}
@@ -412,12 +413,10 @@
PDFDataDecodeResult::PDFDataDecodeResult() = default;
PDFDataDecodeResult::PDFDataDecodeResult(
- std::unique_ptr<uint8_t, FxFreeDeleter> data,
- uint32_t size,
+ DataVector<uint8_t> data,
ByteString image_encoding,
RetainPtr<const CPDF_Dictionary> image_params)
: data(std::move(data)),
- size(size),
image_encoding(std::move(image_encoding)),
image_params(std::move(image_params)) {}
@@ -444,55 +443,41 @@
ByteString decoder = decoder_array[i].first;
RetainPtr<const CPDF_Dictionary> pParam =
ToDictionary(decoder_array[i].second);
- std::unique_ptr<uint8_t, FxFreeDeleter> new_buf;
- uint32_t new_size = 0xFFFFFFFF;
+ DataVector<uint8_t> new_buf;
uint32_t bytes_consumed = FX_INVALID_OFFSET;
if (decoder == "Crypt")
continue;
if (decoder == "FlateDecode" || decoder == "Fl") {
if (bImageAcc && i == nSize - 1) {
- result.size = last_span.size();
result.image_encoding = "FlateDecode";
result.image_params = std::move(pParam);
return result;
}
DataVectorAndBytesConsumed decode_result = FlateOrLZWDecode(
/*use_lzw=*/false, last_span, pParam, estimated_size);
- // TODO(crbug.com/pdfium/1872): Avoid copying.
- new_size = pdfium::checked_cast<uint32_t>(decode_result.data.size());
- new_buf.reset(FX_Alloc(uint8_t, new_size));
- UNSAFE_TODO(
- FXSYS_memcpy(new_buf.get(), decode_result.data.data(), new_size));
+ new_buf = std::move(decode_result.data);
bytes_consumed = decode_result.bytes_consumed;
} else if (decoder == "LZWDecode" || decoder == "LZW") {
DataVectorAndBytesConsumed decode_result =
FlateOrLZWDecode(/*use_lzw=*/true, last_span, pParam, estimated_size);
- // TODO(crbug.com/pdfium/1872): Avoid copying.
- new_size = pdfium::checked_cast<uint32_t>(decode_result.data.size());
- new_buf.reset(FX_Alloc(uint8_t, new_size));
- UNSAFE_TODO(
- FXSYS_memcpy(new_buf.get(), decode_result.data.data(), new_size));
+ new_buf = std::move(decode_result.data);
bytes_consumed = decode_result.bytes_consumed;
} else if (decoder == "ASCII85Decode" || decoder == "A85") {
- DataAndBytesConsumed decode_result = A85Decode(last_span);
+ DataVectorAndBytesConsumed decode_result = A85Decode(last_span);
new_buf = std::move(decode_result.data);
- new_size = decode_result.size;
bytes_consumed = decode_result.bytes_consumed;
} else if (decoder == "ASCIIHexDecode" || decoder == "AHx") {
- DataAndBytesConsumed decode_result = HexDecode(last_span);
+ DataVectorAndBytesConsumed decode_result = HexDecode(last_span);
new_buf = std::move(decode_result.data);
- new_size = decode_result.size;
bytes_consumed = decode_result.bytes_consumed;
} else if (decoder == "RunLengthDecode" || decoder == "RL") {
if (bImageAcc && i == nSize - 1) {
- result.size = last_span.size();
result.image_encoding = "RunLengthDecode";
result.image_params = std::move(pParam);
return result;
}
- DataAndBytesConsumed decode_result = RunLengthDecode(last_span);
+ DataVectorAndBytesConsumed decode_result = RunLengthDecode(last_span);
new_buf = std::move(decode_result.data);
- new_size = decode_result.size;
bytes_consumed = decode_result.bytes_consumed;
} else {
// If we get here, assume it's an image decoder.
@@ -501,7 +486,6 @@
} else if (decoder == "CCF") {
decoder = "CCITTFaxDecode";
}
- result.size = last_span.size();
result.image_encoding = std::move(decoder);
result.image_params = std::move(pParam);
return result;
@@ -510,12 +494,10 @@
return std::nullopt;
}
- // SAFETY: relies on out params of FlateOrLZWDecode().
- last_span = UNSAFE_BUFFERS(pdfium::make_span(new_buf.get(), new_size));
+ last_span = pdfium::make_span(new_buf);
result.data = std::move(new_buf);
}
- result.size = last_span.size();
result.image_encoding.clear();
result.image_params = nullptr;
return result;
diff --git a/core/fpdfapi/parser/fpdf_parser_decode.h b/core/fpdfapi/parser/fpdf_parser_decode.h
index d2552ad..27b628d 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode.h
+++ b/core/fpdfapi/parser/fpdf_parser_decode.h
@@ -17,7 +17,6 @@
#include "core/fxcodec/data_and_bytes_consumed.h"
#include "core/fxcrt/data_vector.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
#include "core/fxcrt/fx_string.h"
#include "core/fxcrt/retain_ptr.h"
#include "core/fxcrt/span.h"
@@ -54,12 +53,14 @@
int bpc,
const CPDF_Dictionary* pParams);
-fxcodec::DataAndBytesConsumed RunLengthDecode(
+fxcodec::DataVectorAndBytesConsumed RunLengthDecode(
pdfium::span<const uint8_t> src_span);
-fxcodec::DataAndBytesConsumed A85Decode(pdfium::span<const uint8_t> src_span);
+fxcodec::DataVectorAndBytesConsumed A85Decode(
+ pdfium::span<const uint8_t> src_span);
-fxcodec::DataAndBytesConsumed HexDecode(pdfium::span<const uint8_t> src_span);
+fxcodec::DataVectorAndBytesConsumed HexDecode(
+ pdfium::span<const uint8_t> src_span);
fxcodec::DataVectorAndBytesConsumed FlateOrLZWDecode(
bool use_lzw,
@@ -79,17 +80,14 @@
struct PDFDataDecodeResult {
PDFDataDecodeResult();
- PDFDataDecodeResult(std::unique_ptr<uint8_t, FxFreeDeleter> data,
- uint32_t size,
+ PDFDataDecodeResult(DataVector<uint8_t> data,
ByteString image_encoding,
RetainPtr<const CPDF_Dictionary> image_params);
PDFDataDecodeResult(PDFDataDecodeResult&& that) noexcept;
PDFDataDecodeResult& operator=(PDFDataDecodeResult&& that) noexcept;
~PDFDataDecodeResult();
- // TODO(crbug.com/pdfium/1872): Convert to DataVector.
- std::unique_ptr<uint8_t, FxFreeDeleter> data;
- uint32_t size = 0;
+ DataVector<uint8_t> data;
ByteString image_encoding;
RetainPtr<const CPDF_Dictionary> image_params;
};
diff --git a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
index 806f279..b4bf142 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
@@ -288,13 +288,13 @@
STR_IN_OUT_CASE("FCfN8FCfN8vw", "testtest", 11),
};
for (const auto& test_case : kTestData) {
- DataAndBytesConsumed result = A85Decode(
+ DataVectorAndBytesConsumed result = A85Decode(
UNSAFE_TODO(pdfium::make_span(test_case.input, test_case.input_size)));
EXPECT_EQ(test_case.processed_size, result.bytes_consumed)
<< "for case " << test_case.input;
- ASSERT_EQ(test_case.expected_size, result.size);
- const uint8_t* result_ptr = result.data.get();
- for (size_t j = 0; j < result.size; ++j) {
+ ASSERT_EQ(test_case.expected_size, result.data.size());
+ const uint8_t* result_ptr = result.data.data();
+ for (size_t j = 0; j < result.data.size(); ++j) {
EXPECT_EQ(test_case.expected[j], result_ptr[j])
<< "for case " << test_case.input << " char " << j;
}
@@ -321,13 +321,13 @@
STR_IN_OUT_CASE("12AcED3c3456", "\x12\xac\xed\x3c\x34\x56", 12),
};
for (const auto& test_case : kTestData) {
- DataAndBytesConsumed result = HexDecode(
+ DataVectorAndBytesConsumed result = HexDecode(
UNSAFE_TODO(pdfium::make_span(test_case.input, test_case.input_size)));
EXPECT_EQ(test_case.processed_size, result.bytes_consumed)
<< "for case " << test_case.input;
- ASSERT_EQ(test_case.expected_size, result.size);
- const uint8_t* result_ptr = result.data.get();
- for (size_t j = 0; j < result.size; ++j) {
+ ASSERT_EQ(test_case.expected_size, result.data.size());
+ const uint8_t* result_ptr = result.data.data();
+ for (size_t j = 0; j < result.data.size(); ++j) {
EXPECT_EQ(test_case.expected[j], result_ptr[j])
<< "for case " << test_case.input << " char " << j;
}
diff --git a/core/fxcodec/basic/rle_unittest.cpp b/core/fxcodec/basic/rle_unittest.cpp
index 4f150b0..50251e2 100644
--- a/core/fxcodec/basic/rle_unittest.cpp
+++ b/core/fxcodec/basic/rle_unittest.cpp
@@ -39,10 +39,10 @@
// Case 1: Match, match
const uint8_t src_buf_1[] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4};
DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_1);
- DataAndBytesConsumed result = RunLengthDecode(dest_buf);
- ASSERT_EQ(sizeof(src_buf_1), result.size);
- auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
- for (uint32_t i = 0; i < result.size; i++) {
+ DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+ ASSERT_EQ(sizeof(src_buf_1), result.data.size());
+ auto decoded_buf_span = pdfium::make_span(result.data);
+ for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
EXPECT_EQ(src_buf_1[i], decoded_buf_span[i]) << " at " << i;
}
}
@@ -51,10 +51,10 @@
// Case 2: Match, non-match
const uint8_t src_buf_2[] = {2, 2, 2, 2, 1, 2, 3, 4, 5, 6};
DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_2);
- DataAndBytesConsumed result = RunLengthDecode(dest_buf);
- ASSERT_EQ(sizeof(src_buf_2), result.size);
- auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
- for (uint32_t i = 0; i < result.size; i++) {
+ DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+ ASSERT_EQ(sizeof(src_buf_2), result.data.size());
+ auto decoded_buf_span = pdfium::make_span(result.data);
+ for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
EXPECT_EQ(src_buf_2[i], decoded_buf_span[i]) << " at " << i;
}
}
@@ -63,10 +63,10 @@
// Case 3: Non-match, match
const uint8_t src_buf_3[] = {1, 2, 3, 4, 5, 3, 3, 3, 3, 3};
DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_3);
- DataAndBytesConsumed result = RunLengthDecode(dest_buf);
- ASSERT_EQ(sizeof(src_buf_3), result.size);
- auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
- for (uint32_t i = 0; i < result.size; i++) {
+ DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+ ASSERT_EQ(sizeof(src_buf_3), result.data.size());
+ auto decoded_buf_span = pdfium::make_span(result.data);
+ for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
EXPECT_EQ(src_buf_3[i], decoded_buf_span[i]) << " at " << i;
}
}
@@ -79,10 +79,10 @@
// Case 1: Match, match
const uint8_t src_buf_1[260] = {1};
DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_1);
- DataAndBytesConsumed result = RunLengthDecode(dest_buf);
- ASSERT_EQ(sizeof(src_buf_1), result.size);
- auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
- for (uint32_t i = 0; i < result.size; i++) {
+ DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+ ASSERT_EQ(sizeof(src_buf_1), result.data.size());
+ auto decoded_buf_span = pdfium::make_span(result.data);
+ for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
EXPECT_EQ(src_buf_1[i], decoded_buf_span[i]) << " at " << i;
}
}
@@ -93,10 +93,10 @@
for (uint16_t i = 128; i < 260; i++)
src_buf_2[i] = static_cast<uint8_t>(i - 125);
DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_2);
- DataAndBytesConsumed result = RunLengthDecode(dest_buf);
- ASSERT_EQ(sizeof(src_buf_2), result.size);
- auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
- for (uint32_t i = 0; i < result.size; i++) {
+ DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+ ASSERT_EQ(sizeof(src_buf_2), result.data.size());
+ auto decoded_buf_span = pdfium::make_span(result.data);
+ for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
EXPECT_EQ(src_buf_2[i], decoded_buf_span[i]) << " at " << i;
}
}
@@ -107,10 +107,10 @@
for (uint8_t i = 0; i < 128; i++)
src_buf_3[i] = i;
DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_3);
- DataAndBytesConsumed result = RunLengthDecode(dest_buf);
- ASSERT_EQ(sizeof(src_buf_3), result.size);
- auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
- for (uint32_t i = 0; i < result.size; i++) {
+ DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+ ASSERT_EQ(sizeof(src_buf_3), result.data.size());
+ auto decoded_buf_span = pdfium::make_span(result.data);
+ for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
EXPECT_EQ(src_buf_3[i], decoded_buf_span[i]) << " at " << i;
}
}
@@ -121,10 +121,10 @@
for (uint16_t i = 0; i < 260; i++)
src_buf_4[i] = static_cast<uint8_t>(i);
DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_4);
- DataAndBytesConsumed result = RunLengthDecode(dest_buf);
- ASSERT_EQ(sizeof(src_buf_4), result.size);
- auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
- for (uint32_t i = 0; i < result.size; i++) {
+ DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+ ASSERT_EQ(sizeof(src_buf_4), result.data.size());
+ auto decoded_buf_span = pdfium::make_span(result.data);
+ for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
EXPECT_EQ(src_buf_4[i], decoded_buf_span[i]) << " at " << i;
}
}
diff --git a/fpdfsdk/fpdf_attachment.cpp b/fpdfsdk/fpdf_attachment.cpp
index 4136ad5..a47ba62 100644
--- a/fpdfsdk/fpdf_attachment.cpp
+++ b/fpdfsdk/fpdf_attachment.cpp
@@ -35,8 +35,8 @@
constexpr char kChecksumKey[] = "CheckSum";
ByteString CFXByteStringHexDecode(const ByteString& bsHex) {
- DataAndBytesConsumed result = HexDecode(bsHex.unsigned_span());
- return ByteString(result.data.get(), result.size);
+ DataVectorAndBytesConsumed result = HexDecode(bsHex.unsigned_span());
+ return ByteString(ByteStringView(result.data));
}
// TODO(tsepez): should be UNSAFE_BUFFER_USAGE.