#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(
missing_docs,
missing_debug_implementations,
rust_2018_idioms,
unreachable_pub
)]
pub mod archive;
pub mod buffer_pool;
pub mod builder;
pub mod compare;
pub mod compression;
pub mod crypto;
pub mod database;
pub mod error;
pub mod header;
pub mod io;
pub mod modification;
pub mod parallel;
pub mod patch;
pub mod patch_chain;
pub mod path;
pub mod rebuild;
pub mod security;
pub mod single_archive_parallel;
pub mod special_files;
pub mod tables;
#[cfg(feature = "simd")]
#[cfg_attr(docsrs, doc(cfg(feature = "simd")))]
pub mod simd;
#[cfg(any(test, feature = "test-utils", doc))]
pub mod test_utils;
pub mod debug;
pub use archive::{
Archive, ArchiveInfo, FileEntry, FileInfo, Md5Status, OpenOptions, SignatureStatus, TableInfo,
UserDataInfo,
};
pub use buffer_pool::{BufferPool, BufferSize, PoolConfig, PoolStatistics};
pub use builder::{ArchiveBuilder, AttributesOption, ListfileOption};
pub use compare::{
CompareOptions, ComparisonResult, ComparisonSummary, FileComparison, MetadataComparison,
compare_archives,
};
pub use error::{Error, Result};
pub use header::{FormatVersion, MpqHeader};
pub use modification::{AddFileOptions, MutableArchive};
pub use patch_chain::{ChainInfo, PatchChain};
pub use rebuild::{RebuildOptions, RebuildSummary, rebuild_archive};
pub use tables::{BetFileInfo, BetTable, BlockEntry, BlockTable, HashEntry, HashTable, HetTable};
pub use crypto::{
decrypt_block, decrypt_dword, encrypt_block, hash_string, hash_type, jenkins_hash,
};
pub use compression::{compress, decompress};
pub use archive::decrypt_file_data;
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub use io::{
AsyncArchiveReader, AsyncConfig, AsyncDecompressionMonitor, AsyncMetrics, AsyncOperationStats,
};
#[cfg(feature = "mmap")]
#[cfg_attr(docsrs, doc(cfg(feature = "mmap")))]
pub use io::{MemoryMapConfig, MemoryMapManager, MemoryMapStats, MemoryMappedArchive};
#[cfg(feature = "simd")]
#[cfg_attr(docsrs, doc(cfg(feature = "simd")))]
pub use simd::{CpuFeatures, SimdOps};
pub use security::{DecompressionMonitor, SecurityLimits, SessionTracker};
pub mod signatures {
pub const MPQ_ARCHIVE: u32 = 0x1A51504D;
pub const MPQ_USERDATA: u32 = 0x1B51504D;
pub const HET_TABLE: u32 = 0x1A544548;
pub const BET_TABLE: u32 = 0x1A544542;
pub const STRONG_SIGNATURE: [u8; 4] = *b"NGIS";
}
#[inline]
pub fn calculate_sector_size(block_size_shift: u16) -> usize {
512 << block_size_shift
}
#[inline]
pub fn is_power_of_two(value: u32) -> bool {
value != 0 && (value & (value - 1)) == 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calculate_sector_size() {
assert_eq!(calculate_sector_size(0), 512);
assert_eq!(calculate_sector_size(1), 1024);
assert_eq!(calculate_sector_size(2), 2048);
assert_eq!(calculate_sector_size(3), 4096);
assert_eq!(calculate_sector_size(4), 8192);
assert_eq!(calculate_sector_size(5), 16384);
assert_eq!(calculate_sector_size(6), 32768);
assert_eq!(calculate_sector_size(7), 65536);
assert_eq!(calculate_sector_size(8), 131072);
assert_eq!(calculate_sector_size(9), 262144);
assert_eq!(calculate_sector_size(10), 524288);
assert_eq!(calculate_sector_size(11), 1048576);
assert_eq!(calculate_sector_size(12), 2097152);
assert_eq!(calculate_sector_size(13), 4194304);
assert_eq!(calculate_sector_size(14), 8388608);
assert_eq!(calculate_sector_size(15), 16777216);
}
#[test]
fn test_calculate_sector_size_edge_cases() {
let max_shift = 16; let result = calculate_sector_size(max_shift);
assert_eq!(result, 512 << 16); }
#[test]
fn test_is_power_of_two() {
assert!(is_power_of_two(1));
assert!(is_power_of_two(2));
assert!(is_power_of_two(4));
assert!(is_power_of_two(8));
assert!(is_power_of_two(16));
assert!(is_power_of_two(32));
assert!(is_power_of_two(64));
assert!(is_power_of_two(128));
assert!(is_power_of_two(256));
assert!(is_power_of_two(512));
assert!(is_power_of_two(1024));
assert!(is_power_of_two(2048));
assert!(is_power_of_two(4096));
assert!(is_power_of_two(8192));
assert!(is_power_of_two(16384));
assert!(is_power_of_two(32768));
assert!(is_power_of_two(65536));
assert!(is_power_of_two(0x100000)); assert!(is_power_of_two(0x80000000));
assert!(!is_power_of_two(0));
assert!(!is_power_of_two(3));
assert!(!is_power_of_two(5));
assert!(!is_power_of_two(6));
assert!(!is_power_of_two(7));
assert!(!is_power_of_two(9));
assert!(!is_power_of_two(10));
assert!(!is_power_of_two(15));
assert!(!is_power_of_two(100));
assert!(!is_power_of_two(127));
assert!(!is_power_of_two(255));
assert!(!is_power_of_two(1023));
assert!(!is_power_of_two(1025));
assert!(!is_power_of_two(0xFFFFFFFF));
}
#[test]
fn test_hash_table_size_validation() {
let valid_sizes = [
4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536,
];
for size in &valid_sizes {
assert!(
is_power_of_two(*size),
"Hash table size {size} should be valid"
);
}
let invalid_sizes = [0, 3, 5, 7, 9, 15, 100, 1000, 1023, 1025, 4095, 4097];
for size in &invalid_sizes {
assert!(
!is_power_of_two(*size),
"Hash table size {size} should be invalid"
);
}
}
#[test]
fn test_typical_mpq_configurations() {
let d2_sector_size = calculate_sector_size(3);
assert_eq!(d2_sector_size, 4096);
let wc3_sector_size_small = calculate_sector_size(3);
let wc3_sector_size_large = calculate_sector_size(4);
assert_eq!(wc3_sector_size_small, 4096);
assert_eq!(wc3_sector_size_large, 8192);
let wow_sector_size_min = calculate_sector_size(4);
let wow_sector_size_typical = calculate_sector_size(6);
let wow_sector_size_max = calculate_sector_size(8);
assert_eq!(wow_sector_size_min, 8192);
assert_eq!(wow_sector_size_typical, 32768);
assert_eq!(wow_sector_size_max, 131072);
let sc2_sector_size = calculate_sector_size(9);
assert_eq!(sc2_sector_size, 262144); }
#[test]
#[cfg(feature = "mmap")]
fn test_memory_mapping_config_availability() {
let _config = MemoryMapConfig::default();
let _stats = MemoryMapStats::default();
}
#[test]
#[cfg(feature = "simd")]
fn test_simd_ops_availability() {
let simd = SimdOps::new();
let _features = simd.features();
let _has_support = simd.has_simd_support();
}
#[test]
fn test_security_limits_availability() {
let _limits = SecurityLimits::default();
let _tracker = SessionTracker::new();
}
}