tiger_pkg/d2_prebl/
impl.rs1use std::{
2 fs::File,
3 io::{BufReader, Seek, SeekFrom},
4 sync::Arc,
5};
6
7use binrw::{BinReaderExt, Endian, VecArgs};
8
9use crate::{
10 d2_prebl::structs::PackageHeader,
11 d2_shared::{HashTableEntry, PackageCommonD2, PackageNamedTagEntry},
12 package::{Package, PackageLanguage, PackagePlatform, ReadSeek, UEntryHeader, UHashTableEntry},
13 DestinyVersion,
14};
15
16pub struct PackageD2PreBL {
17 common: PackageCommonD2,
18 pub header: PackageHeader,
19 pub named_tags: Vec<PackageNamedTagEntry>,
20}
21
22unsafe impl Send for PackageD2PreBL {}
23unsafe impl Sync for PackageD2PreBL {}
24
25impl PackageD2PreBL {
26 pub fn open(path: &str) -> anyhow::Result<PackageD2PreBL> {
27 let _span = tracing::trace_span!("PackageD2PreBL::open", path);
28 let reader = File::open(path)?;
29
30 Self::from_reader(path, reader)
31 }
32
33 pub fn from_reader<R: ReadSeek + 'static>(
34 path: &str,
35 reader: R,
36 ) -> anyhow::Result<PackageD2PreBL> {
37 let _span = tracing::trace_span!("PackageD2PreBL::from_reader", path);
38 let mut reader = BufReader::new(reader);
39 let header: PackageHeader = reader.read_le()?;
40
41 reader.seek(SeekFrom::Start(header.entry_table_offset as u64 - 16))?;
42 let entry_table_size_bytes = reader.read_le::<u32>()? * 16;
43
44 reader.seek(SeekFrom::Start(header.entry_table_offset as _))?;
45 let entries = reader.read_le_args(VecArgs {
46 count: header.entry_table_size as _,
47 inner: (),
48 })?;
49
50 reader.seek(SeekFrom::Start(
51 (header.entry_table_offset + entry_table_size_bytes + 32) as _,
52 ))?;
53 let blocks = reader.read_le_args(VecArgs {
54 count: header.block_table_size as _,
55 inner: (),
56 })?;
57
58 let hashes: Vec<HashTableEntry> = if header.misc_data_offset != 0 {
59 reader.seek(SeekFrom::Start((header.misc_data_offset + 0x30) as _))?;
60 let h64_table_size: u64 = reader.read_le()?;
61 let real_h64_table_offset: u64 = reader.read_le()?;
62 reader.seek(SeekFrom::Current(-8 + real_h64_table_offset as i64 + 16))?;
63 reader.read_le_args(VecArgs {
64 count: h64_table_size as _,
65 inner: (),
66 })?
67 } else {
68 vec![]
69 };
70
71 let named_tags: Vec<PackageNamedTagEntry> = if header.misc_data_offset != 0 {
72 reader.seek(SeekFrom::Start((header.misc_data_offset + 0x10) as _))?;
73 let named_tags_size: u64 = reader.read_le()?;
74 let real_named_tags_offset: u64 = reader.read_le()?;
75 reader.seek(SeekFrom::Current(-8 + real_named_tags_offset as i64 + 16))?;
76 reader.read_le_args(VecArgs {
77 count: named_tags_size as _,
78 inner: (),
79 })?
80 } else {
81 vec![]
82 };
83
84 Ok(PackageD2PreBL {
85 common: PackageCommonD2::new(
86 reader.into_inner(),
87 DestinyVersion::Destiny2Shadowkeep,
88 header.pkg_id,
89 header.patch_id,
90 header.group_id,
91 entries,
92 blocks,
93 hashes,
94 path.to_string(),
95 header.language,
96 )?,
97 header,
98 named_tags,
99 })
100 }
101}
102
103impl Package for PackageD2PreBL {
105 fn endianness(&self) -> Endian {
106 Endian::Little }
108
109 fn pkg_id(&self) -> u16 {
110 self.common.pkg_id
111 }
112
113 fn patch_id(&self) -> u16 {
114 self.common.patch_id
115 }
116
117 fn language(&self) -> PackageLanguage {
118 self.common.language
119 }
120
121 fn platform(&self) -> PackagePlatform {
122 self.header.platform
123 }
124
125 fn hash64_table(&self) -> Vec<UHashTableEntry> {
126 self.common
127 .hashes
128 .iter()
129 .map(|h| UHashTableEntry {
130 hash64: h.hash64,
131 hash32: h.hash32,
132 reference: h.reference,
133 })
134 .collect()
135 }
136
137 fn named_tags(&self) -> Vec<PackageNamedTagEntry> {
138 self.named_tags.clone()
139 }
140
141 fn entries(&self) -> &[UEntryHeader] {
142 &self.common.entries_unified
143 }
144
145 fn entry(&self, index: usize) -> Option<UEntryHeader> {
146 self.common.entries_unified.get(index).cloned()
147 }
148
149 fn get_block(&self, index: usize) -> anyhow::Result<Arc<Vec<u8>>> {
150 self.common.get_block(index)
151 }
152}