use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ZipAnomaly {
FakeEocdInComment { offset: u64 },
EocdNotAtEnd { expected_len: u64, actual_len: u64 },
CentralDirectoryShifted { declared: u64, actual: u64 },
ExtraCentralDirectoryRecords { declared: u64, extra: u64 },
MissingCentralDirectoryRecords { declared: u64, parsed: u64 },
DuplicateEntry { entry: String },
EntryPathConflict { entry: String, file: String },
InvalidUtf8Name { entry: String },
CompressionMethodMismatch {
entry: String,
central: u16,
local: u16,
},
UnknownCompressionMethod { entry: String, method: u16 },
StoredSizeMismatch {
entry: String,
compressed: u64,
uncompressed: u64,
},
EncryptionFlag { entry: String },
LocalHeaderShifted {
entry: String,
declared: u64,
actual: u64,
},
LocalHeaderMissing { entry: String },
}
impl ZipAnomaly {
pub fn code(&self) -> &'static str {
match self {
ZipAnomaly::FakeEocdInComment { .. } => "fake_eocd_in_comment",
ZipAnomaly::EocdNotAtEnd { .. } => "eocd_not_at_end",
ZipAnomaly::CentralDirectoryShifted { .. } => "central_directory_shifted",
ZipAnomaly::ExtraCentralDirectoryRecords { .. } => "extra_central_directory_records",
ZipAnomaly::MissingCentralDirectoryRecords { .. } => {
"missing_central_directory_records"
}
ZipAnomaly::DuplicateEntry { .. } => "duplicate_entry",
ZipAnomaly::EntryPathConflict { .. } => "entry_path_conflict",
ZipAnomaly::InvalidUtf8Name { .. } => "invalid_utf8_name",
ZipAnomaly::CompressionMethodMismatch { .. } => "compression_method_mismatch",
ZipAnomaly::UnknownCompressionMethod { .. } => "unknown_compression_method",
ZipAnomaly::StoredSizeMismatch { .. } => "stored_size_mismatch",
ZipAnomaly::EncryptionFlag { .. } => "encryption_flag",
ZipAnomaly::LocalHeaderShifted { .. } => "local_header_shifted",
ZipAnomaly::LocalHeaderMissing { .. } => "local_header_missing",
}
}
pub fn entry(&self) -> Option<&str> {
match self {
ZipAnomaly::DuplicateEntry { entry }
| ZipAnomaly::EntryPathConflict { entry, .. }
| ZipAnomaly::InvalidUtf8Name { entry }
| ZipAnomaly::CompressionMethodMismatch { entry, .. }
| ZipAnomaly::UnknownCompressionMethod { entry, .. }
| ZipAnomaly::StoredSizeMismatch { entry, .. }
| ZipAnomaly::EncryptionFlag { entry }
| ZipAnomaly::LocalHeaderShifted { entry, .. }
| ZipAnomaly::LocalHeaderMissing { entry } => Some(entry),
_ => None,
}
}
}
impl fmt::Display for ZipAnomaly {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ZipAnomaly::FakeEocdInComment { offset } => write!(
f,
"end of central directory signature planted at {offset:#x}, in the archive comment"
),
ZipAnomaly::EocdNotAtEnd {
expected_len,
actual_len,
} => write!(
f,
"end of central directory ends at {expected_len:#x}, the file at {actual_len:#x}"
),
ZipAnomaly::CentralDirectoryShifted { declared, actual } => write!(
f,
"central directory declared at {declared:#x}, found at {actual:#x}"
),
ZipAnomaly::ExtraCentralDirectoryRecords { declared, extra } => write!(
f,
"{extra} central directory records past the declared {declared}"
),
ZipAnomaly::MissingCentralDirectoryRecords { declared, parsed } => write!(
f,
"{declared} central directory records declared, {parsed} present"
),
ZipAnomaly::DuplicateEntry { .. } => write!(f, "duplicate central directory record"),
ZipAnomaly::EntryPathConflict { file, .. } => {
write!(f, "path runs through the file {file:?}")
}
ZipAnomaly::InvalidUtf8Name { .. } => write!(f, "name is not valid UTF-8"),
ZipAnomaly::CompressionMethodMismatch { central, local, .. } => write!(
f,
"compression method {central} in the central directory, {local} in the local header"
),
ZipAnomaly::UnknownCompressionMethod { method, .. } => {
write!(f, "unknown compression method {method}")
}
ZipAnomaly::StoredSizeMismatch {
compressed,
uncompressed,
..
} => write!(
f,
"stored entry with compressed size {compressed} and uncompressed size {uncompressed}"
),
ZipAnomaly::EncryptionFlag { .. } => write!(f, "encryption flag is set"),
ZipAnomaly::LocalHeaderShifted {
declared, actual, ..
} => write!(
f,
"local header declared at {declared:#x}, found at {actual:#x}"
),
ZipAnomaly::LocalHeaderMissing { .. } => write!(f, "local header not found"),
}
}
}