wowlib 0.0.0
Read & write World of Warcraft client files — a C++26 core
Loading...
Searching...
No Matches
roundtrip_blp.cpp
Go to the documentation of this file.
1
6
7#include <algorithm>
8#include <cstddef>
9#include <cstdint>
10#include <format>
11#include <optional>
12#include <string>
13
16
17namespace {
18 using namespace wowlib;
19 using namespace wowlib::audit;
20 using namespace wowlib::formats;
21
29 std::optional<std::string> firstDivergenceBlp(const FileBuffer& original,
30 const FileBuffer& rewritten,
31 const blp::BLP& entity) {
32 if (original == rewritten) return std::nullopt;
33
34 const std::size_t common = std::min(original.size(), rewritten.size());
35 std::size_t at = 0;
36 while (at < common && original[at] == rewritten[at]) ++at;
37
38 std::string inside = "gap/tail";
39 if (at < 0x94) inside = "header";
40 else if (at < blp::BlpHeaderBytes) inside = "palette";
41 else
42 for (std::size_t level = 0; level < blp::BlpMaxMips; ++level) {
43 const std::uint32_t offset = entity.storedLayout.offsets[level];
44 const std::uint32_t size = entity.storedLayout.sizes[level];
45 if (offset != 0 && size != 0 && at >= offset && at < std::uint64_t{offset} + size) {
46 inside = std::format("mip {}", level);
47 break;
48 }
49 }
50 return std::format("first divergence at {:#x} inside {} (sizes {} vs {})", at, inside, original.size(),
51 rewritten.size());
52 }
53
58 RoundtripReport roundtripBlp(fs::FileSystem& fs, const std::string& path) {
59 RoundtripReport report;
60 const auto raw = fs.readFile(FileKey{path});
61 if (auto outcome = audit::detail::classifyRead(report, "read", raw)) return *outcome;
62
63 blp::BLP entity;
64 if (auto r = entity.read(*raw); !r) return audit::detail::failWith(report, "parse", r.error().message);
65
66 const auto rewritten = entity.write();
67 if (!rewritten)
68 return audit::detail::failWith(report, "write", rewritten.error().message);
69 if (auto divergence = firstDivergenceBlp(*raw, *rewritten, entity)) return audit::detail::failWith(
70 report, "compare", *divergence);
71 return report;
72 }
73}
74
75namespace wowlib::audit::detail {
77 return guarded([&] { return roundtripBlp(fs, path); });
78 }
79}
The BLP entity (namespace wowlib::formats::blp): Blizzard's texture format.
static RoundtripReport blp(fs::FileSystem &fs, const std::string &path)
Byte-perfect round-trip of one BLP texture (the format is version-stable, so no version dispatch).
Internals of the round-trip audit (namespace wowlib::audit::detail): the per-format driver class — on...
RoundtripReport failWith(RoundtripReport &report, std::string stage, std::string error)
Mark report failed in place and hand it back — keeps the unknown-chunk tally gathered before the fail...
Definition detail.hpp:57
std::optional< RoundtripReport > classifyRead(RoundtripReport &report, std::string stage, const Result< FileBuffer > &result)
Classify a client-file read for the audit: content behind an unknown TACT key and zero-byte archive e...
Definition detail.hpp:72
RoundtripReport guarded(F &&f)
Run one file's driver, converting any escaping exception into a failed outcome — one pathological fil...
Definition detail.hpp:100
constexpr std::size_t BlpHeaderBytes
The full header region: 148-byte header + 1024-byte palette.
Definition blp.hpp:53
constexpr std::size_t BlpMaxMips
The mip table capacity: a BLP addresses at most 16 levels.
Definition blp.hpp:49
std::vector< std::byte > FileBuffer
Owning byte buffer for file contents read out of a client storage.
Definition buffer.hpp:16
detail::StoredLayout storedLayout
The read-recorded on-disk placement (see detail::StoredLayout).
Definition blp.hpp:189
Result< void > read(std::span< const std::byte > data)
Parse a BLP2 file from memory, replacing this entity's contents.
Definition blp.cpp:596
Result< FileBuffer > write() const
Serialize this entity.
Definition blp.cpp:668
std::array< std::uint32_t, BlpMaxMips > sizes
The header's size table, verbatim.
Definition blp.hpp:119
std::array< std::uint32_t, BlpMaxMips > offsets
The header's offset table, verbatim.
Definition blp.hpp:117