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>,
|
||||
#[serde(default)]
|
||||
pub name_pair_summaries: Vec<SmpSavePlacedStructureDynamicSideBufferNamePairSummary>,
|
||||
#[serde(default)]
|
||||
pub payload_envelope_summary:
|
||||
Option<SmpSavePlacedStructureDynamicSideBufferPayloadEnvelopeSummary>,
|
||||
pub evidence: Vec<String>,
|
||||
}
|
||||
|
||||
|
|
@ -1912,6 +1915,50 @@ pub struct SmpSavePlacedStructureDynamicSideBufferNamePairSummary {
|
|||
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)]
|
||||
pub struct SmpSavePlacedStructureDynamicSideBufferAlignmentProbe {
|
||||
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)
|
||||
.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(),
|
||||
"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(),
|
||||
|
|
@ -4448,8 +4510,9 @@ pub fn load_save_slice_from_report(
|
|||
}
|
||||
if let Some(probe) = &placed_structure_dynamic_side_buffer_probe {
|
||||
let dominant_pattern = probe.compact_prefix_pattern_summaries.first();
|
||||
let payload_envelope_summary = probe.payload_envelope_summary.as_ref();
|
||||
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.owner_shared_dword_hex,
|
||||
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.unique_compact_prefix_pattern_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
|
||||
.map(|pattern| pattern.prefix_leading_dword_hex.as_str())
|
||||
.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() {
|
||||
let dominant_pattern = side_buffer.compact_prefix_pattern_summaries.first();
|
||||
let payload_envelope_summary = side_buffer.payload_envelope_summary.as_ref();
|
||||
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.decoded_embedded_name_row_count,
|
||||
side_buffer.unique_embedded_name_pair_count,
|
||||
side_buffer.decoded_embedded_name_row_with_tertiary_name_count,
|
||||
side_buffer.unique_compact_prefix_pattern_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
|
||||
.map(|pattern| pattern.prefix_leading_dword_hex.as_str())
|
||||
.unwrap_or("0x00000000"),
|
||||
|
|
@ -11762,6 +11856,20 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
|||
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") {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -11917,6 +12025,70 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
|||
})
|
||||
})
|
||||
.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
|
||||
.iter()
|
||||
.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.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 dominant_compact_prefix_pattern = compact_prefix_pattern_summaries.first().cloned();
|
||||
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,
|
||||
compact_prefix_pattern_summaries,
|
||||
name_pair_summaries,
|
||||
payload_envelope_summary,
|
||||
evidence: vec![
|
||||
"exact little-endian u32 tag family 0x38a5/0x38a6/0x38a7 appears as a separate save-side tagged collection on grounded saves".to_string(),
|
||||
format!(
|
||||
|
|
@ -12156,6 +12423,33 @@ fn parse_save_placed_structure_dynamic_side_buffer_probe(
|
|||
,
|
||||
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
|
||||
.map(|pattern| {
|
||||
format!(
|
||||
|
|
@ -12571,9 +12865,9 @@ fn parse_save_len_prefixed_ascii_name_pair(bytes: &[u8]) -> Option<(String, Stri
|
|||
Some((first, second))
|
||||
}
|
||||
|
||||
fn parse_save_len_prefixed_ascii_name_triplet(
|
||||
fn parse_save_len_prefixed_ascii_name_triplet_and_consumed_len(
|
||||
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 mut second_len_offset = first_end;
|
||||
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)) {
|
||||
third_len_offset += 1;
|
||||
}
|
||||
let third = parse_save_varlen_ascii_name_at(bytes, third_len_offset)
|
||||
.map(|(text, _)| text)
|
||||
.filter(|text| !text.is_empty());
|
||||
let (third, consumed_len) = parse_save_varlen_ascii_name_at(bytes, third_len_offset)
|
||||
.map(|(text, end)| {
|
||||
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))
|
||||
}
|
||||
|
||||
|
|
@ -20301,6 +20606,22 @@ mod tests {
|
|||
probe.name_pair_summaries[0].dominant_prefix_leading_dword_hex,
|
||||
"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]
|
||||
|
|
@ -20394,6 +20715,18 @@ mod tests {
|
|||
"0x000055f3"
|
||||
);
|
||||
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]
|
||||
|
|
@ -20421,6 +20754,21 @@ mod tests {
|
|||
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]
|
||||
fn aligns_placed_structure_dynamic_side_buffer_name_pairs_with_triplets() {
|
||||
let side_buffer = SmpSavePlacedStructureDynamicSideBufferProbe {
|
||||
|
|
@ -20490,6 +20838,7 @@ mod tests {
|
|||
dominant_prefix_count: 1,
|
||||
},
|
||||
],
|
||||
payload_envelope_summary: None,
|
||||
evidence: vec![],
|
||||
};
|
||||
let triplets = SmpSavePlacedStructureRecordTripletProbe {
|
||||
|
|
@ -22128,6 +22477,21 @@ mod tests {
|
|||
dominant_prefix_separator_byte_hex: "0xff".to_string(),
|
||||
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(),
|
||||
});
|
||||
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
|
||||
callbacks consumed by `0x0048dcf0`, and which restored child fields still retain those embedded
|
||||
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
|
||||
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
|
||||
|
|
@ -214,6 +222,11 @@ Working rule:
|
|||
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
|
||||
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
|
||||
infrastructure pass should start with the attach/rebuild strip instead of treating all
|
||||
candidate owners as equally likely.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue