use std::path::Path;
use std::sync::Arc;
use anyhow::{bail, Result};
use crate::backends::{MmapMosaicBackend, MosaicBackend};
use crate::ebml::MosaicTag;
use crate::reader::{Cursor, MosaicReader, MosaicReaderError};
pub fn check(filename: &Path) -> Result<String> {
let backend = Arc::new(MmapMosaicBackend::new(filename)?);
let reader = MosaicReader::with_backend(filename, backend.clone())?;
let mut cursor = Cursor::new(backend.clone());
let size = cursor.seek_to_element(MosaicTag::Mosaic)?;
if backend.len() != cursor.offset + size {
bail!(
"Root element's length ({} from position {}) does not match file's size ({})",
size,
cursor.offset,
backend.len()
)
}
let md_size = cursor.seek_to_element(MosaicTag::ContainerMetaData)?;
cursor.skip(md_size)?;
let mut nb_tiles = 0;
let mut broken_tiles = 0;
while cursor.offset < reader.end_of_tiles_offset {
let next_tile_size = cursor.seek_to_and_check(MosaicTag::Tile);
if let Ok(size) = next_tile_size {
nb_tiles += 1;
cursor.skip(size)?;
} else {
broken_tiles += 1;
let broken_tile_size = cursor.seek_to_element(MosaicTag::Tile)?;
cursor.skip(broken_tile_size)?;
}
}
cursor.offset = reader.end_of_tiles_offset;
let mut nb_indexes = 0;
let mut broken_indexes = 0;
while cursor.offset < backend.len() {
let next_index_size = cursor.seek_to_and_check(MosaicTag::Index);
if let Ok(size) = next_index_size {
nb_indexes += 1;
cursor.skip(size)?;
} else {
broken_indexes += 1;
let broken_index_size = cursor.seek_to_element(MosaicTag::Index)?;
cursor.skip(broken_index_size)?;
}
}
if broken_tiles == 0 && broken_indexes == 0 {
Ok(format!(
"{}: OK, {} tiles and {} indexes checked",
filename.display(),
nb_tiles,
nb_indexes
))
} else {
Err(MosaicReaderError::BrokenMosaic {
filename: filename.display().to_string(),
broken_tiles,
broken_indexes,
}
.into())
}
}