Expose region payload prefix dword candidates
This commit is contained in:
parent
5bc7b3090e
commit
ad7576b65b
2 changed files with 148 additions and 0 deletions
|
|
@ -1711,6 +1711,8 @@ pub struct SmpSaveRegionRecordTripletEntryProbe {
|
|||
pub pre_name_prefix_len: usize,
|
||||
#[serde(default)]
|
||||
pub pre_name_prefix_hex_bytes: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub pre_name_prefix_dword_candidates: Vec<SmpSaveDwordCandidate>,
|
||||
pub policy_chunk_len: usize,
|
||||
pub profile_chunk_len: usize,
|
||||
pub policy_leading_f32_0: f32,
|
||||
|
|
@ -13195,6 +13197,10 @@ fn parse_save_region_record_triplet_probe(
|
|||
}
|
||||
let pre_name_prefix =
|
||||
records_payload.get(record_payload_relative_offset..name_tag_relative_offset)?;
|
||||
let pre_name_prefix_dword_candidates = build_region_record_prefix_dword_candidates(
|
||||
record_payload_relative_offset,
|
||||
pre_name_prefix,
|
||||
);
|
||||
let name_payload =
|
||||
records_payload.get(name_tag_relative_offset + 4..policy_tag_relative_offset)?;
|
||||
let name = parse_save_len_prefixed_ascii_name(name_payload)?;
|
||||
|
|
@ -13231,6 +13237,7 @@ fn parse_save_region_record_triplet_probe(
|
|||
.iter()
|
||||
.map(|byte| format!("0x{byte:02x}"))
|
||||
.collect(),
|
||||
pre_name_prefix_dword_candidates,
|
||||
policy_chunk_len,
|
||||
profile_chunk_len,
|
||||
policy_leading_f32_0,
|
||||
|
|
@ -13291,6 +13298,29 @@ fn parse_save_region_record_triplet_probe(
|
|||
})
|
||||
}
|
||||
|
||||
fn build_region_record_prefix_dword_candidates(
|
||||
record_payload_relative_offset: usize,
|
||||
prefix_bytes: &[u8],
|
||||
) -> Vec<SmpSaveDwordCandidate> {
|
||||
prefix_bytes
|
||||
.chunks_exact(4)
|
||||
.enumerate()
|
||||
.map(|(index, chunk)| {
|
||||
let raw_u32 = u32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
|
||||
let relative_offset = record_payload_relative_offset + index * 4;
|
||||
SmpSaveDwordCandidate {
|
||||
label: format!("pre_name_prefix_word_{}", index + 1),
|
||||
relative_offset,
|
||||
relative_offset_hex: format!("0x{relative_offset:x}"),
|
||||
raw_u32,
|
||||
raw_u32_hex: format!("0x{raw_u32:08x}"),
|
||||
value_i32: raw_u32 as i32,
|
||||
value_f32: f32::from_bits(raw_u32),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn parse_save_region_queued_notice_record_probe(
|
||||
bytes: &[u8],
|
||||
file_extension_hint: Option<&str>,
|
||||
|
|
@ -23333,6 +23363,7 @@ mod tests {
|
|||
profile_tag_relative_offset: 0x2e,
|
||||
pre_name_prefix_len: 0,
|
||||
pre_name_prefix_hex_bytes: Vec::new(),
|
||||
pre_name_prefix_dword_candidates: Vec::new(),
|
||||
policy_chunk_len: 0x1a,
|
||||
profile_chunk_len: 0x40,
|
||||
policy_leading_f32_0: 368.0,
|
||||
|
|
@ -23374,6 +23405,7 @@ mod tests {
|
|||
profile_tag_relative_offset: 0x9c,
|
||||
pre_name_prefix_len: 0,
|
||||
pre_name_prefix_hex_bytes: Vec::new(),
|
||||
pre_name_prefix_dword_candidates: Vec::new(),
|
||||
policy_chunk_len: 0x1a,
|
||||
profile_chunk_len: 0x20,
|
||||
policy_leading_f32_0: 552.0,
|
||||
|
|
@ -23789,6 +23821,11 @@ mod tests {
|
|||
assert_eq!(triplet_probe.entries[0].policy_leading_f32_0, 368.0);
|
||||
assert_eq!(triplet_probe.entries[0].policy_leading_f32_1, 0.0);
|
||||
assert_eq!(triplet_probe.entries[0].policy_leading_f32_2, 92.0);
|
||||
assert!(
|
||||
triplet_probe.entries[0]
|
||||
.pre_name_prefix_dword_candidates
|
||||
.is_empty()
|
||||
);
|
||||
assert_eq!(
|
||||
triplet_probe.entries[0].policy_reserved_dwords,
|
||||
vec![0, 0, 0]
|
||||
|
|
@ -23798,6 +23835,111 @@ mod tests {
|
|||
assert_eq!(triplet_probe.entries[1].policy_leading_f32_0, 552.0);
|
||||
assert_eq!(triplet_probe.entries[1].policy_leading_f32_1, 1.5);
|
||||
assert_eq!(triplet_probe.entries[1].policy_leading_f32_2, 276.0);
|
||||
assert!(
|
||||
triplet_probe.entries[1]
|
||||
.pre_name_prefix_dword_candidates
|
||||
.is_empty()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_region_record_triplet_prefix_dword_candidates() {
|
||||
let mut bytes = vec![0u8; 0x320];
|
||||
let metadata_tag_offset = 0x0usize;
|
||||
let records_tag_offset = 0x100usize;
|
||||
let close_tag_offset = 0x200usize;
|
||||
bytes[metadata_tag_offset..metadata_tag_offset + 4]
|
||||
.copy_from_slice(&0x00005209u32.to_le_bytes());
|
||||
bytes[records_tag_offset..records_tag_offset + 4]
|
||||
.copy_from_slice(&0x0000520au32.to_le_bytes());
|
||||
bytes[close_tag_offset..close_tag_offset + 4].copy_from_slice(&0x0000520bu32.to_le_bytes());
|
||||
let mut cursor = records_tag_offset + 4;
|
||||
let first_record_relative_offset = 0usize;
|
||||
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
|
||||
bytes[cursor + 4] = 8;
|
||||
bytes[cursor + 5..cursor + 13].copy_from_slice(b"Marker11");
|
||||
cursor += 0x10;
|
||||
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_POLICY_TAG.to_le_bytes());
|
||||
bytes[cursor + 4..cursor + 8].copy_from_slice(&100.0f32.to_bits().to_le_bytes());
|
||||
bytes[cursor + 8..cursor + 12].copy_from_slice(&2.0f32.to_bits().to_le_bytes());
|
||||
bytes[cursor + 12..cursor + 16].copy_from_slice(&50.0f32.to_bits().to_le_bytes());
|
||||
bytes[cursor + 28..cursor + 30].copy_from_slice(&1u16.to_le_bytes());
|
||||
cursor += 0x1e;
|
||||
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_PROFILE_TAG.to_le_bytes());
|
||||
cursor += 0x20;
|
||||
let second_record_relative_offset = cursor - (records_tag_offset + 4);
|
||||
bytes[cursor..cursor + 4].copy_from_slice(&0x11223344u32.to_le_bytes());
|
||||
bytes[cursor + 4..cursor + 8].copy_from_slice(&0x55667788u32.to_le_bytes());
|
||||
cursor += 8;
|
||||
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_NAME_TAG.to_le_bytes());
|
||||
bytes[cursor + 4] = 8;
|
||||
bytes[cursor + 5..cursor + 13].copy_from_slice(b"Marker12");
|
||||
cursor += 0x10;
|
||||
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_POLICY_TAG.to_le_bytes());
|
||||
bytes[cursor + 4..cursor + 8].copy_from_slice(&120.0f32.to_bits().to_le_bytes());
|
||||
bytes[cursor + 8..cursor + 12].copy_from_slice(&3.0f32.to_bits().to_le_bytes());
|
||||
bytes[cursor + 12..cursor + 16].copy_from_slice(&60.0f32.to_bits().to_le_bytes());
|
||||
bytes[cursor + 28..cursor + 30].copy_from_slice(&1u16.to_le_bytes());
|
||||
cursor += 0x1e;
|
||||
bytes[cursor..cursor + 2].copy_from_slice(&SAVE_REGION_RECORD_PROFILE_TAG.to_le_bytes());
|
||||
let directory_root_byte_offset = SAVE_REGION_COLLECTION_DIRECTORY_ROOT_DWORD_INDEX * 4;
|
||||
let first_payload_relative_offset = records_tag_offset - metadata_tag_offset;
|
||||
let second_payload_relative_offset =
|
||||
first_payload_relative_offset + second_record_relative_offset;
|
||||
bytes[metadata_tag_offset + 4 + directory_root_byte_offset
|
||||
..metadata_tag_offset + 8 + directory_root_byte_offset]
|
||||
.copy_from_slice(&(first_payload_relative_offset as u32).to_le_bytes());
|
||||
bytes[metadata_tag_offset + 16 + directory_root_byte_offset
|
||||
..metadata_tag_offset + 20 + directory_root_byte_offset]
|
||||
.copy_from_slice(&(second_payload_relative_offset as u32).to_le_bytes());
|
||||
|
||||
let header_probe = SmpSaveTaggedCollectionHeaderProbe {
|
||||
profile_family: "rt3-105-save-container-v1".to_string(),
|
||||
source_kind: "save-region-tagged-header-counts".to_string(),
|
||||
semantic_family: "scenario-save-region-header-counts".to_string(),
|
||||
metadata_tag_offset,
|
||||
records_tag_offset,
|
||||
close_tag_offset,
|
||||
direct_collection_flag: 0,
|
||||
direct_collection_flag_hex: "0x00000000".to_string(),
|
||||
direct_record_stride: 0x06,
|
||||
direct_record_stride_hex: "0x00000006".to_string(),
|
||||
live_id_bound: 0x96,
|
||||
live_id_bound_hex: "0x00000096".to_string(),
|
||||
live_record_count: 2,
|
||||
live_record_count_hex: "0x00000002".to_string(),
|
||||
header_words: vec![0, 6, 0x0a, 0x14, 0x96, 0x02],
|
||||
header_hex_words: vec![],
|
||||
evidence: vec![],
|
||||
};
|
||||
let triplet_probe = parse_save_region_record_triplet_probe(&bytes, Some(&header_probe))
|
||||
.expect("region triplet probe should parse");
|
||||
|
||||
assert_eq!(triplet_probe.entries.len(), 2);
|
||||
assert_eq!(
|
||||
triplet_probe.entries[0].record_payload_relative_offset,
|
||||
first_record_relative_offset
|
||||
);
|
||||
assert_eq!(triplet_probe.entries[0].pre_name_prefix_len, 0);
|
||||
assert_eq!(
|
||||
triplet_probe.entries[1].record_payload_relative_offset,
|
||||
second_record_relative_offset
|
||||
);
|
||||
assert_eq!(triplet_probe.entries[1].pre_name_prefix_len, 8);
|
||||
assert_eq!(
|
||||
triplet_probe.entries[1]
|
||||
.pre_name_prefix_dword_candidates
|
||||
.len(),
|
||||
2
|
||||
);
|
||||
assert_eq!(
|
||||
triplet_probe.entries[1].pre_name_prefix_dword_candidates[0].raw_u32_hex,
|
||||
"0x11223344"
|
||||
);
|
||||
assert_eq!(
|
||||
triplet_probe.entries[1].pre_name_prefix_dword_candidates[1].relative_offset_hex,
|
||||
"0x52"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -25906,6 +26048,7 @@ mod tests {
|
|||
profile_tag_relative_offset: 0,
|
||||
pre_name_prefix_len: 0,
|
||||
pre_name_prefix_hex_bytes: Vec::new(),
|
||||
pre_name_prefix_dword_candidates: Vec::new(),
|
||||
policy_chunk_len: 0,
|
||||
profile_chunk_len: 0,
|
||||
policy_leading_f32_0: 368.0,
|
||||
|
|
|
|||
|
|
@ -544,6 +544,11 @@ Working rule:
|
|||
`[region+0x2a4]` or `[region+0x310/+0x338/+0x360]`, and they still do not touch
|
||||
`[region+0x276/+0x302/+0x316]`. That means the remaining region restore target is now the later
|
||||
owner that rebuilds those latches or the separate tagged body seam that persists them.
|
||||
- The save-side region payload probe is wider now too: the checked-in `region_record_triplets`
|
||||
surface no longer stops at raw pre-name prefix bytes and now also emits structured prefix dword
|
||||
candidates per record. That gives the next region payload pass a direct way to compare the
|
||||
opaque pre-`0x55f1` band against the remaining acquisition-side lane shapes instead of redoing
|
||||
raw hex inspection by hand.
|
||||
- The rest of `0x00455fc0` is ruled down further now too: after the `+0x48` callback it only runs
|
||||
`0x0052ebd0`, which reads two one-byte generic flags through `0x531150` into base object bytes
|
||||
`[this+0x20]`, `[this+0x8d]`, `[this+0x5c..+0x61]`, `[this+0x1ee]`, `[this+0x1fa]`, and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue