129 if (bytes.size() < file_detail::header_bytes)
throw std::invalid_argument(
"truncated Everett header");
131 bool recognized =
false;
132 for (
auto kind : {file_kind::native_blob, file_kind::fractional_index}) {
133 auto magic = file_detail::magic(kind);
135 for (std::size_t i = 0; i < 8; ++i)
136 if (std::to_integer<unsigned char>(bytes[i]) !=
static_cast<unsigned char>(magic[i])) match =
false;
137 if (match) { header.
kind = kind; recognized =
true;
break; }
139 if (!recognized)
throw std::invalid_argument(
"unrecognized Everett magic");
140 if (file_detail::get(bytes, 8, 2) != file_detail::version ||
141 file_detail::get(bytes, 10, 2) != file_detail::header_bytes)
142 throw std::invalid_argument(
"unsupported Everett file version or header length");
143 if (file_detail::get(bytes, 68, 4) != file_detail::header_checksum(bytes))
144 throw std::invalid_argument(
"Everett header CRC32C mismatch");
145 auto flags = file_detail::get(bytes, 12, 4);
146 if (flags & ~std::uint64_t{3})
throw std::invalid_argument(
"unsupported Everett header flags");
147 if (file_detail::get(bytes, 16, 1) > 1 ||
148 file_detail::get(bytes, 16, 1) !=
static_cast<unsigned>(P::unit))
149 throw std::invalid_argument(
"Everett address unit disagrees with policy");
150 if (file_detail::get(bytes, 17, 1) != 1)
throw std::invalid_argument(
"unsupported Everett checksum kind");
151 if (file_detail::get(bytes, 19, 1))
152 throw std::invalid_argument(
"nonzero Everett reserved header bytes");
153 auto backspace = file_detail::get(bytes, 18, 1);
154 auto backspace_parameter = file_detail::get(bytes, 88, 8);
155 if (backspace >
static_cast<unsigned>(bit_backspace_code::golomb) ||
156 (backspace ==
static_cast<unsigned>(bit_backspace_code::exponential_golomb) && backspace_parameter > 63) ||
157 (backspace ==
static_cast<unsigned>(bit_backspace_code::golomb) && !backspace_parameter) ||
158 (P::unit == profile_unit::byte && (backspace || backspace_parameter)))
159 throw std::invalid_argument(
"unsupported Everett backspace descriptor");
160 if (file_detail::get(bytes, 20, 4) != P::codec_block_size ||
161 file_detail::get(bytes, 24, 8) != P::group_size ||
162 backspace !=
static_cast<unsigned>(P::backspace_code) || backspace_parameter != P::backspace_parameter)
163 throw std::invalid_argument(
"Everett stored policy descriptor mismatch");
166 else if (file_detail::get(bytes, 32, 8))
167 throw std::invalid_argument(
"variable policy width must encode zero");
169 else if (file_detail::get(bytes, 40, 8))
throw std::invalid_argument(
"absent common width must encode zero");
170 header.
extent = file_detail::get(bytes, 48, 8);
172 file_detail::validate_metadata(header);
173 if (file_detail::get(bytes, 72, 8) != file_detail::header_bytes ||
174 file_detail::get(bytes, 80, 8) != file_detail::total_bytes<P>(header.
extent))
175 throw std::invalid_argument(
"noncanonical Everett body offset or physical extent");
180 auto header = decode_file_header<P>(bytes);
181 if (file_detail::total_bytes<P>(header.extent) != bytes.size())
182 throw std::invalid_argument(
"truncated or trailing Everett object bytes");
183 auto body = bytes.subspan(file_detail::header_bytes);
184 file_detail::validate_body(header, body);
185 if (file_detail::get(bytes, 64, 4) != crc32c<typename P::architecture>(body))
186 throw std::invalid_argument(
"Everett body CRC32C mismatch");
195 file_detail::validate_metadata(header);
196 auto total = file_detail::total_bytes<P>(header.
extent);
197 std::array<std::byte, file_detail::header_bytes> result{};
198 auto magic = file_detail::magic(header.
kind);
199 for (std::size_t i = 0; i < 8; ++i) result[i] = std::byte(static_cast<unsigned char>(magic[i]));
200 file_detail::put(result, 8, 2, file_detail::version);
201 file_detail::put(result, 10, 2, file_detail::header_bytes);
203 file_detail::put(result, 16, 1,
static_cast<unsigned>(P::unit));
204 file_detail::put(result, 17, 1, 1);
205 file_detail::put(result, 18, 1,
static_cast<unsigned>(P::backspace_code));
206 file_detail::put(result, 20, 4, P::codec_block_size);
207 file_detail::put(result, 24, 8, P::group_size);
210 file_detail::put(result, 48, 8, header.
extent);
212 file_detail::put(result, 64, 4, body_crc);
213 file_detail::put(result, 72, 8, file_detail::header_bytes);
214 file_detail::put(result, 80, 8, total);
215 file_detail::put(result, 88, 8, P::backspace_parameter);
216 file_detail::put(result, 68, 4, file_detail::header_checksum(result));
222 std::span<std::byte const> body) {
223 file_detail::validate_metadata(header);
224 file_detail::validate_body(header, body);
225 auto total = file_detail::total_bytes<P>(header.
extent);
226 if (total > std::numeric_limits<std::size_t>::max())
throw std::length_error(
"Everett file is too large");
228 std::vector<std::byte> result(
static_cast<std::size_t
>(total));
229 for (std::size_t i = 0; i < prefix.size(); ++i) result[i] = prefix[i];
230 for (std::size_t i = 0; i < body.size(); ++i) result[file_detail::header_bytes + i] = body[i];