#![forbid(unsafe_code)]
#![cfg_attr(test, allow(clippy::unwrap_used, clippy::expect_used))]
pub mod identify;
pub use identify::{identify, identify_with_limits};
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub enum BlobKind {
BinaryPlist,
XmlPlist,
Gzip,
Zlib,
Snappy,
Base64,
Hex,
Uuid,
Json,
Protobuf,
Utf16Le,
Utf8Text,
Unknown,
}
impl BlobKind {
#[must_use]
pub fn label(self) -> &'static str {
match self {
Self::BinaryPlist => "Apple binary property list",
Self::XmlPlist => "Apple XML property list",
Self::Gzip => "gzip stream",
Self::Zlib => "zlib stream",
Self::Snappy => "Snappy framed stream",
Self::Base64 => "base64 text",
Self::Hex => "hexadecimal text",
Self::Uuid => "UUID / GUID",
Self::Json => "JSON",
Self::Protobuf => "Protocol Buffers (schemaless)",
Self::Utf16Le => "UTF-16LE text",
Self::Utf8Text => "UTF-8 text",
Self::Unknown => "unknown",
}
}
#[must_use]
pub fn citation(self) -> &'static str {
match self {
Self::BinaryPlist | Self::XmlPlist => {
"Apple CoreFoundation CFBinaryPList.c; `man 5 plist`"
}
Self::Gzip => "RFC 1952 (GZIP file format)",
Self::Zlib => "RFC 1950 (ZLIB compressed data format)",
Self::Snappy => "google/snappy framing_format.txt",
Self::Base64 => "RFC 4648 §4-5 (Base 64 / Base64url)",
Self::Hex => "RFC 4648 §8 (Base 16)",
Self::Uuid => "RFC 9562 (UUID)",
Self::Json => "RFC 8259 (JSON)",
Self::Protobuf => "protobuf.dev encoding spec (wire format)",
Self::Utf16Le => "The Unicode Standard; RFC 2781 (UTF-16LE)",
Self::Utf8Text => "RFC 3629 (UTF-8)",
Self::Unknown => "no matching format",
}
}
#[must_use]
pub fn is_wrapper(self) -> bool {
matches!(
self,
Self::Gzip | Self::Zlib | Self::Snappy | Self::Base64 | Self::Hex
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub enum Confidence {
Low,
Medium,
High,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct Candidate {
pub kind: BlobKind,
pub score: Confidence,
pub summary: String,
pub citation: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub inner: Option<Box<DecodedChain>>,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct DecodedChain {
pub decoded_len: usize,
pub capped: bool,
pub best: Box<Candidate>,
}
#[derive(Debug, Clone, Copy)]
pub struct Limits {
pub max_depth: usize,
pub max_output: usize,
pub max_input: usize,
}
impl Default for Limits {
fn default() -> Self {
Self {
max_depth: 8,
max_output: 64 * 1024 * 1024,
max_input: 128 * 1024 * 1024,
}
}
}