hff_async_std/read/
async_std_reader.rs

1use super::ReadSeek;
2use async_std::{
3    io::{prelude::SeekExt, ReadExt},
4    sync::{Mutex, MutexGuard},
5};
6use hff_core::{
7    byteorder::ReadBytesExt, ByteOrder, Chunk, ChunkCache, ContentInfo, Ecc, Endian, Error, Header,
8    Result, Table, Version, BE, LE,
9};
10use std::mem::size_of;
11
12/// Implements a std reader wrapper around the source.
13pub struct AsyncStdReader {
14    source: Mutex<Box<dyn ReadSeek>>,
15}
16
17impl std::fmt::Debug for AsyncStdReader {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        write!(f, "AsyncStdReader")
20    }
21}
22
23impl AsyncStdReader {
24    /// Create a new std reader type.
25    pub fn new(source: impl ReadSeek + 'static) -> Self {
26        Self {
27            source: Mutex::new(Box::new(source)),
28        }
29    }
30
31    /// Read the given content.
32    pub async fn read(&self, content: &dyn ContentInfo) -> Result<Vec<u8>> {
33        let mut source = self.source.lock().await;
34        source
35            .seek(std::io::SeekFrom::Start(content.offset()))
36            .await?;
37        let mut result = vec![0; content.len() as usize];
38        source.read_exact(result.as_mut_slice()).await?;
39        Ok(result)
40    }
41
42    /// Get he appropriate reader implementation.
43    pub async fn reader(
44        &self,
45        content: impl ContentInfo,
46    ) -> Result<MutexGuard<'_, Box<dyn ReadSeek>>> {
47        let mut source = self.source.lock().await;
48        source
49            .seek(std::io::SeekFrom::Start(content.offset()))
50            .await?;
51        Ok(source)
52    }
53
54    /// Read the header from the given stream.
55    pub(super) async fn read_header(
56        reader: &mut (dyn async_std::io::Read + std::marker::Unpin),
57    ) -> Result<Header> {
58        // Read in the entire header ignorant of the endian.
59        let mut header = [0_u8; Header::SIZE];
60        reader.read_exact(&mut header).await?;
61
62        // Build a byte reader from the buffer.
63        let reader: &mut dyn std::io::Read = &mut header.as_slice();
64
65        // Read out the magic value to detect endian.
66        let magic = reader.read_u64::<LE>()?;
67
68        // Detect the file content endianess.  NOTE: This only describes
69        // the file structure itself, the chunk content is "not" considered
70        // part of this.  It is up to the user to deal with endianess of
71        // the chunks.
72        match Ecc::HFF_MAGIC.endian(magic.into()) {
73            Some(endian) => match endian {
74                Endian::Little => Ok(Header::with(
75                    magic.into(),
76                    Version::read::<LE>(reader)?,
77                    reader.read_u32::<LE>()?,
78                    Ecc::read::<LE>(reader)?,
79                    reader.read_u32::<LE>()?,
80                    reader.read_u32::<LE>()?,
81                )),
82                Endian::Big => Ok(Header::with(
83                    magic.into(),
84                    Version::read::<BE>(reader)?,
85                    reader.read_u32::<BE>()?,
86                    Ecc::read::<BE>(reader)?,
87                    reader.read_u32::<BE>()?,
88                    reader.read_u32::<BE>()?,
89                )),
90            },
91            None => Err(Error::Invalid("Not an HFF file.".into())),
92        }
93    }
94
95    /// Read the tables from the given stream.
96    pub(super) async fn read_tables<E: ByteOrder>(
97        reader: &mut (dyn async_std::io::Read + std::marker::Unpin),
98        count: u32,
99    ) -> Result<Vec<Table>> {
100        if count > 0 {
101            // Create a buffer with appropriate size.
102            let mut buffer = vec![0; count as usize * std::mem::size_of::<Table>()];
103            reader.read_exact(&mut buffer.as_mut_slice()).await?;
104
105            // Read all the tables out of the buffer.
106            let mut tables = vec![];
107            let reader: &mut dyn std::io::Read = &mut buffer.as_slice();
108            for _ in 0..count {
109                let table = Table::read::<E>(reader)?;
110                tables.push(table);
111            }
112
113            Ok(tables)
114        } else {
115            // TODO: Does an empty file make sense?  It's not an error but ....
116            Ok(vec![])
117        }
118    }
119
120    /// Read the chunks from the given stream.
121    pub(super) async fn read_chunks<E: ByteOrder>(
122        reader: &mut (dyn async_std::io::Read + std::marker::Unpin),
123        count: u32,
124    ) -> Result<Vec<Chunk>> {
125        if count > 0 {
126            // Create a buffer with the appropriate size.
127            let mut buffer = vec![0; count as usize * std::mem::size_of::<Chunk>()];
128            reader.read_exact(&mut buffer.as_mut_slice()).await?;
129
130            // Read the chunks out of the buffer.
131            let mut chunks = vec![];
132            let reader: &mut dyn std::io::Read = &mut buffer.as_slice();
133            for _ in 0..count {
134                let chunk = Chunk::read::<E>(reader)?;
135                chunks.push(chunk);
136            }
137            Ok(chunks)
138        } else {
139            // No chunks, perhaps they put all the real data into the metadata so this is
140            // still a viable file.
141            Ok(vec![])
142        }
143    }
144
145    /// Read the body of data from the given stream.  Assumes the stream
146    /// has an 'end' to read to.
147    pub(super) async fn read_body(
148        reader: &mut (dyn async_std::io::Read + std::marker::Unpin),
149        tables: usize,
150        chunks: usize,
151    ) -> Result<ChunkCache> {
152        let mut buffer = vec![];
153        reader.read_to_end(&mut buffer).await?;
154
155        let offset = Header::SIZE + size_of::<Table>() * tables + size_of::<Chunk>() * chunks;
156        Ok(ChunkCache::new(offset, buffer))
157    }
158}