Skip to main content

halfbit/data_cell/
content_stream.rs

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/* ContentStream ************************************************************/
39#[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}