root_io/tree_reader/
container.rs

1use failure::Error;
2use nom::combinator::rest;
3use nom::number::complete::*;
4use nom::*;
5
6use crate::core::*;
7
8#[derive(Debug, Clone)]
9pub(crate) enum Container {
10    /// Decompressed content of a `TBasket`
11    InMemory(Vec<u8>),
12    /// Filename, start byte, and len of a `TBasket` on disk
13    OnDisk(Source, u64, u64),
14}
15
16impl Container {
17    /// Return the number of entries and the data; reading it from disk if necessary
18    pub(crate) async fn raw_data(self) -> Result<(u32, Vec<u8>), Error> {
19        let buf = match self {
20            Container::InMemory(buf) => buf,
21            Container::OnDisk(source, seek, len) => source.fetch(seek, len).await?,
22        };
23        match tbasket2vec(buf.as_slice()) {
24            Ok((_, v)) => Ok(v),
25            _ => Err(format_err!("tbasket2vec parser failed")),
26        }
27    }
28    // /// For debugging: Try to find the file of this container. Out of luck if the container was inlined
29    // pub(crate) fn file(&self) -> Option<PathBuf> {
30    //     match *self {
31    //         // No file name available
32    //         Container::InMemory(_) => None,
33    //         Container::OnDisk(ref p, _, _) => Some(p.to_owned())
34    //     }
35    // }
36}
37
38/// Return a tuple indicating the number of elements in this basket
39/// and the content as a Vec<u8>
40#[rustfmt::skip::macros(do_parse)]
41fn tbasket2vec(input: &[u8]) -> IResult<&[u8], (u32, Vec<u8>)> {
42    do_parse!(input,
43              hdr: tkey_header >>
44              _ver: be_u16 >>
45              _buf_size: be_u32 >>
46              _entry_size: be_u32 >>
47	      n_entry_buf: be_u32 >>
48	      last: be_u32 >>
49	      _flag: be_i8 >>
50              buf: rest >>
51              ({
52                  let buf = if hdr.uncomp_len as usize > buf.len() {
53                      decompress(buf).unwrap().1
54                  } else {
55                      buf.to_vec()
56                  };
57                  // Not the whole buffer is filled, no, no, no, that
58                  // would be to easy! Its only filled up to `last`,
59                  // whereby we have to take the key_len into account...
60                  let useful_bytes = (last - hdr.key_len as u32) as usize;
61                  (n_entry_buf, buf.as_slice()[..useful_bytes].to_vec())
62              }))
63}
64
65#[cfg(test)]
66mod tests {
67    use crate::core::tkey_header;
68    use nom::*;
69    use std::fs::File;
70    use std::io::{BufReader, Read, Seek, SeekFrom};
71
72    use super::tbasket2vec;
73
74    #[test]
75    fn basket_simple() {
76        let path = "./src/test_data/simple.root";
77        let f = File::open(&path).unwrap();
78        let mut reader = BufReader::new(f);
79        // Go to first basket
80        reader.seek(SeekFrom::Start(218)).unwrap();
81        // size from fbasketbytes
82        let mut buf = vec![0; 86];
83        // let mut buf = vec![0; 386];
84        reader.read_exact(&mut buf).unwrap();
85
86        println!("{}", buf.to_hex(16));
87        println!("{:?}", tkey_header(&buf));
88        // println!("{:#?}", tbasket(&buf, be_u32));
89        println!("{:#?}", tbasket2vec(&buf));
90    }
91
92    // /// Test the first basket of the "Tracks.fP[5]" branch
93    // #[test]
94    // fn basket_esd() {
95    //     // This test is broken since the numbers were hardcoded for a specific file
96    //     use alice_open_data;
97    //     let path = alice_open_data::test_file().unwrap();
98
99    //     let f = File::open(&path).unwrap();
100    //     let mut reader = BufReader::new(f);
101    //     // Go to first basket
102    //     reader.seek(SeekFrom::Start(77881)).unwrap();
103    //     // size from fbasketbytes
104    //     let mut buf = vec![0; 87125];
105    //     reader.read_exact(&mut buf).unwrap();
106
107    //     println!("{:?}", tkey_header(&buf).unwrap().1);
108    //     // println!("{:#?}", tbasket(&buf, |i| count!(i, be_f32, 15)).unwrap().1);
109    //     println!("{:#?}", tbasket2vec(&buf));
110    // }
111}