17 std::format(
"{}: {} bytes is too small for a WDB2 header", info.
name, data.size()));
19 std::memcpy(&header, data.data(),
sizeof header);
24 std::format(
"{}: file record_size {} disagrees with the generated schema stride {}", info.
name,
28 std::format(
"{}: WDB2 max_id {} below min_id {}", info.
name, header.
maxId, header.
minId));
30 const std::size_t indexBytes = header.
maxId != 0
33 const std::size_t recordsAt =
sizeof header + indexBytes;
34 const std::size_t expected = recordsAt + std::size_t{header.
recordCount} * header.
recordSize + header.
36 if (data.size() != expected)
38 "{}: {} bytes on disk, but the header describes {} ({} records of {} bytes "
39 "+ {} index + {} string + {} copy-table bytes)", info.
name, data.size(), expected,
45 if (
auto r = state.
strings.
read(data.subspan(recordsAt + std::size_t{header.recordCount} * header.
recordSize,
50 for (std::uint32_t i = 0; i < header.
recordCount; ++i) {
51 const std::size_t rec = sink.
add();
52 const auto image = data.subspan(recordsAt + std::size_t{i} * stride, stride);
56 const auto indexBlock = data.subspan(
sizeof header, indexBytes);
57 state.
wdb2Index.assign(indexBlock.begin(), indexBlock.end());
59 state.
wdb2Copy.assign(copyBlock.begin(), copyBlock.end());
60 const auto* hb =
reinterpret_cast<const std::byte*
>(&header);
61 state.
wdb2Header.assign(hb, hb +
sizeof header);
73 if (loaded && state.
wdb2Header.size() ==
sizeof header) std::memcpy(
74 &header, state.
wdb2Header.data(),
sizeof header);
79 "{}: the WDB2 id-index block cannot be rebuilt yet; adding or removing "
80 "records of an indexed table is unsupported (had {}, have {})", info.
name,
93 out.resize(
sizeof header);
95 std::size_t cursor = 0;
96 for (std::size_t r = 0; r < source.
size(); ++r)
100 if (
auto w = pool.
block.
write(out); !w)
return std::unexpected{w.error()};
103 std::memcpy(out.data(), &header,
sizeof header);
The decode target: the codecs build the record vector through this, one field at a time.
virtual std::size_t add()=0
virtual void reserve(std::size_t n)=0
The encode source: the codecs read the record vector through this.
virtual std::size_t size() const =0
Shared codec internals for the fixed-stride formats (WDBC, WDB2): the string pool that reproduces byt...
std::size_t stringSlotCount(std::span< const Column > schema)
The per-record string-reference count of schema (the offset journal width).
void decodeInlineRecord(std::span< const Column > schema, std::size_t record, std::span< const std::byte > image, RecordSink &sink, TableState &state)
Decode one fixed-stride record's inline fields into sink and journal its string offsets (record then ...
void encodeInlineRecord(std::span< const Column > schema, const RecordSource &source, std::size_t record, FileBuffer &out, StringPool &pool, const TableState &state, std::size_t &cursor)
Encode one fixed-stride record's inline fields from source, appending to out and resolving strings th...
std::size_t recordStride(std::span< const Column > schema)
The fixed record stride (WDBC/WDB2) of schema.
std::uint32_t fieldSlotCount(std::span< const Column > schema)
The expanded on-disk field-slot count of schema (WDBC/WDB2 fieldCount).
constexpr std::size_t Wdb2IndexEntryBytes
The per-id index block entry stride when maxId != 0: int32 indices[maxId - minId + 1] followed by int...
constexpr std::uint32_t Wdb2Magic
The WDB2 magic as memcpy'd off the file front (the bytes "WDB2").
Result< FileBuffer > writeWdb2(const TableInfo &info, const RecordSource &source, const TableState &state)
Encode a WDB2 image; header identity and the verbatim index/copy blocks are re-emitted.
Result< void > readWdb2(const TableInfo &info, std::span< const std::byte > data, RecordSink &sink, TableState &state)
Decode a WDB2 image: header, optional id-index block, fixed-stride records, string block,...
std::expected< T, Error > Result
Every fallible wowlib operation returns Result<T>; bindings translate the error branch into a target-...
std::unexpected< Error > makeError(ErrorCode code, std::string message, std::uint32_t nativeError=0)
Shorthand for constructing the error branch of a Result.
@ InvalidEntityState
An entity's members disagree (e.g.
@ SchemaMismatch
A client-database record layout disagrees with the generated WoWDBDefs schema.
@ TableTruncated
A client-database header, record block or satellite block overruns the file.
std::vector< std::byte > FileBuffer
Owning byte buffer for file contents read out of a client storage.
std::uint32_t build
Exact client build number, e.g.
The per-table identity a codec needs beyond the record data: the client version (format selection,...
ClientVersion version
The record's client version.
std::span< const Column > schema
The record schema (schemaOf<Record>()).
std::string_view name
The WoWDBDefs table name.
The preserved decode state a table carries between read() and write() so a WDBC/WDB2 write is byte-pe...
std::vector< std::byte > wdb2Copy
Preserved WDB2 copy table, verbatim.
formats::StringBlock strings
Preserved string block; offsets never move.
void reset()
Reset the per-read state before decoding a fresh image.
std::vector< std::byte > wdb2Header
Preserved WDB2 header identity bytes.
std::vector< std::uint32_t > stringOffsets
The original string-block offset of every string field, row-major in record then schema order — the b...
std::vector< std::byte > wdb2Index
Preserved WDB2 id-index block, verbatim.
std::uint32_t recordSize
Preserved header recordSize.
std::uint32_t fieldCount
Preserved header fieldCount (not always derivable).
std::uint32_t sourceMagic
The magic read() sniffed; 0 for a fresh table.
A writable string block resolving values to byte-perfect offsets: the journaled original offset while...
formats::StringBlock block
WDB2 — the .db2 format of the Cataclysm..WoD MPQ/early-CASC era (4.0.1.12911 .