img_archive_parser/
lib.rs1use byteorder::{LittleEndian, ReadBytesExt};
2use std::io::{Read, Seek, SeekFrom, Write};
3
4const IMG_HEADER: u32 = 0x32524556;
5const ENTRY_SIZE: u64 = 0x20;
6const SECTOR_SIZE: u32 = 0x800;
7
8#[repr(C)]
9#[derive(Debug)]
10pub struct Entry {
11 pub offset: u32,
12 pub streaming_size: u16,
13 pub archive_size: u16,
14 pub file_name: [u8; 24], }
16
17#[derive(Debug)]
18pub struct IMGArchive<B: Read + Seek> {
19 buffer: B,
20 entry_count: u32,
21}
22
23impl<B: Read + Seek> IMGArchive<B> {
24 pub fn new(mut buffer: B) -> Result<Self, Box<dyn std::error::Error>> {
25 let header = buffer.read_u32::<LittleEndian>()?;
26 if header != IMG_HEADER {
27 return Err("invalid .img file".into());
28 }
29 let entry_count = buffer.read_u32::<LittleEndian>()?;
30 Ok(IMGArchive {
31 buffer,
32 entry_count,
33 })
34 }
35
36 pub fn extract<W: Write>(&mut self, entry: &Entry, writer: &mut W) -> std::io::Result<()> {
37 let current_pos = self.buffer.stream_position()?;
38
39 let offset = (entry.offset as u64) * SECTOR_SIZE as u64;
43 let size = (entry.streaming_size as u32) * SECTOR_SIZE;
44
45 self.buffer.seek(SeekFrom::Start(offset))?;
46 let mut buffer = vec![0; size as usize];
47 self.buffer.read_exact(&mut buffer)?;
48 writer.write_all(&buffer)?;
49
50 self.buffer.seek(SeekFrom::Start(current_pos))?;
52
53 Ok(())
54 }
55}
56
57impl<B: Read + Seek> Iterator for IMGArchive<B> {
58 type Item = Result<Entry, Box<dyn std::error::Error>>;
59
60 fn next(&mut self) -> Option<Self::Item> {
61 let current_pos = match self.buffer.stream_position() {
62 Ok(pos) => pos,
63 Err(e) => return Some(Err(e.into())),
64 };
65 if (current_pos / ENTRY_SIZE) > self.entry_count as u64 {
66 return None;
67 }
68
69 let offset = match self.buffer.read_u32::<LittleEndian>() {
70 Ok(offset) => offset,
71 Err(e) => return Some(Err(e.into())),
72 };
73 let streaming_size = match self.buffer.read_u16::<LittleEndian>() {
74 Ok(size) => size,
75 Err(e) => return Some(Err(e.into())),
76 };
77 let archive_size = match self.buffer.read_u16::<LittleEndian>() {
78 Ok(size) => size,
79 Err(e) => return Some(Err(e.into())),
80 };
81
82 let mut file_name = [0u8; 24];
83 match self.buffer.read_exact(&mut file_name) {
84 Ok(_) => (),
85 Err(e) => return Some(Err(e.into())),
86 };
87
88 Some(Ok(Entry {
89 offset,
90 streaming_size,
91 archive_size,
92 file_name,
93 }))
94 }
95}