#include "stretch.h" #include "icon_bitmap.h" #include "icon_data.h" #include #include #include #include #include #include static void check(bool condition, const char *message) { if (!condition) throw std::runtime_error(message); } static std::vector read_file(const std::filesystem::path &path) { std::ifstream file(path, std::ios::binary | std::ios::ate); check(bool(file) && file.tellg() > 0 && file.tellg() <= 64 * 1024 * 1024, "invalid raster fixture"); std::vector bytes(static_cast(file.tellg())); file.seekg(0); check(bool(file.read(reinterpret_cast(bytes.data()), static_cast(bytes.size()))), "cannot read raster fixture"); return bytes; } static uint32_t number(std::span bytes, size_t offset, size_t size = 4) { check(offset <= bytes.size() && size <= bytes.size() - offset, "truncated raster fixture"); uint32_t value = 0; for (size_t index = 0; index < size; ++index) value |= uint32_t(bytes[offset + index]) << (index * 8); return value; } static void rejected(std::span bytes, uint32_t width, uint32_t height, uint32_t channels, uint32_t target_width, uint32_t target_height, std::string_view expected) { std::string failure; try { raven::stretch_blackonwhite(bytes, width, height, channels, target_width, target_height); } catch (const std::runtime_error &error) { failure = error.what(); } check(failure.find(expected) != failure.npos, "raster negative failed for another reason"); } static std::vector bitmap_pixels(std::span bytes) { const auto width = number(bytes, 4), height = number(bytes, 8), stride = number(bytes, 12), depth = number(bytes, 18, 2); check(width && height && width <= 8192 && height <= 8192 && number(bytes, 16, 2) == 1 && (depth == 1 || depth == 32), "invalid reference bitmap"); check(stride == (depth == 32 ? width * 4 : (width + 15) / 16 * 2) && uint64_t(stride) * height == bytes.size() - 32, "invalid reference bitmap storage"); if (depth == 32) return {bytes.begin() + 32, bytes.end()}; std::vector pixels(size_t(width) * height); for (uint32_t y = 0; y < height; ++y) for (uint32_t x = 0; x < width; ++x) pixels[size_t(y) * width + x] = uint8_t((bytes[32 + size_t(y) * stride + x / 8] >> (7 - x % 8)) & 1); return pixels; } int main(int argc, char **argv) { try { check(argc == 2 || argc == 4, "scan reference and optional bitmap manifest/output required"); const std::array pixel{1,2,4,8}; rejected(pixel,0,1,4,1,1,"geometry"); rejected(pixel,1,1,3,1,1,"channels"); rejected(pixel,1,1,4,8193,1,"geometry"); rejected(pixel,1,1,4,8192,8192,"limit"); rejected(pixel,8192,8192,4,1,1,"limit"); rejected(std::span(pixel).first(3),1,1,4,1,1,"storage"); rejected(pixel,1,16385,1,1,1,"geometry"); check(raven::stretch_blackonwhite(std::vector(16384,1),1,16384,1,1,2) == std::vector({1,1}), "bounded compound mask height was rejected"); check(raven::stretch_blackonwhite(pixel,1,1,4,2,3) == std::vector({1,2,4,8,1,2,4,8,1,2,4,8,1,2,4,8,1,2,4,8,1,2,4,8}), "constant alpha/channels did not survive expansion"); const auto known_color = raven::decode_icon_dib(color_icon); check(raven::stretch_blackonwhite(known_color.color.rgba,3,2,4,2,1) == std::vector({0,0,0,0,0,0,8,0}),"known resource channels/alpha differ from Wine"); check(raven::stretch_blackonwhite(known_color.color.rgba,3,2,4,2,1,raven::StretchOperation::bitmap) == std::vector({0,0,0,0,0,0,255,255}),"bitmap endpoint contract was mixed with DIB input"); const auto known_mono = raven::decode_icon_dib(mono_icon); auto compound = known_mono.and_mask; compound.insert(compound.end(),known_mono.xor_mask.begin(),known_mono.xor_mask.end()); check(raven::stretch_blackonwhite(compound,4,4,1,2,2) == std::vector(4,0), "known monochrome compound resource differs from Wine"); for (const auto operation : {raven::StretchOperation::bitmap,raven::StretchOperation::dibits}) { auto reference_path = std::filesystem::path(argv[1]); if (operation == raven::StretchOperation::dibits) reference_path.replace_filename("blackonwhite_dibits_reference.bin"); const auto reference = read_file(reference_path); check(reference.size() >= 8 && std::string(reference.begin(), reference.begin() + 4) == "RBW1" && number(reference,4) == 2552, "scan reference identity differs"); size_t offset = 8; for (unsigned test = 0; test < 2552; ++test) { const auto source = number(reference,offset,2), target = number(reference,offset+2,2); offset += 4; std::vector> ranges; for (uint32_t index = 0; index < target; ++index) { const auto begin = number(reference,offset,2), end = number(reference,offset+2,2); check(begin < end && end <= source, "invalid scan reference interval"); ranges.push_back({begin,end}); offset += 4; } for (bool vertical : {false,true}) { for (uint32_t block = 0; block < source; block += 24) { std::vector colors(size_t(source) * 4,255); for (uint32_t index = block; index < source && index < block+24; ++index) colors[size_t(index)*4+(index-block)/8] &= uint8_t(~(1U<<((index-block)%8))); const auto color = raven::stretch_blackonwhite(colors,vertical?1:source,vertical?source:1,4, vertical?1:target,vertical?target:1,operation); for (uint32_t index = 0; index < target; ++index) { uint32_t expected = 0xffffffff; for (uint32_t contributor = ranges[index][0]; contributor < ranges[index][1]; ++contributor) if (contributor >= block && contributor < block+24) expected &= ~(1U<<(contributor-block)); check(number(color,size_t(index)*4) == expected,"color scan footprint differs"); } const uint32_t width = vertical?24:source, height = vertical?source:24; std::vector mono(size_t(width)*height,1); for (uint32_t bit=0; bit<24 && block+bit=ranges[index][0] && block+bit>source_path>>target_path>>label),"truncated raster manifest row"); for (const char *suffix : {".color",".mask"}) { auto from=std::filesystem::path(source_path),to=std::filesystem::path(target_path); from.replace_extension(suffix);to.replace_extension(suffix); const auto input=read_file(from), expected=read_file(to); const auto pixels=bitmap_pixels(input), result=bitmap_pixels(expected); const uint32_t channels=number(input,18,2)==32?4:1; const auto actual=raven::stretch_blackonwhite(pixels,number(input,4),number(input,8),channels,number(expected,4),number(expected,8)); check(actual==result,"real bitmap BLACKONWHITE output differs"); std::ofstream file(std::filesystem::path(argv[3])/(label+suffix),std::ios::binary); file.write(reinterpret_cast(actual.data()),static_cast(actual.size())); check(bool(file),"cannot save native raster evidence"); } ++cases; } check(manifest.eof() && cases>0 && cases<=10000,"incomplete real raster manifest"); std::cout<