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::{CommonPackageData, 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 wide_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 path.to_string(),
89 CommonPackageData {
90 pkg_id: header.pkg_id,
91 patch_id: header.patch_id,
92 group_id: header.group_id,
93 entries,
94 blocks,
95 wide_hashes,
96 language: header.language,
97 },
98 )?,
99 header,
100 named_tags,
101 })
102 }
103}
104
105impl Package for PackageD2PreBL {
107 fn endianness(&self) -> Endian {
108 Endian::Little }
110
111 fn pkg_id(&self) -> u16 {
112 self.common.pkg_id
113 }
114
115 fn patch_id(&self) -> u16 {
116 self.common.patch_id
117 }
118
119 fn language(&self) -> PackageLanguage {
120 self.common.language
121 }
122
123 fn platform(&self) -> PackagePlatform {
124 self.header.platform
125 }
126
127 fn hash64_table(&self) -> Vec<UHashTableEntry> {
128 self.common
129 .wide_hashes
130 .iter()
131 .map(|h| UHashTableEntry {
132 hash64: h.hash64,
133 hash32: h.hash32,
134 reference: h.reference,
135 })
136 .collect()
137 }
138
139 fn named_tags(&self) -> Vec<PackageNamedTagEntry> {
140 self.named_tags.clone()
141 }
142
143 fn entries(&self) -> &[UEntryHeader] {
144 &self.common.entries_unified
145 }
146
147 fn entry(&self, index: usize) -> Option<UEntryHeader> {
148 self.common.entries_unified.get(index).cloned()
149 }
150
151 fn get_block(&self, index: usize) -> anyhow::Result<Arc<Vec<u8>>> {
152 self.common.get_block(index)
153 }
154}