qualia_core_db/
archive.rs1#[cfg(not(target_arch = "wasm32"))]
2use memmap2::MmapOptions;
3#[cfg(not(target_arch = "wasm32"))]
4use std::fs::File;
5#[cfg(not(target_arch = "wasm32"))]
6use std::io;
7#[cfg(not(target_arch = "wasm32"))]
8use std::io::{Cursor, Read};
9#[cfg(not(target_arch = "wasm32"))]
10use std::path::Path;
11
12pub const Q42_MAGIC: [u8; 4] = [0x51, 0x34, 0x32, 0x00]; #[repr(C, packed)]
17#[derive(Debug, Clone, Copy)]
18pub struct Q42Preamble {
19 pub magic: [u8; 4],
20 pub version: u16,
21 pub global_flags: u16,
22
23 pub dict_manifest_standard: [u16; 2],
26 pub dict_manifest_permissive: [u16; 2],
27 pub dict_manifest_bilateral: [u16; 2],
28 pub dict_manifest_spatiotemporal: [u16; 2],
29
30 pub index_manifest_standard: [u32; 2],
33 pub index_manifest_permissive: [u32; 2],
34 pub index_manifest_bilateral: [u32; 2],
35 pub index_manifest_spatiotemporal: [u32; 2],
36
37 pub eof_marker: u64,
38}
39
40#[repr(C, packed)]
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub struct Q42JumpEntry {
44 pub virtual_chunk_id: u32,
45 pub physical_offset_low: u32,
46 pub physical_offset_high: u16, pub frame_size: u16,
48}
49
50impl Q42JumpEntry {
51 pub fn physical_offset(&self) -> u64 {
52 (self.physical_offset_low as u64) | ((self.physical_offset_high as u64) << 32)
53 }
54}
55
56#[cfg(not(target_arch = "wasm32"))]
58pub struct Q42Archive {
59 mmap: memmap2::Mmap,
60}
61
62#[cfg(not(target_arch = "wasm32"))]
63impl Q42Archive {
64 pub fn open<P: AsRef<Path>>(path: P) -> io::Result<Self> {
66 let file = File::open(path)?;
67 let mmap = unsafe { MmapOptions::new().map(&file)? };
68
69 if mmap.len() < 64 {
70 return Err(io::Error::new(
71 io::ErrorKind::UnexpectedEof,
72 "File too small to contain Q42 Preamble",
73 ));
74 }
75
76 let archive = Self { mmap };
77 let preamble = archive.preamble();
78
79 if preamble.magic != Q42_MAGIC {
80 return Err(io::Error::new(
81 io::ErrorKind::InvalidData,
82 "Invalid Q42 Magic Number",
83 ));
84 }
85
86 Ok(archive)
87 }
88
89 pub fn preamble(&self) -> &Q42Preamble {
91 unsafe { &*(self.mmap.as_ptr() as *const Q42Preamble) }
92 }
93
94 pub fn read_jump_table(&self, offset: u32, size_bytes: u32) -> &[Q42JumpEntry] {
96 let start = offset as usize;
97 let end = start + size_bytes as usize;
98 let count = size_bytes as usize / std::mem::size_of::<Q42JumpEntry>();
99
100 unsafe {
101 std::slice::from_raw_parts(self.mmap[start..end].as_ptr() as *const Q42JumpEntry, count)
102 }
103 }
104
105 pub fn read_dictionary(&self, offset: u16, size_bytes: u16) -> &[u8] {
107 let start = 0x40 + offset as usize;
108 let end = start + size_bytes as usize;
109 &self.mmap[start..end]
110 }
111
112 pub fn decompress_frame(&self, entry: &Q42JumpEntry, dict: &[u8]) -> io::Result<Vec<u8>> {
114 let start = entry.physical_offset() as usize;
115 let end = start + entry.frame_size as usize;
116 let compressed_data = &self.mmap[start..end];
117
118 let mut decoder =
119 zstd::stream::Decoder::with_dictionary(Cursor::new(compressed_data), dict)?;
120 let mut output = Vec::with_capacity(128 * 1024);
121 decoder.read_to_end(&mut output)?;
122
123 Ok(output)
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use std::io::Write;
131 use tempfile::NamedTempFile;
132
133 #[test]
134 fn test_zero_deserialization_header_alignment() {
135 assert_eq!(std::mem::size_of::<Q42Preamble>(), 64);
136 assert_eq!(std::mem::size_of::<Q42JumpEntry>(), 12);
137 }
138
139 #[test]
140 fn test_q42_archive_mapping() {
141 let mut file = NamedTempFile::new().unwrap();
142
143 let preamble = Q42Preamble {
144 magic: Q42_MAGIC,
145 version: 1,
146 global_flags: 0,
147 dict_manifest_standard: [0, 0],
148 dict_manifest_permissive: [0, 0],
149 dict_manifest_bilateral: [0, 0],
150 dict_manifest_spatiotemporal: [0, 0],
151 index_manifest_standard: [0, 0],
152 index_manifest_permissive: [0, 0],
153 index_manifest_bilateral: [0, 0],
154 index_manifest_spatiotemporal: [0, 0],
155 eof_marker: 64,
156 };
157
158 unsafe {
159 let bytes = std::slice::from_raw_parts(&preamble as *const _ as *const u8, 64);
160 file.write_all(bytes).unwrap();
161 }
162
163 let archive = Q42Archive::open(file.path()).unwrap();
164 let mapped_preamble = archive.preamble();
165
166 let magic = mapped_preamble.magic;
167 let version = mapped_preamble.version;
168 let eof = mapped_preamble.eof_marker;
169
170 assert_eq!(magic, Q42_MAGIC);
171 assert_eq!(version, 1);
172 assert_eq!(eof, 64);
173 }
174}