| // Copyright 2024 Google LLC. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Common implementation of SkStreamAdapter for Rust codec FFI. |
| // This is a reusable component that wraps SkStream for Rust Read + Seek traits. |
| |
| #include "rust/common/SkStreamAdapter.h" |
| |
| #include <limits> |
| |
| #include "include/private/base/SkAssert.h" |
| #include "rust/common/SpanUtils.h" |
| #include "src/base/SkSafeMath.h" |
| #include "third_party/rust/cxx/v1/cxx.h" |
| |
| namespace rust { |
| namespace stream { |
| size_t SkStreamAdapter::read(rust::Slice<uint8_t> buffer) { |
| SkASSERT_RELEASE(fStream); |
| SkSpan<uint8_t> span = ToSkSpan(buffer); |
| return fStream->read(span.data(), span.size()); |
| } |
| |
| bool SkStreamAdapter::seek_from_start(uint64_t requestedPos, uint64_t& finalPos) { |
| SkASSERT_RELEASE(fStream); |
| |
| SkSafeMath safe; |
| size_t pos = safe.castTo<size_t>(requestedPos); |
| if (!safe.ok()) { |
| return false; |
| } |
| |
| if (!fStream->seek(pos)) { |
| return false; |
| } |
| SkASSERT_RELEASE(!fStream->hasPosition() || fStream->getPosition() == requestedPos); |
| |
| // Assigning `size_t` to `uint64_t` doesn't need to go through |
| // `SkSafeMath`, because `uint64_t` is never smaller than `size_t`. |
| static_assert(sizeof(uint64_t) >= sizeof(size_t)); |
| finalPos = requestedPos; |
| |
| return true; |
| } |
| |
| bool SkStreamAdapter::seek_from_end(int64_t requestedOffset, uint64_t& finalPos) { |
| SkASSERT_RELEASE(fStream); |
| |
| if (!fStream->hasLength()) { |
| return false; |
| } |
| size_t length = fStream->getLength(); |
| |
| SkSafeMath safe; |
| uint64_t endPos = safe.castTo<uint64_t>(length); |
| if (requestedOffset > 0) { |
| // IIUC `SkStream` doesn't support reading beyond the current length. |
| return false; |
| } |
| if (requestedOffset == std::numeric_limits<int64_t>::min()) { |
| // `-requestedOffset` below wouldn't work. |
| return false; |
| } |
| uint64_t offset = safe.castTo<uint64_t>(-requestedOffset); |
| if (!safe.ok()) { |
| return false; |
| } |
| if (offset > endPos) { |
| // `endPos - offset` below wouldn't work. |
| return false; |
| } |
| |
| return this->seek_from_start(endPos - offset, finalPos); |
| } |
| |
| bool SkStreamAdapter::seek_relative(int64_t requestedOffset, uint64_t& finalPos) { |
| SkASSERT_RELEASE(fStream); |
| |
| if (!fStream->hasPosition()) { |
| return false; |
| } |
| |
| SkSafeMath safe; |
| long offset = safe.castTo<long>(requestedOffset); |
| if (!safe.ok()) { |
| return false; |
| } |
| |
| if (!fStream->move(offset)) { |
| return false; |
| } |
| |
| finalPos = safe.castTo<uint64_t>(fStream->getPosition()); |
| if (!safe.ok()) { |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace stream |
| } // namespace rust |