Validate PPI project layout
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "foundation/binary_stream.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace pp::assets {
|
||||
|
||||
namespace {
|
||||
@@ -70,4 +72,66 @@ pp::foundation::Result<PpiHeaderInfo> parse_ppi_header(std::span<const std::byte
|
||||
return pp::foundation::Result<PpiHeaderInfo>::success(info);
|
||||
}
|
||||
|
||||
pp::foundation::Result<std::size_t> ppi_thumbnail_byte_size(PpiThumbnailInfo thumbnail) noexcept
|
||||
{
|
||||
if (thumbnail.width == 0 || thumbnail.height == 0 || thumbnail.components == 0) {
|
||||
return pp::foundation::Result<std::size_t>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI thumbnail descriptor is invalid"));
|
||||
}
|
||||
|
||||
const auto width = static_cast<std::uint64_t>(thumbnail.width);
|
||||
const auto height = static_cast<std::uint64_t>(thumbnail.height);
|
||||
const auto components = static_cast<std::uint64_t>(thumbnail.components);
|
||||
if (width > std::numeric_limits<std::uint64_t>::max() / height) {
|
||||
return pp::foundation::Result<std::size_t>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI thumbnail byte size overflows"));
|
||||
}
|
||||
|
||||
const auto pixels = width * height;
|
||||
if (pixels > std::numeric_limits<std::uint64_t>::max() / components) {
|
||||
return pp::foundation::Result<std::size_t>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI thumbnail byte size overflows"));
|
||||
}
|
||||
|
||||
const auto bytes = pixels * components;
|
||||
if (bytes > static_cast<std::uint64_t>(std::numeric_limits<std::size_t>::max())) {
|
||||
return pp::foundation::Result<std::size_t>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI thumbnail byte size exceeds addressable memory"));
|
||||
}
|
||||
|
||||
return pp::foundation::Result<std::size_t>::success(static_cast<std::size_t>(bytes));
|
||||
}
|
||||
|
||||
pp::foundation::Result<PpiProjectLayout> parse_ppi_project_layout(std::span<const std::byte> bytes) noexcept
|
||||
{
|
||||
const auto header = parse_ppi_header(bytes);
|
||||
if (!header) {
|
||||
return pp::foundation::Result<PpiProjectLayout>::failure(header.status());
|
||||
}
|
||||
|
||||
const auto thumbnail_bytes = ppi_thumbnail_byte_size(header.value().thumbnail);
|
||||
if (!thumbnail_bytes) {
|
||||
return pp::foundation::Result<PpiProjectLayout>::failure(thumbnail_bytes.status());
|
||||
}
|
||||
|
||||
if (thumbnail_bytes.value() > std::numeric_limits<std::size_t>::max() - ppi_header_size) {
|
||||
return pp::foundation::Result<PpiProjectLayout>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI thumbnail byte size overflows"));
|
||||
}
|
||||
|
||||
const auto body_offset = ppi_header_size + thumbnail_bytes.value();
|
||||
if (bytes.size() < body_offset) {
|
||||
return pp::foundation::Result<PpiProjectLayout>::failure(
|
||||
pp::foundation::Status::out_of_range("PPI thumbnail payload is truncated"));
|
||||
}
|
||||
|
||||
return pp::foundation::Result<PpiProjectLayout>::success(PpiProjectLayout {
|
||||
.header = header.value(),
|
||||
.thumbnail_offset = ppi_header_size,
|
||||
.thumbnail_bytes = thumbnail_bytes.value(),
|
||||
.body_offset = body_offset,
|
||||
.body_bytes = bytes.size() - body_offset,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,20 @@ struct PpiHeaderInfo {
|
||||
PpiThumbnailInfo thumbnail;
|
||||
};
|
||||
|
||||
struct PpiProjectLayout {
|
||||
PpiHeaderInfo header;
|
||||
std::size_t thumbnail_offset = 0;
|
||||
std::size_t thumbnail_bytes = 0;
|
||||
std::size_t body_offset = 0;
|
||||
std::size_t body_bytes = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<PpiHeaderInfo> parse_ppi_header(
|
||||
std::span<const std::byte> bytes) noexcept;
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<std::size_t> ppi_thumbnail_byte_size(PpiThumbnailInfo thumbnail) noexcept;
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<PpiProjectLayout> parse_ppi_project_layout(
|
||||
std::span<const std::byte> bytes) noexcept;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user