1#include <fcb/generated/header_generated.h>
22const ::Header* HeaderView::raw()
const {
25 if (buffer_ ==
nullptr)
27 return GetSizePrefixedHeader(buffer_->data() +
kBodyAlignPad);
45double read_f64_at(
const void* base, std::size_t byte_offset) {
47 std::memcpy(&d,
static_cast<const std::uint8_t*
>(base) + byte_offset,
sizeof(
double));
53std::uint32_t read_u32_le(
const std::vector<std::uint8_t>& b, std::size_t at) {
54 return static_cast<std::uint32_t
>(b[at]) | (
static_cast<std::uint32_t
>(b[at + 1]) << 8) |
55 (
static_cast<std::uint32_t
>(b[at + 2]) << 16) |
56 (
static_cast<std::uint32_t
>(b[at + 3]) << 24);
59void collect_columns(
const flatbuffers::Vector<flatbuffers::Offset<::Column>>* cols,
60 std::vector<ColumnInfo>& out) {
63 out.reserve(cols->size());
64 for (
const auto* c : *cols) {
68 ci.index = c->index();
69 ci.name = c->name() !=
nullptr ? c->name()->str() : std::string();
70 ci.type =
static_cast<std::uint8_t
>(c->type());
71 ci.nullable = c->nullable();
72 out.push_back(std::move(ci));
76void fill_columns(const ::Header* hdr, FileInfo& info) {
77 collect_columns(hdr->columns(), info.columns);
78 collect_columns(hdr->semantic_columns(), info.semantic_columns);
81void fill_metadata(const ::Header* hdr, FileInfo& info) {
82 info.features_count = hdr->features_count();
83 info.index_node_size = hdr->index_node_size();
87 if (
const auto* t = hdr->transform()) {
88 info.has_transform =
true;
89 info.scale = {read_f64_at(t, 0), read_f64_at(t, 8), read_f64_at(t, 16)};
90 info.translate = {read_f64_at(t, 24), read_f64_at(t, 32), read_f64_at(t, 40)};
94 if (
const auto* e = hdr->geographical_extent()) {
95 info.has_extent =
true;
96 info.geographical_extent = {read_f64_at(e, 0), read_f64_at(e, 8), read_f64_at(e, 16),
97 read_f64_at(e, 24), read_f64_at(e, 32), read_f64_at(e, 40)};
100 if (
const auto* rs = hdr->reference_system()) {
101 const std::string authority =
102 rs->authority() !=
nullptr ? rs->authority()->str() : std::string(
"EPSG");
103 if (rs->code() != 0) {
104 info.crs = authority +
":" + std::to_string(rs->code());
105 }
else if (rs->code_string() !=
nullptr) {
106 info.crs = authority +
":" + rs->code_string()->str();
110 if (hdr->version() !=
nullptr)
111 info.cityjson_version = hdr->version()->str();
118 if (hdr->identifier() !=
nullptr)
119 info.identifier = hdr->identifier()->str();
120 if (hdr->title() !=
nullptr)
121 info.title = hdr->title()->str();
122 if (hdr->reference_date() !=
nullptr)
123 info.reference_date = hdr->reference_date()->str();
125 if (hdr->poc_contact_name() !=
nullptr) {
126 info.poc_contact_name = hdr->poc_contact_name()->str();
128 if (hdr->poc_contact_type() !=
nullptr) {
129 info.poc_contact_type = hdr->poc_contact_type()->str();
131 if (hdr->poc_role() !=
nullptr)
132 info.poc_role = hdr->poc_role()->str();
133 if (hdr->poc_phone() !=
nullptr)
134 info.poc_phone = hdr->poc_phone()->str();
135 if (hdr->poc_email() !=
nullptr)
136 info.poc_email = hdr->poc_email()->str();
137 if (hdr->poc_website() !=
nullptr)
138 info.poc_website = hdr->poc_website()->str();
139 if (hdr->poc_address_thoroughfare_number() !=
nullptr) {
140 info.poc_address_thoroughfare_number = hdr->poc_address_thoroughfare_number()->str();
142 if (hdr->poc_address_thoroughfare_name() !=
nullptr) {
143 info.poc_address_thoroughfare_name = hdr->poc_address_thoroughfare_name()->str();
145 if (hdr->poc_address_locality() !=
nullptr) {
146 info.poc_address_locality = hdr->poc_address_locality()->str();
148 if (hdr->poc_address_postcode() !=
nullptr) {
149 info.poc_address_postcode = hdr->poc_address_postcode()->str();
151 if (hdr->poc_address_country() !=
nullptr) {
152 info.poc_address_country = hdr->poc_address_country()->str();
159std::uint64_t collect_attr_indices(const ::Header* hdr, std::vector<AttrIndexInfo>& out) {
160 const auto* ais = hdr->attribute_index();
164 out.reserve(ais->size());
165 for (
const auto* ai : *ais) {
168 AttrIndexInfo info{};
169 info.column_index = ai->index();
170 info.length = ai->length();
171 info.branching_factor = ai->branching_factor();
172 info.num_unique_items = ai->num_unique_items();
177 std::sort(out.begin(), out.end(), [](
const AttrIndexInfo& a,
const AttrIndexInfo& b) {
178 return a.column_index < b.column_index;
183 for (std::size_t i = 1; i < out.size(); ++i) {
184 if (out[i].column_index == out[i - 1].column_index) {
186 std::to_string(out[i].column_index));
190 std::uint64_t total = 0;
191 for (
const auto& ai : out) {
203 const std::uint64_t total_size =
reader->total_size();
219 const std::uint32_t header_size = read_u32_le(size_bytes, 0);
222 "illegal header size: " + std::to_string(header_size));
233 const std::uint64_t want =
kHeaderSizeSize +
static_cast<std::uint64_t
>(header_size);
235 if (raw_buf.size() < want) {
238 std::vector<std::uint8_t> buf(
kBodyAlignPad + raw_buf.size());
239 std::copy(raw_buf.begin(), raw_buf.end(), buf.begin() +
kBodyAlignPad);
250 if (!VerifySizePrefixedHeaderBuffer(verifier)) {
255 view.buffer_ = std::make_shared<const std::vector<std::uint8_t>>(std::move(buf));
257 const ::Header* hdr = view.raw();
258 fill_metadata(hdr, view.info_);
259 fill_columns(hdr, view.info_);
261 const std::uint64_t attr_index_size = collect_attr_indices(hdr, view.attr_indices_);
268 for (
auto& ai : view.attr_indices_) {
Caching decorator: over-fetches to min_req_size and serves subsequent reads inside the cached window ...
std::vector< std::uint8_t > read(std::uint64_t offset, std::uint64_t length) override
Read length bytes at offset, subject to the contract above.
Every failure the library reports is one of these.
std::uint64_t checked_add(std::uint64_t a, std::uint64_t b, const char *what="add")
span< const std::uint8_t > bytes_view
The workhorse alias: a read-only view over bytes.
constexpr std::size_t kHeaderMaxBufferSize
constexpr std::size_t kHeaderSizeSize
HeaderView read_header(std::shared_ptr< RangeReader > reader)
Read and validate the file preamble and header.
FileLayout compute_layout(std::uint32_t header_size, std::uint64_t features_count, std::uint16_t index_node_size, std::uint64_t attr_index_size)
Throws fcb::Error{IllegalHeaderSize} when header_size is out of range or any size arithmetic overflow...
void validate_layout_against_size(const FileLayout &l, std::uint64_t total_size)
Throws unless the computed sections fit inside the resource.
bool check_magic_bytes(bytes_view b)
Mirrors fcb_core::check_magic_bytes (src/rust/fcb_core/src/lib.rs:56-58).
constexpr std::size_t kMagicBytesSize
static constexpr std::size_t kBodyAlignPad
No padding needed.
std::uint16_t index_node_size
std::uint64_t features_count
std::uint64_t attr_index_begin