9#include <unordered_set>
16 using namespace std::string_view_literals;
19 512ULL * 1024ULL * 1024ULL;
23 const std::filesystem::path&
path,
26 std::optional<DataTag> tag = std::nullopt)
29 detail =
"line " + std::to_string(line) +
": " + detail;
30 return {code,
path, tag, std::move(detail)};
33 [[
nodiscard]] std::optional<std::array<std::string_view, 4>>
36 std::array<std::string_view, 4> result{};
40 if (
index + 1 == result.size())
42 if (
separator != std::string_view::npos)
return std::nullopt;
46 if (
separator == std::string_view::npos)
return std::nullopt;
53 [[
nodiscard]] std::optional<std::uint16_t>
58 if (
value.starts_with(
"0x") ||
value.starts_with(
"0X"))
60 value.remove_prefix(2);
63 if (
value.empty())
return std::nullopt;
68 parsed > std::numeric_limits<std::uint16_t>::max())
70 return static_cast<std::uint16_t
>(
parsed);
73 [[
nodiscard]] std::optional<LegacyDataType>
76 constexpr std::array
types{
101 const std::filesystem::path&
path)
103 if (
path.empty() ||
path.is_absolute() ||
path.has_root_path())
111 std::string_view
text)
117 return std::filesystem::path(std::move(
value));
120 [[
nodiscard]] std::expected<SharedDataBytes, DataError>
122 const std::filesystem::path&
path,
123 std::optional<DataTag> tag)
125 std::ifstream
input(
path, std::ios::binary | std::ios::ate);
127 return std::unexpected(DataError{
129 "loose DATA payload cannot be opened"});
131 const auto end =
input.tellg();
134 return std::unexpected(DataError{
136 "loose DATA payload must be 1..512 MiB"});
138 auto bytes = std::make_shared<DataBytes>(
139 static_cast<std::size_t
>(end));
140 input.seekg(0, std::ios::beg);
142 reinterpret_cast<char*
>(
bytes->data()),
143 static_cast<std::streamsize
>(
bytes->size()));
145 return std::unexpected(DataError{
147 "loose DATA payload could not be read completely"});
148 return std::const_pointer_cast<const DataBytes>(
bytes);
153 std::expected<std::vector<DataSourceOverride>, DataError>
162 "loose DATA manifest cannot be opened"));
164 std::vector<DataSourceOverride> result;
165 std::unordered_set<DataId>
seen;
168 while (std::getline(
manifest, line))
171 if (!line.empty() && line.back() ==
'\r') line.pop_back();
172 if (line.empty() || line.starts_with(
'#'))
continue;
173 if (line ==
"group\ttag\ttype\tpath")
continue;
181 "expected four tab-separated columns: group, tag, type, path"));
184 const auto tag =
parseU16((*fields)[1]);
190 "group and tag must be unsigned 16-bit integers; group cannot be zero"));
192 const auto type =
parseType((*fields)[2]);
198 "unknown LegacyDataType name",
207 "payload path must stay relative to the manifest directory",
213 if (!
seen.emplace(
id).second)
218 "logical DATA id is declared more than once",
225 return std::unexpected(payload.error());
239 "loose DATA manifest read failed"));
std::vector< std::byte > bytes
std::expected< std::vector< DataSourceOverride >, DataError > loadLooseDataOverrides(const std::filesystem::path &manifestPath)
constexpr DataId packDataId(std::uint16_t group, DataTag tag) noexcept