use bitvec::order::Lsb0;
use bitvec::slice::BitSlice;
use bitvec::view::BitView as _;
use usize_cast::IntoUsize as _;
use crate::LazyParsed::Raw;
use crate::MltError::{BufferUnderflow, MissingLayerName, TrailingLayerData};
use crate::codecs::varint::parse_varint;
use crate::decoder::stream::header02;
use crate::decoder::stream::header02::{StrLayout, StreamCtx02};
use crate::decoder::{
Column02, ColumnType02, DataType02, DictLayout, DictionaryType, FloatLogical, GeoLayout, Id,
Layer01, LayerLayout, LengthType, LogicalEncoding, Presence02, RawFloats, RawFloatsEncoding,
RawFsstData, RawGeometry, RawId, RawIdValue, RawPlainData, RawPresence, RawScalar,
RawSharedDict, RawSharedDictEncoding, RawSharedDictItem, RawStream, RawStrings,
RawStringsEncoding, SharedDictKind,
};
use crate::tile::Extent;
use crate::utils::{SetOptionOnce as _, parse_string, parse_u8, take};
use crate::{Lazy, MltError, MltRefResult, MltResult, Parser};
pub(crate) fn parse_layer02<'a>(
input: &'a [u8],
parser: &mut Parser,
) -> MltResult<Layer01<'a, Lazy>> {
let (input, layer_name) = parse_string(input)?;
if layer_name.is_empty() {
return Err(MissingLayerName);
}
let (input, extent) = parse_varint::<u32>(input)?;
let extent = Extent::new(extent)?;
let (input, feature_count) = parse_varint::<u32>(input)?;
let (input, layout_byte) = parse_u8(input)?;
let layout = LayerLayout::parse(layout_byte)?;
let (input, cols) = parse_shared_presence(input, layout, feature_count)?;
let (input, geometry) = parse_geometry(input, layout.geometry, feature_count, parser)?;
let (mut input, column_count) = parse_varint::<u32>(input)?;
if input.len() < column_count.into_usize() {
return Err(BufferUnderflow(column_count, input.len()));
}
let mut id_column: Option<Id> = None;
let mut properties = Vec::with_capacity(column_count.into_usize());
#[cfg(fuzzing)]
let mut layer_order = vec![crate::decoder::fuzzing::LayerOrdering::Geometry];
for _ in 0..column_count {
use crate::decoder::RawProperty as RP;
let typ_byte;
(input, typ_byte) = parse_u8(input)?;
let typ = match cols.column(typ_byte)? {
Column02::SharedDict(kind) => {
let shared_dict;
(input, shared_dict) = parse_shared_dict02(input, kind, &cols, parser)?;
properties.push(Raw(RP::SharedDict(shared_dict)));
#[cfg(fuzzing)]
layer_order.push(crate::decoder::fuzzing::LayerOrdering::Property);
continue;
}
Column02::Values(typ) => typ,
};
let name = if typ.data.has_name() {
let named;
(input, named) = parse_string(input)?;
named
} else {
""
};
let presence;
(input, presence) = cols.presence(typ, input)?;
let data_count = cols.count(&presence)?;
#[cfg(fuzzing)]
layer_order.push(match typ.data {
DataType02::Id | DataType02::LongId => crate::decoder::fuzzing::LayerOrdering::Id,
_ => crate::decoder::fuzzing::LayerOrdering::Property,
});
if typ.data == DataType02::Str {
let strings;
(input, strings) = parse_strings(input, name, presence, data_count, parser)?;
properties.push(Raw(RP::Str(strings)));
continue;
}
let ctx = StreamCtx02::Property(typ.data);
let value;
(input, value) = header02::parse_stream(input, ctx, data_count, parser)?;
let prop = match typ.data {
DataType02::Id => {
id_column.set_once(Raw(RawId {
presence,
value: RawIdValue::Id32(value),
}))?;
continue;
}
DataType02::LongId => {
id_column.set_once(Raw(RawId {
presence,
value: RawIdValue::Id64(value),
}))?;
continue;
}
DataType02::Bool => RP::Bool(RawScalar::new(name, presence, value)),
DataType02::I8 => RP::I8(RawScalar::new(name, presence, value)),
DataType02::U8 => RP::U8(RawScalar::new(name, presence, value)),
DataType02::I32 => RP::I32(RawScalar::new(name, presence, value)),
DataType02::U32 => RP::U32(RawScalar::new(name, presence, value)),
DataType02::I64 => RP::I64(RawScalar::new(name, presence, value)),
DataType02::U64 => RP::U64(RawScalar::new(name, presence, value)),
DataType02::F32 | DataType02::F64 => {
let floats;
(input, floats) = parse_floats(input, typ.data, name, presence, value, parser)?;
if typ.data == DataType02::F32 {
RP::F32(floats)
} else {
RP::F64(floats)
}
}
DataType02::Str => unreachable!("string columns are read before this match"),
};
properties.push(Raw(prop));
}
if !input.is_empty() {
return Err(TrailingLayerData(input.len()));
}
Ok(Layer01 {
name: layer_name,
extent,
id: id_column,
geometry: Raw(geometry),
properties,
#[cfg(fuzzing)]
layer_order,
})
}
fn parse_floats<'a>(
input: &'a [u8],
typ: DataType02,
name: &'a str,
presence: RawPresence<'a>,
data: RawStream<'a>,
parser: &mut Parser,
) -> MltRefResult<'a, RawFloats<'a>> {
let (input, encoding) = match data.meta.encoding.logical {
LogicalEncoding::Float(FloatLogical::Alp(params)) => {
(input, RawFloatsEncoding::Alp { params, data })
}
LogicalEncoding::Float(FloatLogical::Dict) => {
let ctx = StreamCtx02::PropertyDictionary(typ);
let (input, dictionary) =
header02::parse_stream(input, ctx, data.meta.num_values, parser)?;
let encoding = RawFloatsEncoding::Dictionary {
codes: data,
dictionary,
};
(input, encoding)
}
LogicalEncoding::Float(FloatLogical::None)
| LogicalEncoding::Int(_)
| LogicalEncoding::Bool(_)
| LogicalEncoding::Vertex(_) => (input, RawFloatsEncoding::Single(data)),
};
Ok((
input,
RawFloats {
name,
presence,
encoding,
},
))
}
fn parse_shared_dict02<'a>(
input: &'a [u8],
kind: SharedDictKind,
cols: &LayerCols<'a>,
parser: &mut Parser,
) -> MltRefResult<'a, RawSharedDict<'a>> {
let (input, name) = parse_string(input)?;
let (input, child_count) = parse_varint::<u32>(input)?;
if input.len() < child_count.into_usize() {
return Err(BufferUnderflow(child_count, input.len()));
}
parser.reserve(child_count)?;
let stream =
|input: &'a [u8], ctx, parser: &mut Parser| header02::parse_stream(input, ctx, 0, parser);
let (input, encoding, dict) = match kind {
SharedDictKind::Plain => {
let (input, lengths) = stream(input, StreamCtx02::StrDictLengths, parser)?;
let dict = blob_layout(input)?;
let (input, data) =
stream(input, StreamCtx02::StrBlob(DictionaryType::Shared), parser)?;
let plain = RawPlainData::new(lengths, data)?;
(input, RawSharedDictEncoding::plain(plain), dict)
}
SharedDictKind::Fsst => {
let (input, lengths) = stream(input, StreamCtx02::StrDictLengths, parser)?;
let (input, symbol_lengths) = stream(input, StreamCtx02::StrSymbolLengths, parser)?;
let (input, symbols) =
stream(input, StreamCtx02::StrBlob(DictionaryType::Fsst), parser)?;
let dict = blob_layout(input)?;
let (input, corpus) =
stream(input, StreamCtx02::StrBlob(DictionaryType::Shared), parser)?;
let fsst = RawFsstData::new(symbol_lengths, symbols, lengths, corpus)?;
(input, RawSharedDictEncoding::fsst_plain(fsst), dict)
}
};
let mut input = input;
let mut children = Vec::with_capacity(child_count.into_usize());
for _ in 0..child_count {
let child_byte;
(input, child_byte) = parse_u8(input)?;
let child_typ = cols.column_type(child_byte)?;
if child_typ.data != DataType02::Str {
return Err(MltError::ParsingColumnType(child_byte));
}
let child_name;
(input, child_name) = parse_string(input)?;
let presence;
(input, presence) = cols.presence(child_typ, input)?;
let count = cols.count(&presence)?;
let data;
(input, data) =
header02::parse_stream(input, StreamCtx02::StrData(StrLayout::Dict), count, parser)?;
children.push(RawSharedDictItem {
name: child_name,
presence,
data,
});
}
Ok((input, RawSharedDict::new(name, encoding, dict, children)))
}
fn blob_layout(input: &[u8]) -> MltResult<DictLayout> {
let (_, enc_byte) = parse_u8(input)?;
Ok(DictLayout::from_bits(enc_byte).unwrap_or(DictLayout::Plain))
}
fn parse_strings<'a>(
input: &'a [u8],
name: &'a str,
presence: RawPresence<'a>,
count: u32,
parser: &mut Parser,
) -> MltRefResult<'a, RawStrings<'a>> {
let (_, enc_byte) = parse_u8(input)?;
let layout = StrLayout::from_bits(enc_byte);
let stream = |input: &'a [u8], ctx, parser: &mut Parser| {
header02::parse_stream(input, ctx, count, parser)
};
let (input, leading) = stream(input, StreamCtx02::StrData(layout), parser)?;
let (input, encoding) = match layout {
StrLayout::Plain => {
let (input, data) = stream(input, StreamCtx02::StrBlob(DictionaryType::None), parser)?;
let plain = RawPlainData::new(leading, data)?;
(input, RawStringsEncoding::plain(plain))
}
StrLayout::Dict => {
let (input, lengths) = stream(input, StreamCtx02::StrDictLengths, parser)?;
let dict = blob_layout(input)?;
let (input, data) =
stream(input, StreamCtx02::StrBlob(DictionaryType::Single), parser)?;
let plain = RawPlainData::new(lengths, data)?;
(input, RawStringsEncoding::dictionary(plain, leading, dict)?)
}
StrLayout::Fsst => {
let (input, symbol_lengths) = stream(input, StreamCtx02::StrSymbolLengths, parser)?;
let (input, symbols) =
stream(input, StreamCtx02::StrBlob(DictionaryType::Fsst), parser)?;
let (input, corpus) =
stream(input, StreamCtx02::StrBlob(DictionaryType::Single), parser)?;
let fsst = RawFsstData::new(symbol_lengths, symbols, leading, corpus)?;
(input, RawStringsEncoding::fsst_plain(fsst))
}
StrLayout::FsstDict => {
let (input, lengths) = stream(input, StreamCtx02::StrDictLengths, parser)?;
let (input, symbol_lengths) = stream(input, StreamCtx02::StrSymbolLengths, parser)?;
let (input, symbols) =
stream(input, StreamCtx02::StrBlob(DictionaryType::Fsst), parser)?;
let dict = blob_layout(input)?;
let (input, corpus) =
stream(input, StreamCtx02::StrBlob(DictionaryType::Single), parser)?;
let fsst = RawFsstData::new(symbol_lengths, symbols, lengths, corpus)?;
(
input,
RawStringsEncoding::fsst_dictionary(fsst, leading, dict)?,
)
}
};
Ok((
input,
RawStrings {
name,
presence,
encoding,
},
))
}
struct LayerCols<'a> {
shared: Vec<&'a BitSlice<u8, Lsb0>>,
feature_count: u32,
}
impl<'a> LayerCols<'a> {
fn shared_count(&self) -> MltResult<u8> {
Ok(u8::try_from(self.shared.len())?)
}
fn column(&self, byte: u8) -> MltResult<Column02> {
Column02::parse(byte, self.shared_count()?)
}
fn column_type(&self, byte: u8) -> MltResult<ColumnType02> {
ColumnType02::parse(byte, self.shared_count()?)
}
fn presence(&self, typ: ColumnType02, input: &'a [u8]) -> MltRefResult<'a, RawPresence<'a>> {
match typ.presence {
Presence02::AllPresent => Ok((input, RawPresence::AllPresent)),
Presence02::Inline => {
let (input, bits) = parse_bitfield(input, self.feature_count)?;
Ok((input, RawPresence::Bitfield(bits)))
}
Presence02::Shared(index) => self
.shared
.get(usize::from(index))
.map(|&bits| (input, RawPresence::Bitfield(bits)))
.ok_or_else(|| MltError::ParsingColumnType(typ.to_byte())),
}
}
fn count(&self, presence: &RawPresence<'_>) -> MltResult<u32> {
Ok(match presence {
RawPresence::Bitfield(bits) => u32::try_from(bits.count_ones())?,
RawPresence::AllPresent | RawPresence::Stream(_) => self.feature_count,
})
}
}
fn parse_shared_presence(
input: &[u8],
layout: LayerLayout,
feature_count: u32,
) -> MltRefResult<'_, LayerCols<'_>> {
let mut input = input;
let mut shared = Vec::with_capacity(usize::from(layout.shared_presence));
for _ in 0..layout.shared_presence {
let bits;
(input, bits) = parse_bitfield(input, feature_count)?;
shared.push(bits);
}
Ok((
input,
LayerCols {
shared,
feature_count,
},
))
}
fn parse_bitfield(input: &[u8], feature_count: u32) -> MltRefResult<'_, &BitSlice<u8, Lsb0>> {
let (input, bytes) = take(input, feature_count.div_ceil(8))?;
Ok((
input,
&bytes.view_bits::<Lsb0>()[..feature_count.into_usize()],
))
}
fn parse_geometry<'a>(
input: &'a [u8],
layout: GeoLayout,
feature_count: u32,
parser: &mut Parser,
) -> MltRefResult<'a, RawGeometry<'a>> {
let (mut input, types) =
header02::parse_stream(input, StreamCtx02::GeomTypes, feature_count, parser)?;
let mut items = Vec::with_capacity(6);
let mut stream = |input: &'a [u8], ctx, items: &mut Vec<_>| -> MltResult<&'a [u8]> {
let (rest, parsed) = header02::parse_stream(input, ctx, feature_count, parser)?;
items.push(parsed);
Ok(rest)
};
let lengths = [
(layout.has_geo_lengths(), LengthType::Geometries),
(layout.has_part_lengths(), LengthType::Parts),
(layout.has_ring_lengths(), LengthType::Rings),
];
for (present, length_type) in lengths {
if present {
input = stream(input, StreamCtx02::GeomOffsets(length_type), &mut items)?;
}
}
if layout.is_tess() {
let triangles = StreamCtx02::GeomOffsets(LengthType::Triangles);
input = stream(input, triangles, &mut items)?;
input = stream(input, StreamCtx02::GeomIndices, &mut items)?;
}
input = stream(input, StreamCtx02::GeomVertices, &mut items)?;
if layout.is_dict() {
input = stream(input, StreamCtx02::GeomVertexOffsets, &mut items)?;
}
Ok((input, RawGeometry { meta: types, items }))
}