Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
LegacyDataArchive.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "DataBanks.hpp"
4
5#include <cstddef>
6#include <cstdint>
7#include <expected>
8#include <filesystem>
9#include <fstream>
10#include <memory>
11#include <mutex>
12#include <optional>
13#include <span>
14#include <string>
15#include <string_view>
16#include <unordered_map>
17#include <vector>
18
19namespace monopoly::data
20{
21 namespace detail { class RawDataPool; }
22 // Ordre et valeurs de LE_DATA_DataType dans Source/artlib/L_Data.h.
23 enum class LegacyDataType : std::uint8_t
24 {
25 Unknown = 0,
26 Bitmap = 1,
27 DopeTable = 2,
28 Uap = 3,
29 Native = 4,
30 GbmTexture = 5,
31 GbmPicture = 6,
32 GenericBitmap = 7,
33 Wave = 8,
34 String = 9,
35 UserCreated1 = 10,
36 IndexTable = 11,
37 Chunky = 12,
38 TextureArray = 13,
39 Model3D = 14,
40 Pose3D = 15,
41 Hmd = 16,
42 MeshX = 17
43 };
44
45
46 [[nodiscard]] std::string_view legacyDataTypeName(
47 LegacyDataType type) noexcept;
48
49
90
91
92 struct DataError
93 {
95 std::filesystem::path path;
96 std::optional<DataTag> tag;
97 std::string detail;
98 };
99
100
101 [[nodiscard]] std::string_view dataErrorCodeName(
102 DataErrorCode code) noexcept;
103
104
106 {
107 std::uint16_t major{};
108 std::uint16_t minor{};
109 std::uint16_t patchMajor{};
110 std::uint16_t patchMinor{};
111 };
112
113
115 {
118 std::uint32_t offset{};
119 std::uint32_t uncompressedSize{};
120 std::uint32_t compressedSize{};
121
122 [[nodiscard]] constexpr bool present() const noexcept
123 {
124 return
126 offset != 0 ||
127 uncompressedSize != 0 ||
128 compressedSize != 0;
129 }
130 };
131
132
133 enum class ChecksumPolicy
134 {
135 Verify,
136 Ignore
137 };
138
139
141 {
142 // L_Data conservait et journalisait le CRC sans jamais le verifier.
143 // La convention annoncee par le header reste disponible comme audit
144 // opt-in, mais ne doit pas rendre le chemin runtime plus strict que
145 // l'original tant qu'aucune banque retail n'a permis de la confirmer.
147 std::uint32_t maximumUncompressedItemSize{ 512U * 1024U * 1024U };
148 };
149
150
151 using DataBytes = std::vector<std::byte>;
152 using SharedDataBytes = std::shared_ptr<const DataBytes>;
153
154 // C_ArtLib.h:470 / L_Data.cpp:943: global soft eviction threshold.
155 // The source's 18 MiB value was a heap reservation, not a cache limit.
156 inline constexpr std::size_t LegacyRawDataCacheBudget = 30U * 1024U * 1024U;
157
159 {
160 std::size_t residentBytes{}; // Includes externally leased, unloaded data.
161 std::size_t reservedBytes{}; // Concurrent loads not yet published.
162 std::size_t cachedItems{};
163 std::size_t leasedItems{};
164 };
165
166 [[nodiscard]] RawDataCacheStats rawDataCacheStats() noexcept;
167
168
170 {
171 public:
172 static constexpr std::size_t PhysicalHeaderSize = 28;
173 static constexpr std::size_t PhysicalIndexRecordSize = 16;
174 static constexpr std::uint16_t SupportedVersionMajor = 2;
175 static constexpr std::uint16_t SupportedVersionMinor = 3;
176 static constexpr std::size_t MaximumItemCount = 65'536;
177
182
184
185 [[nodiscard]] static std::expected<
186 std::shared_ptr<LegacyDataArchive>,
187 DataError>
188 open(
189 const std::filesystem::path& path,
190 std::uint16_t group,
191 ArchiveOpenOptions options = {});
192
193 void close() noexcept;
194
195 [[nodiscard]] bool isOpen() const noexcept;
199 [[nodiscard]] std::uint32_t storedChecksum() const noexcept;
200 [[nodiscard]] std::size_t itemCount() const noexcept;
201
202 [[nodiscard]] std::expected<ArchiveItemMetadata, DataError>
204
205 [[nodiscard]] std::expected<LegacyDataType, DataError>
206 initialDataType(DataTag tag) const;
207
208 [[nodiscard]] std::expected<std::uint32_t, DataError>
209 initialSize(DataTag tag) const;
210
211 // Loads raw DAT bytes if necessary and returns their decompressed size.
212 // Bitmap/mesh post-load conversions are owned by their modern runtimes.
213 [[nodiscard]] std::expected<std::uint32_t, DataError>
214 loadedRawSize(DataTag tag);
215
216 [[nodiscard]] std::expected<SharedDataBytes, DataError>
217 load(DataTag tag);
218
219 // LE_DATA_LoadRawIntoBuffer: read raw decompressed bytes without
220 // installing or touching cache ownership/post-load state.
221 [[nodiscard]] std::expected<std::size_t, DataError>
222 readRaw(
223 DataTag tag,
224 std::span<std::byte> destination,
225 std::uint32_t startOffset = 0);
226
227 // Safe LE_DATA_GetPointer equivalent: report whether the item has
228 // live cache/lease ownership without exposing a raw pointer.
229 [[nodiscard]] std::expected<bool, DataError>
230 isLoaded(DataTag tag) const;
231
232 // Retire seulement la possession du cache. Les SharedDataBytes deja
233 // remis aux callers restent valides, contrairement aux pointeurs nus
234 // de L_Data.
235 [[nodiscard]] std::expected<bool, DataError> unload(DataTag tag);
236 void clearCache() noexcept;
237 [[nodiscard]] std::size_t cachedItemCount() const noexcept;
238
239 private:
241
242 [[nodiscard]] static DataError makeError(
243 DataErrorCode code,
244 const std::filesystem::path& path,
245 std::string detail,
246 std::optional<DataTag> tag = std::nullopt);
247
248 mutable std::mutex mutex_;
249 std::filesystem::path path_;
250 std::ifstream stream_;
251 std::uint16_t group_{};
252 ArchiveVersion version_{};
253 std::uint32_t checksum_{};
254 std::uint64_t fileSize_{};
255 std::uint32_t maximumUncompressedItemSize_{};
256 bool open_{};
257 std::vector<ArchiveItemMetadata> items_;
258 std::vector<std::weak_ptr<const DataBytes>> cache_;
259 std::shared_ptr<detail::RawDataPool> rawDataPool_;
260 };
261
262
263 // Read-only logical DATA surface consumed by the modern runtime.
264 // Legacy DAT banks are one backend; future native asset providers can
265 // implement the same contract without exposing archive/container details.
267 {
268 public:
269 virtual ~DataSource() = default;
270
271 [[nodiscard]] virtual std::expected<ArchiveItemMetadata, DataError>
272 metadata(DataId id) const = 0;
273
274 [[nodiscard]] virtual std::expected<LegacyDataType, DataError>
275 initialDataType(DataId id) const = 0;
276
277 [[nodiscard]] virtual std::expected<std::uint32_t, DataError>
278 initialSize(DataId id) const = 0;
279
280 [[nodiscard]] virtual std::expected<std::uint32_t, DataError>
281 loadedRawSize(DataId id) const = 0;
282
283 [[nodiscard]] virtual std::expected<SharedDataBytes, DataError>
284 load(DataId id) const = 0;
285
286 [[nodiscard]] virtual std::expected<std::size_t, DataError>
288 DataId id,
289 std::span<std::byte> destination,
290 std::uint32_t startOffset = 0) const = 0;
291
292 [[nodiscard]] virtual std::expected<bool, DataError>
293 isLoaded(DataId id) const = 0;
294 };
295
296
298 {
299 public:
300 [[nodiscard]] std::expected<
301 std::shared_ptr<LegacyDataArchive>,
302 DataError>
303 mount(
304 const std::filesystem::path& path,
305 std::uint16_t group,
306 ArchiveOpenOptions options = {});
307
308 [[nodiscard]] std::expected<
309 std::shared_ptr<LegacyDataArchive>,
310 DataError>
311 archive(std::uint16_t group) const;
312
313 [[nodiscard]] std::expected<ArchiveItemMetadata, DataError>
314 metadata(DataId id) const override;
315
316 [[nodiscard]] std::expected<LegacyDataType, DataError>
317 initialDataType(DataId id) const override;
318
319 [[nodiscard]] std::expected<std::uint32_t, DataError>
320 initialSize(DataId id) const override;
321
322 [[nodiscard]] std::expected<std::uint32_t, DataError>
323 loadedRawSize(DataId id) const override;
324
325 [[nodiscard]] std::expected<SharedDataBytes, DataError>
326 load(DataId id) const override;
327
328 [[nodiscard]] std::expected<std::size_t, DataError>
329 readRaw(
330 DataId id,
331 std::span<std::byte> destination,
332 std::uint32_t startOffset = 0) const override;
333
334 [[nodiscard]] std::expected<bool, DataError>
335 isLoaded(DataId id) const override;
336
337 // LE_DATA_Unload at registry scope. Already-unloaded items are a
338 // successful no-op. Existing SharedDataBytes leases remain valid;
339 // only registry/cache ownership is retired.
340 [[nodiscard]] std::expected<void, DataError>
341 unload(DataId id) const;
342
343 // Drop cache ownership for every mounted archive without unmounting
344 // the banks themselves. Outstanding leases keep their bytes alive.
345 void clearCaches() noexcept;
346
347 [[nodiscard]] std::size_t cachedItemCount() const noexcept;
348
349 [[nodiscard]] std::expected<void, DataError>
350 unmount(std::uint16_t group);
351
352 void clear() noexcept;
353 [[nodiscard]] std::size_t mountedCount() const noexcept;
354
355 private:
356 mutable std::mutex mutex_;
357 std::unordered_map<
358 std::uint16_t,
359 std::shared_ptr<LegacyDataArchive>> archives_;
360 };
361
362
364 {
365 std::uint32_t indexValue{};
367 };
368
369
371 {
372 public:
373 static constexpr std::size_t PhysicalEntrySize = 6;
374
375 [[nodiscard]] static std::expected<DataIndexTable, DataError>
376 parse(std::span<const std::byte> bytes);
377
378 [[nodiscard]] std::optional<DataTag> find(
379 std::uint32_t indexValue) const noexcept;
380
381 [[nodiscard]] std::span<const DataIndexEntry> entries()
383
384 private:
385 std::vector<DataIndexEntry> entries_;
386 };
387
388
389 [[nodiscard]] std::expected<DataId, DataError>
393 std::uint32_t indexValue);
394
395 // Compatibility form of LE_DATA_GetIndexedItemId. The original returns
396 // LE_DATA_EmptyItem for a non-index item or an absent logical key.
397 // I/O, archive and corruption failures remain typed errors.
398 [[nodiscard]] std::expected<DataId, DataError>
402 std::uint32_t indexValue);
403}
std::uint16_t group
LegacyBitmapMetadata metadata
std::vector< std::byte > bytes
std::shared_ptr< const data::HmdTextureImage > source
unsigned index
std::string path
std::expected< LegacyDataType, DataError > initialDataType(DataId id) const override
std::expected< std::uint32_t, DataError > loadedRawSize(DataId id) const override
std::expected< void, DataError > unmount(std::uint16_t group)
std::size_t cachedItemCount() const noexcept
std::expected< SharedDataBytes, DataError > load(DataId id) const override
std::expected< void, DataError > unload(DataId id) const
std::expected< std::uint32_t, DataError > initialSize(DataId id) const override
std::expected< std::shared_ptr< LegacyDataArchive >, DataError > mount(const std::filesystem::path &path, std::uint16_t group, ArchiveOpenOptions options={})
std::size_t mountedCount() const noexcept
std::expected< bool, DataError > isLoaded(DataId id) const override
std::expected< std::shared_ptr< LegacyDataArchive >, DataError > archive(std::uint16_t group) const
std::expected< std::size_t, DataError > readRaw(DataId id, std::span< std::byte > destination, std::uint32_t startOffset=0) const override
std::optional< DataTag > find(std::uint32_t indexValue) const noexcept
std::span< const DataIndexEntry > entries() const noexcept
static std::expected< DataIndexTable, DataError > parse(std::span< const std::byte > bytes)
static constexpr std::size_t PhysicalEntrySize
virtual std::expected< LegacyDataType, DataError > initialDataType(DataId id) const =0
virtual std::expected< std::uint32_t, DataError > loadedRawSize(DataId id) const =0
virtual std::expected< bool, DataError > isLoaded(DataId id) const =0
virtual std::expected< std::uint32_t, DataError > initialSize(DataId id) const =0
virtual std::expected< ArchiveItemMetadata, DataError > metadata(DataId id) const =0
virtual ~DataSource()=default
virtual std::expected< std::size_t, DataError > readRaw(DataId id, std::span< std::byte > destination, std::uint32_t startOffset=0) const =0
virtual std::expected< SharedDataBytes, DataError > load(DataId id) const =0
LegacyDataArchive & operator=(const LegacyDataArchive &)=delete
LegacyDataArchive(LegacyDataArchive &&)=delete
LegacyDataArchive(const LegacyDataArchive &)=delete
LegacyDataArchive & operator=(LegacyDataArchive &&)=delete
std::uint32_t DataId
Definition DataBanks.hpp:10
std::string_view legacyDataTypeName(LegacyDataType type) noexcept
std::vector< std::byte > DataBytes
std::uint16_t DataTag
Definition DataBanks.hpp:11
RawDataCacheStats rawDataCacheStats() noexcept
std::expected< DataId, DataError > lookupIndexedDataIdLegacy(const DataSource &source, DataId indexTableId, std::uint32_t indexValue)
std::shared_ptr< const DataBytes > SharedDataBytes
std::expected< DataId, DataError > lookupIndexedDataId(const DataSource &source, DataId indexTableId, std::uint32_t indexValue)
std::string_view dataErrorCodeName(DataErrorCode code) noexcept
constexpr std::size_t LegacyRawDataCacheBudget
constexpr bool present() const noexcept
std::filesystem::path path
std::optional< DataTag > tag