1use crate::{DbcHeader, Error, Result};
4use std::io::{Read, Seek, SeekFrom};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum DbcVersion {
9 WDBC,
11 WDB2,
13 WDB3,
15 WDB4,
17 WDB5,
19}
20
21impl DbcVersion {
22 pub fn detect<R: Read + Seek>(reader: &mut R) -> Result<Self> {
24 reader.seek(SeekFrom::Start(0))?;
25
26 let mut magic = [0u8; 4];
27 reader.read_exact(&mut magic)?;
28
29 match &magic {
30 b"WDBC" => Ok(DbcVersion::WDBC),
31 b"WDB2" => Ok(DbcVersion::WDB2),
32 b"WDB3" => Ok(DbcVersion::WDB3),
33 b"WDB4" => Ok(DbcVersion::WDB4),
34 b"WDB5" => Ok(DbcVersion::WDB5),
35 _ => Err(Error::InvalidHeader(format!(
36 "Unknown DBC version: {:?}",
37 std::str::from_utf8(&magic).unwrap_or("Invalid UTF-8")
38 ))),
39 }
40 }
41
42 pub fn magic(&self) -> [u8; 4] {
44 match self {
45 DbcVersion::WDBC => *b"WDBC",
46 DbcVersion::WDB2 => *b"WDB2",
47 DbcVersion::WDB3 => *b"WDB3",
48 DbcVersion::WDB4 => *b"WDB4",
49 DbcVersion::WDB5 => *b"WDB5",
50 }
51 }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub struct Wdb2Header {
57 pub magic: [u8; 4],
59 pub record_count: u32,
61 pub field_count: u32,
63 pub record_size: u32,
65 pub string_block_size: u32,
67 pub table_hash: u32,
69 pub build: u32,
71}
72
73impl Wdb2Header {
74 pub const SIZE: usize = 28;
76
77 pub fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
79 reader.seek(SeekFrom::Start(0))?;
81
82 let mut magic = [0u8; 4];
84 reader.read_exact(&mut magic)?;
85
86 if magic != *b"WDB2" {
88 return Err(Error::InvalidHeader(format!(
89 "Invalid magic signature: {:?}, expected: {:?}",
90 magic, b"WDB2"
91 )));
92 }
93
94 let mut buf = [0u8; 4];
96
97 reader.read_exact(&mut buf)?;
98 let record_count = u32::from_le_bytes(buf);
99
100 reader.read_exact(&mut buf)?;
101 let field_count = u32::from_le_bytes(buf);
102
103 reader.read_exact(&mut buf)?;
104 let record_size = u32::from_le_bytes(buf);
105
106 reader.read_exact(&mut buf)?;
107 let string_block_size = u32::from_le_bytes(buf);
108
109 reader.read_exact(&mut buf)?;
110 let table_hash = u32::from_le_bytes(buf);
111
112 reader.read_exact(&mut buf)?;
113 let build = u32::from_le_bytes(buf);
114
115 Ok(Self {
116 magic,
117 record_count,
118 field_count,
119 record_size,
120 string_block_size,
121 table_hash,
122 build,
123 })
124 }
125
126 pub fn to_dbc_header(&self) -> DbcHeader {
128 DbcHeader {
129 magic: *b"WDBC", record_count: self.record_count,
131 field_count: self.field_count,
132 record_size: self.record_size,
133 string_block_size: self.string_block_size,
134 }
135 }
136
137 pub fn string_block_offset(&self) -> u64 {
139 Self::SIZE as u64 + (self.record_count as u64 * self.record_size as u64)
140 }
141
142 pub fn total_size(&self) -> u64 {
144 self.string_block_offset() + self.string_block_size as u64
145 }
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150pub struct Wdb5Header {
151 pub magic: [u8; 4],
153 pub record_count: u32,
155 pub field_count: u32,
157 pub record_size: u32,
159 pub string_block_size: u32,
161 pub table_hash: u32,
163 pub layout_hash: u32,
165 pub min_id: u32,
167 pub max_id: u32,
169 pub locale: u32,
171 pub flags: u16,
173 pub id_index: u16,
175}
176
177impl Wdb5Header {
178 pub const SIZE: usize = 48;
180
181 pub fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
183 reader.seek(SeekFrom::Start(0))?;
185
186 let mut magic = [0u8; 4];
188 reader.read_exact(&mut magic)?;
189
190 if magic != *b"WDB5" {
192 return Err(Error::InvalidHeader(format!(
193 "Invalid magic signature: {:?}, expected: {:?}",
194 magic, b"WDB5"
195 )));
196 }
197
198 let mut buf4 = [0u8; 4];
200 let mut buf2 = [0u8; 2];
201
202 reader.read_exact(&mut buf4)?;
203 let record_count = u32::from_le_bytes(buf4);
204
205 reader.read_exact(&mut buf4)?;
206 let field_count = u32::from_le_bytes(buf4);
207
208 reader.read_exact(&mut buf4)?;
209 let record_size = u32::from_le_bytes(buf4);
210
211 reader.read_exact(&mut buf4)?;
212 let string_block_size = u32::from_le_bytes(buf4);
213
214 reader.read_exact(&mut buf4)?;
215 let table_hash = u32::from_le_bytes(buf4);
216
217 reader.read_exact(&mut buf4)?;
218 let layout_hash = u32::from_le_bytes(buf4);
219
220 reader.read_exact(&mut buf4)?;
221 let min_id = u32::from_le_bytes(buf4);
222
223 reader.read_exact(&mut buf4)?;
224 let max_id = u32::from_le_bytes(buf4);
225
226 reader.read_exact(&mut buf4)?;
227 let locale = u32::from_le_bytes(buf4);
228
229 reader.read_exact(&mut buf2)?;
230 let flags = u16::from_le_bytes(buf2);
231
232 reader.read_exact(&mut buf2)?;
233 let id_index = u16::from_le_bytes(buf2);
234
235 Ok(Self {
236 magic,
237 record_count,
238 field_count,
239 record_size,
240 string_block_size,
241 table_hash,
242 layout_hash,
243 min_id,
244 max_id,
245 locale,
246 flags,
247 id_index,
248 })
249 }
250
251 pub fn to_dbc_header(&self) -> DbcHeader {
253 DbcHeader {
254 magic: *b"WDBC", record_count: self.record_count,
256 field_count: self.field_count,
257 record_size: self.record_size,
258 string_block_size: self.string_block_size,
259 }
260 }
261
262 pub fn string_block_offset(&self) -> u64 {
264 Self::SIZE as u64 + (self.record_count as u64 * self.record_size as u64)
265 }
266
267 pub fn total_size(&self) -> u64 {
269 self.string_block_offset() + self.string_block_size as u64
270 }
271}