1extern crate alloc;
4
5mod archive_extra_data_record;
6mod central_directory_header;
7mod data_descriptor;
8mod digital_signature;
9mod end_of_central_directory;
10mod extensible_data;
11mod local_file_header;
12mod zip64_end_of_central_directory;
13
14#[cfg(feature = "std")] use std::error::Error;
15
16#[derive(Debug, PartialEq)]
17pub enum FixedSizeError {
18 UnsufficientExactBytes(usize),
22}
23
24#[derive(Debug, PartialEq)]
25pub enum DynamicSizeError {
26 NotContiguous(usize),
32 UnsufficientExactBytes(usize),
37 UnsufficientAtLeastBytes(usize),
46}
47
48#[derive(Debug, PartialEq)]
56pub enum DynamicSizeTotalSizeError {
57 Dynamic(DynamicSizeError),
58 TotalSizeInFieldIsInvalid,
59}
60
61pub(super) fn preview_u16_from_buf(buf: &[u8], pos: usize) -> Option<u16> {
62 buf.get(pos..pos + 2)
63 .map(|src| unsafe { u16::from_le_bytes(*(src as *const _ as *const [_; 2])) })
64}
65
66pub(super) fn validate_length<E, T: Fn(usize) -> E>(have: usize, want: usize, e: T) -> Result<(), E> {
68 if have < want {
69 return Err(e(want - have));
70 }
71 Ok(())
72}
73
74pub(super) fn validate_length_fixed<E, T: Fn(usize) -> E, T2>(
76 have: usize,
77 want: usize,
78 fixed: T2,
79 e: T,
80) -> Result<T2, (E, T2)> {
81 if have < want {
82 return Err((e(want - have), fixed));
83 }
84 Ok(fixed)
85}
86
87pub trait Parse {
88 type Error;
89
90 fn from_buf<T: bytes::Buf>(buf: &mut T) -> Result<Self, Self::Error>
93 where
94 Self: Sized;
95
96 fn to_buf<T: bytes::BufMut>(&self, buf: &mut T) -> Result<(), Self::Error>;
101}
102
103pub trait ParseExtend {
104 type Fixed;
105 type Error;
106
107 fn from_buf_fixed<T: bytes::Buf>(buf: &mut T, fixed: Self::Fixed) -> Result<Self, (Self::Error, Self::Fixed)>
111 where
112 Self: Sized;
113}
114
115impl FixedSizeError {
116 pub(super) fn in_dynamic(self) -> DynamicSizeError {
117 match self {
118 FixedSizeError::UnsufficientExactBytes(b) => DynamicSizeError::UnsufficientAtLeastBytes(b),
120 }
121 }
122}
123
124impl From<DynamicSizeError> for DynamicSizeTotalSizeError {
125 fn from(value: DynamicSizeError) -> Self { DynamicSizeTotalSizeError::Dynamic(value) }
126}
127
128impl core::fmt::Display for FixedSizeError {
129 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
130 match self {
131 FixedSizeError::UnsufficientExactBytes(n) => write!(
132 f,
133 "Unsufficient Bytes to parse structure, the buffer needs to have {n} additional bytes to parse"
134 ),
135 }
136 }
137}
138
139impl core::fmt::Display for DynamicSizeError {
140 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
141 match self {
142 DynamicSizeError::NotContiguous(n) => write!(
143 f,
144 "Bytes support data not beeing Continous, however to peek data its required that the data is within \
145 the first chunk of data. You need to reorganize the underlying data structure so that the first {n} \
146 bytes are within the first chun."
147 ),
148 DynamicSizeError::UnsufficientExactBytes(n) => write!(
149 f,
150 "Unsufficient Bytes to parse structure, the buffer needs to have {n} additional bytes to parse"
151 ),
152 DynamicSizeError::UnsufficientAtLeastBytes(n) => write!(
153 f,
154 "Unsufficient Bytes to parse structure, the buffer needs to have at least {n} additional bytes to \
155 parse, probably even more bytes are needed. An exact estimation cannot be made yet"
156 ),
157 }
158 }
159}
160
161impl core::fmt::Display for DynamicSizeTotalSizeError {
162 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
163 match self {
164 DynamicSizeTotalSizeError::Dynamic(e) => write!(f, "{e}"),
165 DynamicSizeTotalSizeError::TotalSizeInFieldIsInvalid => write!(
166 f,
167 "The Record contains an corrupt field stating the total size is lower than the minimum size"
168 ),
169 }
170 }
171}
172
173#[cfg(feature = "std")]
174impl Error for FixedSizeError {}
175#[cfg(feature = "std")]
176impl Error for DynamicSizeError {}
177#[cfg(feature = "std")]
178impl Error for DynamicSizeTotalSizeError {}
179
180#[inline(always)]
183#[allow(clippy::manual_find)] pub fn find_next_signature(buf: &[u8], signature: [u8; 4]) -> Option<usize> {
185 if buf.len() > 3 {
186 for i in 0..buf.len() - 3 {
187 if buf[i] == signature[0]
188 && buf[i + 1] == signature[1]
189 && buf[i + 2] == signature[2]
190 && buf[i + 3] == signature[3]
191 {
192 return Some(i);
193 }
194 }
195 }
196 None
197 }
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
209 fn find_next_signature_test() {
210 let buf = [1, 2, 3, 4, 5, 6, 7, 8];
211 assert_eq!(find_next_signature(&buf, [1, 2, 3, 4]), Some(0));
212 assert_eq!(find_next_signature(&buf, [2, 3, 4, 5]), Some(1));
213 assert_eq!(find_next_signature(&buf, [3, 4, 5, 6]), Some(2));
214 assert_eq!(find_next_signature(&buf, [4, 3, 2, 1]), None);
215 assert_eq!(find_next_signature(&buf, [0, 1, 2, 3]), None);
216 assert_eq!(find_next_signature(&buf, [6, 7, 8, 9]), None);
217 assert_eq!(find_next_signature(&buf, [5, 6, 7, 8]), Some(4));
218
219 let buf = [1, 2, 3];
220 assert_eq!(find_next_signature(&buf, [1, 2, 3, 4]), None);
221
222 let buf = [1, 2];
223 assert_eq!(find_next_signature(&buf, [1, 2, 3, 4]), None);
224
225 let buf = [];
226 assert_eq!(find_next_signature(&buf, [1, 2, 3, 4]), None);
227 }
228
229 #[test]
230 fn display_dont_panic() {
231 let mut buf = vec![0; 20000];
232 use std::io::Write;
233 write!(buf, "{}", FixedSizeError::UnsufficientExactBytes(1)).unwrap();
234 write!(buf, "{}", DynamicSizeError::NotContiguous(2)).unwrap();
235 write!(buf, "{}", DynamicSizeError::UnsufficientExactBytes(3)).unwrap();
236 write!(buf, "{}", DynamicSizeError::UnsufficientAtLeastBytes(4)).unwrap();
237 write!(
238 buf,
239 "{}",
240 DynamicSizeTotalSizeError::Dynamic(DynamicSizeError::NotContiguous(5))
241 )
242 .unwrap();
243 write!(buf, "{}", DynamicSizeTotalSizeError::TotalSizeInFieldIsInvalid).unwrap();
244 }
245}