use std::error::Error;
use wow_mpq::compression::CompressionMethod;
use wow_mpq::{AddFileOptions, Archive, ArchiveBuilder, MutableArchive};
fn main() -> Result<(), Box<dyn Error>> {
let archive_path = "bulk_test.mpq";
println!("📦 Creating test archive with mixed content...");
create_test_archive(archive_path)?;
println!("\n🔧 Performing bulk modifications...");
bulk_modify_archive(archive_path)?;
println!("\n📊 Final archive contents:");
list_archive_details(archive_path)?;
std::fs::remove_file(archive_path)?;
Ok(())
}
fn create_test_archive(path: &str) -> Result<(), Box<dyn Error>> {
let mut builder = ArchiveBuilder::new();
let file_types = [
("docs/readme.txt", b"Documentation for the project".to_vec()),
("docs/license.txt", b"MIT License".to_vec()),
(
"src/main.cpp",
b"#include <iostream>\nint main() { }".to_vec(),
),
("assets/texture.tga", vec![0xAA; 1024]), ("data/config.ini", b"[Settings]\nvalue=42".to_vec()),
];
let file_count = file_types.len();
for (name, data) in file_types {
builder = builder.add_file_data(data, name);
}
builder.build(path)?;
println!("✅ Created archive with {file_count} files");
Ok(())
}
fn bulk_modify_archive(path: &str) -> Result<(), Box<dyn Error>> {
let mut archive = MutableArchive::open(path)?;
println!("\n📝 Updating text files with compression...");
let text_files = [
("docs/changelog.txt", "Version 1.0 - Initial release"),
("docs/api.txt", "API Documentation"),
(
"src/utils.cpp",
"#include \"utils.h\"\n// Utility functions",
),
];
for (name, content) in &text_files {
let options = AddFileOptions::new().compression(CompressionMethod::Zlib);
archive.add_file_data(content.as_bytes(), name, options)?;
println!(" ✅ Added: {name}");
}
println!("\n🔐 Adding encrypted files...");
let sensitive_files = [
("keys/private.key", "-----BEGIN PRIVATE KEY-----"),
("config/database.conf", "password=secret123"),
];
for (name, content) in &sensitive_files {
let options = AddFileOptions::new()
.compression(CompressionMethod::Zlib)
.encrypt();
archive.add_file_data(content.as_bytes(), name, options)?;
println!(" 🔒 Added encrypted: {name}");
}
println!("\n📦 Adding large binary files...");
let large_data = vec![0xFF; 100_000];
let compression_tests = [
("binary/test_none.bin", CompressionMethod::None),
("binary/test_zlib.bin", CompressionMethod::Zlib),
("binary/test_bzip2.bin", CompressionMethod::BZip2),
];
for (name, method) in &compression_tests {
let options = AddFileOptions::new().compression(*method);
archive.add_file_data(&large_data, name, options)?;
println!(" ✅ Added with {method:?}: {name}");
}
println!("\n🔄 Testing file replacement...");
let no_replace = AddFileOptions::new().replace_existing(false);
match archive.add_file_data(b"New content", "docs/readme.txt", no_replace) {
Err(e) => println!(" ✅ Correctly rejected duplicate: {e}"),
Ok(_) => println!(" ❌ Error: should have rejected duplicate!"),
}
let replace = AddFileOptions::new().replace_existing(true);
archive.add_file_data(b"Updated readme content", "docs/readme.txt", replace)?;
println!(" ✅ Successfully replaced docs/readme.txt");
println!("\n✏️ Performing batch renames...");
let renames = [
("src/main.cpp", "source/main.cpp"),
("src/utils.cpp", "source/utils.cpp"),
];
for (old, new) in &renames {
archive.rename_file(old, new)?;
println!(" ✅ Renamed: {old} -> {new}");
}
println!("\n💾 Flushing all changes...");
archive.flush()?;
Ok(())
}
fn list_archive_details(path: &str) -> Result<(), Box<dyn Error>> {
let mut archive = Archive::open(path)?;
let files = archive.list_all()?;
println!("\nTotal files: {}", files.len());
println!("\nFile listing:");
println!(
"{:<30} {:>10} {:>10} {:>10}",
"Name", "Size", "Compressed", "Encrypted"
);
println!("{:-<60}", "");
for entry in files {
if let Some(info) = archive.find_file(&entry.name)? {
let encrypted = if info.is_encrypted() { "Yes" } else { "No" };
println!(
"{:<30} {:>10} {:>10} {:>10}",
entry.name, info.file_size, info.compressed_size, encrypted
);
}
}
Ok(())
}