1use super::*;
2use byteorder::{ByteOrder, LittleEndian};
3use std::io::{Read, Result, SeekFrom};
4use std::mem;
5
6#[derive(Default, Debug)]
8pub struct FragmentsTab {
9 pub entries: Vec<FragmentEntry>,
10}
11
12#[derive(Default, Debug)]
13pub struct FragmentEntry {
14 pub start: u64,
15 pub size: u32,
16 pub compressed: bool,
17}
18
19#[repr(C)]
20#[derive(Default, Debug)]
21struct FragmentEntryInternal {
22 start: u64,
23 size: u32,
24 _padding: u32,
25}
26
27impl_converter!(FragmentEntryInternal);
28
29pub const FRAGMENT_SIZE: usize = mem::size_of::<FragmentEntryInternal>();
30pub const UNCOMPRESSED_FRAGMENT_FLAG: u32 = 0x1000_000;
31
32pub fn read_fragment_table(r: &mut SqsIoReader, sb: Superblock) -> Result<FragmentsTab> {
33 let mut blocks = sb.fragment_entry_count / 512;
34 if sb.fragment_entry_count % 512 > 0 {
35 blocks += 1;
36 }
37
38 let mut tab = FragmentsTab::default();
39 r.seek(SeekFrom::Start(sb.fragment_table_start))?;
40 let mut buf = [0u8; 8];
41 while blocks > 0 {
42 r.read_exact(&mut buf)?;
43
44 trace!("block={} buf={:?}", blocks, buf);
45
46 let offset = LittleEndian::read_u64(&buf);
47 let (metadata, _) = read_meta_block(r, sb.compressor, offset)?;
48
49 let total = metadata.len() / FRAGMENT_SIZE;
50 let mut idx = 0;
51 while idx < total {
52 let start = idx * FRAGMENT_SIZE;
53 let end = (idx + 1) * FRAGMENT_SIZE;
54 let fragment = parse_fragment(&mut &metadata[start..end])?;
55 tab.entries.push(fragment);
56 idx = idx + 1;
57 }
58
59 debug!(
60 "[read_fragment_table] total={}, parsed={}",
61 total,
62 tab.entries.len()
63 );
64
65 trace!("[read_fragment_table] parsed.fragment={:?}", tab.entries);
66
67 blocks -= 1;
68 }
69
70 Ok(tab)
71}
72
73fn is_uncompressed_fragment(s: u32) -> bool {
74 s & UNCOMPRESSED_FRAGMENT_FLAG == UNCOMPRESSED_FRAGMENT_FLAG
75}
76
77fn parse_fragment(metadata: &mut &[u8]) -> Result<FragmentEntry> {
78 if metadata.len() != FRAGMENT_SIZE {
79 return Err(invalid_error!("invalid fragment data, should has 16 bytes"));
80 }
81 trace!("[parse_fragment] bytes={:x?}, {:x?}", metadata, 1 << 24);
82 let mut internal = FragmentEntryInternal::default();
83 metadata.read_exact(&mut internal.as_mut())?;
84
85 Ok(FragmentEntry {
86 start: internal.start,
87 size: internal.size,
88 compressed: !is_uncompressed_fragment(internal.size),
89 })
90}
91
92#[cfg(test)]
93mod tests {
94 use crate::tests::*;
95 use crate::*;
96 use std::io::Result;
97
98 #[test]
99 #[cfg_attr(not(feature = "gzip-sqs"), ignore)]
100 fn test_read_fragment_table() -> Result<()> {
101 prepare_tests()?;
102 let (mut reader, sb) = prepare_tests()?;
103 read_fragment_table(&mut reader, sb)?;
104
105 Ok(())
106 }
107}