mirror of
https://github.com/redstrate/Physis.git
synced 2025-05-15 22:47:46 +00:00
Fix how we read/write packed booleans in EXD, add another write test
Apparently we were reading packed booleans wrong the whole time (whoops!) They are packed into *bytes*, oops... That is fixed now, and I also expanded write support for packed booleans. It makes the assumption that the byte is always at the end of the row, but I think that's OK for now. I also added a good test-case for this, the PhysicsGroup EXD. It has a lot of rows, and some packed booleans thrown in. The columns also have out-of-order column definitions (as in, their offsets don't increase in order.)
This commit is contained in:
parent
dae35ecfb8
commit
0313f75abb
4 changed files with 94 additions and 20 deletions
BIN
resources/tests/physicsgroup.exh
Normal file
BIN
resources/tests/physicsgroup.exh
Normal file
Binary file not shown.
BIN
resources/tests/physicsgroup_1.exd
Normal file
BIN
resources/tests/physicsgroup_1.exd
Normal file
Binary file not shown.
112
src/exd.rs
112
src/exd.rs
|
@ -135,14 +135,63 @@ fn write_rows(rows: &Vec<ExcelRow>, exh: &EXH) -> BinResult<()> {
|
||||||
// write column data
|
// write column data
|
||||||
{
|
{
|
||||||
let mut write_row = |row: &ExcelSingleRow| {
|
let mut write_row = |row: &ExcelSingleRow| {
|
||||||
for (i, column) in row.columns.iter().enumerate() {
|
let mut column_definitions: Vec<(ExcelColumnDefinition, ColumnData)> = exh
|
||||||
EXD::write_column(writer, &column, &exh.column_definitions[i]);
|
.column_definitions
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.zip(row.columns.clone().into_iter())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// TODO: temporary workaround until i can figure out why it has 4 extra bytes
|
// we need to sort them by offset
|
||||||
if exh.column_definitions[i].data_type == ColumnDataType::Int8 {
|
column_definitions.sort_by(|(a, _), (b, _)| a.offset.cmp(&b.offset));
|
||||||
|
|
||||||
|
for (definition, column) in &column_definitions {
|
||||||
|
EXD::write_column(writer, &column, &definition);
|
||||||
|
|
||||||
|
// TODO: temporary workaround until i can figure out why it has 4 extra bytes in test_write's case
|
||||||
|
if definition.data_type == ColumnDataType::Int8 && column_definitions.len() == 1
|
||||||
|
{
|
||||||
0u32.write_le(writer).unwrap();
|
0u32.write_le(writer).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle packed bools
|
||||||
|
let mut packed_byte = 0u8;
|
||||||
|
let mut byte_offset = 0;
|
||||||
|
|
||||||
|
let mut write_packed_bool =
|
||||||
|
|definition: &ExcelColumnDefinition, shift: i32, boolean: &bool| {
|
||||||
|
byte_offset = definition.offset; // NOTE: it looks like there is only one byte for all of the packed booleans
|
||||||
|
|
||||||
|
if *boolean {
|
||||||
|
let bit = 1 << shift;
|
||||||
|
packed_byte |= bit;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (definition, column) in &column_definitions {
|
||||||
|
match &column {
|
||||||
|
ColumnData::Bool(val) => match definition.data_type {
|
||||||
|
ColumnDataType::PackedBool0 => write_packed_bool(definition, 0, val),
|
||||||
|
ColumnDataType::PackedBool1 => write_packed_bool(definition, 1, val),
|
||||||
|
ColumnDataType::PackedBool2 => write_packed_bool(definition, 2, val),
|
||||||
|
ColumnDataType::PackedBool3 => write_packed_bool(definition, 3, val),
|
||||||
|
ColumnDataType::PackedBool4 => write_packed_bool(definition, 4, val),
|
||||||
|
ColumnDataType::PackedBool5 => write_packed_bool(definition, 5, val),
|
||||||
|
ColumnDataType::PackedBool6 => write_packed_bool(definition, 6, val),
|
||||||
|
ColumnDataType::PackedBool7 => write_packed_bool(definition, 7, val),
|
||||||
|
_ => {} // not relevant
|
||||||
|
},
|
||||||
|
_ => {} // not relevant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the new packed boolean byte
|
||||||
|
// NOTE: This is a terrible way to check if there are packed booleans
|
||||||
|
// NOTE: Assumption: the packed boolean is always at the end of the row
|
||||||
|
if byte_offset != 0 {
|
||||||
|
packed_byte.write_le(writer).unwrap();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match &row.kind {
|
match &row.kind {
|
||||||
|
@ -394,7 +443,7 @@ impl EXD {
|
||||||
) -> Option<ColumnData> {
|
) -> Option<ColumnData> {
|
||||||
let mut read_packed_bool = |shift: i32| -> bool {
|
let mut read_packed_bool = |shift: i32| -> bool {
|
||||||
let bit = 1 << shift;
|
let bit = 1 << shift;
|
||||||
let bool_data: i32 = Self::read_data_raw(cursor).unwrap_or(0);
|
let bool_data: u8 = Self::read_data_raw(cursor).unwrap_or(0);
|
||||||
|
|
||||||
(bool_data & bit) == bit
|
(bool_data & bit) == bit
|
||||||
};
|
};
|
||||||
|
@ -462,11 +511,6 @@ impl EXD {
|
||||||
column: &ColumnData,
|
column: &ColumnData,
|
||||||
column_definition: &ExcelColumnDefinition,
|
column_definition: &ExcelColumnDefinition,
|
||||||
) {
|
) {
|
||||||
let write_packed_bool = |cursor: &mut T, shift: i32, boolean: &bool| {
|
|
||||||
let val = 0i32; // TODO
|
|
||||||
Self::write_data_raw(cursor, &val);
|
|
||||||
};
|
|
||||||
|
|
||||||
match column {
|
match column {
|
||||||
ColumnData::String(_) => {
|
ColumnData::String(_) => {
|
||||||
let string_offset = 0u32; // TODO, but 0 is fine for single string column data
|
let string_offset = 0u32; // TODO, but 0 is fine for single string column data
|
||||||
|
@ -474,14 +518,15 @@ impl EXD {
|
||||||
}
|
}
|
||||||
ColumnData::Bool(val) => match column_definition.data_type {
|
ColumnData::Bool(val) => match column_definition.data_type {
|
||||||
ColumnDataType::Bool => todo!(),
|
ColumnDataType::Bool => todo!(),
|
||||||
ColumnDataType::PackedBool0 => write_packed_bool(cursor, 0, val),
|
// packed bools are handled in write_rows
|
||||||
ColumnDataType::PackedBool1 => write_packed_bool(cursor, 1, val),
|
ColumnDataType::PackedBool0 => {}
|
||||||
ColumnDataType::PackedBool2 => write_packed_bool(cursor, 2, val),
|
ColumnDataType::PackedBool1 => {}
|
||||||
ColumnDataType::PackedBool3 => write_packed_bool(cursor, 3, val),
|
ColumnDataType::PackedBool2 => {}
|
||||||
ColumnDataType::PackedBool4 => write_packed_bool(cursor, 4, val),
|
ColumnDataType::PackedBool3 => {}
|
||||||
ColumnDataType::PackedBool5 => write_packed_bool(cursor, 5, val),
|
ColumnDataType::PackedBool4 => {}
|
||||||
ColumnDataType::PackedBool6 => write_packed_bool(cursor, 6, val),
|
ColumnDataType::PackedBool5 => {}
|
||||||
ColumnDataType::PackedBool7 => write_packed_bool(cursor, 7, val),
|
ColumnDataType::PackedBool6 => {}
|
||||||
|
ColumnDataType::PackedBool7 => {}
|
||||||
_ => panic!("This makes no sense!"),
|
_ => panic!("This makes no sense!"),
|
||||||
},
|
},
|
||||||
ColumnData::Int8(val) => Self::write_data_raw(cursor, val),
|
ColumnData::Int8(val) => Self::write_data_raw(cursor, val),
|
||||||
|
@ -595,7 +640,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
// row 1
|
// row 1
|
||||||
assert_eq!(exd.rows[1].row_id, 1441693);
|
assert_eq!(exd.rows[1].row_id, 1441793);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
exd.rows[1].kind,
|
exd.rows[1].kind,
|
||||||
ExcelRowKind::SingleRow(ExcelSingleRow {
|
ExcelRowKind::SingleRow(ExcelSingleRow {
|
||||||
|
@ -801,4 +846,33 @@ mod tests {
|
||||||
let actual_exd_bytes = expected_exd.write_to_buffer(&exh).unwrap();
|
let actual_exd_bytes = expected_exd.write_to_buffer(&exh).unwrap();
|
||||||
assert_eq!(actual_exd_bytes, expected_exd_bytes);
|
assert_eq!(actual_exd_bytes, expected_exd_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this doesn't have any strings, but a LOT of columns and some packed booleans!
|
||||||
|
#[test]
|
||||||
|
fn test_write_many_columns() {
|
||||||
|
// exh
|
||||||
|
let exh;
|
||||||
|
{
|
||||||
|
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
d.push("resources/tests");
|
||||||
|
d.push("physicsgroup.exh");
|
||||||
|
|
||||||
|
exh = EXH::from_existing(&read(d).unwrap()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// exd
|
||||||
|
let expected_exd_bytes;
|
||||||
|
let expected_exd;
|
||||||
|
{
|
||||||
|
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
d.push("resources/tests");
|
||||||
|
d.push("physicsgroup_1.exd");
|
||||||
|
|
||||||
|
expected_exd_bytes = read(d).unwrap();
|
||||||
|
expected_exd = EXD::from_existing(&exh, &expected_exd_bytes).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let actual_exd_bytes = expected_exd.write_to_buffer(&exh).unwrap();
|
||||||
|
assert_eq!(actual_exd_bytes, expected_exd_bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub struct EXHHeader {
|
||||||
pub(crate) page_count: u16,
|
pub(crate) page_count: u16,
|
||||||
pub(crate) language_count: u16,
|
pub(crate) language_count: u16,
|
||||||
|
|
||||||
#[br(dbg)]
|
/// Usually 0
|
||||||
pub unk1: u16,
|
pub unk1: u16,
|
||||||
|
|
||||||
#[br(temp)]
|
#[br(temp)]
|
||||||
|
|
Loading…
Add table
Reference in a new issue