载入中...
搜索中...
未找到
EvpackRange.cpp
浏览该文件的文档.
1#include "asset/EvpackRange.h"
2
4
5#include "data/HashFunction.h"
6
7#include <algorithm>
8#include <fstream>
9#include <limits>
10
11namespace eve::asset {
12namespace {
13
14std::uint64_t little64(std::span<const std::uint8_t> bytes, std::size_t offset) {
15 std::uint64_t value = 0;
16 for (unsigned index = 0; index != 8; ++index) value |= std::uint64_t(bytes[offset + index]) << (index * 8);
17 return value;
18}
19
20std::array<std::uint8_t, 32> sha256(std::span<const std::uint8_t> bytes) {
21 data::HashFunction::Value digest{};
23 ->hash("sha256", reinterpret_cast<const char*>(bytes.data()), bytes.size(), digest);
24 std::array<std::uint8_t, 32> result{};
25 std::copy_n(reinterpret_cast<const std::uint8_t*>(digest.data), result.size(), result.begin());
26 return result;
27}
28
29} // namespace
30
32 std::error_code ec;
33 const auto value = std::filesystem::file_size(path_, ec);
34 if (ec)
36 "cannot read runtime package size: " + ec.message(),
37 path_.string(), {}, "asset.evpack.range"));
39}
40
42 std::uint64_t size) const {
43 if (size > std::numeric_limits<std::size_t>::max() ||
44 offset > static_cast<std::uint64_t>(std::numeric_limits<std::streamoff>::max()) ||
45 size > static_cast<std::uint64_t>(std::numeric_limits<std::streamsize>::max()))
47 "file range cannot be represented",
48 path_.string(), {}, "asset.evpack.range"));
49 std::ifstream input(path_, std::ios::binary);
50 if (!input)
52 DiagnosticCode::NotFound, "cannot open runtime package", path_.string(), {}, "asset.evpack.range"));
53 input.seekg(static_cast<std::streamoff>(offset));
54 if (!input)
56 DiagnosticCode::Failed, "cannot seek runtime package", path_.string(), {}, "asset.evpack.range"));
57 std::vector<std::uint8_t> bytes(static_cast<std::size_t>(size));
58 if (!bytes.empty()) input.read(reinterpret_cast<char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()));
59 if (!input || static_cast<std::uint64_t>(input.gcount()) != size)
61 DiagnosticCode::Failed, "runtime package range is truncated", path_.string(), {}, "asset.evpack.range"));
62 return Result<std::vector<std::uint8_t>>::success(std::move(bytes));
63}
64
65Result<EvpackRangeMount> prepareEvpackRangeMount(std::shared_ptr<const EvpackRangeSource> source,
66 const EvpackLimits& limits,
67 const EvpackTrust& trust) {
68 if (!source)
70 DiagnosticCode::InvalidArgument, "range source is required", {}, {}, "asset.evpack.range"));
71 auto sourceSize = source->size();
72 if (!sourceSize) return Result<EvpackRangeMount>::failure(sourceSize.status());
73 if (sourceSize.value() < 128 || sourceSize.value() > limits.maximumPackageBytes)
75 "range source size is outside package limits", {},
76 {}, "asset.evpack.range"));
77 auto header = source->read(0, 128);
78 if (!header) return Result<EvpackRangeMount>::failure(header.status());
79 if (header.value().size() != 128)
81 DiagnosticCode::Failed, "range source returned a short header", {}, {}, "asset.evpack.range"));
82 // Header offsets are still untrusted here; only use them to request the bounded metadata prefix.
83 const std::uint64_t tocOffset = little64(header.value(), 48);
84 const std::uint64_t tocSize = little64(header.value(), 56);
85 const std::uint64_t signatureOffset = little64(header.value(), 80);
86 const std::uint64_t signatureSize = little64(header.value(), 88);
87 if (tocOffset > sourceSize.value() || tocSize > sourceSize.value() - tocOffset ||
88 tocOffset + tocSize > limits.maximumMetadataBytes + 128)
90 DiagnosticCode::ParseError, "runtime package metadata extent is invalid", {}, {}, "asset.evpack.range"));
91 std::uint64_t metadataSize = tocOffset + tocSize;
92 if (signatureSize != 0) {
93 if (signatureOffset > sourceSize.value() || signatureSize > sourceSize.value() - signatureOffset)
95 "runtime package signature extent is invalid",
96 {}, {}, "asset.evpack.range"));
97 metadataSize = std::max(metadataSize, signatureOffset + signatureSize);
98 }
99 auto metadata = source->read(0, metadataSize);
100 if (!metadata) return Result<EvpackRangeMount>::failure(metadata.status());
101 if (metadata.value().size() != metadataSize)
103 DiagnosticCode::Failed, "range source returned a short metadata prefix", {}, {}, "asset.evpack.range"));
104 auto index = parseEvpackMetadata(metadata.value(), sourceSize.value(), limits, trust);
105 if (!index) return Result<EvpackRangeMount>::failure(index.status());
107 EvpackRangeMount(std::move(source), std::move(index).takeValue(), limits));
108}
109
111 if (index >= index_.chunks().size())
113 DiagnosticCode::InvalidArgument, "chunk index is outside the TOC", {}, {}, "asset.evpack.range"));
114 const auto& chunk = index_.chunks()[index];
115 if (chunk.storedSize > limits_.maximumChunkBytes)
117 "range chunk exceeds configured budget",
118 chunk.type, {}, "asset.evpack.range"));
119 auto bytes = source_->read(chunk.offset, chunk.storedSize);
120 if (!bytes) return Result<std::vector<std::uint8_t>>::failure(bytes.status());
121 if (bytes.value().size() != chunk.storedSize)
123 DiagnosticCode::Failed, "range source returned a short chunk", chunk.type, {}, "asset.evpack.range"));
124 auto decoded = decompressEvpackChunk(chunk.codec, bytes.value(), chunk.decodedSize,
125 limits_.maximumDecodedBytes);
126 if (!decoded) return Result<std::vector<std::uint8_t>>::failure(decoded.status());
127 if (sha256(decoded.value()) != chunk.contentHash)
129 DiagnosticCode::HashMismatch, "range chunk hash does not match", chunk.type, {}, "asset.evpack.range"));
130 return decoded;
131}
132
133} // namespace eve::asset
double value
Bounded deterministic compression used by the .evpack wire format.
Range-readable .evpack admission and on-demand verified chunks.
EvpackChunkInput input
Definition Evpack.cpp:170
size_t offset
std::uint64_t bytes
std::string digest
float size
Definition TreeMesh.cpp:156
uint32_t index
const UnitySourceAsset & source
const AssetImportLimits & limits
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Admitted metadata plus an immutable range source retained by shared ownership.
Definition EvpackRange.h:53
const Evpack & index() const noexcept
Verified package metadata and random-access TOC.
Definition EvpackRange.h:56
Result< std::vector< std::uint8_t > > readChunk(std::size_t index) const
Fetch, size-check and hash-verify one complete independently streamable chunk.
const std::vector< EvpackChunk > & chunks() const noexcept
Verified random-access chunk table.
Definition Evpack.h:173
Result< std::vector< std::uint8_t > > read(std::uint64_t offset, std::uint64_t size) const override
Reads .
Result< std::uint64_t > size() const override
Returns the size of .
static HashFunction * getHashFunction(std::string function)
Get a HashFunction instance for the given function.
virtual void hash(std::string function, const char *input, uint64_t length, Value &output) const =0
Hash the input, producing an set of bytes as output.
std::string sha256(std::span< const std::uint8_t > bytes)
Sha 256.
Result< EvpackRangeMount > prepareEvpackRangeMount(std::shared_ptr< const EvpackRangeSource > source, const EvpackLimits &limits, const EvpackTrust &trust)
Read only header/manifest/TOC and prepare on-demand range loading.
Result< std::vector< std::uint8_t > > decompressEvpackChunk(EvpackCodec codec, std::span< const std::uint8_t > stored, std::uint64_t decodedSize, std::uint64_t maximumDecodedBytes)
Decode one chunk into its authenticated canonical bytes.
Result< Evpack > parseEvpackMetadata(std::span< const std::uint8_t > bytes, std::uint64_t packageSize, const EvpackLimits &limits, const EvpackTrust &trust)
Admit only the contiguous header/manifest/TOC prefix of a range-readable package.
Definition Evpack.cpp:361
Resource limits checked before package allocations and hash work.
Definition Evpack.h:126
std::uint64_t maximumDecodedBytes
Definition Evpack.h:129
std::uint64_t maximumChunkBytes
Definition Evpack.h:128
Trust inputs kept separate from size/resource limits.
Definition Evpack.h:75