use std::collections::HashMap;
use crate::entries::{
BundleEntry, ChunkingParamEntry, DirectoryEntry, FileEntry, KeyEntry, TagEntry,
};
use crate::generated::rman::root_as_manifest_with_opts;
use crate::File;
use crate::Result;
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct ManifestData {
pub bundle_entries: Vec<BundleEntry>,
pub directory_entries: Vec<DirectoryEntry>,
pub file_entries: Vec<FileEntry>,
pub key_entries: Vec<KeyEntry>,
pub tag_entries: Vec<TagEntry>,
pub chunking_param_entries: Vec<ChunkingParamEntry>,
pub files: Vec<File>,
}
macro_rules! map_vector {
($manifest: ident, $name: ident, $entry: ident) => {
$manifest
.$name()
.unwrap_or_default()
.iter()
.map(|i| $entry::from(i))
.collect()
};
}
impl ManifestData {
pub fn parse(
bytes: &[u8],
flatbuffer_verifier_options: Option<&flatbuffers::VerifierOptions>,
) -> Result<Self> {
let opts = flatbuffers::VerifierOptions {
max_tables: 10_000_000,
..Default::default()
};
let manifest =
root_as_manifest_with_opts(flatbuffer_verifier_options.unwrap_or(&opts), bytes)?;
let bundle_entries: Vec<_> = map_vector!(manifest, bundles, BundleEntry);
let directory_entries: Vec<_> = map_vector!(manifest, directories, DirectoryEntry);
let file_entries: Vec<_> = map_vector!(manifest, files, FileEntry);
let key_entries = map_vector!(manifest, keys, KeyEntry);
let tag_entries: Vec<_> = map_vector!(manifest, tags, TagEntry);
let chunking_param_entries = map_vector!(manifest, chunking_params, ChunkingParamEntry);
let mapped_tags = Self::map_tags(&tag_entries);
let mapped_directories = Self::map_directories(&directory_entries);
let mapped_chunks = Self::map_chunks(&bundle_entries);
let files = file_entries
.iter()
.map(|f| File::parse(f, &mapped_tags, &mapped_directories, &mapped_chunks))
.collect::<Result<Vec<File>>>()?;
Ok(Self {
bundle_entries,
directory_entries,
file_entries,
key_entries,
tag_entries,
chunking_param_entries,
files,
})
}
fn map_tags(tag_entries: &[TagEntry]) -> HashMap<u8, String> {
tag_entries.iter().map(|l| (l.id, l.name.clone())).collect()
}
fn map_directories(directory_entries: &[DirectoryEntry]) -> HashMap<i64, (String, i64)> {
directory_entries
.iter()
.map(|d| (d.id, (d.name.clone(), d.parent_id)))
.collect()
}
fn map_chunks(bundle_entries: &[BundleEntry]) -> HashMap<i64, (i64, u32, u32, u32)> {
bundle_entries
.iter()
.flat_map(|b| {
b.chunks.iter().scan(0, move |offset, c| {
*offset += c.compressed_size;
Some((
c.id,
(
b.id,
*offset - c.compressed_size,
c.uncompressed_size,
c.compressed_size,
),
))
})
})
.collect()
}
}