hff_std/read/
api.rs

1use crate::{ReadSeek, StdReader};
2use hff_core::{
3    byteorder::ReadBytesExt,
4    read::{Hff, Inspection},
5    ByteOrder, Chunk, ChunkCache, Ecc, Endian, Error, Header, Result, Table, Version, BE, LE, NE,
6    OP,
7};
8use std::{io::Read, mem::size_of};
9
10/// Opens the input and maintains it for random access to the
11/// metadata and chunks.
12pub fn open(mut source: impl ReadSeek + 'static) -> Result<Hff<StdReader>> {
13    let (header, tables, chunks) = read_hff(&mut source)?;
14    Ok(Hff::new(StdReader::new(source), header, tables, chunks))
15}
16
17/// Reads an entire Hff into memory.
18pub fn read(source: &mut dyn Read) -> Result<Hff<ChunkCache>> {
19    let (header, tables, chunks, cache) = read_hff_full(source)?;
20    Ok(Hff::new(cache, header, tables, chunks))
21}
22
23/// Read the structure of a Hff into memory.  Provides access
24/// only to the structure without any of the metadata or chunk
25/// data available.
26pub fn inspect(source: &mut dyn Read) -> Result<Hff<Inspection>> {
27    let (header, tables, chunks) = read_hff(source)?;
28    Ok(Hff::new(Inspection, header, tables, chunks))
29}
30
31// Helpers to read hff from std::io::Read traits.
32
33pub(super) fn read_hff(reader: &mut dyn Read) -> Result<(Header, Vec<Table>, Vec<Chunk>)> {
34    // The header determines the structure endianess.
35    let header = read_header(reader)?;
36    let (tables, chunks) = if header.is_native_endian() {
37        (
38            read_tables::<NE>(reader, header.table_count())?,
39            read_chunks::<NE>(reader, header.chunk_count())?,
40        )
41    } else {
42        (
43            read_tables::<OP>(reader, header.table_count())?,
44            read_chunks::<OP>(reader, header.chunk_count())?,
45        )
46    };
47
48    Ok((header, tables, chunks))
49}
50
51fn read_hff_full(reader: &mut dyn Read) -> Result<(Header, Vec<Table>, Vec<Chunk>, ChunkCache)> {
52    let (header, tables, chunks) = read_hff(reader)?;
53
54    let mut buffer = vec![];
55    reader.read_to_end(&mut buffer)?;
56
57    let offset = size_of::<Header>()
58        + (size_of::<Table>() * tables.len())
59        + (size_of::<Chunk>() * chunks.len());
60    let cache = ChunkCache::new(offset, buffer);
61
62    Ok((header, tables, chunks, cache))
63}
64
65/// Read the header from a given stream.
66fn read_header(reader: &mut dyn Read) -> Result<Header> {
67    let mut magic = [0_u8; 8];
68    reader.read_exact(&mut magic)?;
69
70    // Detect the file content endianess.  NOTE: This only describes
71    // the file structure itself, the chunk content is "not" considered
72    // part of this.  It is up to the user to deal with endianess of
73    // the chunks.
74    match Ecc::HFF_MAGIC.endian(magic.into()) {
75        Some(endian) => match endian {
76            Endian::Little => Ok(Header::with(
77                magic.into(),
78                Version::read::<LE>(reader)?,
79                reader.read_u32::<LE>()?,
80                Ecc::read::<LE>(reader)?,
81                reader.read_u32::<LE>()?,
82                reader.read_u32::<LE>()?,
83            )),
84            Endian::Big => Ok(Header::with(
85                magic.into(),
86                Version::read::<BE>(reader)?,
87                reader.read_u32::<BE>()?,
88                Ecc::read::<BE>(reader)?,
89                reader.read_u32::<BE>()?,
90                reader.read_u32::<BE>()?,
91            )),
92        },
93        None => Err(Error::Invalid("Not an HFF file.".into())),
94    }
95}
96
97fn read_tables<E: ByteOrder>(reader: &mut dyn Read, count: u32) -> Result<Vec<Table>> {
98    if count > 0 {
99        // Create a buffer with appropriate size.
100        let mut buffer = vec![0; count as usize * size_of::<Table>()];
101        reader.read_exact(&mut buffer.as_mut_slice())?;
102
103        // Read all the tables out of the buffer.
104        let mut tables = vec![];
105        let reader: &mut dyn Read = &mut buffer.as_slice();
106        for _ in 0..count {
107            let table = Table::read::<E>(reader)?;
108            tables.push(table);
109        }
110
111        Ok(tables)
112    } else {
113        // TODO: Does an empty file make sense?  It's not an error but ....
114        Ok(vec![])
115    }
116}
117
118fn read_chunks<E: ByteOrder>(reader: &mut dyn Read, count: u32) -> Result<Vec<Chunk>> {
119    if count > 0 {
120        // Create a buffer with the appropriate size.
121        let mut buffer = vec![0; count as usize * size_of::<Chunk>()];
122        reader.read_exact(&mut buffer.as_mut_slice())?;
123
124        // Read the chunks out of the buffer.
125        let mut chunks = vec![];
126        let reader: &mut dyn Read = &mut buffer.as_slice();
127        for _ in 0..count {
128            let chunk = Chunk::read::<E>(reader)?;
129            chunks.push(chunk);
130        }
131        Ok(chunks)
132    } else {
133        // No chunks, perhaps they put all the real data into the metadata so this is
134        // still a viable file.
135        Ok(vec![])
136    }
137}