chat4n6_sqlite_forensics/
record.rs1use chat4n6_plugin_api::EvidenceSource;
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum SqlValue {
5 Null,
6 Int(i64),
7 Real(f64),
8 Text(String),
9 Blob(Vec<u8>),
10}
11
12#[derive(Debug, Clone)]
13pub struct RecoveredRecord {
14 pub table: String,
15 pub row_id: Option<i64>,
16 pub values: Vec<SqlValue>,
17 pub source: EvidenceSource,
18 pub offset: u64,
19 pub confidence: f32,
21}
22
23pub fn decode_serial_type(
26 serial_type: u64,
27 data: &[u8],
28 offset: usize,
29) -> Option<(SqlValue, usize)> {
30 match serial_type {
31 0 => Some((SqlValue::Null, 0)),
32 1 => {
33 let b = *data.get(offset)?;
34 Some((SqlValue::Int(b as i8 as i64), 1))
35 }
36 2 => {
37 let bytes = data.get(offset..offset + 2)?;
38 let v = i16::from_be_bytes([bytes[0], bytes[1]]) as i64;
39 Some((SqlValue::Int(v), 2))
40 }
41 3 => {
42 let bytes = data.get(offset..offset + 3)?;
43 let v = ((bytes[0] as i32) << 16 | (bytes[1] as i32) << 8 | bytes[2] as i32) as i64;
44 let v = if v & 0x800000 != 0 { v | !0xFFFFFF } else { v };
46 Some((SqlValue::Int(v), 3))
47 }
48 4 => {
49 let bytes = data.get(offset..offset + 4)?;
50 let v = i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as i64;
51 Some((SqlValue::Int(v), 4))
52 }
53 5 => {
54 let bytes = data.get(offset..offset + 6)?;
55 let v = (bytes[0] as i64) << 40
56 | (bytes[1] as i64) << 32
57 | (bytes[2] as i64) << 24
58 | (bytes[3] as i64) << 16
59 | (bytes[4] as i64) << 8
60 | bytes[5] as i64;
61 let v = if v & (1i64 << 47) != 0 {
63 v | !0xFFFFFFFFFFFFi64
64 } else {
65 v
66 };
67 Some((SqlValue::Int(v), 6))
68 }
69 6 => {
70 let bytes = data.get(offset..offset + 8)?;
71 let v = i64::from_be_bytes([
72 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
73 ]);
74 Some((SqlValue::Int(v), 8))
75 }
76 7 => {
77 let bytes = data.get(offset..offset + 8)?;
78 let v = f64::from_be_bytes([
79 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
80 ]);
81 Some((SqlValue::Real(v), 8))
82 }
83 8 => Some((SqlValue::Int(0), 0)),
84 9 => Some((SqlValue::Int(1), 0)),
85 n if n >= 12 && n % 2 == 0 => {
86 let len = ((n - 12) / 2) as usize;
87 let bytes = data.get(offset..offset + len)?;
88 Some((SqlValue::Blob(bytes.to_vec()), len))
89 }
90 n if n >= 13 && n % 2 == 1 => {
91 let len = ((n - 13) / 2) as usize;
92 let bytes = data.get(offset..offset + len)?;
93 let text = String::from_utf8_lossy(bytes).into_owned();
94 Some((SqlValue::Text(text), len))
95 }
96 _ => None,
97 }
98}