use crate::{BLTEFile, CompressionMode, Result};
#[derive(Debug)]
pub struct ArchiveBuilder {
files: Vec<BLTEFile>,
target_size: usize, current_size: usize,
}
impl ArchiveBuilder {
pub fn new() -> Self {
Self {
files: Vec::new(),
target_size: 256 * 1024 * 1024, current_size: 0,
}
}
pub fn target_size(mut self, size: usize) -> Self {
self.target_size = size;
self
}
pub fn add_file(&mut self, blte: BLTEFile) -> Result<bool> {
let file_size = blte.total_size();
if self.current_size + file_size > self.target_size && !self.files.is_empty() {
return Ok(false); }
self.current_size += file_size;
self.files.push(blte);
Ok(true) }
pub fn add_data(&mut self, data: Vec<u8>, mode: CompressionMode) -> Result<bool> {
let blte = crate::compress::compress_data_single(data, mode, None)?;
let blte_file = BLTEFile::parse(blte)?;
self.add_file(blte_file)
}
pub fn build(self) -> Result<Vec<u8>> {
let mut archive_data = Vec::with_capacity(self.current_size);
for blte in self.files {
archive_data.extend_from_slice(&blte.raw_data());
}
Ok(archive_data)
}
pub fn current_size(&self) -> usize {
self.current_size
}
pub fn file_count(&self) -> usize {
self.files.len()
}
pub fn has_capacity(&self, additional_size: usize) -> bool {
self.current_size + additional_size <= self.target_size
}
}
impl Default for ArchiveBuilder {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct MultiArchiveBuilder {
current_archive: ArchiveBuilder,
completed_archives: Vec<Vec<u8>>,
max_archive_size: usize,
}
impl MultiArchiveBuilder {
pub fn new() -> Self {
Self {
current_archive: ArchiveBuilder::new(),
completed_archives: Vec::new(),
max_archive_size: 256 * 1024 * 1024,
}
}
pub fn max_archive_size(mut self, size: usize) -> Self {
self.max_archive_size = size;
self.current_archive = self.current_archive.target_size(size);
self
}
pub fn add_data(&mut self, data: Vec<u8>, mode: CompressionMode) -> Result<()> {
let blte = crate::compress::compress_data_single(data, mode, None)?;
let blte_file = BLTEFile::parse(blte)?;
if !self.current_archive.add_file(blte_file.clone())? {
let completed_archive = std::mem::replace(
&mut self.current_archive,
ArchiveBuilder::new().target_size(self.max_archive_size),
);
self.completed_archives.push(completed_archive.build()?);
self.current_archive.add_file(blte_file)?;
}
Ok(())
}
pub fn finalize(mut self) -> Result<Vec<Vec<u8>>> {
if self.current_archive.file_count() > 0 {
self.completed_archives.push(self.current_archive.build()?);
}
Ok(self.completed_archives)
}
pub fn archive_count(&self) -> usize {
self.completed_archives.len()
+ if self.current_archive.file_count() > 0 {
1
} else {
0
}
}
}
impl Default for MultiArchiveBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_archive_builder_creation() {
let builder = ArchiveBuilder::new();
assert_eq!(builder.target_size, 256 * 1024 * 1024);
assert_eq!(builder.current_size, 0);
assert_eq!(builder.file_count(), 0);
}
#[test]
fn test_archive_builder_custom_size() {
let builder = ArchiveBuilder::new().target_size(1024 * 1024);
assert_eq!(builder.target_size, 1024 * 1024);
}
#[test]
fn test_multi_archive_builder() {
let builder = MultiArchiveBuilder::new();
assert_eq!(builder.max_archive_size, 256 * 1024 * 1024);
assert_eq!(builder.archive_count(), 0);
}
}