Skip to main content

imagesize/
util.rs

1use crate::{ImageError, ImageResult};
2use std::io::{self, BufRead, Seek};
3
4/// Used for TIFF decoding
5pub enum Endian {
6    Little,
7    Big,
8}
9
10pub fn read_u64<R: BufRead + Seek>(reader: &mut R, endianness: &Endian) -> ImageResult<u64> {
11    let mut buf = [0; 8];
12    reader.read_exact(&mut buf)?;
13
14    match endianness {
15        Endian::Little => Ok(u64::from_le_bytes(buf)),
16        Endian::Big => Ok(u64::from_be_bytes(buf)),
17    }
18}
19
20pub fn read_i32<R: BufRead + Seek>(reader: &mut R, endianness: &Endian) -> ImageResult<i32> {
21    let mut attr_size_buf = [0; 4];
22    reader.read_exact(&mut attr_size_buf)?;
23    match endianness {
24        Endian::Little => Ok(i32::from_le_bytes(attr_size_buf)),
25        Endian::Big => Ok(i32::from_be_bytes(attr_size_buf)),
26    }
27}
28
29pub fn read_u32<R: BufRead + Seek>(reader: &mut R, endianness: &Endian) -> ImageResult<u32> {
30    let mut buf = [0; 4];
31    reader.read_exact(&mut buf)?;
32
33    match endianness {
34        Endian::Little => Ok(u32::from_le_bytes(buf)),
35        Endian::Big => Ok(u32::from_be_bytes(buf)),
36    }
37}
38
39pub fn read_u24<R: BufRead + Seek>(reader: &mut R, endianness: &Endian) -> ImageResult<u32> {
40    let mut buf = [0; 3];
41    reader.read_exact(&mut buf)?;
42
43    match endianness {
44        Endian::Little => Ok(((buf[2] as u32) << 16) | ((buf[1] as u32) << 8) | (buf[0] as u32)),
45        Endian::Big => Ok(((buf[0] as u32) << 16) | ((buf[1] as u32) << 8) | (buf[2] as u32)),
46    }
47}
48
49pub fn read_u16<R: BufRead + Seek>(reader: &mut R, endianness: &Endian) -> ImageResult<u16> {
50    let mut buf = [0; 2];
51    reader.read_exact(&mut buf)?;
52
53    match endianness {
54        Endian::Little => Ok(u16::from_le_bytes(buf)),
55        Endian::Big => Ok(u16::from_be_bytes(buf)),
56    }
57}
58
59pub fn read_u8<R: BufRead + Seek>(reader: &mut R) -> ImageResult<u8> {
60    let mut buf = [0; 1];
61    reader.read_exact(&mut buf)?;
62    Ok(buf[0])
63}
64
65pub fn read_bits(source: u128, num_bits: usize, offset: usize, size: usize) -> ImageResult<usize> {
66    if offset + num_bits < size {
67        Ok((source >> offset) as usize & ((1 << num_bits) - 1))
68    } else {
69        Err(ImageError::CorruptedImage)
70    }
71}
72
73/// Assumes tags are in format of 4 char string followed by big endian size for tag
74pub fn read_tag<R: BufRead + Seek>(reader: &mut R) -> ImageResult<(String, usize)> {
75    let mut tag_buf = [0; 4];
76    let size = read_u32(reader, &Endian::Big)? as usize;
77    reader.read_exact(&mut tag_buf)?;
78
79    Ok((String::from_utf8_lossy(&tag_buf).into_owned(), size))
80}
81
82pub fn read_until_capped<R: BufRead>(
83    reader: &mut R,
84    delimiter: u8,
85    max_size: usize,
86) -> io::Result<Vec<u8>> {
87    let mut bytes = Vec::new();
88    let mut amount_read = 0;
89
90    while amount_read < max_size {
91        let mut byte = [0; 1];
92        reader.read_exact(&mut byte)?;
93
94        if byte[0] == delimiter {
95            break;
96        }
97
98        bytes.push(byte[0]);
99        amount_read += 1;
100    }
101
102    if amount_read >= max_size {
103        return Err(io::Error::new(
104            io::ErrorKind::InvalidData,
105            format!("Delimiter not found within {} bytes", max_size),
106        ));
107    }
108
109    Ok(bytes)
110}
111
112/// Skips all starting whitespace characters and then reads a string until the next whitespace character
113/// Example:
114///     "    test   string" => "test"
115pub fn read_until_whitespace<R: BufRead>(reader: &mut R, max_size: usize) -> io::Result<String> {
116    let mut bytes = Vec::new();
117    let mut amount_read = 0;
118    let mut seen_non_whitespace = false;
119
120    while amount_read < max_size {
121        amount_read += 1;
122
123        let mut byte = [0; 1];
124        reader.read_exact(&mut byte)?;
125
126        if byte[0].is_ascii_whitespace() {
127            // If we've seen a non-whitespace character before then exit
128            if seen_non_whitespace {
129                break;
130            }
131
132            // Skip whitespace until we found first non-whitespace character
133            continue;
134        }
135
136        bytes.push(byte[0]);
137        seen_non_whitespace = true;
138    }
139
140    if amount_read >= max_size {
141        return Err(io::Error::new(
142            io::ErrorKind::InvalidData,
143            format!("Delimiter not found within {} bytes", max_size),
144        ));
145    }
146
147    String::from_utf8(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
148}
149
150pub fn read_line_capped<R: BufRead>(reader: &mut R, max_size: usize) -> io::Result<String> {
151    let bytes = read_until_capped(reader, b'\n', max_size)?;
152    String::from_utf8(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
153}
154
155pub fn read_null_terminated_string<R: BufRead>(
156    reader: &mut R,
157    max_size: usize,
158) -> io::Result<String> {
159    let bytes = read_until_capped(reader, 0, max_size)?;
160    String::from_utf8(bytes).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
161}