win-rar 0.1.0

A Windows archive manager supporting ZIP, 7z, RAR, TAR with encryption, shell integration, and drag-and-drop
/// 全面可用性测试脚本
use std::fs;
use std::io::Write;
use std::path::Path;

use zip::unstable::write::FileOptionsExt;

fn main() {
    let test_dir = r"d:\workspace\win-rar\test-data";
    let output_dir = r"d:\workspace\win-rar\test-data\output";
    let _ = fs::create_dir_all(output_dir);

    println!("=== WinRAR 可用性测试 ===\n");

    print_test("1. ZIP 压缩(单文件)");
    test_zip_compress_single(test_dir, output_dir);

    print_test("2. ZIP 压缩(多文件)");
    test_zip_compress_multi(test_dir, output_dir);

    print_test("3. ZIP 解压");
    test_zip_extract(output_dir);

    print_test("4. 7Z 压缩");
    test_7z_compress(test_dir, output_dir);

    print_test("5. 7Z 解压");
    test_7z_extract(output_dir);

    print_test("6. TAR.GZ 压缩与解压");
    test_targz(test_dir, output_dir);

    print_test("7. TAR.BZ2 压缩与解压");
    test_tarbz2(test_dir, output_dir);

    print_test("8. TAR.XZ 压缩与解压");
    test_tarxz(test_dir, output_dir);

    print_test("9. ZIP 带密码压缩与解压");
    test_zip_password(test_dir, output_dir);

    print_test("10. 7Z 带密码压缩与解压");
    test_7z_password(test_dir, output_dir);

    print_test("11. 文件夹压缩(ZIP)");
    test_folder_compress(test_dir, output_dir);

    print_test("12. 列出归档内容");
    test_list_archive(output_dir);

    println!("\n=== 测试完成 ===");
}

fn print_test(name: &str) {
    println!("\n--- {} ---", name);
}

fn test_zip_compress_single(test_dir: &str, output_dir: &str) {
    let output = format!(r"{}\single.zip", output_dir);
    let file = std::fs::File::create(&output).expect("创建zip失败");
    let mut zip = zip::ZipWriter::new(file);
    let options = zip::write::SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated);
    let data = std::fs::read(format!(r"{}\test1.txt", test_dir)).expect("读取文件失败");
    zip.start_file("test1.txt", options).expect("start_file失败");
    zip.write_all(&data).expect("write失败");
    zip.finish().expect("finish失败");
    println!("  OK: {} ({} bytes)", output, std::fs::metadata(&output).unwrap().len());
}

fn test_zip_compress_multi(test_dir: &str, output_dir: &str) {
    let files = vec![
        format!(r"{}\test1.txt", test_dir),
        format!(r"{}\test2.txt", test_dir),
        format!(r"{}\test3.txt", test_dir),
    ];
    let output = format!(r"{}\multi.zip", output_dir);
    let file = std::fs::File::create(&output).expect("创建zip失败");
    let mut zip = zip::ZipWriter::new(file);
    let options = zip::write::SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated);
    for f in &files {
        let name = Path::new(f).file_name().unwrap().to_string_lossy().to_string();
        let data = std::fs::read(f).expect("读取文件失败");
        zip.start_file(&name, options).expect("start_file失败");
        zip.write_all(&data).expect("write失败");
    }
    zip.finish().expect("finish失败");
    println!("  OK: {} ({} bytes)", output, std::fs::metadata(&output).unwrap().len());
}

fn test_zip_extract(output_dir: &str) {
    let zip_path = format!(r"{}\multi.zip", output_dir);
    let extract_dir = format!(r"{}\zip_extracted", output_dir);
    let _ = fs::create_dir_all(&extract_dir);
    let file = std::fs::File::open(&zip_path).expect("打开zip失败");
    let mut archive = zip::ZipArchive::new(file).expect("读取zip失败");
    for i in 0..archive.len() {
        let mut entry = archive.by_index(i).expect("读取条目失败");
        let name = entry.name().to_string();
        let out_path = format!(r"{}\{}", extract_dir, name);
        let mut out_file = std::fs::File::create(&out_path).expect("创建输出文件失败");
        std::io::copy(&mut entry, &mut out_file).expect("写入失败");
        println!("  解压: {} ({} bytes)", name, entry.size());
    }
    println!("  OK: 解压到 {}", extract_dir);
}

