1use crate::{Error, Result};
4use std::io::{Read, Seek, SeekFrom};
5
6pub const DBC_MAGIC: [u8; 4] = *b"WDBC";
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct DbcHeader {
12 pub magic: [u8; 4],
14 pub record_count: u32,
16 pub field_count: u32,
18 pub record_size: u32,
20 pub string_block_size: u32,
22}
23
24impl DbcHeader {
25 pub const SIZE: usize = 20;
27
28 pub fn parse<R: Read + Seek>(reader: &mut R) -> Result<Self> {
30 reader.seek(SeekFrom::Start(0))?;
32
33 let mut magic = [0u8; 4];
35 reader.read_exact(&mut magic)?;
36
37 if magic != DBC_MAGIC {
39 return Err(Error::InvalidHeader(format!(
40 "Invalid magic signature: {magic:?}, expected: {DBC_MAGIC:?}"
41 )));
42 }
43
44 let mut buf = [0u8; 4];
46
47 reader.read_exact(&mut buf)?;
48 let record_count = u32::from_le_bytes(buf);
49
50 reader.read_exact(&mut buf)?;
51 let field_count = u32::from_le_bytes(buf);
52
53 reader.read_exact(&mut buf)?;
54 let record_size = u32::from_le_bytes(buf);
55
56 reader.read_exact(&mut buf)?;
57 let string_block_size = u32::from_le_bytes(buf);
58
59 if record_size == 0 && record_count > 0 {
61 return Err(Error::InvalidHeader(
62 "Record size cannot be 0 if record count is greater than 0".to_string(),
63 ));
64 }
65
66 if field_count == 0 && record_count > 0 {
67 return Err(Error::InvalidHeader(
68 "Field count cannot be 0 if record count is greater than 0".to_string(),
69 ));
70 }
71
72 Ok(Self {
73 magic,
74 record_count,
75 field_count,
76 record_size,
77 string_block_size,
78 })
79 }
80
81 pub fn string_block_offset(&self) -> u64 {
83 DbcHeader::SIZE as u64 + (self.record_count as u64 * self.record_size as u64)
84 }
85
86 pub fn total_size(&self) -> u64 {
88 self.string_block_offset() + self.string_block_size as u64
89 }
90}