physis/sqpack/
db.rs

1// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4use std::io::Cursor;
5
6use crate::ByteSpan;
7use crate::common_file_operations::read_string;
8use crate::common_file_operations::write_string;
9use crate::sqpack::SqPackHeader;
10use binrw::BinRead;
11use binrw::binrw;
12use binrw::helpers::until_eof;
13
14#[binrw]
15#[derive(Debug)]
16pub struct SQDBHeader {
17    size: u32,
18    #[br(pad_after = 1016)] // nothing
19    unk: u32,
20}
21
22// 264 bytes
23#[binrw]
24#[derive(Debug)]
25pub struct SQDBEntry {
26    #[br(pad_before = 4)] // 4 empty bytes
27    offset: u32, // TODO: just a guess, offset into what?
28    #[br(pad_after = 4)] // 4 more empty bytes
29    size: u32, // TODO: also a guess
30
31    // Corresponds to SplitPath hash
32    filename_hash: u32,
33    path_hash: u32,
34
35    // TODO: this is terrible, just read until string nul terminator
36    #[br(count = 240)]
37    #[br(map = read_string)]
38    #[bw(map = write_string)]
39    path: String,
40}
41
42#[binrw]
43#[derive(Debug)]
44#[brw(little)]
45pub struct SqPackDatabase {
46    sqpack_header: SqPackHeader,
47
48    header: SQDBHeader,
49
50    #[br(parse_with = until_eof)]
51    entries: Vec<SQDBEntry>,
52}
53
54impl SqPackDatabase {
55    /// Reads an existing SQDB file
56    pub fn from_existing(buffer: ByteSpan) -> Option<Self> {
57        let mut cursor = Cursor::new(buffer);
58        Self::read(&mut cursor).ok()
59    }
60}