fn test_7z_compress(test_dir: &str, output_dir: &str) {
    let output = format!(r"{}\test.7z", output_dir);
    let files = vec![
        format!(r"{}\test1.txt", test_dir),
        format!(r"{}\test2.txt", test_dir),
    ];
    let mut writer = sevenz_rust::SevenZWriter::create(&output)
        .expect("SevenZWriter创建失败");
    for f in &files {
        let name = Path::new(f).file_name().unwrap().to_string_lossy().to_string();
        let entry = sevenz_rust::SevenZArchiveEntry::from_path(f, name);
        let file = std::fs::File::open(f).expect("打开文件失败");
        writer.push_archive_entry(entry, Some(file)).expect("push失败");
    }
    writer.finish().expect("finish失败");
    println!("  OK: {} ({} bytes)", output, std::fs::metadata(&output).unwrap().len());
}

fn test_7z_extract(output_dir: &str) {
    let sz_path = format!(r"{}\test.7z", output_dir);
    let extract_dir = format!(r"{}\7z_extracted", output_dir);
    let _ = fs::create_dir_all(&extract_dir);
    sevenz_rust::decompress_file(&sz_path, &extract_dir)
        .expect("7z解压失败");
    for entry in fs::read_dir(&extract_dir).expect("读取目录失败") {
        let entry = entry.expect("entry失败");
        let path = entry.path();
        if path.is_file() {
            let len = std::fs::metadata(&path).unwrap().len();
            println!("  解压: {} ({} bytes)", path.file_name().unwrap().to_string_lossy(), len);
        }
    }
    println!("  OK: 解压到 {}", extract_dir);
}

fn test_targz(test_dir: &str, output_dir: &str) {
    let output = format!(r"{}\test.tar.gz", output_dir);
    let extract_dir = format!(r"{}\targz_extracted", output_dir);
    let _ = fs::create_dir_all(extract_dir.clone());
    let file = std::fs::File::create(&output).expect("创建tar.gz失败");
    let enc = flate2::write::GzEncoder::new(file, flate2::Compression::default());
    let mut tar = tar::Builder::new(enc);
    let data1 = std::fs::read(format!(r"{}\test1.txt", test_dir)).expect("读取test1失败");
    let data2 = std::fs::read(format!(r"{}\test2.txt", test_dir)).expect("读取test2失败");
    let mut header1 = tar::Header::new_gnu();
    header1.set_path("test1.txt").expect("set_path失败");
    header1.set_size(data1.len() as u64);
    header1.set_mode(0o644);
    header1.set_cksum();
    tar.append(&header1, &*data1).expect("append失败");
    let mut header2 = tar::Header::new_gnu();
    header2.set_path("test2.txt").expect("set_path失败");
    header2.set_size(data2.len() as u64);
    header2.set_mode(0o644);
    header2.set_cksum();
    tar.append(&header2, &*data2).expect("append失败");
    let enc = tar.into_inner().expect("into_inner失败");
    enc.finish().expect("finish失败");
    println!("  压缩 OK: {} ({} bytes)", output, std::fs::metadata(&output).unwrap().len());
    let file = std::fs::File::open(&output).expect("打开tar.gz失败");
    let dec = flate2::read::GzDecoder::new(file);
    let mut archive = tar::Archive::new(dec);
    archive.unpack(&extract_dir).expect("解压失败");
    println!("  解压 OK: {}", extract_dir);
}

