binocular/preview/binary/
mod.rs1mod 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}