1#![doc = document_features::document_features!()]
33#![cfg_attr(not(any(test, feature = "std")), no_std)]
42#![cfg_attr(docsrs, feature(doc_cfg))]
43
44extern crate alloc;
45
46pub use binrw;
48
49#[deprecated(
51 since = "0.2.3",
52 note = "Will be removed at the next major release. Use `abootimg_oxide::binrw::io::BufReader` instead."
53)]
54#[doc(no_inline)]
55#[cfg(feature = "std")]
56pub use binrw::io::BufReader;
57
58mod standard;
59mod vendor;
60mod version;
61
62#[binrw::binrw]
64#[derive(Clone, Debug, PartialEq, Eq, Hash)]
65#[brw(little)]
66pub enum EitherHeader {
67 Standard(
69 #[br(parse_with = |r, _, ()| Header::parse(r))]
71 #[bw(write_with = |hdr, w, _, ()| hdr.write(w))]
72 Header,
73 ),
74 Vendor(VendorHeader),
76}
77
78pub use standard::{Header, HeaderV0, HeaderV0Versioned, HeaderV3};
79pub use vendor::{VendorHeader, VendorHeaderV4};
80pub use version::{OsPatch, OsVersion, OsVersionPatch};
81
82#[cfg(test)]
83mod tests {
84 use alloc::string::ToString;
85 use alloc::vec::Vec;
86 use binrw::{io::Cursor, BinRead};
87
88 use super::*;
89
90 #[track_caller]
91 fn check<T: core::fmt::Debug, E: core::fmt::Display>(
92 res: Result<T, E>,
93 target_err_msgs: &[&str],
94 ) {
95 let s = res.unwrap_err().to_string();
96 for target in target_err_msgs {
97 assert!(
98 s.contains(target),
99 "---\\\n{s}\n\\--- should contain {target:?}"
100 );
101 }
102 }
103
104 #[test]
105 fn invalid_file_signature_either() {
106 let data = b"aaaaaaaa";
107 check(
108 EitherHeader::read(&mut Cursor::new(data)),
109 &["no variants matched", "bad magic"],
110 );
111 }
112 #[test]
113 fn invalid_version_either() {
114 let mut data = Vec::new();
115 data.extend_from_slice(b"ANDROID!");
116 data.append(&mut b"aaaa".repeat(8));
117 data.extend_from_slice(&u32::MAX.to_le_bytes());
118 data.extend_from_slice(b"aaaa");
119 data.append(&mut b"a".repeat(16 + 512 + 32 + 1024));
120
121 check(
122 HeaderV0::read(&mut Cursor::new(&data)),
123 &["invalid header version"],
124 );
125 }
126 #[test]
127 fn invalid_version_direct_v0() {
128 let mut data = Vec::new();
129 data.extend_from_slice(b"ANDROID!");
130 data.append(&mut b"aaaa".repeat(8));
131 data.extend_from_slice(&3u32.to_le_bytes());
132 data.extend_from_slice(b"aaaa");
133 data.append(&mut b"a".repeat(16 + 512 + 32 + 1024));
134
135 check(
136 HeaderV0::read(&mut Cursor::new(&data)),
137 &["invalid header version"],
138 );
139 }
140 #[test]
141 fn invalid_version_direct_v3() {
142 let mut data = Vec::new();
143 data.extend_from_slice(b"ANDROID!");
144 data.append(&mut b"aaaa".repeat(4));
145 data.append(&mut b"a".repeat(16));
146 data.extend_from_slice(&0u32.to_le_bytes());
147 data.append(&mut b"a".repeat(512 + 1024));
148
149 check(
150 HeaderV3::read(&mut Cursor::new(&data)),
151 &["invalid header version"],
152 );
153 }
154
155 #[test]
156 fn invalid_size_direct_v3() {
157 let mut data = Vec::new();
158 data.extend_from_slice(b"ANDROID!");
159 data.append(&mut b"aaaa".repeat(4));
160 data.append(&mut b"a".repeat(16));
161 data.extend_from_slice(&3u32.to_le_bytes());
162 data.append(&mut b"a".repeat(512 + 1024));
163
164 check(
165 HeaderV3::read(&mut Cursor::new(&data)),
166 &["invalid header size"],
167 );
168 }
169
170 #[test]
171 fn invalid_size_either_v3() {
172 let mut data = Vec::new();
173 data.extend_from_slice(b"ANDROID!");
174 data.append(&mut b"aaaa".repeat(4));
175 data.append(&mut b"a".repeat(16));
176 data.extend_from_slice(&3u32.to_le_bytes());
177 data.append(&mut b"a".repeat(512 + 1024));
178
179 check(
180 EitherHeader::read(&mut Cursor::new(&data)),
181 &["invalid header size"],
182 );
183 }
184}