Skip to main content

binocular/preview/binary/
mod.rs

1mod analysis;
2mod detect;
3mod hex_dump;
4mod metadata;
5mod strings;
6
7use crate::preview::doc::PreviewDoc;
8use ratatui::text::Text;
9use std::fs;
10use std::io::Read;
11use std::path::Path;
12
13pub(super) const HEADER_READ_BYTES: usize = 512;
14pub(super) const ENTROPY_SAMPLE_BYTES: usize = 1024 * 1024;
15pub(super) const HEX_DUMP_BYTES: usize = 128;
16pub(super) const STRINGS_SAMPLE_BYTES: usize = 8192;
17pub(super) const MIN_PRINTABLE_STRING_LEN: usize = 6;
18pub(super) const MAX_PRINTABLE_STRINGS_SHOWN: usize = 15;
19pub(super) const MAX_STRING_PREVIEW_LEN: usize = 60;
20
21pub(super) const SECTION_FILE_INFO: &str = "File Info";
22pub(super) const SECTION_FILE_TYPE: &str = "File Type";
23pub(super) const SECTION_ANALYSIS: &str = "Analysis";
24pub(super) const SECTION_HEX_DUMP: &str = "Hex Dump (first 128 bytes)";
25pub(super) const SECTION_PRINTABLE_STRINGS: &str = "Printable Strings";
26
27pub use analysis::calculate_entropy;
28pub use hex_dump::create_hex_dump;
29pub use strings::extract_printable_strings;
30
31pub fn generate_preview(path: &Path) -> Text<'static> {
32    let mut doc = PreviewDoc::new();
33    metadata::append_file_metadata(path, &mut doc);
34
35    let Ok(mut file) = fs::File::open(path) else {
36        return doc.into_text();
37    };
38
39    let header = read_prefix(&mut file, HEADER_READ_BYTES);
40    if header.is_empty() {
41        return doc.into_text();
42    }
43
44    detect::append_file_type_info(path, &header, &mut doc);
45    analysis::append_analysis(&mut file, &mut doc);
46    hex_dump::append_hex_dump(&header, &mut doc);
47    strings::append_printable_strings(path, &mut doc);
48
49    doc.into_text()
50}
51
52pub(super) fn read_prefix(file: &mut fs::File, max_bytes: usize) -> Vec<u8> {
53    if max_bytes == 0 {
54        return Vec::new();
55    }
56
57    let mut buffer = vec![0u8; max_bytes];
58    let bytes_read = file.read(&mut buffer).unwrap_or(0);
59    buffer.truncate(bytes_read);
60    buffer
61}