fn test_tarbz2(test_dir: &str, output_dir: &str) {
    let output = format!(r"{}\test.tar.bz2", output_dir);
    let extract_dir = format!(r"{}\tarbz2_extracted", output_dir);
    let _ = fs::create_dir_all(extract_dir.clone());
    let file = std::fs::File::create(&output).expect("创建tar.bz2失败");
    let enc = bzip2::write::BzEncoder::new(file, bzip2::Compression::default());
    let mut tar = tar::Builder::new(enc);
    let data1 = std::fs::read(format!(r"{}\test1.txt", test_dir)).expect("读取test1失败");
    let mut header1 = tar::Header::new_gnu();
    header1.set_path("test1.txt").expect("set_path失败");
    header1.set_size(data1.len() as u64);
    header1.set_mode(0o644);
    header1.set_cksum();
    tar.append(&header1, &*data1).expect("append失败");
    let enc = tar.into_inner().expect("into_inner失败");
    enc.finish().expect("finish失败");
    println!("  压缩 OK: {} ({} bytes)", output, std::fs::metadata(&output).unwrap().len());
    let file = std::fs::File::open(&output).expect("打开tar.bz2失败");
    let dec = bzip2::read::BzDecoder::new(file);
    let mut archive = tar::Archive::new(dec);
    archive.unpack(&extract_dir).expect("解压失败");
    println!("  解压 OK: {}", extract_dir);
}

fn test_tarxz(test_dir: &str, output_dir: &str) {
    let output = format!(r"{}\test.tar.xz", output_dir);
    let extract_dir = format!(r"{}\tarxz_extracted", output_dir);
    let _ = fs::create_dir_all(extract_dir.clone());
    let file = std::fs::File::create(&output).expect("创建tar.xz失败");
    let enc = xz2::write::XzEncoder::new(file, 6);
    let mut tar = tar::Builder::new(enc);
    let data1 = std::fs::read(format!(r"{}\test1.txt", test_dir)).expect("读取test1失败");
    let mut header1 = tar::Header::new_gnu();
    header1.set_path("test1.txt").expect("set_path失败");
    header1.set_size(data1.len() as u64);
    header1.set_mode(0o644);
    header1.set_cksum();
    tar.append(&header1, &*data1).expect("append失败");
    let enc = tar.into_inner().expect("into_inner失败");
    enc.finish().expect("finish失败");
    println!("  压缩 OK: {} ({} bytes)", output, std::fs::metadata(&output).unwrap().len());
    let file = std::fs::File::open(&output).expect("打开tar.xz失败");
    let dec = xz2::read::XzDecoder::new(file);
    let mut archive = tar::Archive::new(dec);
    archive.unpack(&extract_dir).expect("解压失败");
    println!("  解压 OK: {}", extract_dir);
}

fn test_zip_password(test_dir: &str, output_dir: &str) {
    let output = format!(r"{}\encrypted.zip", output_dir);
    let extract_dir = format!(r"{}\zip_encrypted_extracted", output_dir);
    let _ = fs::create_dir_all(extract_dir.clone());
    let file = std::fs::File::create(&output).expect("创建zip失败");
    let mut zip = zip::ZipWriter::new(file);
    let options = zip::write::SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated)
        .with_deprecated_encryption(b"test123");
    let data = std::fs::read(format!(r"{}\test1.txt", test_dir)).expect("读取文件失败");
    zip.start_file("test1.txt", options).expect("start_file失败");
    zip.write_all(&data).expect("write失败");
    zip.finish().expect("finish失败");
    println!("  压缩 OK: {} ({} bytes)", output, std::fs::metadata(&output).unwrap().len());
    let file = std::fs::File::open(&output).expect("打开zip失败");
    let mut archive = zip::ZipArchive::new(file).expect("读取zip失败");
    for i in 0..archive.len() {
        let mut entry = archive.by_index_decrypt(i, b"test123").expect("解密失败");
        let name = entry.name().to_string();
        let out_path = format!(r"{}\{}", extract_dir, name);
        let mut out_file = std::fs::File::create(&out_path).expect("创建输出文件失败");
        std::io::copy(&mut entry, &mut out_file).expect("写入失败");
        println!("  解压: {} ({} bytes)", name, entry.size());
    }
    println!("  解压 OK: {}", extract_dir);
}

