#include "assets/ppi_header.h" #include "document/ppi_import.h" #include "test_harness.h" #include #include #include #include #include using pp::assets::decode_ppi_project_images; using pp::foundation::StatusCode; using pp::document::import_ppi_project_document; namespace { void append_u32(std::vector& bytes, std::uint32_t value) { bytes.push_back(static_cast(value & 0xffU)); bytes.push_back(static_cast((value >> 8U) & 0xffU)); bytes.push_back(static_cast((value >> 16U) & 0xffU)); bytes.push_back(static_cast((value >> 24U) & 0xffU)); } void append_f32(std::vector& bytes, float value) { append_u32(bytes, std::bit_cast(value)); } void append_ascii(std::vector& bytes, std::string_view value) { for (const auto ch : value) { bytes.push_back(static_cast(ch)); } } std::vector transparent_png_1x1() { return { std::byte { 0x89 }, std::byte { 0x50 }, std::byte { 0x4e }, std::byte { 0x47 }, std::byte { 0x0d }, std::byte { 0x0a }, std::byte { 0x1a }, std::byte { 0x0a }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x0d }, std::byte { 0x49 }, std::byte { 0x48 }, std::byte { 0x44 }, std::byte { 0x52 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x01 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x01 }, std::byte { 0x08 }, std::byte { 0x06 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x1f }, std::byte { 0x15 }, std::byte { 0xc4 }, std::byte { 0x89 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x0b }, std::byte { 0x49 }, std::byte { 0x44 }, std::byte { 0x41 }, std::byte { 0x54 }, std::byte { 0x78 }, std::byte { 0x9c }, std::byte { 0x63 }, std::byte { 0x60 }, std::byte { 0x00 }, std::byte { 0x02 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x05 }, std::byte { 0x00 }, std::byte { 0x01 }, std::byte { 0x7a }, std::byte { 0x5e }, std::byte { 0xab }, std::byte { 0x3f }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x00 }, std::byte { 0x49 }, std::byte { 0x45 }, std::byte { 0x4e }, std::byte { 0x44 }, std::byte { 0xae }, std::byte { 0x42 }, std::byte { 0x60 }, std::byte { 0x82 }, }; } std::vector ppi_project_with_face_payload(std::vector payload) { std::vector bytes { std::byte { 'P' }, std::byte { 'P' }, std::byte { 'I' }, std::byte { 0 }, }; append_u32(bytes, 0); append_u32(bytes, 4); append_u32(bytes, 0); append_u32(bytes, 2); append_u32(bytes, 3); append_u32(bytes, 1024); append_u32(bytes, 128); append_u32(bytes, 128); append_u32(bytes, 4); bytes.resize(pp::assets::ppi_header_size + (128U * 128U * 4U), std::byte { 0 }); append_u32(bytes, 64); append_u32(bytes, 32); append_u32(bytes, 1); append_u32(bytes, 1); append_u32(bytes, 0); append_f32(bytes, 1.0F); append_u32(bytes, 3); append_ascii(bytes, "Ink"); append_u32(bytes, 0); bytes.push_back(std::byte { 0 }); bytes.push_back(std::byte { 1 }); append_u32(bytes, 1); append_u32(bytes, 100); append_u32(bytes, 1); append_u32(bytes, 2); append_u32(bytes, 3); append_u32(bytes, 3); append_u32(bytes, 4); append_u32(bytes, static_cast(payload.size())); bytes.insert(bytes.end(), payload.begin(), payload.end()); for (std::uint32_t i = 1; i < 6U; ++i) { append_u32(bytes, 0); } append_u32(bytes, 0); return bytes; } void imports_decoded_ppi_pixels_into_document(pp::tests::Harness& h) { const auto project_bytes = ppi_project_with_face_payload(transparent_png_1x1()); const auto decoded = decode_ppi_project_images(project_bytes); PP_EXPECT(h, decoded.ok()); const auto document = import_ppi_project_document(decoded.value()); PP_EXPECT(h, document.ok()); PP_EXPECT(h, document.value().width() == 64U); PP_EXPECT(h, document.value().height() == 32U); PP_EXPECT(h, document.value().face_pixel_payload_count() == 1U); PP_EXPECT(h, document.value().layers()[0].frames[0].face_pixels.size() == 1U); PP_EXPECT(h, document.value().layers()[0].frames[0].face_pixels[0].face_index == 0U); PP_EXPECT(h, document.value().layers()[0].frames[0].face_pixels[0].x == 2U); PP_EXPECT(h, document.value().layers()[0].frames[0].face_pixels[0].y == 3U); PP_EXPECT(h, document.value().layers()[0].frames[0].face_pixels[0].width == 1U); PP_EXPECT(h, document.value().layers()[0].frames[0].face_pixels[0].height == 1U); PP_EXPECT(h, document.value().layers()[0].frames[0].face_pixels[0].rgba8.size() == 4U); PP_EXPECT(h, document.value().layers()[0].frames[0].face_pixels[0].rgba8[3] == 0U); } void rejects_decoded_payloads_outside_document_layers(pp::tests::Harness& h) { const auto project_bytes = ppi_project_with_face_payload(transparent_png_1x1()); const auto decoded = decode_ppi_project_images(project_bytes); PP_EXPECT(h, decoded.ok()); auto decoded_value = decoded.value(); decoded_value.faces[0].layer_index = 99; const auto document = import_ppi_project_document(decoded_value); PP_EXPECT(h, !document.ok()); PP_EXPECT(h, document.status().code == StatusCode::out_of_range); } } int main() { pp::tests::Harness harness; harness.run("imports_decoded_ppi_pixels_into_document", imports_decoded_ppi_pixels_into_document); harness.run("rejects_decoded_payloads_outside_document_layers", rejects_decoded_payloads_outside_document_layers); return harness.finish(); }