magical_rs/lib.rs
1//! # File Magic Detection
2//!
3//! This crate detects file types by matching magic bytes (signatures) at specific offsets.
4//!
5//! ---
6//!
7//! ## How It Works
8//!
9//! - Each file type (e.g., PNG, ISO, ZIP) has one or more known byte signatures.
10//! - Some signatures are at offset 0 (e.g., PNG), but others are at large offsets (e.g., ISO at 32769).
11//! - To detect **all supported types**, you must read enough bytes from the file header.
12//!
13//! ---
14//!
15//! ## Example:
16//! * With default constant [`DEFAULT_MAX_BYTES_READ`]:
17//!
18//! [`DEFAULT_MAX_BYTES_READ`]: https://docs.rs/magical_rs/0.0.4/magical_rs/magical/bytes_read/constant.DEFAULT_MAX_BYTES_READ.html
19//!
20//! ```no_run
21//! # #[cfg(not(feature = "no_std"))]
22//! # use magical_rs::magical::bytes_read::DEFAULT_MAX_BYTES_READ;
23//! # #[cfg(not(feature = "no_std"))]
24//! # use magical_rs::magical::{
25//! # bytes_read::{read_file_header, with_bytes_read},
26//! # magic::FileKind,
27//! # };
28//!
29//! # #[cfg(not(feature = "no_std"))]
30//! # let png_file = "example.png";
31//! # #[cfg(not(feature = "no_std"))]
32//! # let header_bytes = read_file_header(png_file, DEFAULT_MAX_BYTES_READ).unwrap();
33//!
34//! # #[cfg(not(feature = "no_std"))]
35//! # assert_eq!(FileKind::match_types(&header_bytes), FileKind::Png);
36//! # #[cfg(not(feature = "no_std"))]
37//! # assert_ne!(FileKind::match_types(&header_bytes), FileKind::Unknown);
38//! ```
39//!
40//! ---
41//!
42//! * Use with [`with_bytes_read`]:
43//! ```no_run
44//! # #[cfg(not(feature = "no_std"))]
45//! # use magical_rs::magical::bytes_read::DEFAULT_MAX_BYTES_READ;
46//! # #[cfg(not(feature = "no_std"))]
47//! # use magical_rs::magical::{
48//! # bytes_read::{read_file_header, with_bytes_read},
49//! # magic::FileKind,
50//! # };
51//! # #[cfg(not(feature = "no_std"))]
52//! # let iso_file = "example.iso";
53//! # #[cfg(not(feature = "no_std"))]
54//! # let bytes_max = with_bytes_read();
55//! # #[cfg(not(feature = "no_std"))]
56//! # let wrong_max = DEFAULT_MAX_BYTES_READ;
57//! # #[cfg(not(feature = "no_std"))]
58//! # let header_bytes = read_file_header(iso_file, bytes_max).unwrap();
59//! # #[cfg(not(feature = "no_std"))]
60//! # assert_eq!(FileKind::match_types(&header_bytes), FileKind::ISO);
61//! # #[cfg(not(feature = "no_std"))]
62//! # assert_ne!(FileKind::match_types(&header_bytes), FileKind::Unknown);
63//! ```
64//! ---
65//!
66//! ## Warning: Use [`with_bytes_read`] for **correct detection.**
67//!
68//! * Always use [`with_bytes_read`] to determine how many bytes to read.
69//!
70//! [`with_bytes_read`]: https://docs.rs/magical_rs/0.0.4/magical_rs/magical/bytes_read/fn.with_bytes_read.html
71//! * Do **NOT** use [`DEFAULT_MAX_BYTES_READ`] unless you only care about common formats (PNG, JPG, etc.).
72//!
73//! ---
74//!
75//! ### Why?
76//!
77//! - [`DEFAULT_MAX_BYTES_READ`] is too small for formats like: `.iso` (needs ~36KB)
78//! - If you read only 2048 bytes, those files will be misclassified as `Unknown`.
79//!
80//! ---
81//!
82//! * **Correct usage:**
83//! ```no_run
84//! # # [cfg(not(feature = "no_std"))]
85//! # use magical_rs::magical::bytes_read::{with_bytes_read, read_file_header, DEFAULT_MAX_BYTES_READ};
86//! # #[cfg(not(feature = "no_std"))]
87//! # use magical_rs::magical::magic::FileKind;
88//! #
89//! # #[cfg(not(feature = "no_std"))]
90//! # let max_bytes = with_bytes_read(); // ← Auto-calculated safe size
91//! #
92//! # #[cfg(not(feature = "no_std"))]
93//! # let header = read_file_header("file.iso", max_bytes).unwrap();
94//! # #[cfg(not(feature = "no_std"))]
95//! # let kind = FileKind::match_types(&header);
96//! ```
97//!
98//! ---
99//!
100//! * **Avoid:**
101//! ```no_run
102//! #[cfg(not(feature = "no_std"))]
103//! # use magical_rs::magical::bytes_read::{with_bytes_read, read_file_header, DEFAULT_MAX_BYTES_READ};
104//!
105//! #[cfg(not(feature = "no_std"))]
106//! # let header = read_file_header("file.iso", DEFAULT_MAX_BYTES_READ).unwrap(); // ← Will fail to detect!
107//! ```
108//! ---
109//!
110//! See [`magical_rs`] for more information.
111//!
112//! ---
113//!
114//! [`magical_rs`]: https://docs.rs/magical_rs/0.0.4/magical_rs
115//!
116#![deny(clippy::pedantic, clippy::all, clippy::nursery, clippy::perf)]
117#![cfg_attr(feature = "no_std", no_std)]
118pub mod magical {
119 pub mod bytes_read;
120
121 pub mod ext_fn {
122 pub mod webp;
123 }
124
125 pub mod magic;
126 pub mod magic_custom;
127 pub mod match_rules;
128 pub mod signatures;
129}