use archivator::zip::ZipError; use archivator::{Archive, Zip}; use std::io::{Cursor, Read, Seek, SeekFrom}; #[test] fn test_zip_aes() { let mut archive = Archive::::read_from_file("tests/files/archive_aes.zip").unwrap(); assert_eq!(archive.comment(), "archive comment"); assert_eq!( archive .files() .iter() .map(|f| &f.name) .collect::>(), vec![ "aes128/store", "aes192/store", "aes256/store", "aes128/deflate", "aes192/deflate", "aes256/deflate", "aes128/bzip", "aes192/bzip", "aes256/bzip", "aes128/lzma", "aes192/lzma", "aes256/lzma", ] ); for encryption in ["aes128", "aes192", "aes256"] { assert!(archive .get_file_reader_by_name(&format!("{encryption}/store")) .is_err_and(|e| e == ZipError::PasswordIsNotSpecified)); assert!(archive .get_file_reader_by_name_with_password("aes128/store", b"wrong_passwd") .is_err_and(|e| e == ZipError::WrongPassword)); for (name, check) in [ ("store", "98f64f03b3d168875ffa778f7fb4"), ("deflate", "0230e7cadb76460e80cd9de611eb"), ("bzip", "061c17646f025837e33e00425cca"), ("lzma", "43ef5e8ed799eb7a0f25501824ff"), ] { let mut f = archive .get_file_reader_by_name_with_password(&format!("{encryption}/{name}"), b"passwd") .unwrap(); let mut data = String::new(); f.read_to_string(&mut data).unwrap(); assert_eq!(&data[..24], "test encrypted file data"); assert_eq!(&data[172..], check); } } } #[test] fn test_zip_weak() { let mut archive = Archive::::read_from_file("tests/files/archive_weak.zip").unwrap(); assert_eq!(archive.comment(), "archive comment"); assert_eq!( archive .files() .iter() .map(|f| &f.name) .collect::>(), vec!["store", "deflate", "bzip"] ); assert!(archive .get_file_reader_by_name("store") .is_err_and(|e| e == ZipError::PasswordIsNotSpecified)); assert!(archive .get_file_reader_by_name_with_password("store", b"wrong_passwd") .is_err_and(|e| e == ZipError::WrongPassword)); for (name, check) in [ ("store", "1e643774f40510e37c6f3c451d9d"), ("deflate", "a70aff4b6b2754ad47852503236a"), ("bzip", "f7085f4f8ecc512a8c2c3cbe8227"), ] { let mut f = archive .get_file_reader_by_name_with_password(name, b"passwd") .unwrap(); let mut data = String::new(); f.read_to_string(&mut data).unwrap(); assert_eq!(&data[..24], "test encrypted file data"); assert_eq!(&data[172..], check); } } const EMPTY: Cursor<&[u8]> = Cursor::new(b"PK\x05\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); #[test] fn test_zip() { assert_eq!(Archive::>::read(EMPTY).unwrap().len(), 0); let mut archive = Archive::::read_from_file("tests/files/archive.zip").unwrap(); assert_eq!(archive.comment(), "archive comment"); assert_eq!( archive .files() .iter() .map(|f| &f.name) .collect::>(), vec!["store", "deflate", "bzip", "lzma", "zstd", "xz"] ); assert_eq!( archive.get_file_info_by_name("none").unwrap_err(), ZipError::FileNotFound ); let mut f = archive.get_file_reader_by_name("store").unwrap(); let mut data = String::new(); f.read_to_string(&mut data).unwrap(); assert_eq!(data, "test file data"); assert_eq!(f.seek(SeekFrom::Start(5)).unwrap(), 5); let mut data = String::new(); f.read_to_string(&mut data).unwrap(); assert_eq!(data, "file data"); assert_eq!(f.seek(SeekFrom::Start(0)).unwrap(), 0); let mut data = vec![0; 4]; f.read_exact(&mut data).unwrap(); assert_eq!(String::from_utf8(data).unwrap(), "test"); assert_eq!(f.seek(SeekFrom::Current(1)).unwrap(), 5); let mut data = vec![0; 4]; f.read_exact(&mut data).unwrap(); assert_eq!(String::from_utf8(data).unwrap(), "file"); assert_eq!(f.seek(SeekFrom::End(-4)).unwrap(), 10); let mut data = vec![0; 4]; f.read_exact(&mut data).unwrap(); assert_eq!(String::from_utf8(data).unwrap(), "data"); f.seek(SeekFrom::Start(7)).unwrap(); assert_eq!(f.seek(SeekFrom::Current(0)).unwrap(), 7); assert!(f .seek(SeekFrom::End(-100)) .is_err_and(|e| e.get_ref().unwrap().to_string() == "Invalid seek to a negative or overflowing position")); assert_eq!(f.seek(SeekFrom::Current(0)).unwrap(), 7); assert_eq!(f.seek(SeekFrom::Start(100)).unwrap(), 14); for index in 0..archive.len() { let mut f = archive.get_file_reader_by_index(index).unwrap(); let mut data = String::new(); f.read_to_string(&mut data).unwrap(); assert_eq!(data, "test file data"); assert!(!f.is_seekable() || f.info().name == "store") } } const NOT_FOUND: Cursor<&[u8]> = Cursor::new(b""); const INVALID: Cursor<&[u8]> = Cursor::new( b"PK\x06\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0PK\x05\x06\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0", ); const OVERLAP: Cursor<&[u8]> = Cursor::new(b"PK\x05\x06\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0"); const OVERLAP64: Cursor<&[u8]> = Cursor::new(b"PK\x06\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0PK\x06\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0PK\x05\x06\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0"); #[test] fn test_bad_zip() { assert!( Archive::>::read(NOT_FOUND).is_err_and(|e| e == ZipError::StructNotFound("Eocdr")) ); assert!( Archive::>::read(INVALID).is_err_and(|e| e == ZipError::InvalidSignature("Eocdr64")) ); assert!(Archive::>::read(OVERLAP).is_err_and(|e| e == ZipError::Overlapping( "Central directory records", "End of central directory record" ))); assert!(Archive::>::read(OVERLAP64).is_err_and(|e| e == ZipError::Overlapping( "Central directory records", "Zip64 end of central directory record" ))); }