wowlib 0.0.0
Read & write World of Warcraft client files — a C++26 core
Loading...
Searching...
No Matches
detail.hpp
Go to the documentation of this file.
1#pragma once
2
10
11#include <algorithm>
12#include <cstddef>
13#include <cstdint>
14#include <cstring>
15#include <exception>
16#include <format>
17#include <optional>
18#include <span>
19#include <string>
20#include <utility>
21
28
34 inline RoundtripReport failed(std::string stage, std::string error) {
35 RoundtripReport report;
36 report.ok = false;
37 report.stage = std::move(stage);
38 report.error = std::move(error);
39 return report;
40 }
41
45 inline RoundtripReport skipped(std::string_view reason) {
46 RoundtripReport report;
47 report.stage = std::format("skipped:{}", reason);
48 return report;
49 }
50
57 inline RoundtripReport failWith(RoundtripReport& report, std::string stage, std::string error) {
58 report.ok = false;
59 report.stage = std::move(stage);
60 report.error = std::move(error);
61 return std::move(report);
62 }
63
72 inline std::optional<RoundtripReport> classifyRead(RoundtripReport& report,
73 std::string stage,
74 const Result<FileBuffer>& result) {
75 if (!result) {
76 if (result.error().code == ErrorCode::EncryptedContent) return skipped("encrypted");
77 return failWith(report, std::move(stage), result.error().message);
78 }
79 if (result->empty()) return skipped("empty-file");
80 return std::nullopt;
81 }
82
87 inline void tallyUnknown(RoundtripReport& report,
88 const formats::ChunkExtras& extras,
90 for (const formats::UnknownChunk& unknown : extras.unknown)
91 report.unknownChunks.push_back(formats::fourccToString(unknown.fourcc, endian));
92 }
93
99 template <typename F>
101 try {
102 return f();
103 }
104 catch (const std::exception& e) {
105 return failed("exception", e.what());
106 }
107 catch (...) {
108 return failed("exception", "unknown exception");
109 }
110 }
111
118 inline std::optional<std::string> firstDivergence(const FileBuffer& original, const FileBuffer& rewritten) {
119 if (original == rewritten) return std::nullopt;
120
121 const std::size_t common = std::min(original.size(), rewritten.size());
122 std::size_t at = 0;
123 while (at < common && original[at] == rewritten[at]) ++at;
124 return std::format("first divergence at {:#x} (sizes {} vs {})", at, original.size(), rewritten.size());
125 }
126
134 inline std::optional<std::string> firstDivergenceChunked(const FileBuffer& original, const FileBuffer& rewritten) {
135 if (original == rewritten) return std::nullopt;
136
137 const std::size_t common = std::min(original.size(), rewritten.size());
138 std::size_t at = 0;
139 while (at < common && original[at] == rewritten[at]) ++at;
140
141 // locate the chunk of the original stream the divergence falls into
142 std::string inside = "<no chunk>";
143 for (std::size_t pos = 0; pos + 8 <= original.size();) {
144 std::uint32_t fourcc = 0;
145 std::uint32_t size = 0;
146 std::memcpy(&fourcc, original.data() + pos, 4);
147 std::memcpy(&size, original.data() + pos + 4, 4);
148 if (at < pos + 8 + size) {
149 inside = formats::fourccToString(fourcc);
150 break;
151 }
152 pos += 8 + size;
153 }
154 return std::format("first divergence at {:#x} inside chunk {} (sizes {} vs {})", at, inside, original.size(),
155 rewritten.size());
156 }
157
165 template <typename F>
166 bool withVersion(const ClientVersion v, F&& f) {
167 bool matched = false;
168 const auto tryOne = [&]<ClientVersion V>() {
169 if (!matched && v == V) {
170 matched = true;
171 f.template operator()<V>();
172 }
173 };
174 tryOne.template operator()<versions::Vanilla>();
175 tryOne.template operator()<versions::Tbc>();
176 tryOne.template operator()<versions::Wotlk>();
177 tryOne.template operator()<versions::Cata>();
178 tryOne.template operator()<versions::Mop>();
179 tryOne.template operator()<versions::Wod>();
180 tryOne.template operator()<versions::Legion>();
181 tryOne.template operator()<versions::Bfa>();
182 tryOne.template operator()<versions::Shadowlands>();
183 tryOne.template operator()<versions::Dragonflight>();
184 tryOne.template operator()<versions::Tww>();
185 return matched;
186 }
187
193 constexpr bool versionSupported(std::span<const ClientVersion> grid, const ClientVersion v) {
194 for (const ClientVersion& g : grid)
195 if (g == v) return true;
196 return false;
197 }
198
203 return failed("dispatch", std::format(
204 "unrecognized client version {}.{}.{} (build {}) — not one of " "the targeted releases", v.major,
205 v.minor, v.patch, v.build));
206 }
207
215 public:
222 static RoundtripReport wmo(fs::FileSystem& fs, const std::string& path, ClientVersion version);
223
231 static RoundtripReport m2(fs::FileSystem& fs, const std::string& path, ClientVersion version);
232
239 static RoundtripReport adt(fs::FileSystem& fs, const std::string& path, ClientVersion version);
240
246 static RoundtripReport wdt(fs::FileSystem& fs, const std::string& path, ClientVersion version);
247
253 static RoundtripReport wdl(fs::FileSystem& fs, const std::string& path, ClientVersion version);
254
260 static RoundtripReport blp(fs::FileSystem& fs, const std::string& path);
261 };
262}
The owning byte buffer file contents are read into.
The chunk framework, vocabulary and engine in one header.
The per-format round-trip drivers behind Auditor::roundtrip.
Definition detail.hpp:214
static RoundtripReport wdl(fs::FileSystem &fs, const std::string &path, ClientVersion version)
Byte-perfect round-trip of one WDL file.
static RoundtripReport wmo(fs::FileSystem &fs, const std::string &path, ClientVersion version)
Byte-perfect round-trip of one root WMO and all its group files (GFID-located on Legion+,...
static RoundtripReport wdt(fs::FileSystem &fs, const std::string &path, ClientVersion version)
Byte-perfect round-trip of one main WDT file.
static RoundtripReport adt(fs::FileSystem &fs, const std::string &path, ClientVersion version)
Stability round-trip of one terrain tile (monolithic pre-Cata, split Cata+), deriving the map's alpha...
static RoundtripReport m2(fs::FileSystem &fs, const std::string &path, ClientVersion version)
Stability round-trip of one model: the assembly read (satellites baked in), then write -> parse -> wr...
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).
Client version identity, the flavor axis that separates a client's CONTENT version from the engine ge...
The runtime facade over the static compositions — the primary welder binding surface of the fs layer.
FourCC chunk identifiers: compile-time conversion of the four-letter codes to the host integers chunk...
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
bool withVersion(const ClientVersion v, F &&f)
Invoke f with the targeted release constant matching v as a compile-time template argument — the runt...
Definition detail.hpp:166
constexpr bool versionSupported(std::span< const ClientVersion > grid, const ClientVersion v)
Whether a format's instantiation grid carries v — the per-format if constexpr guard of the version di...
Definition detail.hpp:193
RoundtripReport skipped(std::string_view reason)
A skipped outcome — ok, tagged with the reason.
Definition detail.hpp:45
std::optional< std::string > firstDivergenceChunked(const FileBuffer &original, const FileBuffer &rewritten)
The first byte divergence between an original chunk stream and its rewrite, located within the enclos...
Definition detail.hpp:134
RoundtripReport guarded(F &&f)
Run one file's driver, converting any escaping exception into a failed outcome — one pathological fil...
Definition detail.hpp:100
std::optional< std::string > firstDivergence(const FileBuffer &original, const FileBuffer &rewritten)
The first byte divergence between an original and a rewrite, described by offset and sizes — the stab...
Definition detail.hpp:118
void tallyUnknown(RoundtripReport &report, const formats::ChunkExtras &extras, formats::FourCCEndian endian=formats::FourCCEndian::Reversed)
Append every unmodeled chunk of a parsed entity to the report's tally, one fourcc spelling per occurr...
Definition detail.hpp:87
RoundtripReport failed(std::string stage, std::string error)
A failed outcome.
Definition detail.hpp:34
RoundtripReport unrecognizedVersion(const ClientVersion v)
The dispatch-failure outcome for a version outside the targeted releases.
Definition detail.hpp:202
constexpr std::string fourccToString(std::uint32_t fourcc, FourCCEndian endian=FourCCEndian::Reversed)
The readable four-character spelling of a scanned chunk id.
Definition fourcc.hpp:46
FourCCEndian
How a chunk's FourCC characters are laid out on disk.
Definition fourcc.hpp:14
@ Reversed
The characters are stored reversed: 'MVER' appears in the file as the bytes "REVM".
Definition fourcc.hpp:18
constexpr ClientVersion Shadowlands
constexpr ClientVersion Tww
constexpr ClientVersion Bfa
constexpr ClientVersion Mop
constexpr ClientVersion Wod
constexpr ClientVersion Tbc
constexpr ClientVersion Vanilla
constexpr ClientVersion Legion
constexpr ClientVersion Dragonflight
constexpr ClientVersion Cata
constexpr ClientVersion Wotlk
std::expected< T, Error > Result
Every fallible wowlib operation returns Result<T>; bindings translate the error branch into a target-...
Definition error.hpp:100
@ EncryptedContent
Content is behind an unknown TACT encryption key.
Definition error.hpp:31
std::vector< std::byte > FileBuffer
Owning byte buffer for file contents read out of a client storage.
Definition buffer.hpp:16
The round-trip audit surface (namespace wowlib::audit): one welded entry point that read->write->comp...
std::uint16_t patch
Patch version within the minor release.
std::uint32_t build
Exact client build number, e.g.
std::uint16_t major
Expansion number, e.g.
std::uint16_t minor
Minor version within the expansion.
std::string error
The failure diagnostic; empty on success and on skips.
Definition roundtrip.hpp:27
std::vector< std::string > unknownChunks
Definition roundtrip.hpp:29
bool ok
Whether the round-trip succeeded; skipped files count as ok.
Definition roundtrip.hpp:22
Round-trip bookkeeping common to every chunked entity: the encounter journal, unmodeled chunks,...
std::vector< UnknownChunk > unknown
A chunk the entity does not model, preserved verbatim for round-trip.
std::uint32_t fourcc
The id as scanned (memcpy'd host u32).