wowlib 0.0.0
Read & write World of Warcraft client files — a C++26 core
Loading...
Searching...
No Matches
roundtrip.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <array>
5#include <cctype>
6#include <string>
7#include <string_view>
8
10#include <wowlib/core/path.hpp>
11
12namespace {
13 using namespace wowlib;
14 using namespace wowlib::audit;
15
16 // "{root}_NNN.wmo" — a group file, covered through its root's round-trip.
17 bool isWmoGroup(std::string_view canonical) {
18 const std::size_t stemEnd = canonical.size() - 4; // caller checked ".wmo"
19 return stemEnd >= 4 && canonical[stemEnd - 4] == '_' &&
20 std::isdigit(static_cast<unsigned char>(canonical[stemEnd - 3])) &&
21 std::isdigit(static_cast<unsigned char>(canonical[stemEnd - 2])) && std::isdigit(
22 static_cast<unsigned char>(canonical[stemEnd - 1]));
23 }
24
25 // The WDT satellite suffixes — each a separate format, not a main WDT (the
26 // full set the 9.2.7 listfile carries, as in test_wdt_wdl_roundtrip.cpp).
27 bool isAuxWdt(std::string_view stem) {
28 for (const std::string_view suffix : {"_occ", "_lgt", "_fogs", "_mpv", "_tex", "_wmo", "_psd", "_pd4"})
29 if (stem.ends_with(suffix)) return true;
30 return false;
31 }
32
33 // A Cata+ split-file sibling, merged into (and covered through) its root
34 // tile's round-trip.
35 bool isAdtSplitFile(std::string_view stem) {
36 for (const std::string_view suffix : {"_tex0", "_tex1", "_obj0", "_obj1", "_lod"})
37 if (stem.ends_with(suffix)) return true;
38 return false;
39 }
40}
41
42namespace wowlib::audit {
44 const std::string canonical = normalizePath(path);
45 const std::string_view view{canonical};
46
47 if (view.ends_with(".wmo")) {
48 if (isWmoGroup(view)) return audit::detail::skipped("wmo-group");
49 // LOD variants ("{root}_lod1.wmo") are alternate group geometry, not
50 // stand-alone roots. Suffix-anchored: "hunting_lodge.wmo" is a root.
51 const std::string_view stem = view.substr(0, view.size() - 4);
52 if (const auto lod = stem.rfind("_lod"); lod != std::string_view::npos && lod + 4 < stem.size() &&
53 std::ranges::all_of(stem.substr(lod + 4), [](char c) {
54 return std::isdigit(static_cast<unsigned char>(c));
55 }))
56 return audit::detail::skipped("wmo-lod");
57 return audit::detail::FormatDrivers::wmo(fs, canonical, version);
58 }
59
60 if (view.ends_with(".m2")) return audit::detail::FormatDrivers::m2(fs, canonical, version);
61
62 // Pre-M2 model spellings; sighted in early clients but not parsed here.
63 if (view.ends_with(".mdx") || view.ends_with(".mdl")) return audit::detail::skipped("mdx");
64
65 if (view.ends_with(".wdt")) {
66 if (isAuxWdt(view.substr(0, view.size() - 4))) return audit::detail::skipped("aux-wdt");
67 return audit::detail::FormatDrivers::wdt(fs, canonical, version);
68 }
69
70 if (view.ends_with(".wdl")) return audit::detail::FormatDrivers::wdl(fs, canonical, version);
71
72 if (view.ends_with(".blp")) return audit::detail::FormatDrivers::blp(fs, canonical);
73
74 if (view.ends_with(".adt")) {
75 if (isAdtSplitFile(view.substr(0, view.size() - 4))) return audit::detail::skipped("adt-split-file");
76 return audit::detail::FormatDrivers::adt(fs, canonical, version);
77 }
78
79 return audit::detail::skipped("unknown-format");
80 }
81}
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).
Internals of the round-trip audit (namespace wowlib::audit::detail): the per-format driver class — on...
RoundtripReport skipped(std::string_view reason)
A skipped outcome — ok, tagged with the reason.
Definition detail.hpp:45
std::string normalizePath(std::string_view path)
Canonicalize a client-internal file path.
Definition path.cpp:4
Client-internal path canonicalization.
The round-trip audit surface (namespace wowlib::audit): one welded entry point that read->write->comp...
static RoundtripReport roundtrip(fs::FileSystem &fs, std::string_view path, ClientVersion version)
Definition roundtrip.cpp:43