fn test_7z_password(test_dir: &str, output_dir: &str) {
    let output = format!(r"{}\encrypted.7z", output_dir);
    let extract_dir = format!(r"{}\7z_encrypted_extracted", output_dir);
    let _ = fs::create_dir_all(extract_dir.clone());
    let mut writer = sevenz_rust::SevenZWriter::create(&output)
        .expect("SevenZWriter创建失败");
    let pwd = sevenz_rust::Password::from("test123");
    writer.set_content_methods(vec![
        sevenz_rust::AesEncoderOptions::new(pwd).into(),
        sevenz_rust::SevenZMethod::LZMA2.into(),
    ]);
    let f_path = format!(r"{}\test1.txt", test_dir);
    let entry = sevenz_rust::SevenZArchiveEntry::from_path(&f_path, "test1.txt".to_string());
    let f = std::fs::File::open(&f_path).expect("打开文件失败");
    writer.push_archive_entry(entry, Some(f)).expect("push失败");
    writer.finish().expect("finish失败");
    println!("  压缩 OK: {} ({} bytes)", output, std::fs::metadata(&output).unwrap().len());
    let pwd = sevenz_rust::Password::from("test123");
    sevenz_rust::decompress_file_with_password(&output, &extract_dir, pwd)
        .expect("7z密码解压失败");
    for entry in fs::read_dir(&extract_dir).expect("读取目录失败") {
        let entry = entry.expect("entry失败");
        let path = entry.path();
        if path.is_file() {
            let len = std::fs::metadata(&path).unwrap().len();
            println!("  解压: {} ({} bytes)", path.file_name().unwrap().to_string_lossy(), len);
        }
    }
    println!("  解压 OK: {}", extract_dir);
}

fn test_folder_compress(test_dir: &str, output_dir: &str) {
    let output = format!(r"{}\folder.zip", output_dir);
    let folder = format!(r"{}\subdir", test_dir);
    let file = std::fs::File::create(&output).expect("创建zip失败");
    let mut zip = zip::ZipWriter::new(file);
    let options = zip::write::SimpleFileOptions::default()
        .compression_method(zip::CompressionMethod::Deflated);
    zip.add_directory("subdir/", options).expect("add_directory失败");
    for entry in fs::read_dir(&folder).expect("读取目录失败") {
        let entry = entry.expect("entry失败");
        let path = entry.path();
        if path.is_file() {
            let name = format!("subdir/{}", path.file_name().unwrap().to_string_lossy());
            let data = fs::read(&path).expect("读取文件失败");
            zip.start_file(&name, options).expect("start_file失败");
            zip.write_all(&data).expect("write失败");
            println!("  添加: {}", name);
        }
    }
    zip.finish().expect("finish失败");
    println!("  OK: {} ({} bytes)", output, std::fs::metadata(&output).unwrap().len());
}

fn test_list_archive(output_dir: &str) {
    let zip_path = format!(r"{}\multi.zip", output_dir);
    let file = std::fs::File::open(&zip_path).expect("打开zip失败");
    let mut archive = zip::ZipArchive::new(file).expect("读取zip失败");
    println!("  ZIP 内容 ({} 个文件):", archive.len());
    for i in 0..archive.len() {
        let entry = archive.by_index(i).expect("读取条目失败");
        println!("    {} - {} bytes (压缩: {} bytes)", entry.name(), entry.size(), entry.compressed_size());
    }
    let sz_path = format!(r"{}\test.7z", output_dir);
    let len = std::fs::metadata(&sz_path).unwrap().len();
    let file = std::fs::File::open(&sz_path).expect("打开7z失败");
    let reader = sevenz_rust::SevenZReader::new(file, len, sevenz_rust::Password::empty())
        .expect("SevenZReader创建失败");
    let files = &reader.archive().files;
    println!("  7Z 内容 ({} 个文件):", files.len());
    for f in files {
        println!("    {} - {} bytes", f.name(), f.size());
    }
}