1#![allow(clippy::unnecessary_fallible_conversions)] use std::io::Cursor;
7
8use binrw::BinRead;
9use binrw::binrw;
10
11use crate::ByteSpan;
12use crate::common::Language;
13
14#[binrw]
15#[brw(magic = b"EXHF")]
16#[brw(big)]
17#[allow(dead_code)]
18pub struct EXHHeader {
19 pub(crate) version: u16,
20
21 pub data_offset: u16,
22 pub(crate) column_count: u16,
23 pub(crate) page_count: u16,
24 pub(crate) language_count: u16,
25
26 #[br(pad_before = 6)]
27 #[br(pad_after = 8)]
28 pub row_count: u32,
29}
30
31#[binrw]
32#[brw(repr(u16))]
33#[repr(u16)]
34#[derive(PartialEq, Eq, Clone, Debug)]
35pub enum ColumnDataType {
36 String = 0x0,
37 Bool = 0x1,
38 Int8 = 0x2,
39 UInt8 = 0x3,
40 Int16 = 0x4,
41 UInt16 = 0x5,
42 Int32 = 0x6,
43 UInt32 = 0x7,
44 Float32 = 0x9,
45 Int64 = 0xA,
46 UInt64 = 0xB,
47
48 PackedBool0 = 0x19,
49 PackedBool1 = 0x1A,
50 PackedBool2 = 0x1B,
51 PackedBool3 = 0x1C,
52 PackedBool4 = 0x1D,
53 PackedBool5 = 0x1E,
54 PackedBool6 = 0x1F,
55 PackedBool7 = 0x20,
56}
57
58#[binrw]
59#[brw(big)]
60pub struct ExcelColumnDefinition {
61 pub data_type: ColumnDataType,
62 pub offset: u16,
63}
64
65#[binrw]
66#[brw(big)]
67#[allow(dead_code)]
68pub struct ExcelDataPagination {
69 pub start_id: u32,
70 pub row_count: u32,
71}
72
73#[binrw]
74#[brw(big)]
75#[allow(dead_code)]
76pub struct EXH {
77 pub header: EXHHeader,
78
79 #[br(count = header.column_count)]
80 pub column_definitions: Vec<ExcelColumnDefinition>,
81
82 #[br(count = header.page_count)]
83 pub pages: Vec<ExcelDataPagination>,
84
85 #[br(count = header.language_count)]
86 pub languages: Vec<Language>,
87}
88
89impl EXH {
90 pub fn from_existing(buffer: ByteSpan) -> Option<EXH> {
91 EXH::read(&mut Cursor::new(&buffer)).ok()
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use std::fs::read;
98 use std::path::PathBuf;
99
100 use super::*;
101
102 #[test]
103 fn test_invalid() {
104 let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
105 d.push("resources/tests");
106 d.push("random");
107
108 EXH::from_existing(&read(d).unwrap());
110 }
111}