Summarize infrastructure payload envelopes
This commit is contained in:
parent
1873db0b08
commit
1011f557e5
2 changed files with 384 additions and 7 deletions
|
|
@ -1855,6 +1855,9 @@ pub struct SmpSavePlacedStructureDynamicSideBufferProbe {
|
||||||
Vec<SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary>,
|
Vec<SmpSavePlacedStructureDynamicSideBufferPrefixPatternSummary>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub name_pair_summaries: Vec<SmpSavePlacedStructureDynamicSideBufferNamePairSummary>,
|
pub name_pair_summaries: Vec<SmpSavePlacedStructureDynamicSideBufferNamePairSummary>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub payload_envelope_summary:
|
||||||
|
Option<SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary>,
|
||||||
pub evidence: Vec<String>,
|
pub evidence: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1912,6 +1915,50 @@ pub struct SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
|
||||||
pub dominant_prefix_count: usize,
|
pub dominant_prefix_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary {
|
||||||
|
pub row_count_with_policy_tag_before_next_name: usize,
|
||||||
|
pub row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope: usize,
|
||||||
|
pub row_count_missing_policy_tag_before_next_name: usize,
|
||||||
|
pub row_count_missing_profile_tag_after_policy: usize,
|
||||||
|
#[serde(default)]
|
||||||
|
pub unique_policy_chunk_lens: Vec<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub unique_profile_chunk_lens: Vec<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub dominant_policy_chunk_len: Option<usize>,
|
||||||
|
pub dominant_policy_chunk_len_count: usize,
|
||||||
|
#[serde(default)]
|
||||||
|
pub dominant_profile_chunk_len: Option<usize>,
|
||||||
|
pub dominant_profile_chunk_len_count: usize,
|
||||||
|
#[serde(default)]
|
||||||
|
pub sample_rows: Vec<SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSample>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSample {
|
||||||
|
pub sample_index: usize,
|
||||||
|
pub name_tag_relative_offset: usize,
|
||||||
|
#[serde(default)]
|
||||||
|
pub primary_name: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub secondary_name: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub name_payload_end_relative_offset: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub policy_tag_relative_offset: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub profile_tag_relative_offset: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub next_name_tag_relative_offset: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub name_to_policy_gap_len: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub policy_chunk_len: Option<usize>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub profile_chunk_len_to_next_name_or_end: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
|
pub struct SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
|
||||||
pub unique_side_buffer_name_pair_count: usize,
|
pub unique_side_buffer_name_pair_count: usize,
|
||||||
|
|
@ -3973,6 +4020,21 @@ fn build_infrastructure_asset_trace_report(
|
||||||
.map(|probe| probe.decoded_embedded_name_row_with_tertiary_name_count)
|
.map(|probe| probe.decoded_embedded_name_row_with_tertiary_name_count)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
),
|
),
|
||||||
|
format!(
|
||||||
|
"current save-side probe also reports {} complete 0x55f1/0x55f2/0x55f3 envelopes, dominant 0x55f2 chunk len 0x{:x}, and dominant 0x55f3 span 0x{:x}",
|
||||||
|
side_buffer
|
||||||
|
.and_then(|probe| probe.payload_envelope_summary.as_ref())
|
||||||
|
.map(|summary| summary.row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
side_buffer
|
||||||
|
.and_then(|probe| probe.payload_envelope_summary.as_ref())
|
||||||
|
.and_then(|summary| summary.dominant_policy_chunk_len)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
side_buffer
|
||||||
|
.and_then(|probe| probe.payload_envelope_summary.as_ref())
|
||||||
|
.and_then(|summary| summary.dominant_profile_chunk_len)
|
||||||
|
.unwrap_or_default()
|
||||||
|
),
|
||||||
"local .rdata at 0x005cfd00 now also proves the infrastructure child table uses the shared tagged callback strip directly: slot +0x40 = 0x455fc0, slot +0x48 = 0x455870, and slot +0x4c = 0x455930".to_string(),
|
"local .rdata at 0x005cfd00 now also proves the infrastructure child table uses the shared tagged callback strip directly: slot +0x40 = 0x455fc0, slot +0x48 = 0x455870, and slot +0x4c = 0x455930".to_string(),
|
||||||
"direct disassembly now shows 0x0048a1e0 cloning the first child triplet bands through 0x52e880/0x52e720, destroying the prior child, seeding a new literal Infrastructure child through 0x455b70 with payload seed 0x5c87a8, attaching through 0x5395d0 or 0x53a5d0, and republishing the two bands through 0x52e8b0/0x530720".to_string(),
|
"direct disassembly now shows 0x0048a1e0 cloning the first child triplet bands through 0x52e880/0x52e720, destroying the prior child, seeding a new literal Infrastructure child through 0x455b70 with payload seed 0x5c87a8, attaching through 0x5395d0 or 0x53a5d0, and republishing the two bands through 0x52e8b0/0x530720".to_string(),
|
||||||
"direct disassembly now also shows the outer owner at 0x0048dcf0 reading a child count plus optional primary-child ordinal from the tagged stream through 0x531150, zeroing [this+0x08], dispatching each fresh child through 0x455a50 -> vtable slot +0x40, culling ordinals above 5, and restoring cached primary-child slot [this+0x248] from the saved ordinal".to_string(),
|
"direct disassembly now also shows the outer owner at 0x0048dcf0 reading a child count plus optional primary-child ordinal from the tagged stream through 0x531150, zeroing [this+0x08], dispatching each fresh child through 0x455a50 -> vtable slot +0x40, culling ordinals above 5, and restoring cached primary-child slot [this+0x248] from the saved ordinal".to_string(),
|
||||||
|
|
@ -4448,8 +4510,9 @@ pub fn load_save_slice_from_report(
|
||||||
}
|
}
|
||||||
if let Some(probe) = &placed_structure_dynamic_side_buffer_probe {
|
if let Some(probe) = &placed_structure_dynamic_side_buffer_probe {
|
||||||
let dominant_pattern = probe.compact_prefix_pattern_summaries.first();
|
let dominant_pattern = probe.compact_prefix_pattern_summaries.first();
|
||||||
|
let payload_envelope_summary = probe.payload_envelope_summary.as_ref();
|
||||||
notes.push(format!(
|
notes.push(format!(
|
||||||
"Raw save also exposes the separate placed-structure dynamic-side-buffer candidate 0x38a5/0x38a6/0x38a7: live_record_count={}, owner-shared 0x38a6 dword={} at relative offset 0x{:x}, first compact prefix=({},{},{}), first embedded names={:?}/{:?}/{:?}, embedded 0x55f1 row count={}, rows with tertiary 0x55f1 string={}, unique compact prefix patterns={}, 0x55f3-leading rows={}, dominant compact pattern={}/{}/{} x{}.",
|
"Raw save also exposes the separate placed-structure dynamic-side-buffer candidate 0x38a5/0x38a6/0x38a7: live_record_count={}, owner-shared 0x38a6 dword={} at relative offset 0x{:x}, first compact prefix=({},{},{}), first embedded names={:?}/{:?}/{:?}, embedded 0x55f1 row count={}, rows with tertiary 0x55f1 string={}, unique compact prefix patterns={}, 0x55f3-leading rows={}, complete 0x55f1/0x55f2/0x55f3 envelopes={}, dominant 0x55f2 chunk len=0x{:x} x{}, dominant 0x55f3 span=0x{:x} x{}, dominant compact pattern={}/{}/{} x{}.",
|
||||||
probe.live_record_count,
|
probe.live_record_count,
|
||||||
probe.owner_shared_dword_hex,
|
probe.owner_shared_dword_hex,
|
||||||
probe.owner_shared_dword_relative_offset,
|
probe.owner_shared_dword_relative_offset,
|
||||||
|
|
@ -4463,6 +4526,21 @@ pub fn load_save_slice_from_report(
|
||||||
probe.decoded_embedded_name_row_with_tertiary_name_count,
|
probe.decoded_embedded_name_row_with_tertiary_name_count,
|
||||||
probe.unique_compact_prefix_pattern_count,
|
probe.unique_compact_prefix_pattern_count,
|
||||||
probe.prefix_leading_dword_matching_embedded_profile_tag_count,
|
probe.prefix_leading_dword_matching_embedded_profile_tag_count,
|
||||||
|
payload_envelope_summary
|
||||||
|
.map(|summary| summary.row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
payload_envelope_summary
|
||||||
|
.and_then(|summary| summary.dominant_policy_chunk_len)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
payload_envelope_summary
|
||||||
|
.map(|summary| summary.dominant_policy_chunk_len_count)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
payload_envelope_summary
|
||||||
|
.and_then(|summary| summary.dominant_profile_chunk_len)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
payload_envelope_summary
|
||||||
|
.map(|summary| summary.dominant_profile_chunk_len_count)
|
||||||
|
.unwrap_or_default(),
|
||||||
dominant_pattern
|
dominant_pattern
|
||||||
.map(|pattern| pattern.prefix_leading_dword_hex.as_str())
|
.map(|pattern| pattern.prefix_leading_dword_hex.as_str())
|
||||||
.unwrap_or("0x00000000"),
|
.unwrap_or("0x00000000"),
|
||||||
|
|
@ -4946,14 +5024,30 @@ pub fn inspect_save_company_and_chairman_analysis_bytes(
|
||||||
}
|
}
|
||||||
if let Some(side_buffer) = placed_structure_dynamic_side_buffer.as_ref() {
|
if let Some(side_buffer) = placed_structure_dynamic_side_buffer.as_ref() {
|
||||||
let dominant_pattern = side_buffer.compact_prefix_pattern_summaries.first();
|
let dominant_pattern = side_buffer.compact_prefix_pattern_summaries.first();
|
||||||
|
let payload_envelope_summary = side_buffer.payload_envelope_summary.as_ref();
|
||||||
notes.push(format!(
|
notes.push(format!(
|
||||||
"Placed-structure analysis now also exports the separate 0x38a5 dynamic side-buffer owner seam with {} embedded name rows, {} decoded rows across {} unique name pairs, {} rows with a tertiary 0x55f1 string, {} unique compact prefix patterns, {} rows whose leading dword matches 0x55f3, and dominant compact pattern={}/{}/{} x{}.",
|
"Placed-structure analysis now also exports the separate 0x38a5 dynamic side-buffer owner seam with {} embedded name rows, {} decoded rows across {} unique name pairs, {} rows with a tertiary 0x55f1 string, {} unique compact prefix patterns, {} rows whose leading dword matches 0x55f3, {} complete 0x55f1/0x55f2/0x55f3 envelopes, dominant 0x55f2 chunk len=0x{:x} x{}, dominant 0x55f3 span=0x{:x} x{}, and dominant compact pattern={}/{}/{} x{}.",
|
||||||
side_buffer.embedded_name_tag_count,
|
side_buffer.embedded_name_tag_count,
|
||||||
side_buffer.decoded_embedded_name_row_count,
|
side_buffer.decoded_embedded_name_row_count,
|
||||||
side_buffer.unique_embedded_name_pair_count,
|
side_buffer.unique_embedded_name_pair_count,
|
||||||
side_buffer.decoded_embedded_name_row_with_tertiary_name_count,
|
side_buffer.decoded_embedded_name_row_with_tertiary_name_count,
|
||||||
side_buffer.unique_compact_prefix_pattern_count,
|
side_buffer.unique_compact_prefix_pattern_count,
|
||||||
side_buffer.prefix_leading_dword_matching_embedded_profile_tag_count,
|
side_buffer.prefix_leading_dword_matching_embedded_profile_tag_count,
|
||||||
|
payload_envelope_summary
|
||||||
|
.map(|summary| summary.row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
payload_envelope_summary
|
||||||
|
.and_then(|summary| summary.dominant_policy_chunk_len)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
payload_envelope_summary
|
||||||
|
.map(|summary| summary.dominant_policy_chunk_len_count)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
payload_envelope_summary
|
||||||
|
.and_then(|summary| summary.dominant_profile_chunk_len)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
payload_envelope_summary
|
||||||
|
.map(|summary| summary.dominant_profile_chunk_len_count)
|
||||||
|
.unwrap_or_default(),
|
||||||
dominant_pattern
|
dominant_pattern
|
||||||
.map(|pattern| pattern.prefix_leading_dword_hex.as_str())
|
.map(|pattern| pattern.prefix_leading_dword_hex.as_str())
|
||||||
.unwrap_or("0x00000000"),
|
.unwrap_or("0x00000000"),
|
||||||
|
|
@ -11762,6 +11856,20 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
||||||
prefix_counts: BTreeMap<(u32, u16, u8), usize>,
|
prefix_counts: BTreeMap<(u32, u16, u8), usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct PayloadEnvelopeRow {
|
||||||
|
name_tag_relative_offset: usize,
|
||||||
|
primary_name: Option<String>,
|
||||||
|
secondary_name: Option<String>,
|
||||||
|
name_payload_end_relative_offset: Option<usize>,
|
||||||
|
policy_tag_relative_offset: Option<usize>,
|
||||||
|
profile_tag_relative_offset: Option<usize>,
|
||||||
|
next_name_tag_relative_offset: Option<usize>,
|
||||||
|
name_to_policy_gap_len: Option<usize>,
|
||||||
|
policy_chunk_len: Option<usize>,
|
||||||
|
profile_chunk_len_to_next_name_or_end: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
if file_extension_hint != Some("gms") {
|
if file_extension_hint != Some("gms") {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
@ -11917,6 +12025,70 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
let policy_tag_offsets =
|
||||||
|
find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_POLICY_TAG);
|
||||||
|
let profile_tag_offsets =
|
||||||
|
find_u16_le_offsets(records_payload, SAVE_REGION_RECORD_PROFILE_TAG);
|
||||||
|
let payload_envelope_rows = embedded_name_rows
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(row_index, row)| {
|
||||||
|
let next_name_tag_relative_offset = embedded_name_tag_offsets
|
||||||
|
.get(row_index + 1)
|
||||||
|
.copied()
|
||||||
|
.or(Some(records_payload.len()));
|
||||||
|
let name_payload_end_relative_offset = records_payload
|
||||||
|
.get(row.name_tag_relative_offset + 4..)
|
||||||
|
.and_then(parse_save_len_prefixed_ascii_name_triplet_and_consumed_len)
|
||||||
|
.map(|(_, consumed_len)| row.name_tag_relative_offset + 4 + consumed_len);
|
||||||
|
let policy_tag_relative_offset =
|
||||||
|
policy_tag_offsets.iter().copied().find(|offset| {
|
||||||
|
*offset > row.name_tag_relative_offset
|
||||||
|
&& next_name_tag_relative_offset
|
||||||
|
.is_none_or(|next_name| *offset < next_name)
|
||||||
|
});
|
||||||
|
let profile_tag_relative_offset = policy_tag_relative_offset.and_then(|policy| {
|
||||||
|
profile_tag_offsets.iter().copied().find(|offset| {
|
||||||
|
*offset > policy
|
||||||
|
&& next_name_tag_relative_offset
|
||||||
|
.is_none_or(|next_name| *offset < next_name)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let name_to_policy_gap_len = name_payload_end_relative_offset
|
||||||
|
.zip(policy_tag_relative_offset)
|
||||||
|
.and_then(
|
||||||
|
|(name_payload_end_relative_offset, policy_tag_relative_offset)| {
|
||||||
|
policy_tag_relative_offset.checked_sub(name_payload_end_relative_offset)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let policy_chunk_len = policy_tag_relative_offset
|
||||||
|
.zip(profile_tag_relative_offset)
|
||||||
|
.and_then(
|
||||||
|
|(policy_tag_relative_offset, profile_tag_relative_offset)| {
|
||||||
|
profile_tag_relative_offset.checked_sub(policy_tag_relative_offset + 4)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let profile_chunk_len_to_next_name_or_end =
|
||||||
|
profile_tag_relative_offset.and_then(|profile_tag_relative_offset| {
|
||||||
|
next_name_tag_relative_offset.and_then(|next_name_tag_relative_offset| {
|
||||||
|
next_name_tag_relative_offset
|
||||||
|
.checked_sub(profile_tag_relative_offset + 4)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
PayloadEnvelopeRow {
|
||||||
|
name_tag_relative_offset: row.name_tag_relative_offset,
|
||||||
|
primary_name: row.primary_name.clone(),
|
||||||
|
secondary_name: row.secondary_name.clone(),
|
||||||
|
name_payload_end_relative_offset,
|
||||||
|
policy_tag_relative_offset,
|
||||||
|
profile_tag_relative_offset,
|
||||||
|
next_name_tag_relative_offset,
|
||||||
|
name_to_policy_gap_len,
|
||||||
|
policy_chunk_len,
|
||||||
|
profile_chunk_len_to_next_name_or_end,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let embedded_name_row_samples = embedded_name_rows
|
let embedded_name_row_samples = embedded_name_rows
|
||||||
.iter()
|
.iter()
|
||||||
.take(8)
|
.take(8)
|
||||||
|
|
@ -12078,6 +12250,100 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
||||||
.then_with(|| left.primary_name.cmp(&right.primary_name))
|
.then_with(|| left.primary_name.cmp(&right.primary_name))
|
||||||
.then_with(|| left.secondary_name.cmp(&right.secondary_name))
|
.then_with(|| left.secondary_name.cmp(&right.secondary_name))
|
||||||
});
|
});
|
||||||
|
let row_count_with_policy_tag_before_next_name = payload_envelope_rows
|
||||||
|
.iter()
|
||||||
|
.filter(|row| row.policy_tag_relative_offset.is_some())
|
||||||
|
.count();
|
||||||
|
let row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope = payload_envelope_rows
|
||||||
|
.iter()
|
||||||
|
.filter(|row| {
|
||||||
|
row.policy_tag_relative_offset.is_some()
|
||||||
|
&& row.profile_tag_relative_offset.is_some()
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
let row_count_missing_policy_tag_before_next_name = payload_envelope_rows
|
||||||
|
.iter()
|
||||||
|
.filter(|row| row.policy_tag_relative_offset.is_none())
|
||||||
|
.count();
|
||||||
|
let row_count_missing_profile_tag_after_policy = payload_envelope_rows
|
||||||
|
.iter()
|
||||||
|
.filter(|row| {
|
||||||
|
row.policy_tag_relative_offset.is_some()
|
||||||
|
&& row.profile_tag_relative_offset.is_none()
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
let mut policy_chunk_len_counts = BTreeMap::<usize, usize>::new();
|
||||||
|
let mut profile_chunk_len_counts = BTreeMap::<usize, usize>::new();
|
||||||
|
for row in &payload_envelope_rows {
|
||||||
|
if let Some(policy_chunk_len) = row.policy_chunk_len {
|
||||||
|
*policy_chunk_len_counts.entry(policy_chunk_len).or_default() += 1;
|
||||||
|
}
|
||||||
|
if let Some(profile_chunk_len_to_next_name_or_end) =
|
||||||
|
row.profile_chunk_len_to_next_name_or_end
|
||||||
|
{
|
||||||
|
*profile_chunk_len_counts
|
||||||
|
.entry(profile_chunk_len_to_next_name_or_end)
|
||||||
|
.or_default() += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let unique_policy_chunk_lens = policy_chunk_len_counts.keys().copied().collect::<Vec<_>>();
|
||||||
|
let unique_profile_chunk_lens =
|
||||||
|
profile_chunk_len_counts.keys().copied().collect::<Vec<_>>();
|
||||||
|
let dominant_policy_chunk_len = policy_chunk_len_counts
|
||||||
|
.iter()
|
||||||
|
.max_by(|(left_len, left_count), (right_len, right_count)| {
|
||||||
|
left_count
|
||||||
|
.cmp(right_count)
|
||||||
|
.then_with(|| right_len.cmp(left_len))
|
||||||
|
})
|
||||||
|
.map(|(len, count)| (*len, *count));
|
||||||
|
let dominant_profile_chunk_len = profile_chunk_len_counts
|
||||||
|
.iter()
|
||||||
|
.max_by(|(left_len, left_count), (right_len, right_count)| {
|
||||||
|
left_count
|
||||||
|
.cmp(right_count)
|
||||||
|
.then_with(|| right_len.cmp(left_len))
|
||||||
|
})
|
||||||
|
.map(|(len, count)| (*len, *count));
|
||||||
|
let payload_envelope_summary = Some(
|
||||||
|
SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary {
|
||||||
|
row_count_with_policy_tag_before_next_name,
|
||||||
|
row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope,
|
||||||
|
row_count_missing_policy_tag_before_next_name,
|
||||||
|
row_count_missing_profile_tag_after_policy,
|
||||||
|
unique_policy_chunk_lens,
|
||||||
|
unique_profile_chunk_lens,
|
||||||
|
dominant_policy_chunk_len: dominant_policy_chunk_len.map(|(len, _)| len),
|
||||||
|
dominant_policy_chunk_len_count: dominant_policy_chunk_len
|
||||||
|
.map(|(_, count)| count)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
dominant_profile_chunk_len: dominant_profile_chunk_len.map(|(len, _)| len),
|
||||||
|
dominant_profile_chunk_len_count: dominant_profile_chunk_len
|
||||||
|
.map(|(_, count)| count)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
sample_rows: payload_envelope_rows
|
||||||
|
.iter()
|
||||||
|
.take(8)
|
||||||
|
.enumerate()
|
||||||
|
.map(|(sample_index, row)| {
|
||||||
|
SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSample {
|
||||||
|
sample_index,
|
||||||
|
name_tag_relative_offset: row.name_tag_relative_offset,
|
||||||
|
primary_name: row.primary_name.clone(),
|
||||||
|
secondary_name: row.secondary_name.clone(),
|
||||||
|
name_payload_end_relative_offset: row.name_payload_end_relative_offset,
|
||||||
|
policy_tag_relative_offset: row.policy_tag_relative_offset,
|
||||||
|
profile_tag_relative_offset: row.profile_tag_relative_offset,
|
||||||
|
next_name_tag_relative_offset: row.next_name_tag_relative_offset,
|
||||||
|
name_to_policy_gap_len: row.name_to_policy_gap_len,
|
||||||
|
policy_chunk_len: row.policy_chunk_len,
|
||||||
|
profile_chunk_len_to_next_name_or_end: row
|
||||||
|
.profile_chunk_len_to_next_name_or_end,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
);
|
||||||
let unique_embedded_name_pair_count = name_pair_summaries.len();
|
let unique_embedded_name_pair_count = name_pair_summaries.len();
|
||||||
let dominant_compact_prefix_pattern = compact_prefix_pattern_summaries.first().cloned();
|
let dominant_compact_prefix_pattern = compact_prefix_pattern_summaries.first().cloned();
|
||||||
let decoded_embedded_name_row_count = embedded_name_rows
|
let decoded_embedded_name_row_count = embedded_name_rows
|
||||||
|
|
@ -12130,6 +12396,7 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
||||||
embedded_name_row_samples,
|
embedded_name_row_samples,
|
||||||
compact_prefix_pattern_summaries,
|
compact_prefix_pattern_summaries,
|
||||||
name_pair_summaries,
|
name_pair_summaries,
|
||||||
|
payload_envelope_summary,
|
||||||
evidence: vec![
|
evidence: vec![
|
||||||
"exact little-endian u32 tag family 0x38a5/0x38a6/0x38a7 appears as a separate save-side tagged collection on grounded saves".to_string(),
|
"exact little-endian u32 tag family 0x38a5/0x38a6/0x38a7 appears as a separate save-side tagged collection on grounded saves".to_string(),
|
||||||
format!(
|
format!(
|
||||||
|
|
@ -12156,6 +12423,33 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
||||||
,
|
,
|
||||||
decoded_embedded_name_row_with_tertiary_name_count
|
decoded_embedded_name_row_with_tertiary_name_count
|
||||||
),
|
),
|
||||||
|
format!(
|
||||||
|
"{} of {} embedded 0x55f1 rows currently have a complete 0x55f1/0x55f2/0x55f3 envelope before the next name row; {} rows are still missing 0x55f2 and {} rows have 0x55f2 without a later 0x55f3",
|
||||||
|
row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope,
|
||||||
|
embedded_name_rows.len(),
|
||||||
|
row_count_missing_policy_tag_before_next_name,
|
||||||
|
row_count_missing_profile_tag_after_policy
|
||||||
|
),
|
||||||
|
dominant_policy_chunk_len
|
||||||
|
.map(|(policy_chunk_len, count)| {
|
||||||
|
format!(
|
||||||
|
"dominant embedded 0x55f2 policy chunk length is 0x{policy_chunk_len:x} bytes across {count} rows"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
"no dominant embedded 0x55f2 policy chunk length was available"
|
||||||
|
.to_string()
|
||||||
|
}),
|
||||||
|
dominant_profile_chunk_len
|
||||||
|
.map(|(profile_chunk_len, count)| {
|
||||||
|
format!(
|
||||||
|
"dominant embedded 0x55f3 payload-to-next-name span is 0x{profile_chunk_len:x} bytes across {count} rows"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
"no dominant embedded 0x55f3 payload-to-next-name span was available"
|
||||||
|
.to_string()
|
||||||
|
}),
|
||||||
dominant_compact_prefix_pattern
|
dominant_compact_prefix_pattern
|
||||||
.map(|pattern| {
|
.map(|pattern| {
|
||||||
format!(
|
format!(
|
||||||
|
|
@ -12571,9 +12865,9 @@ fn parse_save_len_prefixed_ascii_name_pair(bytes: &[u8]) -> Option<(String, Stri
|
||||||
Some((first, second))
|
Some((first, second))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_save_len_prefixed_ascii_name_triplet(
|
fn parse_save_len_prefixed_ascii_name_triplet_and_consumed_len(
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
) -> Option<(String, String, Option<String>)> {
|
) -> Option<((String, String, Option<String>), usize)> {
|
||||||
let (first, first_end) = parse_save_varlen_ascii_name_at(bytes, 0)?;
|
let (first, first_end) = parse_save_varlen_ascii_name_at(bytes, 0)?;
|
||||||
let mut second_len_offset = first_end;
|
let mut second_len_offset = first_end;
|
||||||
while matches!(bytes.get(second_len_offset), Some(0)) {
|
while matches!(bytes.get(second_len_offset), Some(0)) {
|
||||||
|
|
@ -12587,9 +12881,20 @@ fn parse_save_len_prefixed_ascii_name_triplet(
|
||||||
while matches!(bytes.get(third_len_offset), Some(0)) {
|
while matches!(bytes.get(third_len_offset), Some(0)) {
|
||||||
third_len_offset += 1;
|
third_len_offset += 1;
|
||||||
}
|
}
|
||||||
let third = parse_save_varlen_ascii_name_at(bytes, third_len_offset)
|
let (third, consumed_len) = parse_save_varlen_ascii_name_at(bytes, third_len_offset)
|
||||||
.map(|(text, _)| text)
|
.map(|(text, end)| {
|
||||||
.filter(|text| !text.is_empty());
|
let third = (!text.is_empty()).then_some(text);
|
||||||
|
(third, end)
|
||||||
|
})
|
||||||
|
.unwrap_or((None, second_end));
|
||||||
|
Some(((first, second, third), consumed_len))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_save_len_prefixed_ascii_name_triplet(
|
||||||
|
bytes: &[u8],
|
||||||
|
) -> Option<(String, String, Option<String>)> {
|
||||||
|
let ((first, second, third), _) =
|
||||||
|
parse_save_len_prefixed_ascii_name_triplet_and_consumed_len(bytes)?;
|
||||||
Some((first, second, third))
|
Some((first, second, third))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20301,6 +20606,22 @@ mod tests {
|
||||||
probe.name_pair_summaries[0].dominant_prefix_leading_dword_hex,
|
probe.name_pair_summaries[0].dominant_prefix_leading_dword_hex,
|
||||||
"0x0005d368"
|
"0x0005d368"
|
||||||
);
|
);
|
||||||
|
let payload_envelope_summary = probe
|
||||||
|
.payload_envelope_summary
|
||||||
|
.as_ref()
|
||||||
|
.expect("payload envelope summary should be present");
|
||||||
|
assert_eq!(
|
||||||
|
payload_envelope_summary.row_count_with_policy_tag_before_next_name,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
payload_envelope_summary.row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
payload_envelope_summary.row_count_missing_policy_tag_before_next_name,
|
||||||
|
1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -20394,6 +20715,18 @@ mod tests {
|
||||||
"0x000055f3"
|
"0x000055f3"
|
||||||
);
|
);
|
||||||
assert_eq!(probe.name_pair_summaries[1].count, 1);
|
assert_eq!(probe.name_pair_summaries[1].count, 1);
|
||||||
|
let payload_envelope_summary = probe
|
||||||
|
.payload_envelope_summary
|
||||||
|
.as_ref()
|
||||||
|
.expect("payload envelope summary should be present");
|
||||||
|
assert_eq!(
|
||||||
|
payload_envelope_summary.row_count_with_policy_tag_before_next_name,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
payload_envelope_summary.row_count_missing_policy_tag_before_next_name,
|
||||||
|
3
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -20421,6 +20754,21 @@ mod tests {
|
||||||
assert_eq!(parsed.2, None);
|
assert_eq!(parsed.2, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_save_len_prefixed_ascii_name_triplet_with_consumed_len() {
|
||||||
|
let bytes = [
|
||||||
|
5u8, b'F', b'i', b'r', b's', b't', 0, 6, b'S', b'e', b'c', b'o', b'n', b'd', 0, 5,
|
||||||
|
b'T', b'h', b'i', b'r', b'd', 0xff,
|
||||||
|
];
|
||||||
|
let (parsed, consumed_len) =
|
||||||
|
parse_save_len_prefixed_ascii_name_triplet_and_consumed_len(&bytes)
|
||||||
|
.expect("triplet parser should decode consumed len");
|
||||||
|
assert_eq!(parsed.0, "First");
|
||||||
|
assert_eq!(parsed.1, "Second");
|
||||||
|
assert_eq!(parsed.2.as_deref(), Some("Third"));
|
||||||
|
assert_eq!(consumed_len, 21);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn aligns_placed_structure_dynamic_side_buffer_name_pairs_with_triplets() {
|
fn aligns_placed_structure_dynamic_side_buffer_name_pairs_with_triplets() {
|
||||||
let side_buffer = SmpSavePlacedStructureDynamicSideBufferProbe {
|
let side_buffer = SmpSavePlacedStructureDynamicSideBufferProbe {
|
||||||
|
|
@ -20490,6 +20838,7 @@ mod tests {
|
||||||
dominant_prefix_count: 1,
|
dominant_prefix_count: 1,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
payload_envelope_summary: None,
|
||||||
evidence: vec![],
|
evidence: vec![],
|
||||||
};
|
};
|
||||||
let triplets = SmpSavePlacedStructureRecordTripletProbe {
|
let triplets = SmpSavePlacedStructureRecordTripletProbe {
|
||||||
|
|
@ -22128,6 +22477,21 @@ mod tests {
|
||||||
dominant_prefix_separator_byte_hex: "0xff".to_string(),
|
dominant_prefix_separator_byte_hex: "0xff".to_string(),
|
||||||
dominant_prefix_count: 9,
|
dominant_prefix_count: 9,
|
||||||
}],
|
}],
|
||||||
|
payload_envelope_summary: Some(
|
||||||
|
SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary {
|
||||||
|
row_count_with_policy_tag_before_next_name: 120,
|
||||||
|
row_count_with_complete_0x55f1_0x55f2_0x55f3_envelope: 118,
|
||||||
|
row_count_missing_policy_tag_before_next_name: 18,
|
||||||
|
row_count_missing_profile_tag_after_policy: 2,
|
||||||
|
unique_policy_chunk_lens: vec![0x1a, 0x24],
|
||||||
|
unique_profile_chunk_lens: vec![0x08, 0x14],
|
||||||
|
dominant_policy_chunk_len: Some(0x1a),
|
||||||
|
dominant_policy_chunk_len_count: 110,
|
||||||
|
dominant_profile_chunk_len: Some(0x08),
|
||||||
|
dominant_profile_chunk_len_count: 90,
|
||||||
|
sample_rows: Vec::new(),
|
||||||
|
},
|
||||||
|
),
|
||||||
evidence: Vec::new(),
|
evidence: Vec::new(),
|
||||||
});
|
});
|
||||||
analysis.placed_structure_dynamic_side_buffer_alignment =
|
analysis.placed_structure_dynamic_side_buffer_alignment =
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,14 @@ Working rule:
|
||||||
maps the direct `0x38a5` rows into the child count, primary-child ordinal, and per-child payload
|
maps the direct `0x38a5` rows into the child count, primary-child ordinal, and per-child payload
|
||||||
callbacks consumed by `0x0048dcf0`, and which restored child fields still retain those embedded
|
callbacks consumed by `0x0048dcf0`, and which restored child fields still retain those embedded
|
||||||
name-pair semantics before route/local-runtime follow-ons take over.
|
name-pair semantics before route/local-runtime follow-ons take over.
|
||||||
|
- The save-side `0x38a5` probe is now tighter at the payload-envelope level too: grounded
|
||||||
|
`q.gms` shows all `138` embedded `0x55f1` rows already live inside complete
|
||||||
|
`0x55f1 -> 0x55f2 -> 0x55f3` envelopes before the next name row, every embedded `0x55f2` chunk
|
||||||
|
is the fixed `0x1a` bytes that `0x00455fc0` expects, and the dominant embedded `0x55f3`
|
||||||
|
payload-to-next-name span is the short `0x06`-byte form across `72` rows. So the next
|
||||||
|
infrastructure pass should stop asking whether the shared tagged callback sequence is present at
|
||||||
|
all and instead decode the short `0x55f3` payload role and its relation to the compact-prefix
|
||||||
|
regimes and primary-child restore path.
|
||||||
- Reconstruct the save-side region record body on top of the newly corrected non-direct tagged
|
- Reconstruct the save-side region record body on top of the newly corrected non-direct tagged
|
||||||
region seam (`0x5209/0x520a/0x520b`, stride hint `0x06`, `Marker09` record stems) now that the
|
region seam (`0x5209/0x520a/0x520b`, stride hint `0x06`, `Marker09` record stems) now that the
|
||||||
`0x55f3` payload is known to be fully consumed by the embedded profile collection on grounded
|
`0x55f3` payload is known to be fully consumed by the embedded profile collection on grounded
|
||||||
|
|
@ -214,6 +222,11 @@ Working rule:
|
||||||
consumer candidates rooted at the `Infrastructure` child attach/rebuild/serializer helpers and
|
consumer candidates rooted at the `Infrastructure` child attach/rebuild/serializer helpers and
|
||||||
the later route/local-runtime follow-on owners. That means the next `0x38a5` pass can be
|
the later route/local-runtime follow-on owners. That means the next `0x38a5` pass can be
|
||||||
targeted static mapping instead of another generic scan.
|
targeted static mapping instead of another generic scan.
|
||||||
|
- The same `0x38a5` probe now also exports payload-envelope summaries directly instead of only flat
|
||||||
|
name rows: policy/profile tag presence, dominant embedded `0x55f2` and `0x55f3` span lengths,
|
||||||
|
and sampled row boundaries. That means the next pass can decode the short embedded `0x55f3`
|
||||||
|
payload lane on top of already grounded row boundaries instead of rediscovering the same
|
||||||
|
envelopes again.
|
||||||
- That same trace now also ranks those consumers into explicit hypotheses, so the next
|
- That same trace now also ranks those consumers into explicit hypotheses, so the next
|
||||||
infrastructure pass should start with the attach/rebuild strip instead of treating all
|
infrastructure pass should start with the attach/rebuild strip instead of treating all
|
||||||
candidate owners as equally likely.
|
candidate owners as equally likely.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue