1use core::cell::RefCell;
2
3use crate::ExecutionContext;
4use crate::conv::int_be_decode;
5use crate::data_cell::DCOVector;
6use crate::data_cell::DataCell;
7use crate::data_cell::DataCellOpsMut;
8use crate::data_cell::Error;
9use crate::data_cell::Record;
10use crate::data_cell::RecordDesc;
11use crate::data_cell::U64Cell;
12use crate::data_cell::output_byte_slice_as_human_readable_text;
13use crate::io::ErrorCode as IOErrorCode;
14use crate::io::IOPartialError;
15use crate::io::IOPartialResult;
16use crate::io::stream::RandomAccessRead;
17use crate::io::stream::SeekFrom;
18use crate::io::stream::Write;
19use crate::mm::Vector;
20use crate::num::fmt as num_fmt;
21
22pub const ELFCLASSNONE: u8 = 0;
23pub const ELFCLASS32: u8 = 1;
24pub const ELFCLASS64: u8 = 2;
25
26pub const ELFDATANONE: u8 = 0;
27pub const ELFDATA2LSB: u8 = 1;
28pub const ELFDATA2MSB: u8 = 2;
29
30const ELF_HEADER: RecordDesc<'static> = RecordDesc::new(
31 "elf_header",
32 &[
33 "ei_magic", "ei_class", "ei_data", "ei_version",
34 "ei_osabi", "ei_abiversion", "ei_pad",
35 "e_type", "e_machine", "e_version", "e_entry", "e_phoff", "e_shoff",
36 ]);
37
38#[derive(Debug)]
40pub struct ContentStream<'a, T: ?Sized + RandomAccessRead> {
41 stream: &'a mut T
42}
43
44impl<'a, T: ?Sized + RandomAccessRead> ContentStream<'a, T> {
45
46 pub fn new(stream: &'a mut T) -> Self {
47 ContentStream { stream }
48 }
49 fn extract_first_byte <'x>(
50 &mut self,
51 xc: &mut ExecutionContext<'x>,
52 ) -> Result<DataCell<'x>, Error<'x>> {
53 self.stream.seek(SeekFrom::Start(0), xc)
54 .map_err(|e| IOPartialError::from_error_and_size(e, 0))
55 .and_then(|_| self.stream.read_u8(xc))
56 .map(|v| DataCell::U64(U64Cell {
57 n: v as u64,
58 fmt_pack: num_fmt::MiniNumFmtPack::new(
59 num_fmt::Radix::new(16).unwrap(),
60 num_fmt::RadixNotation::DefaultExplicitPrefix,
61 num_fmt::MinDigitCount::new(2).unwrap(),
62 num_fmt::PositiveSign::Hidden,
63 num_fmt::ZeroSign::Hidden)
64 }))
65 .map_err(|e|
66 if e.get_error_code() == IOErrorCode::UnexpectedEnd {
67 Error::NotApplicable
68 } else {
69 Error::IO(e.to_error())
70 })
71 }
72
73 fn first_8_bytes<'x>(
74 &mut self,
75 xc: &mut ExecutionContext<'x>,
76 ) -> Result<DataCell<'x>, Error<'x>> {
77 let mut buf = [0_u8; 8];
78 let n = self.stream.seek_read(0, &mut buf, xc)?;
79 Ok(DataCell::from_byte_slice(xc.get_main_allocator(), &buf[0..n])?)
80 }
81
82 pub fn identify_top_of_file_records<'x>(
83 &mut self,
84 xc: &mut ExecutionContext<'x>,
85 ) -> Result<DataCell<'x>, Error<'x>> {
86 let mut ids: Vector<'x, DataCell> = Vector::new(xc.get_main_allocator());
87 let mut tof_buffer = [0_u8; 0x40];
88 let tof_len = self.stream.seek_read(0, &mut tof_buffer, xc)?;
89 let tof = &tof_buffer[0..tof_len];
90 if tof_len == 0 {
91 ids.push(DataCell::StaticId("empty"))?;
92 } else if tof.starts_with(b"PK") {
93 ids.push(DataCell::StaticId("zip_record"))?;
94 } else if tof.starts_with(b"#!") {
95 ids.push(DataCell::StaticId("shebang"))?;
96 } else if tof.starts_with(b"\x7FELF") {
97 ids.push(DataCell::StaticId("elf"))?;
98 } else if tof.starts_with(b"MZ") {
99 ids.push(DataCell::StaticId("dos_exe"))?;
100 } else if tof.starts_with(b"ZM") {
101 ids.push(DataCell::StaticId("dos_exe"))?;
102 ids.push(DataCell::StaticId("dos_exe_zm"))?;
103 } else if tof.starts_with(b"\x1F\x8B") {
104 ids.push(DataCell::StaticId("gzip"))?;
105 } else if tof.starts_with(b"BZh") {
106 ids.push(DataCell::StaticId("bzip2"))?;
107 } else if tof.starts_with(b"\xFD7zXZ\x00") {
108 ids.push(DataCell::StaticId("xz"))?;
109 } else if tof.starts_with(b"7z\xBC\xAF\x27\x1C") {
110 ids.push(DataCell::StaticId("seven_zip"))?;
111 } else if tof.starts_with(b"!<arch>\n") {
112 ids.push(DataCell::StaticId("ar"))?;
113 } else if tof.starts_with(b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1") {
114 ids.push(DataCell::StaticId("ms_cfb"))?;
115 } else if tof.starts_with(b"QFI\xFB") {
116 ids.push(DataCell::StaticId("qcow"))?;
117 if tof_len >= 8 {
118 let ver: u32 = int_be_decode(&tof[4..8]).unwrap();
119 match ver {
120 1 => ids.push(DataCell::StaticId("qcow1"))?,
121 2 => ids.push(DataCell::StaticId("qcow2"))?,
122 3 => ids.push(DataCell::StaticId("qcow3"))?,
123 _ => {}
124 }
125 }
126 } else if tof.starts_with(b"SQLite format 3\x00") {
127 ids.push(DataCell::StaticId("sqlite3"))?;
128 } else if tof.starts_with(b"qres\x00\x00\x00\x01") {
129 ids.push(DataCell::StaticId("qt_rcc"))?;
130 }
131 Ok(DataCell::CellVector(xc.rc(RefCell::new(DCOVector(ids)))?))
132 }
133
134 fn extract_elf_header<'x>(
135 &mut self,
136 xc: &mut ExecutionContext<'x>,
137 ) -> Result<DataCell<'x>, Error<'x>> {
138
139 let a = xc.get_main_allocator();
140 let mut eh = Record::new(&ELF_HEADER, a)?;
141
142
143 let mut magic = [0_u8; 4];
144 self.stream.seek_read(0, &mut magic, xc)?;
145 eh.set_field("ei_magic", DataCell::from_byte_slice(a, &magic)?);
146
147 let ei_class = self.stream.read_u8(xc)?;
148 eh.set_field("ei_class", match ei_class {
149 0 => DataCell::from_static_id("ELFCLASSNONE"),
150 1 => DataCell::from_static_id("ELFCLASS32"),
151 2 => DataCell::from_static_id("ELFCLASS64"),
152 n => DataCell::from_u64(n.into()),
153 });
154
155 let ei_data = self.stream.read_u8(xc)?;
156 eh.set_field("ei_data", match ei_data {
157 0 => DataCell::from_static_id("ELFDATANONE"),
158 1 => DataCell::from_static_id("ELFDATA2LSB"),
159 2 => DataCell::from_static_id("ELFDATA2MSB"),
160 n => DataCell::from_u64(n.into()),
161 });
162
163 let ei_version = match self.stream.read_u8(xc)? {
164 0 => DataCell::from_static_id("EV_NONE"),
165 1 => DataCell::from_static_id("EV_CURRENT"),
166 n => DataCell::from_u64(n.into()),
167 };
168 eh.set_field("ei_version", ei_version);
169
170 let ei_osabi = match self.stream.read_u8(xc)? {
171 0 => DataCell::from_static_id("ELFOSABI_NONE"),
172 1 => DataCell::from_static_id("ELFOSABI_HPUX"),
173 2 => DataCell::from_static_id("ELFOSABI_NETBSD"),
174 3 => DataCell::from_static_id("ELFOSABI_LINUX"),
175 6 => DataCell::from_static_id("ELFOSABI_SOLARIS"),
176 7 => DataCell::from_static_id("ELFOSABI_AIX"),
177 8 => DataCell::from_static_id("ELFOSABI_IRIX"),
178 9 => DataCell::from_static_id("ELFOSABI_FREEBSD"),
179 10 => DataCell::from_static_id("ELFOSABI_TRU64"),
180 11 => DataCell::from_static_id("ELFOSABI_MODESTO"),
181 12 => DataCell::from_static_id("ELFOSABI_OPENBSD"),
182 13 => DataCell::from_static_id("ELFOSABI_OPENVMS"),
183 14 => DataCell::from_static_id("ELFOSABI_NSK"),
184 n => DataCell::from_u64(n.into()),
185 };
186 eh.set_field("ei_osabi", ei_osabi);
187
188 let ei_abiversion = self.stream.read_u8(xc)?;
189 eh.set_field("ei_abiversion", DataCell::from_u64(ei_abiversion.into()));
190
191 let mut ei_pad = [0_u8; 7];
192 self.stream.read_uninterrupted(&mut ei_pad, xc)?;
193 eh.set_field("ei_pad", DataCell::from_byte_slice(a, &ei_pad)?);
194
195 fn read_u16le_as_u64<'x, T: ?Sized + RandomAccessRead>(r: &mut T, xc: &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64> {
196 r.read_u16le(xc).map(|v| v as u64)
197 }
198 fn read_u16be_as_u64<'x, T: ?Sized + RandomAccessRead>(r: &mut T, xc: &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64> {
199 r.read_u16be(xc).map(|v| v as u64)
200 }
201 fn read_u32le_as_u64<'x, T: ?Sized + RandomAccessRead>(r: &mut T, xc: &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64> {
202 r.read_u32le(xc).map(|v| v as u64)
203 }
204 fn read_u32be_as_u64<'x, T: ?Sized + RandomAccessRead>(r: &mut T, xc: &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64> {
205 r.read_u32be(xc).map(|v| v as u64)
206 }
207 fn read_u64le_as_u64<'x, T: ?Sized + RandomAccessRead>(r: &mut T, xc: &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64> {
208 r.read_u64le(xc).map(|v| v as u64)
209 }
210 fn read_u64be_as_u64<'x, T: ?Sized + RandomAccessRead>(r: &mut T, xc: &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64> {
211 r.read_u64be(xc).map(|v| v as u64)
212 }
213 let read_half: &dyn Fn(&mut T, &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64>;
214 let read_word: &dyn Fn(&mut T, &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64>;
215 let read_addr: &dyn Fn(&mut T, &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64>;
216 let read_off: &dyn Fn(&mut T, &mut ExecutionContext<'x>) -> IOPartialResult<'x, u64>;
217 if ei_data == ELFDATA2LSB && ei_class == ELFCLASS32 {
218 read_half = &read_u16le_as_u64;
219 read_word = &read_u32le_as_u64;
220 read_addr = &read_u32le_as_u64;
221 read_off = &read_u32le_as_u64;
222 } else if ei_data == ELFDATA2MSB && ei_class == ELFCLASS32 {
223 read_half = &read_u16be_as_u64;
224 read_word = &read_u32be_as_u64;
225 read_addr = &read_u32be_as_u64;
226 read_off = &read_u32be_as_u64;
227 } else if ei_data == ELFDATA2LSB && ei_class == ELFCLASS64 {
228 read_half = &read_u16le_as_u64;
229 read_word = &read_u32le_as_u64;
230 read_addr = &read_u64le_as_u64;
231 read_off = &read_u64le_as_u64;
232 } else if ei_data == ELFDATA2MSB && ei_class == ELFCLASS64 {
233 read_half = &read_u16be_as_u64;
234 read_word = &read_u32be_as_u64;
235 read_addr = &read_u64be_as_u64;
236 read_off = &read_u64be_as_u64;
237 } else {
238 return Ok(DataCell::Record(xc.rc(RefCell::new(eh))?))
239 }
240
241 let e_type = read_half(&mut self.stream, xc)?;
242 eh.set_field("e_type", DataCell::from_u64(e_type));
243
244 let e_machine = read_half(&mut self.stream, xc)?;
245 eh.set_field("e_machine", DataCell::from_u64(e_machine));
246
247 let e_version = read_word(&mut self.stream, xc)?;
248 eh.set_field("e_version", DataCell::from_u64(e_version));
249
250 let e_entry = read_addr(&mut self.stream, xc)?;
251 eh.set_field("e_entry", DataCell::from_u64_cell(U64Cell::hex(e_entry)));
252
253 let e_phoff = read_off(&mut self.stream, xc)?;
254 eh.set_field("e_phoff", DataCell::from_u64_cell(U64Cell::hex(e_phoff)));
255
256 let e_shoff = read_off(&mut self.stream, xc)?;
257 eh.set_field("e_shoff", DataCell::from_u64_cell(U64Cell::hex(e_shoff)));
258
259 Ok(DataCell::Record(xc.rc(RefCell::new(eh))?))
260 }
261
262}
263impl<'a, T: ?Sized + RandomAccessRead> DataCellOpsMut for ContentStream<'a, T> {
264
265 fn get_property_mut<'x>(
266 &mut self,
267 property_name: &str,
268 xc: &mut ExecutionContext<'x>,
269 ) -> Result<DataCell<'x>, Error<'x>> {
270 match property_name {
271 "fourty_two" => Ok(DataCell::U64(U64Cell::new(42))),
272 "first_byte" => self.extract_first_byte(xc),
273 "first_8_bytes" => self.first_8_bytes(xc),
274 "tof_ids" => self.identify_top_of_file_records(xc),
275 "elf_header" => self.extract_elf_header(xc),
276 _ => Err(Error::NotApplicable),
277 }
278 }
279
280 fn output_as_human_readable_mut<'w, 'x>(
281 &mut self,
282 out: &mut (dyn Write + 'w),
283 xc: &mut ExecutionContext<'x>,
284 ) -> Result<(), Error<'x>> {
285 self.stream.seek(SeekFrom::Start(0), xc)?;
286 let mut buffer = [0_u8; 1024];
287 loop {
288 let n = self.stream.read(&mut buffer, xc)?;
289 if n == 0 { break; }
290 output_byte_slice_as_human_readable_text(&buffer[0..n], out, xc)?;
291 }
292 Ok(())
293 }
294
295}