rsomics_bam_quickcheck/
lib.rs1use std::fs::File;
22use std::io::{Read, Seek, SeekFrom};
23use std::path::Path;
24
25use flate2::read::MultiGzDecoder;
26
27pub const BGZF_EOF: [u8; 28] = [
29 0x1f, 0x8b, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x06, 0x00, 0x42, 0x43, 0x02, 0x00,
30 0x1b, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31];
32
33#[derive(Debug, Default, Clone, Copy)]
34pub struct QuickcheckOpts {
35 pub no_eof: bool,
37}
38
39#[derive(Debug)]
40pub enum QuickcheckError {
41 Io(std::io::Error),
42 BadBgzfMagic,
43 BadBamMagic,
44 MissingEof,
45 Truncated,
46}
47
48impl std::fmt::Display for QuickcheckError {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 match self {
51 Self::Io(e) => write!(f, "io: {e}"),
52 Self::BadBgzfMagic => f.write_str("bad BGZF magic (not a BGZF/BAM file)"),
53 Self::BadBamMagic => f.write_str("bad BAM header magic"),
54 Self::MissingEof => f.write_str("missing BGZF EOF marker"),
55 Self::Truncated => f.write_str("file too short to be a valid BAM"),
56 }
57 }
58}
59
60impl std::error::Error for QuickcheckError {}
61
62impl From<std::io::Error> for QuickcheckError {
63 fn from(e: std::io::Error) -> Self {
64 Self::Io(e)
65 }
66}
67
68pub fn quickcheck(path: &Path, opts: &QuickcheckOpts) -> Result<(), QuickcheckError> {
70 let mut f = File::open(path)?;
71 let meta = f.metadata()?;
72 let len = meta.len();
73
74 if len < 28 {
75 return Err(QuickcheckError::Truncated);
76 }
77
78 let mut head = [0u8; 4];
80 f.read_exact(&mut head)?;
81 if head != [0x1f, 0x8b, 0x08, 0x04] {
82 return Err(QuickcheckError::BadBgzfMagic);
83 }
84 f.seek(SeekFrom::Start(0))?;
86
87 let mut bam_magic = [0u8; 4];
90 MultiGzDecoder::new(&mut f).read_exact(&mut bam_magic)?;
91 if bam_magic != *b"BAM\x01" {
92 return Err(QuickcheckError::BadBamMagic);
93 }
94
95 if !opts.no_eof {
97 let mut tail = [0u8; 28];
98 f.seek(SeekFrom::End(-28))?;
99 f.read_exact(&mut tail)?;
100 if tail != BGZF_EOF {
101 return Err(QuickcheckError::MissingEof);
102 }
103 }
104
105 Ok(())
106}