use mzstd::DecodeOperation;
use mzstd::framing::*;
pub const CHUNK_MAGIC: u32 = 0x184D_2A5B;
pub const SEEK_MAGIC: u32 = 0x184D_2A5E;
pub const SEEKABLE_MAGIC: u32 = 0x8F92_EAB1;
pub const EMPTY_FRAME: [u8; 9] = [0x28, 0xb5, 0x2f, 0xfd, 0x20, 0, 1, 0, 0];
pub fn var(mut n: u64) -> Vec<u8> {
let mut out = Vec::new();
while n >= 0x80 {
out.push((n as u8) | 0x80);
n >>= 7;
}
out.push(n as u8);
out
}
pub fn frame(payload: &[u8]) -> Vec<u8> {
zstd_ffi::oracle::compress(payload, 3)
}
pub fn visible_fields(kind: u8, declared: usize, flags: u8, body: &[u8]) -> Vec<u8> {
let mut fields = vec![kind, 2];
fields.extend(var(declared as u64));
fields.push(flags | 4);
fields.extend(var(body.len() as u64));
fields
}
pub struct Builder {
pub bytes: Vec<u8>,
pub frames: Vec<(u32, u32)>,
pub records: Vec<(u64, Vec<u8>)>,
pub directory: u64,
}
impl Builder {
pub fn new(flags: u8) -> Self {
let mut bytes = CHUNK_MAGIC.to_le_bytes().to_vec();
bytes.extend(5u32.to_le_bytes());
bytes.extend(b"MZFR");
bytes.push(flags);
Self {
bytes,
frames: vec![(13, 0)],
records: Vec::new(),
directory: 0,
}
}
pub fn chunk(&mut self, fields: &[u8], inline: &[u8], body: Option<(&[u8], u32)>) -> u64 {
let offset = self.bytes.len() as u64;
let mut header = CHUNK_MAGIC.to_le_bytes().to_vec();
header.extend(((fields.len() + inline.len()) as u32).to_le_bytes());
header.extend_from_slice(fields);
self.bytes.extend_from_slice(&header);
self.bytes.extend_from_slice(inline);
self.frames.push(((header.len() + inline.len()) as u32, 0));
if let Some((body, decoded)) = body {
self.bytes.extend_from_slice(body);
self.frames.push((body.len() as u32, decoded));
}
if (1..=8).contains(&fields.first().copied().unwrap_or(0)) {
self.records.push((offset, header));
}
offset
}
pub fn resource(&mut self, payload: &[u8]) -> u64 {
let body = frame(payload);
self.chunk(
&visible_fields(2, payload.len(), 0, &body),
&[],
Some((&body, payload.len() as u32)),
)
}
pub fn hidden(&mut self, payload: &[u8]) -> u64 {
self.chunk(&[2, 0, 1], payload, None)
}
pub fn metadata(&mut self, kind: u8, fields: &[u8]) -> u64 {
self.chunk(&[kind, 0], fields, None)
}
pub fn padding(&mut self, n: usize) -> u64 {
self.chunk(&[0], &vec![0; n], None)
}
pub fn directory(&mut self, repeat: u64) -> u64 {
let mut content = var(repeat);
for (offset, header) in &self.records {
content.extend(var(*offset));
content.extend(var(header.len() as u64));
content.extend_from_slice(header);
}
let mut fields = vec![9];
fields.extend(content);
let offset = self.chunk(&fields, &[], None);
self.directory = offset;
offset
}
pub fn footer(&mut self) -> u64 {
let size = self.bytes.len() as u64 + 25 + 8 + 8 * (self.frames.len() as u64 + 1) + 9;
self.footer_with(self.directory, size)
}
pub fn footer_with(&mut self, directory: u64, size: u64) -> u64 {
let mut fields = vec![10];
fields.extend(directory.to_le_bytes());
fields.extend(size.to_le_bytes());
self.chunk(&fields, &[], None)
}
pub fn finish(self) -> Vec<u8> {
let frames = self.frames.clone();
self.finish_with(&frames, 0, SEEKABLE_MAGIC)
}
pub fn finish_with(mut self, frames: &[(u32, u32)], descriptor: u8, magic: u32) -> Vec<u8> {
self.bytes.extend(SEEK_MAGIC.to_le_bytes());
self.bytes
.extend(((frames.len() * 8 + 9) as u32).to_le_bytes());
for (c, d) in frames {
self.bytes.extend(c.to_le_bytes());
self.bytes.extend(d.to_le_bytes());
}
self.bytes.extend((frames.len() as u32).to_le_bytes());
self.bytes.push(descriptor);
self.bytes.extend(magic.to_le_bytes());
self.bytes
}
}
pub fn two_resources() -> Vec<u8> {
let mut builder = Builder::new(4);
builder.resource(b"abc");
builder.resource(b"de");
builder.directory(0);
builder.footer();
builder.finish()
}
pub fn single(payload: &[u8]) -> Vec<u8> {
let mut builder = Builder::new(0);
builder.resource(payload);
builder.finish()
}
pub fn drive(
decoder: &mut FramedDecompressor,
bytes: &[u8],
split: usize,
capacity: usize,
) -> Result<(Vec<String>, Vec<u8>), FramedDecodeError> {
let mut session = decoder.start(Default::default())?;
let mut events = Vec::new();
let mut payload = Vec::new();
let mut offered = 0;
let mut position = 0;
let mut output = vec![0; capacity];
loop {
let end = (offered + split.max(1)).min(bytes.len());
let finish = end == bytes.len();
offered = end;
let operation = if finish {
DecodeOperation::Finish
} else {
DecodeOperation::Process
};
loop {
let progress = session
.process(&bytes[position..offered], &mut output, operation)
.map_err(FramedDecodeFailure::into_error)?;
position += progress.consumed;
match progress.status {
FramedDecoderStatus::Finished => return Ok((events, payload)),
FramedDecoderStatus::NeedsInput => break,
FramedDecoderStatus::NeedsOutput => {
if capacity == 0 {
output = vec![0; 1];
}
}
FramedDecoderStatus::Event(event) => {
if let FramedEvent::ResourceData(data) = &event {
payload.extend_from_slice(data.bytes);
}
events.push(render(&event));
}
}
}
if finish && position == bytes.len() {
return Err(FramedDecodeError::InvalidState);
}
}
}
pub fn render(event: &FramedEvent<'_>) -> String {
match event {
FramedEvent::ResourceData(data) => format!("data {:?}", data.position.resource),
other => format!("{other:?}"),
}
}
pub fn drain(
session: &mut FramedEncoderSession<'_>,
wire: &mut Vec<u8>,
operation: FramedEncodeOperation,
) {
let mut output = [0; 4096];
loop {
let progress = session.process(&mut output, operation).expect("process");
wire.extend_from_slice(&output[..progress.produced]);
if progress.status != FramedEncoderStatus::NeedsOutput {
return;
}
}
}
pub fn write(mut resource: FramedResourceSession<'_, '_>, data: &[u8], wire: &mut Vec<u8>) {
let mut output = [0; 4096];
let mut input = data;
loop {
let progress = resource
.process(input, &mut output, mzstd::Operation::End)
.expect("resource");
input = &input[progress.consumed..];
wire.extend_from_slice(&output[..progress.produced]);
if progress.status == FramedEncoderStatus::Finished {
return;
}
}
}
pub const EXTERNAL: DictionaryId = DictionaryId([7; 32]);
pub struct Dictionaries {
pub bytes: Vec<u8>,
pub external: Vec<u8>,
pub trained: Vec<u8>,
pub payloads: Vec<Vec<u8>>,
}
impl DictionaryResolver for Dictionaries {
fn resolve(&self, request: ExternalDictionaryRequest) -> Option<&[u8]> {
match (request.id, request.kind) {
(EXTERNAL, ExternalDictionaryKind::Prefix) => Some(&self.external),
(EXTERNAL, ExternalDictionaryKind::Serialized) => Some(&self.trained),
_ => None,
}
}
}
pub fn dictionaries() -> Dictionaries {
use mzstd::dictionary::{DictionaryBuilder, DictionaryContent};
let samples: Vec<Vec<u8>> = (0..300).map(|i| zstd_ffi::corpus::text(200, i)).collect();
let views: Vec<&[u8]> = samples.iter().map(Vec::as_slice).collect();
let trained = zstd_ffi::oracle::train_dictionary(&views, 4096).expect("train");
let prefix = zstd_ffi::corpus::text(1000, 900);
let external = zstd_ffi::corpus::text(800, 901);
let fields = [MetadataField {
code: *b"DI",
value: &prefix[..400],
}];
let mut payloads = vec![prefix.clone(), trained.clone()];
let mut owner = FramedCompressor::new(FramedEncodeConfig::default().with_framing_config(
FramingConfig {
chunk_bytes: 300,
..Default::default()
},
))
.expect("encoder");
let mut wire = Vec::new();
let mut session = owner.start(Default::default()).expect("start");
drain(&mut session, &mut wire, FramedEncodeOperation::Process);
let hidden = ResourceOptions {
hidden: true,
..Default::default()
};
let prefix_offset = session.next_chunk_offset();
let resource = session.uncompressed_resource(hidden).expect("prefix");
write(resource, &prefix, &mut wire);
let trained_offset = session.next_chunk_offset();
let resource = session
.resource(hidden, Default::default())
.expect("trained");
write(resource, &trained, &mut wire);
let metadata_offset = session.next_chunk_offset();
session
.metadata(MetadataKind::Global, &fields)
.expect("metadata");
drain(&mut session, &mut wire, FramedEncodeOperation::Process);
let metadata_bytes = [b"DI".as_slice(), &[0x90, 0x03], &prefix[..400]].concat();
let raw = |bytes: &[u8]| {
DictionaryBuilder::new(bytes)
.with_content(DictionaryContent::Raw)
.build()
.expect("raw dictionary")
};
let zstd = DictionaryBuilder::new(&trained)
.with_content(DictionaryContent::Zstd)
.build()
.expect("zstd dictionary");
let cases = [
(
raw(&prefix),
vec![DictionaryReference::PrefixResource(prefix_offset)],
),
(
raw(&metadata_bytes),
vec![DictionaryReference::PrefixChunk(metadata_offset)],
),
(
zstd,
vec![DictionaryReference::SerializedResource(trained_offset)],
),
(
raw(&external),
vec![DictionaryReference::PrefixId(EXTERNAL)],
),
(
raw(&[prefix.as_slice(), &external].concat()),
vec![
DictionaryReference::PrefixResource(prefix_offset),
DictionaryReference::PrefixId(EXTERNAL),
],
),
(
DictionaryBuilder::new(&trained)
.with_content(DictionaryContent::Zstd)
.build()
.expect("zstd dictionary"),
vec![DictionaryReference::SerializedId(EXTERNAL)],
),
];
for (i, (dictionary, references)) in cases.iter().enumerate() {
let payload = zstd_ffi::corpus::text(700, 950 + i as u64);
let resource = session
.resource_with_dictionary(
ResourceOptions::default(),
Default::default(),
dictionary,
references,
)
.expect("resource");
write(resource, &payload, &mut wire);
payloads.push(payload);
}
drain(&mut session, &mut wire, FramedEncodeOperation::Finish);
drop(session);
Dictionaries {
bytes: wire,
external,
trained,
payloads,
}
}