Start assets component image signature tests
This commit is contained in:
94
src/assets/image_format.cpp
Normal file
94
src/assets/image_format.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "assets/image_format.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace pp::assets {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::array png_signature {
|
||||
std::byte { 0x89 },
|
||||
std::byte { 0x50 },
|
||||
std::byte { 0x4e },
|
||||
std::byte { 0x47 },
|
||||
std::byte { 0x0d },
|
||||
std::byte { 0x0a },
|
||||
std::byte { 0x1a },
|
||||
std::byte { 0x0a },
|
||||
};
|
||||
|
||||
[[nodiscard]] bool starts_with(std::span<const std::byte> bytes, std::span<const std::byte> prefix) noexcept
|
||||
{
|
||||
if (bytes.size() < prefix.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < prefix.size(); ++i) {
|
||||
if (bytes[i] != prefix[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_prefix_of(std::span<const std::byte> bytes, std::span<const std::byte> signature) noexcept
|
||||
{
|
||||
if (bytes.size() >= signature.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < bytes.size(); ++i) {
|
||||
if (bytes[i] != signature[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pp::foundation::Result<ImageFormat> detect_image_format(std::span<const std::byte> bytes) noexcept
|
||||
{
|
||||
if (bytes.empty()) {
|
||||
return pp::foundation::Result<ImageFormat>::failure(
|
||||
pp::foundation::Status::invalid_argument("image data must not be empty"));
|
||||
}
|
||||
|
||||
if (starts_with(bytes, png_signature)) {
|
||||
return pp::foundation::Result<ImageFormat>::success(ImageFormat::png);
|
||||
}
|
||||
|
||||
if (is_prefix_of(bytes, png_signature)) {
|
||||
return pp::foundation::Result<ImageFormat>::failure(
|
||||
pp::foundation::Status::out_of_range("image data is a truncated PNG signature"));
|
||||
}
|
||||
|
||||
if (bytes.size() < 3U) {
|
||||
return pp::foundation::Result<ImageFormat>::failure(
|
||||
pp::foundation::Status::out_of_range("image data is too short to identify"));
|
||||
}
|
||||
|
||||
if (bytes[0] == std::byte { 0xff } && bytes[1] == std::byte { 0xd8 } && bytes[2] == std::byte { 0xff }) {
|
||||
return pp::foundation::Result<ImageFormat>::success(ImageFormat::jpeg);
|
||||
}
|
||||
|
||||
return pp::foundation::Result<ImageFormat>::failure(
|
||||
pp::foundation::Status::invalid_argument("unsupported image signature"));
|
||||
}
|
||||
|
||||
const char* image_format_name(ImageFormat format) noexcept
|
||||
{
|
||||
switch (format) {
|
||||
case ImageFormat::png:
|
||||
return "png";
|
||||
case ImageFormat::jpeg:
|
||||
return "jpeg";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
}
|
||||
20
src/assets/image_format.h
Normal file
20
src/assets/image_format.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "foundation/result.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <span>
|
||||
|
||||
namespace pp::assets {
|
||||
|
||||
enum class ImageFormat {
|
||||
png,
|
||||
jpeg,
|
||||
};
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<ImageFormat> detect_image_format(
|
||||
std::span<const std::byte> bytes) noexcept;
|
||||
|
||||
[[nodiscard]] const char* image_format_name(ImageFormat format) noexcept;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user