Word Unperfect
public
Read
Owner: themaster
Branch: main
Commits: 0
Git CLI clone URL
git clone https://www.xt-emporium.com/git/word-unperfect.git
Fullscreen desktop URL
Code
Commits
History
Branches
Bug Reports
Discussions
Compare
Settings
word-unperfect
/
rev
/
wp_variable_codes.c
File editor
#include "wp_variable_codes.h" #include "wp_fixed_codes.h" #include "wp_format_table.h" #include <stdio.h> #include <string.h> static uint16_t wp_var_le16(const uint8_t *p) { return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } static void wp_var_put_le16(uint8_t *p, uint16_t value) { p[0] = (uint8_t)(value & 0xFFU); p[1] = (uint8_t)(value >> 8); } static void wp_variable_clear_text_preview(WpVariableTextPreview *preview) { if (preview != NULL) { memset(preview, 0, sizeof(*preview)); } } static void wp_variable_capture_text_preview(const uint8_t *payload, uint16_t payload_length, WpVariableTextPreview *out_preview) { WpVariableTextPreview preview; uint16_t i; wp_variable_clear_text_preview(out_preview); memset(&preview, 0, sizeof(preview)); preview.bytes_seen = payload_length; if (payload == NULL || payload_length == 0U) { if (out_preview != NULL) { *out_preview = preview; } return; } for (i = 0U; i < payload_length; ++i) { uint8_t ch = payload[i]; bool printable = (ch >= 0x20U && ch < 0x7FU); if (printable) { preview.printable_bytes++; } else if (ch == 0U) { preview.nul_bytes++; } if (preview.preview_length < WP_VARIABLE_TEXT_PREVIEW_BYTES) { if (printable) { preview.preview[preview.preview_length] = (char)ch; } else if (ch == 0U) { preview.preview[preview.preview_length] = '|'; } else { preview.preview[preview.preview_length] = '.'; } preview.preview_length++; } else { preview.preview_truncated = true; } } preview.preview[preview.preview_length] = '\0'; if (out_preview != NULL) { *out_preview = preview; } } static uint16_t wp_variable_span_word_as_uint(undefined2 value) { return (uint16_t)value; } const char *wp_variable_action_name(WpVariableAction action) { switch (action) { case WP_VARIABLE_ACTION_INITIAL_FORMAT_TABLE: return "initial format table"; case WP_VARIABLE_ACTION_DEFINITION: return "definition packet"; case WP_VARIABLE_ACTION_OUTLINE_LIST: return "outline/list definition packet"; case WP_VARIABLE_ACTION_GENERATED_TEXT: return "generated-text packet"; case WP_VARIABLE_ACTION_LAYOUT_STATE: return "layout state command"; case WP_VARIABLE_ACTION_REPEAT_GROUP: return "repeat/group command"; case WP_VARIABLE_ACTION_DELAYED_TEXT_GROUP: return "delayed text group"; case WP_VARIABLE_ACTION_BOX_OR_OBJECT: return "box/object packet"; case WP_VARIABLE_ACTION_TABLE_LAYOUT: return "table/layout packet"; case WP_VARIABLE_ACTION_SCANNER_BYPASS: return "scanner bypass command"; case WP_VARIABLE_ACTION_SYSTEM_COMMAND: return "system/merge command"; case WP_VARIABLE_ACTION_GENERIC: default: return "variable-length format code"; } } WpVariableAction wp_variable_action(uint8_t code, uint8_t sub_code) { switch (code) { case 0xD0U: return WP_VARIABLE_ACTION_INITIAL_FORMAT_TABLE; case 0xD1U: return WP_VARIABLE_ACTION_DEFINITION; case 0xD2U: return WP_VARIABLE_ACTION_OUTLINE_LIST; case 0xD3U: return WP_VARIABLE_ACTION_GENERATED_TEXT; case 0xD4U: return WP_VARIABLE_ACTION_LAYOUT_STATE; case 0xD5U: case 0xD6U: return WP_VARIABLE_ACTION_REPEAT_GROUP; case 0xD7U: case 0xD8U: case 0xD9U: return WP_VARIABLE_ACTION_DELAYED_TEXT_GROUP; case 0xDAU: return WP_VARIABLE_ACTION_BOX_OR_OBJECT; case 0xDCU: return WP_VARIABLE_ACTION_TABLE_LAYOUT; case 0xDEU: if (sub_code == 0x31U) { return WP_VARIABLE_ACTION_SCANNER_BYPASS; } return WP_VARIABLE_ACTION_SYSTEM_COMMAND; default: return WP_VARIABLE_ACTION_GENERIC; } } const char *wp_variable_code_name(uint8_t code, uint8_t sub_code) { switch (code) { case 0xD0U: return "D0 initial format/table packet"; case 0xD1U: return "D1 definition packet"; case 0xD2U: return "D2 outline/list definition packet"; case 0xD3U: return "D3 generated-text packet"; case 0xD4U: return "D4 layout state command"; case 0xD5U: return "D5 repeat/group command"; case 0xD6U: return "D6 repeat/group command"; case 0xD7U: return "D7 delayed text/name packet"; case 0xD8U: return "D8 generated item packet"; case 0xD9U: return "D9 prompt/help text packet"; case 0xDAU: return "DA box/object packet"; case 0xDBU: return "DB layout refcount packet"; case 0xDCU: return "DC table/layout packet"; case 0xDEU: if (sub_code == 0x31U) { return "DE/31 scanner bypass command"; } return "DE system/merge command"; default: return "Variable-length format code"; } } const char *wp_variable_d4_record_type_name(uint16_t record_type) { switch (record_type) { case 0x0600U: return "D4 pending span metric record"; case 0x0B00U: return "D4 position marker record"; case 0x1200U: return "D4 line metric checkpoint record"; case 0x1400U: return "D4 line/window transition record"; case 0x1600U: return "D4 layout state restore record"; case 0x1A00U: return "D4 layout anchor/geometry record"; case 0x0A00U: return "D4 compact layout metric record"; default: return "D4 layout command record"; } } static void wp_variable_clear_pending_span(WpD4PendingSpanPayload *span) { if (span != NULL) { memset(span, 0, sizeof(*span)); } } static void wp_variable_clear_line_window(WpD4LineWindowPayload *window) { if (window != NULL) { memset(window, 0, sizeof(*window)); } } static void wp_variable_clear_extension(WpD4ExtensionPayload *extension) { if (extension != NULL) { memset(extension, 0, sizeof(*extension)); } } static void wp_variable_clear_line_metric(WpD4LineMetricPayload *metric) { if (metric != NULL) { memset(metric, 0, sizeof(*metric)); } } static void wp_variable_clear_line_build_checkpoint(WpD4LineBuildCheckpointPayload *checkpoint) { if (checkpoint != NULL) { memset(checkpoint, 0, sizeof(*checkpoint)); } } static void wp_variable_clear_word_pair_checkpoint(WpD4WordPairCheckpointPayload *checkpoint) { if (checkpoint != NULL) { memset(checkpoint, 0, sizeof(*checkpoint)); } } static void wp_variable_clear_position_marker(WpD4PositionMarkerPayload *marker) { if (marker != NULL) { memset(marker, 0, sizeof(*marker)); } } static void wp_variable_clear_control_word(WpD4ControlWordPayload *control) { if (control != NULL) { memset(control, 0, sizeof(*control)); } } static void wp_variable_clear_compact_metric(WpD4CompactMetricPayload *metric) { if (metric != NULL) { memset(metric, 0, sizeof(*metric)); } } static void wp_variable_clear_layout_anchor(WpD4LayoutAnchorPayload *anchor) { if (anchor != NULL) { memset(anchor, 0, sizeof(*anchor)); } } static void wp_variable_clear_definition_payload(WpD1DefinitionPayload *payload) { if (payload != NULL) { memset(payload, 0, sizeof(*payload)); } } static void wp_variable_clear_outline_payload(WpD2OutlinePayload *payload) { if (payload != NULL) { memset(payload, 0, sizeof(*payload)); } } static void wp_variable_clear_generated_text_payload(WpD3GeneratedTextPayload *payload) { if (payload != NULL) { memset(payload, 0, sizeof(*payload)); } } static void wp_variable_clear_delayed_text_payload(WpDelayedTextPayload *payload) { if (payload != NULL) { memset(payload, 0, sizeof(*payload)); } } static void wp_variable_clear_repeat_group_payload(WpRepeatGroupPayload *payload) { if (payload != NULL) { memset(payload, 0, sizeof(*payload)); } } static void wp_variable_clear_box_object_payload(WpBoxObjectPayload *payload) { if (payload != NULL) { memset(payload, 0, sizeof(*payload)); } } static void wp_variable_clear_table_layout_payload(WpTableLayoutPayload *payload) { if (payload != NULL) { memset(payload, 0, sizeof(*payload)); } } static void wp_variable_clear_system_command_payload(WpSystemCommandPayload *payload) { if (payload != NULL) { memset(payload, 0, sizeof(*payload)); } } static void wp_variable_clear_layout_state(WpLayoutStatePayload *state) { if (state != NULL) { memset(state, 0, sizeof(*state)); } } bool wp_variable_decode_pending_span_payload(const uint8_t *payload, uint16_t payload_length, WpD4PendingSpanPayload *out_span) { WpD4PendingSpanPayload span; wp_variable_clear_pending_span(out_span); memset(&span, 0, sizeof(span)); if (payload == NULL || payload_length < 8U) { return false; } span.record_type = wp_var_le16(payload); if (span.record_type != 0x0600U) { return false; } /* process_layout_state_records_main writes the compact 0x0600 pending-span * record as [type][span_a][span_b][carry_width]. It is emitted when the * measured span words need to be replayed after the parser gate drains. */ span.is_pending_span = true; span.span_a = wp_var_le16(payload + 2U); span.span_b = wp_var_le16(payload + 4U); span.carry_width = wp_var_le16(payload + 6U); if (out_span != NULL) { *out_span = span; } return true; } bool wp_variable_decode_pending_span_record(const WpRecord *rec, WpD4PendingSpanPayload *out_span) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U) { wp_variable_clear_pending_span(out_span); return false; } return wp_variable_decode_pending_span_payload(rec->data, rec->data_length, out_span); } bool wp_variable_decode_line_window_payload(const uint8_t *payload, uint16_t payload_length, WpD4LineWindowPayload *out_window) { WpD4LineWindowPayload window; uint16_t tail_offset = 22U; wp_variable_clear_line_window(out_window); memset(&window, 0, sizeof(window)); if (payload == NULL || payload_length < tail_offset) { return false; } window.record_type = wp_var_le16(payload); if (window.record_type != 0x1400U) { return false; } /* layout_emit_or_measure_line_window writes 0x1400 records with the old * line-window words, the restored/new line-window words, and a signed carry * delta. Optional bytes after the first 22 payload bytes come from the * record-extension copy loop in the same decompiled function. */ window.is_line_window = true; window.old_scratch_start = wp_var_le16(payload + 2U); window.old_line_start = wp_var_le16(payload + 4U); window.old_scratch_extent = wp_var_le16(payload + 6U); window.old_line_extent = wp_var_le16(payload + 8U); window.carry_width_before = wp_var_le16(payload + 10U); window.new_scratch_start = wp_var_le16(payload + 12U); window.new_line_start = wp_var_le16(payload + 14U); window.new_scratch_extent = wp_var_le16(payload + 16U); window.new_line_extent = wp_var_le16(payload + 18U); window.carry_delta = (int16_t)wp_var_le16(payload + 20U); window.carry_width_after = (uint16_t)((int)window.carry_width_before + (int)window.carry_delta); if (payload_length > tail_offset) { uint16_t tail = (uint16_t)(payload_length - tail_offset); uint16_t body_len = 0U; window.has_extension_payload = true; window.extension_marker = payload[tail_offset]; if (tail > 1U) { window.extension_size_hint = payload[tail_offset + 1U]; body_len = (uint16_t)(tail - 2U); if (window.extension_size_hint != 0U && window.extension_size_hint < body_len) { body_len = window.extension_size_hint; } window.extension_payload_bytes = body_len; window.trailing_unparsed_bytes = (uint16_t)(tail - 2U - body_len); window.extension_preview_length = body_len; if (window.extension_preview_length > WP_D4_LINE_WINDOW_EXTENSION_PREVIEW_BYTES) { window.extension_preview_length = WP_D4_LINE_WINDOW_EXTENSION_PREVIEW_BYTES; window.extension_preview_truncated = true; } if (window.extension_preview_length != 0U) { memcpy(window.extension_preview, payload + tail_offset + 2U, window.extension_preview_length); } } else { window.trailing_unparsed_bytes = tail; } } if (out_window != NULL) { *out_window = window; } return true; } bool wp_variable_decode_line_window_record(const WpRecord *rec, WpD4LineWindowPayload *out_window) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U) { wp_variable_clear_line_window(out_window); return false; } return wp_variable_decode_line_window_payload(rec->data, rec->data_length, out_window); } bool wp_variable_decode_extension_payload(const uint8_t *payload, uint16_t payload_length, WpD4ExtensionPayload *out_extension) { WpD4ExtensionPayload ext; uint16_t pos = 0U; wp_variable_clear_extension(out_extension); memset(&ext, 0, sizeof(ext)); if (payload == NULL || payload_length < 2U) { return false; } while (pos < payload_length) { uint8_t marker = payload[pos]; uint16_t chunk_body = 0U; const uint8_t *chunk_payload = NULL; uint16_t chunk_total = 0U; uint16_t preview_room; uint16_t preview_copy; if (ext.chunk_count == 0U) { ext.marker = marker; if (pos + 1U < payload_length) { ext.size_hint = payload[pos + 1U]; } } if (marker == 1U) { if (pos + 2U > payload_length) { break; } chunk_body = payload[pos + 1U]; chunk_total = (uint16_t)(2U + chunk_body); if (pos + chunk_total > payload_length) { break; } ext.has_inline_payload = true; ext.inline_payload_bytes = (uint16_t)(ext.inline_payload_bytes + chunk_body); chunk_payload = payload + pos + 2U; } else if (marker == 2U) { uint16_t length_word; uint8_t block_count; uint16_t data_bytes; if (pos + 4U > payload_length) { break; } length_word = wp_var_le16(payload + pos + 1U); block_count = payload[pos + 3U]; data_bytes = (uint16_t)((uint16_t)block_count * 16U); chunk_total = (uint16_t)(4U + data_bytes); if (length_word != (uint16_t)(data_bytes + 1U) || pos + chunk_total > payload_length) { break; } ext.has_block_list = true; ext.is_block_list = true; ext.length_word = length_word; ext.block_count = (uint8_t)(ext.block_count + block_count); ext.block_bytes = (uint16_t)(ext.block_bytes + data_bytes); chunk_body = data_bytes; chunk_payload = payload + pos + 4U; } else { break; } ext.is_extension_payload = true; ext.chunk_count++; ext.extension_payload_bytes = (uint16_t)(ext.extension_payload_bytes + chunk_body); preview_room = (uint16_t)(WP_D4_EXTENSION_PREVIEW_BYTES - ext.preview_length); preview_copy = chunk_body; if (preview_copy > preview_room) { preview_copy = preview_room; ext.preview_truncated = true; } if (preview_copy != 0U && chunk_payload != NULL) { memcpy(ext.preview + ext.preview_length, chunk_payload, preview_copy); ext.preview_length = (uint16_t)(ext.preview_length + preview_copy); } else if (chunk_body != 0U && preview_room == 0U) { ext.preview_truncated = true; } pos = (uint16_t)(pos + chunk_total); } if (!ext.is_extension_payload) { return false; } ext.decoded_payload_bytes = pos; ext.trailing_unparsed_bytes = (uint16_t)(payload_length - pos); if (out_extension != NULL) { *out_extension = ext; } return true; } bool wp_variable_decode_extension_record(const WpRecord *rec, WpD4ExtensionPayload *out_extension) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U || rec->sub_code != 0x02U) { wp_variable_clear_extension(out_extension); return false; } return wp_variable_decode_extension_payload(rec->data, rec->data_length, out_extension); } bool wp_variable_decode_line_metric_payload(const uint8_t *payload, uint16_t payload_length, WpD4LineMetricPayload *out_metric) { WpD4LineMetricPayload metric; uint16_t tail_offset = 20U; wp_variable_clear_line_metric(out_metric); memset(&metric, 0, sizeof(metric)); if (payload == NULL || payload_length < tail_offset) { return false; } metric.record_type = wp_var_le16(payload); if (metric.record_type != 0x1200U) { return false; } /* layout_bootstrap_line_from_secondary_gate / layout_init_line_build_from_postprocess * emit 0x1200 line metric checkpoints before replaying line-build state. * The first 20 bytes are fixed words; any tail is a record-extension copy * using the same marker-1/marker-2 chunks as the D4 line-window path. */ metric.is_line_metric = true; metric.position_word = wp_var_le16(payload + 2U); metric.sequence_word = wp_var_le16(payload + 4U); metric.aux_word_a = wp_var_le16(payload + 6U); metric.aux_word_b = wp_var_le16(payload + 8U); metric.flags_word = wp_var_le16(payload + 10U); metric.gate_word = wp_var_le16(payload + 12U); metric.extent_word_a = wp_var_le16(payload + 14U); metric.extent_word_b = wp_var_le16(payload + 16U); metric.line_start_word = wp_var_le16(payload + 18U); if (payload_length > tail_offset) { metric.has_extension_payload = wp_variable_decode_extension_payload(payload + tail_offset, (uint16_t)(payload_length - tail_offset), &metric.extension); } if (out_metric != NULL) { *out_metric = metric; } return true; } bool wp_variable_decode_line_metric_record(const WpRecord *rec, WpD4LineMetricPayload *out_metric) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U) { wp_variable_clear_line_metric(out_metric); return false; } return wp_variable_decode_line_metric_payload(rec->data, rec->data_length, out_metric); } bool wp_variable_decode_line_build_checkpoint_payload(const uint8_t *payload, uint16_t payload_length, WpD4LineBuildCheckpointPayload *out_checkpoint) { WpD4LineBuildCheckpointPayload checkpoint; wp_variable_clear_line_build_checkpoint(out_checkpoint); memset(&checkpoint, 0, sizeof(checkpoint)); if (payload == NULL || payload_length != 4U) { return false; } checkpoint.is_line_build_checkpoint = true; checkpoint.line_build_word_51f1 = wp_var_le16(payload + 0U); checkpoint.line_build_word_51f3 = wp_var_le16(payload + 2U); if (out_checkpoint != NULL) { *out_checkpoint = checkpoint; } return true; } bool wp_variable_decode_line_build_checkpoint_record(const WpRecord *rec, WpD4LineBuildCheckpointPayload *out_checkpoint) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U || rec->sub_code != 0x05U) { wp_variable_clear_line_build_checkpoint(out_checkpoint); return false; } return wp_variable_decode_line_build_checkpoint_payload(rec->data, rec->data_length, out_checkpoint); } bool wp_variable_decode_word_pair_checkpoint_payload(const uint8_t *payload, uint16_t payload_length, WpD4WordPairCheckpointPayload *out_checkpoint) { WpD4WordPairCheckpointPayload checkpoint; wp_variable_clear_word_pair_checkpoint(out_checkpoint); memset(&checkpoint, 0, sizeof(checkpoint)); if (payload == NULL || payload_length != 4U) { return false; } /* D4/subcode 09 packets in PRINTER.TST carry exactly two little-endian * words and travel through the generic D4 packet path rather than the * deep 01/03/04 layout subcommand path. The field names remain structural * until the exact UI-level meaning is recovered. */ checkpoint.is_word_pair_checkpoint = true; checkpoint.word_a = wp_var_le16(payload + 0U); checkpoint.word_b = wp_var_le16(payload + 2U); if (out_checkpoint != NULL) { *out_checkpoint = checkpoint; } return true; } bool wp_variable_decode_word_pair_checkpoint_record(const WpRecord *rec, WpD4WordPairCheckpointPayload *out_checkpoint) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U || rec->sub_code != 0x09U) { wp_variable_clear_word_pair_checkpoint(out_checkpoint); return false; } return wp_variable_decode_word_pair_checkpoint_payload(rec->data, rec->data_length, out_checkpoint); } bool wp_variable_decode_position_marker_payload(const uint8_t *payload, uint16_t payload_length, WpD4PositionMarkerPayload *out_marker) { WpD4PositionMarkerPayload marker; wp_variable_clear_position_marker(out_marker); memset(&marker, 0, sizeof(marker)); if (payload == NULL || payload_length != 13U) { return false; } marker.record_type = wp_var_le16(payload); if (marker.record_type != 0x0B00U) { return false; } /* External WP 5.1 desktop-publishing tutorial documents use compact * 0x0B00 D4/subcode-00 records as position/sequence checkpoints. The * field names are structural until the exact menu-level meaning is tied * back to the original runtime, but the packet is now byte-bounded and * recognized instead of being parser debt. */ marker.is_position_marker = true; marker.position_word = wp_var_le16(payload + 2U); marker.sequence_word = wp_var_le16(payload + 4U); marker.aux_word_a = wp_var_le16(payload + 6U); marker.aux_word_b = wp_var_le16(payload + 8U); marker.aux_word_c = wp_var_le16(payload + 10U); marker.tail_byte = payload[12U]; if (out_marker != NULL) { *out_marker = marker; } return true; } bool wp_variable_decode_position_marker_record(const WpRecord *rec, WpD4PositionMarkerPayload *out_marker) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U || rec->sub_code != 0x00U) { wp_variable_clear_position_marker(out_marker); return false; } return wp_variable_decode_position_marker_payload(rec->data, rec->data_length, out_marker); } bool wp_variable_decode_control_word_payload(const uint8_t *payload, uint16_t payload_length, WpD4ControlWordPayload *out_control) { WpD4ControlWordPayload control; wp_variable_clear_control_word(out_control); memset(&control, 0, sizeof(control)); if (payload == NULL || payload_length != 2U) { return false; } control.control_word = wp_var_le16(payload); if (control.control_word != 0x0001U) { return false; } control.is_control_word = true; if (out_control != NULL) { *out_control = control; } return true; } bool wp_variable_decode_control_word_record(const WpRecord *rec, WpD4ControlWordPayload *out_control) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U || rec->sub_code != 0x03U) { wp_variable_clear_control_word(out_control); return false; } return wp_variable_decode_control_word_payload(rec->data, rec->data_length, out_control); } bool wp_variable_decode_compact_metric_payload(const uint8_t *payload, uint16_t payload_length, WpD4CompactMetricPayload *out_metric) { WpD4CompactMetricPayload metric; uint16_t i; wp_variable_clear_compact_metric(out_metric); memset(&metric, 0, sizeof(metric)); if (payload == NULL || payload_length != (uint16_t)(WP_D4_COMPACT_METRIC_WORDS * 2U)) { return false; } for (i = 0U; i < WP_D4_COMPACT_METRIC_WORDS; ++i) { metric.raw_words[i] = wp_var_le16(payload + (size_t)i * 2U); } metric.record_type = metric.raw_words[0]; if (metric.record_type != 0x0A00U) { return false; } /* Compact D4 metrics appear in independent WP5.x macro document streams. * Values are kept as raw 16-bit WP layout units; no fixed-point scale is * inferred at this interface. */ metric.is_compact_metric = true; metric.word_a = metric.raw_words[1]; metric.word_b = metric.raw_words[2]; metric.word_c = metric.raw_words[3]; metric.word_d = metric.raw_words[4]; metric.word_e = metric.raw_words[5]; if (out_metric != NULL) { *out_metric = metric; } return true; } bool wp_variable_decode_compact_metric_record(const WpRecord *rec, WpD4CompactMetricPayload *out_metric) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U || rec->sub_code != 0x01U) { wp_variable_clear_compact_metric(out_metric); return false; } return wp_variable_decode_compact_metric_payload(rec->data, rec->data_length, out_metric); } bool wp_variable_decode_layout_anchor_payload(const uint8_t *payload, uint16_t payload_length, WpD4LayoutAnchorPayload *out_anchor) { WpD4LayoutAnchorPayload anchor; uint16_t i; wp_variable_clear_layout_anchor(out_anchor); memset(&anchor, 0, sizeof(anchor)); if (payload == NULL || payload_length != (uint16_t)(WP_D4_LAYOUT_ANCHOR_WORDS * 2U)) { return false; } for (i = 0U; i < WP_D4_LAYOUT_ANCHOR_WORDS; ++i) { anchor.raw_words[i] = wp_var_le16(payload + (size_t)i * 2U); } anchor.record_type = anchor.raw_words[0]; if (anchor.record_type != 0x1A00U) { return false; } /* GraphCat/BookBild macro documents emit this D4/subcode-00 layout * anchor as 15 raw little-endian WP layout words. The words remain in * original WP units; this decoder does not rescale, round, or saturate * them, it only bounds and names the structure so strict analysis can * distinguish it from unresolved parser debt. */ anchor.is_layout_anchor = true; anchor.anchor_word = anchor.raw_words[1]; anchor.sequence_word = anchor.raw_words[2]; anchor.flags_word_a = anchor.raw_words[3]; anchor.flags_word_b = anchor.raw_words[4]; anchor.group_word = anchor.raw_words[5]; anchor.aux_word = anchor.raw_words[6]; anchor.span_word_a = anchor.raw_words[7]; anchor.span_word_b = anchor.raw_words[8]; anchor.span_word_c = anchor.raw_words[9]; anchor.margin_word_a = anchor.raw_words[10]; anchor.margin_word_b = anchor.raw_words[11]; anchor.metric_word = anchor.raw_words[12]; anchor.line_advance_word = anchor.raw_words[13]; anchor.tail_word = anchor.raw_words[14]; if (out_anchor != NULL) { *out_anchor = anchor; } return true; } bool wp_variable_decode_layout_anchor_record(const WpRecord *rec, WpD4LayoutAnchorPayload *out_anchor) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U || rec->sub_code != 0x00U) { wp_variable_clear_layout_anchor(out_anchor); return false; } return wp_variable_decode_layout_anchor_payload(rec->data, rec->data_length, out_anchor); } static bool wp_variable_decode_definition_record(const WpRecord *rec, WpD1DefinitionPayload *out_payload) { WpD1DefinitionPayload payload; const uint8_t *p; uint16_t len; wp_variable_clear_definition_payload(out_payload); memset(&payload, 0, sizeof(payload)); if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD1U) { return false; } p = rec->data; len = rec->data_length; payload.is_definition = true; if (p != NULL && len > 0U) { payload.definition_id = p[0]; } if (p != NULL && len >= 3U) { payload.word_a = wp_var_le16(p + 1U); } if (p != NULL && len >= 5U) { payload.word_b = wp_var_le16(p + 3U); } if (p != NULL && len >= 7U) { payload.word_c = wp_var_le16(p + 5U); } if (p != NULL && len >= 9U) { payload.word_d = wp_var_le16(p + 7U); } if (p != NULL && len >= 10U) { payload.flags_a = p[9U]; } if (p != NULL && len >= 11U) { payload.flags_b = p[10U]; } wp_variable_capture_text_preview(p, len, &payload.text); if (out_payload != NULL) { *out_payload = payload; } return true; } static bool wp_variable_decode_outline_record(const WpRecord *rec, WpD2OutlinePayload *out_payload) { WpD2OutlinePayload payload; const uint8_t *p; uint16_t len; wp_variable_clear_outline_payload(out_payload); memset(&payload, 0, sizeof(payload)); if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD2U) { return false; } p = rec->data; len = rec->data_length; payload.is_outline = true; payload.family = rec->sub_code; if (p != NULL && len > 0U) { payload.level_count = p[0]; } if (p != NULL && len >= 3U) { payload.word_a = wp_var_le16(p + 1U); } if (p != NULL && len >= 5U) { payload.word_b = wp_var_le16(p + 3U); } if (p != NULL && len >= 7U) { payload.word_c = wp_var_le16(p + 5U); } if (p != NULL && len >= 9U) { payload.word_d = wp_var_le16(p + 7U); } wp_variable_capture_text_preview(p, len, &payload.text); if (out_payload != NULL) { *out_payload = payload; } return true; } static bool wp_variable_decode_generated_text_record(const WpRecord *rec, WpD3GeneratedTextPayload *out_payload) { WpD3GeneratedTextPayload payload; const uint8_t *p; uint16_t len; wp_variable_clear_generated_text_payload(out_payload); memset(&payload, 0, sizeof(payload)); if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD3U) { return false; } p = rec->data; len = rec->data_length; payload.is_generated_text = true; if (p != NULL && len > 0U) { payload.selector = p[0]; } if (p != NULL && len >= 3U) { payload.word_a = wp_var_le16(p + 1U); } if (p != NULL && len >= 5U) { payload.word_b = wp_var_le16(p + 3U); } wp_variable_capture_text_preview(p, len, &payload.text); if (out_payload != NULL) { *out_payload = payload; } return true; } static bool wp_variable_decode_delayed_text_record(const WpRecord *rec, WpDelayedTextPayload *out_payload) { WpDelayedTextPayload payload; const uint8_t *p; uint16_t len; wp_variable_clear_delayed_text_payload(out_payload); memset(&payload, 0, sizeof(payload)); if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || (rec->code != 0xD7U && rec->code != 0xD8U && rec->code != 0xD9U)) { return false; } p = rec->data; len = rec->data_length; payload.is_delayed_text = true; payload.code = rec->code; payload.sub_code = rec->sub_code; if (p != NULL && len >= 2U) { payload.prefix_word = wp_var_le16(p); } if (p != NULL && len >= 3U) { payload.selector = p[2U]; } wp_variable_capture_text_preview(p, len, &payload.text); if (out_payload != NULL) { *out_payload = payload; } return true; } static bool wp_variable_decode_repeat_group_record(const WpRecord *rec, WpRepeatGroupPayload *out_payload) { WpRepeatGroupPayload payload; uint16_t word_count; uint16_t i; wp_variable_clear_repeat_group_payload(out_payload); memset(&payload, 0, sizeof(payload)); if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || (rec->code != 0xD5U && rec->code != 0xD6U)) { return false; } if (rec->data_length != 0U && rec->data == NULL) { return false; } payload.is_repeat_group = true; payload.code = rec->code; payload.sub_code = rec->sub_code; payload.payload_bytes = rec->data_length; word_count = (uint16_t)(rec->data_length / 2U); if (word_count > WP_REPEAT_GROUP_PREVIEW_WORDS) { word_count = WP_REPEAT_GROUP_PREVIEW_WORDS; } payload.preview_word_count = (uint8_t)word_count; for (i = 0U; i < word_count; ++i) { payload.preview_words[i] = wp_var_le16(rec->data + (size_t)i * 2U); } if ((rec->data_length & 1U) != 0U && rec->data != NULL) { payload.has_odd_trailing_byte = true; payload.odd_trailing_byte = rec->data[rec->data_length - 1U]; } if (out_payload != NULL) { *out_payload = payload; } return true; } static bool wp_variable_decode_box_object_record(const WpRecord *rec, WpBoxObjectPayload *out_payload) { WpBoxObjectPayload payload; const uint8_t *p; uint16_t len; wp_variable_clear_box_object_payload(out_payload); memset(&payload, 0, sizeof(payload)); if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xDAU) { return false; } p = rec->data; len = rec->data_length; payload.is_box_object = true; if (p != NULL && len > 0U) { payload.object_id = p[0U]; } if (p != NULL && len > 1U) { payload.flags_a = p[1U]; } if (p != NULL && len > 2U) { payload.flags_b = p[2U]; } if (p != NULL && len >= 5U) { payload.word_a = wp_var_le16(p + 3U); } if (p != NULL && len >= 7U) { payload.word_b = wp_var_le16(p + 5U); } if (p != NULL && len >= 9U) { payload.word_c = wp_var_le16(p + 7U); } if (p != NULL && len >= 11U) { payload.word_d = wp_var_le16(p + 9U); } wp_variable_capture_text_preview(p, len, &payload.text); if (out_payload != NULL) { *out_payload = payload; } return true; } static bool wp_variable_decode_table_layout_record(const WpRecord *rec, WpTableLayoutPayload *out_payload) { WpTableLayoutPayload payload; const uint8_t *p; uint16_t len; wp_variable_clear_table_layout_payload(out_payload); memset(&payload, 0, sizeof(payload)); if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xDCU) { return false; } p = rec->data; len = rec->data_length; payload.is_table_layout = true; if (p != NULL && len > 0U) { payload.row = p[0U]; } if (p != NULL && len > 1U) { payload.column = p[1U]; } if (p != NULL && len > 2U) { payload.cell_flags = p[2U]; } if (p != NULL && len > 3U) { payload.layout_flags = p[3U]; } if (p != NULL && len >= 6U) { payload.word_a = wp_var_le16(p + 4U); } if (p != NULL && len >= 8U) { payload.word_b = wp_var_le16(p + 6U); } if (p != NULL && len >= 10U) { payload.word_c = wp_var_le16(p + 8U); } wp_variable_capture_text_preview(p, len, &payload.text); if (out_payload != NULL) { *out_payload = payload; } return true; } static bool wp_variable_decode_system_command_record(const WpRecord *rec, WpSystemCommandPayload *out_payload) { WpSystemCommandPayload payload; wp_variable_clear_system_command_payload(out_payload); memset(&payload, 0, sizeof(payload)); if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xDEU) { return false; } payload.is_system_command = true; payload.sub_code = rec->sub_code; payload.payload_bytes = rec->data_length; if (rec->data != NULL && rec->data_length >= 2U) { payload.has_word_a = true; payload.word_a = wp_var_le16(rec->data); } if (out_payload != NULL) { *out_payload = payload; } return true; } static bool wp_variable_decode_layout_optional_chunks(const uint8_t *payload, uint16_t payload_length, WpLayoutStatePayload *state) { uint16_t pos = 24U; if (state == NULL) { return false; } state->decoded_payload_bytes = pos; if (payload == NULL || payload_length <= pos) { return true; } while (pos < payload_length) { uint8_t marker = payload[pos]; if (!state->has_extension_marker) { state->has_extension_marker = true; state->extension_marker = marker; if (pos + 1U < payload_length) { state->extension_size_hint = payload[pos + 1U]; } } if (marker == 1U) { uint8_t chunk_size; uint16_t chunk_total; uint16_t body; uint16_t tail; if (pos + 2U > payload_length) { break; } chunk_size = payload[pos + 1U]; chunk_total = (uint16_t)(2U + chunk_size); if (chunk_total < 2U || pos + chunk_total > payload_length) { break; } state->has_variant_snapshot = true; state->variant_chunk_size = chunk_size; state->decoded_payload_bytes = (uint16_t)(pos + chunk_total); /* append_layout_state_record stores a chunk-1 marker whose size is * ((variant_count - 1) * 6 + 0x14). The variable-sized prefix is * per-variant metric state; the final 20 bytes restore the common * variant/snapshot words. */ if (chunk_size >= 20U) { state->variant_prefix_bytes = (uint8_t)(chunk_size - 20U); body = (uint16_t)(pos + 2U); tail = (uint16_t)(body + state->variant_prefix_bytes); state->variant_limit = wp_var_le16(payload + tail + 0U); state->saved_wrap_value = wp_var_le16(payload + tail + 2U); state->variant_anchor = wp_var_le16(payload + tail + 4U); state->variant_live_limit = wp_var_le16(payload + tail + 6U); state->saved_snapshot.pending_offset = wp_var_le16(payload + tail + 8U); state->saved_snapshot.pending_level = wp_var_le16(payload + tail + 10U); state->saved_snapshot.primary_limit = wp_var_le16(payload + tail + 12U); state->saved_snapshot.secondary_limit = wp_var_le16(payload + tail + 14U); state->saved_snapshot.primary_origin = wp_var_le16(payload + tail + 16U); state->saved_snapshot.secondary_origin = wp_var_le16(payload + tail + 18U); } pos = (uint16_t)(pos + chunk_total); continue; } if (marker == 2U) { uint16_t length_word; uint8_t block_count; uint16_t data_bytes; uint16_t total; uint16_t preview; if (pos + 4U > payload_length) { break; } length_word = wp_var_le16(payload + pos + 1U); block_count = payload[pos + 3U]; data_bytes = (uint16_t)((uint16_t)block_count * 16U); total = (uint16_t)(4U + data_bytes); /* The original writes length_word=(block_count*16)+1 followed by * the count byte and then 16-byte blocks. Keep the length check * tolerant, because corrupt records should remain bounded rather * than desynchronising the host parser. */ if (length_word != (uint16_t)(data_bytes + 1U) || pos + total > payload_length) { break; } state->has_extension_blocks = true; state->extension_block_count = block_count; state->extension_block_bytes = data_bytes; preview = data_bytes; if (preview > WP_LAYOUT_STATE_EXTENSION_PREVIEW_BYTES) { preview = WP_LAYOUT_STATE_EXTENSION_PREVIEW_BYTES; state->extension_preview_truncated = true; } state->extension_preview_length = preview; if (preview != 0U) { memcpy(state->extension_preview, payload + pos + 4U, preview); } state->decoded_payload_bytes = (uint16_t)(pos + total); pos = (uint16_t)(pos + total); continue; } break; } if (state->decoded_payload_bytes < payload_length) { state->trailing_unparsed_bytes = (uint16_t)(payload_length - state->decoded_payload_bytes); } return true; } bool wp_variable_decode_layout_state_payload(const uint8_t *payload, uint16_t payload_length, WpLayoutStatePayload *out_state) { WpLayoutStatePayload state; wp_variable_clear_layout_state(out_state); if (payload == NULL || payload_length < 24U) { return false; } memset(&state, 0, sizeof(state)); state.record_type = wp_var_le16(payload + 0U); if (state.record_type != 0x1600U) { return false; } /* Ported from append_layout_state_record / restore_layout_state_record * in decompiled_wp_exe.c around 1000:4d10. The mirrored D4 envelope is * stripped by wp_record_parser, so payload[0] begins with the 0x1600 * layout-state record type followed by the saved layout globals. */ state.is_layout_state = true; state.carry_width = wp_var_le16(payload + 2U); state.wrap_value = wp_var_le16(payload + 4U); state.pending_offset = wp_var_le16(payload + 6U); state.pending_level = payload[8U]; state.extra_byte = payload[9U]; state.state_flags = payload[10U]; state.mode_flags = payload[11U]; state.mode_flags_2 = payload[12U]; state.restore_flags = payload[13U]; state.pending_total = wp_var_le16(payload + 14U); state.primary_limit = wp_var_le16(payload + 16U); state.secondary_limit = wp_var_le16(payload + 18U); state.primary_origin = wp_var_le16(payload + 20U); state.secondary_origin = wp_var_le16(payload + 22U); (void)wp_variable_decode_layout_optional_chunks(payload, payload_length, &state); if (out_state != NULL) { *out_state = state; } return true; } bool wp_variable_decode_layout_state_record(const WpRecord *rec, WpLayoutStatePayload *out_state) { if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH || rec->code != 0xD4U) { wp_variable_clear_layout_state(out_state); return false; } return wp_variable_decode_layout_state_payload(rec->data, rec->data_length, out_state); } bool wp_variable_capture_layout_state(const WpLayoutGlobals *wl, WpLayoutStatePayload *out_state) { WpLayoutStatePayload state; uint16_t extension_bytes; uint16_t preview; if (out_state == NULL) { return false; } memset(&state, 0, sizeof(state)); if (wl == NULL) { *out_state = state; return false; } state.is_layout_state = true; state.record_type = 0x1600U; state.carry_width = (uint16_t)wl->carry_width; state.wrap_value = wl->wrap_value; state.pending_offset = wl->pending_offset; state.pending_level = wl->pending_level.bytes[0]; state.extra_byte = wl->record_extra_byte; state.state_flags = wl->state_flags; state.mode_flags = wl->record_mode_flags; state.mode_flags_2 = wl->record_mode_flags_2; state.restore_flags = wl->restore_flags; state.pending_total = wl->pending_total; state.primary_limit = wl->primary_limit; state.secondary_limit = wl->secondary_limit; state.primary_origin = wl->primary_origin; state.secondary_origin = wl->secondary_origin; state.decoded_payload_bytes = 24U; if (wl->variant_count != 0 && wl->variant_count == wl->active_variant_index && (wl->variant_flags & 0xC0U) == 0U) { state.has_extension_marker = true; state.extension_marker = 1U; state.extension_size_hint = 20U; state.has_variant_snapshot = true; state.variant_chunk_size = 20U; state.variant_prefix_bytes = 0U; state.variant_limit = wl->variant_limit; state.saved_wrap_value = wl->saved_wrap_value; state.variant_anchor = wl->variant_anchor; state.variant_live_limit = wl->variant_live_limit; state.saved_snapshot = wl->saved_snapshot; state.decoded_payload_bytes = (uint16_t)(state.decoded_payload_bytes + 22U); } if (wl->record_extension_block_count != 0 && wl->record_extension_buffer != NULL) { extension_bytes = (uint16_t)((uint16_t)wl->record_extension_block_count * 16U); if (!state.has_extension_marker) { state.has_extension_marker = true; state.extension_marker = 2U; state.extension_size_hint = (uint8_t)((extension_bytes + 1U) & 0xFFU); } state.has_extension_blocks = true; state.extension_block_count = wl->record_extension_block_count; state.extension_block_bytes = extension_bytes; preview = extension_bytes; if (preview > WP_LAYOUT_STATE_EXTENSION_PREVIEW_BYTES) { preview = WP_LAYOUT_STATE_EXTENSION_PREVIEW_BYTES; state.extension_preview_truncated = true; } state.extension_preview_length = preview; memcpy(state.extension_preview, wl->record_extension_buffer, preview); state.decoded_payload_bytes = (uint16_t)(state.decoded_payload_bytes + 4U + extension_bytes); } *out_state = state; return true; } bool wp_variable_apply_layout_state(WpLayoutGlobals *wl, const WpLayoutStatePayload *state) { int old_wrap; int carry; bool copied_all_extensions = true; if (wl == NULL || state == NULL || !state->is_layout_state || state->record_type != 0x1600U) { return false; } /* restore_layout_state_record subtracts the default span words from the * restored carry width when restore_mode==1 and restore_control_flags bit 3 * is set. Keep the arithmetic signed to match the 16-bit path. */ carry = (int)(int16_t)state->carry_width; if (wl->restore_mode == 1 && (wl->restore_control_flags & 8U) != 0U) { carry -= (int)(int16_t)wp_variable_span_word_as_uint(wl->default_span_a); carry -= (int)(int16_t)wp_variable_span_word_as_uint(wl->default_span_b); } wl->carry_width = carry; old_wrap = (int)(int16_t)wl->wrap_value; wl->wrap_value = state->wrap_value; wl->running_wrap_total = wl->running_wrap_total - (old_wrap - (int)(int16_t)wl->wrap_value); wl->pending_offset = state->pending_offset; wl->pending_level.word = state->pending_level; if ((wl->restore_control_flags & 4U) != 0U) { wl->record_extra_byte = state->extra_byte; } wl->state_flags = state->state_flags; wl->record_mode_flags = state->mode_flags; wl->record_mode_flags_2 = state->mode_flags_2; wl->restore_flags = state->restore_flags; wl->pending_total = state->pending_total; wl->primary_limit = state->primary_limit; wl->secondary_limit = state->secondary_limit; wl->primary_origin = state->primary_origin; wl->secondary_origin = state->secondary_origin; if (state->has_variant_snapshot) { wl->variant_limit = state->variant_limit; wl->saved_wrap_value = state->saved_wrap_value; wl->variant_anchor = state->variant_anchor; wl->variant_live_limit = state->variant_live_limit; wl->saved_snapshot = state->saved_snapshot; } if (state->has_extension_blocks) { uint16_t capacity_bytes = (uint16_t)((uint16_t)wl->record_extension_block_capacity * 16U); uint16_t copy_bytes = state->extension_block_bytes; if (copy_bytes > state->extension_preview_length) { copy_bytes = state->extension_preview_length; copied_all_extensions = false; } if (copy_bytes > capacity_bytes) { copy_bytes = capacity_bytes; copied_all_extensions = false; } wl->record_extension_block_count = state->extension_block_count; if (wl->record_extension_buffer != NULL && copy_bytes != 0U) { memcpy(wl->record_extension_buffer, state->extension_preview, copy_bytes); } else if (state->extension_block_bytes != 0U) { copied_all_extensions = false; } } return copied_all_extensions && !state->extension_preview_truncated; } size_t wp_variable_layout_state_payload_size(const WpLayoutStatePayload *state) { size_t size = 24U; if (state == NULL || !state->is_layout_state || state->record_type != 0x1600U) { return 0U; } if (state->has_variant_snapshot) { size += 2U + 20U; } if (state->has_extension_blocks) { size += 4U + (size_t)state->extension_block_bytes; } return size; } bool wp_variable_encode_layout_state_payload(const WpLayoutStatePayload *state, uint8_t *out, size_t out_capacity, size_t *out_len) { size_t need; size_t pos = 0U; if (out_len != NULL) { *out_len = 0U; } need = wp_variable_layout_state_payload_size(state); if (state == NULL || need == 0U || out == NULL || out_capacity < need || need > 0xFFFFU) { return false; } wp_var_put_le16(out + 0U, 0x1600U); wp_var_put_le16(out + 2U, state->carry_width); wp_var_put_le16(out + 4U, state->wrap_value); wp_var_put_le16(out + 6U, state->pending_offset); out[8U] = state->pending_level; out[9U] = state->extra_byte; out[10U] = state->state_flags; out[11U] = state->mode_flags; out[12U] = state->mode_flags_2; out[13U] = state->restore_flags; wp_var_put_le16(out + 14U, state->pending_total); wp_var_put_le16(out + 16U, state->primary_limit); wp_var_put_le16(out + 18U, state->secondary_limit); wp_var_put_le16(out + 20U, state->primary_origin); wp_var_put_le16(out + 22U, state->secondary_origin); pos = 24U; if (state->has_variant_snapshot) { out[pos++] = 1U; out[pos++] = 20U; wp_var_put_le16(out + pos + 0U, state->variant_limit); wp_var_put_le16(out + pos + 2U, state->saved_wrap_value); wp_var_put_le16(out + pos + 4U, state->variant_anchor); wp_var_put_le16(out + pos + 6U, state->variant_live_limit); wp_var_put_le16(out + pos + 8U, state->saved_snapshot.pending_offset); wp_var_put_le16(out + pos + 10U, state->saved_snapshot.pending_level); wp_var_put_le16(out + pos + 12U, state->saved_snapshot.primary_limit); wp_var_put_le16(out + pos + 14U, state->saved_snapshot.secondary_limit); wp_var_put_le16(out + pos + 16U, state->saved_snapshot.primary_origin); wp_var_put_le16(out + pos + 18U, state->saved_snapshot.secondary_origin); pos += 20U; } if (state->has_extension_blocks) { uint16_t bytes = state->extension_block_bytes; if (bytes > state->extension_preview_length) { return false; } out[pos++] = 2U; wp_var_put_le16(out + pos, (uint16_t)(bytes + 1U)); pos += 2U; out[pos++] = state->extension_block_count; if (bytes != 0U) { memcpy(out + pos, state->extension_preview, bytes); pos += bytes; } } if (out_len != NULL) { *out_len = pos; } return pos == need; } bool wp_variable_encode_layout_state_record(const WpLayoutStatePayload *state, uint8_t sub_code, uint8_t *out, size_t out_capacity, size_t *out_len) { size_t payload_len; uint16_t declared; if (out_len != NULL) { *out_len = 0U; } payload_len = wp_variable_layout_state_payload_size(state); if (payload_len == 0U || payload_len > 0xFFFBU || out == NULL || out_capacity < payload_len + 8U) { return false; } declared = (uint16_t)(payload_len + 4U); out[0] = 0xD4U; out[1] = sub_code; wp_var_put_le16(out + 2U, declared); if (!wp_variable_encode_layout_state_payload(state, out + 4U, out_capacity - 8U, NULL)) { return false; } wp_var_put_le16(out + 4U + payload_len, declared); out[4U + payload_len + 2U] = sub_code; out[4U + payload_len + 3U] = 0xD4U; if (out_len != NULL) { *out_len = payload_len + 8U; } return true; } static bool wp_variable_raw_record_length(const uint8_t *bytes, uint16_t available, uint16_t *out_length, bool *out_strong_packet) { uint8_t code; const WpFixedCodeInfo *fixed; uint16_t declared; uint16_t total; if (out_length != NULL) { *out_length = 0U; } if (out_strong_packet != NULL) { *out_strong_packet = false; } if (bytes == NULL || available == 0U) { return false; } code = bytes[0]; if (code < 0xC0U) { if (out_length != NULL) { *out_length = 1U; } return true; } if (code < 0xD0U) { fixed = wp_fixed_code_info(code); if (fixed == NULL || fixed->total_length == 0U || fixed->total_length > available) { return false; } if (fixed->mirrored_trailer && bytes[fixed->total_length - 1U] != code) { return false; } if (out_length != NULL) { *out_length = fixed->total_length; } if (out_strong_packet != NULL) { *out_strong_packet = true; } return true; } if (available < 4U) { return false; } declared = wp_var_le16(bytes + 2U); if (declared < 4U) { return false; } total = (uint16_t)(declared + 4U); if (total > available) { return false; } if (wp_var_le16(bytes + total - 4U) != declared || bytes[total - 2U] != bytes[1U] || bytes[total - 1U] != code) { return false; } if (out_length != NULL) { *out_length = total; } if (out_strong_packet != NULL) { *out_strong_packet = true; } return true; } static bool wp_variable_find_nested_stream_hint(const uint8_t *payload, uint16_t payload_length, uint16_t *out_offset) { uint16_t start; if (out_offset != NULL) { *out_offset = 0U; } if (payload == NULL || payload_length == 0U) { return false; } /* D5/D6 records in the bundled corpus often contain a short command header * followed by a nested WP record stream beginning at a strong C0+/D0+ * packet. The decompiled layout_post_compare_record_touch path routes D5 * and D6 into repeated parser calls; this host-side hint locates the first * packet that can be parsed safely without trying to execute it yet. */ for (start = 0U; start < payload_length; ++start) { uint16_t cursor = start; uint16_t consumed = 0U; unsigned records = 0U; bool saw_strong = false; if (payload[start] < 0xC0U) { continue; } while (cursor < payload_length) { uint16_t len = 0U; bool strong = false; if (!wp_variable_raw_record_length(payload + cursor, (uint16_t)(payload_length - cursor), &len, &strong) || len == 0U) { break; } if (strong) { saw_strong = true; } cursor = (uint16_t)(cursor + len); consumed = (uint16_t)(consumed + len); ++records; } if (cursor == payload_length && saw_strong && records != 0U && consumed != 0U) { if (out_offset != NULL) { *out_offset = start; } return true; } } return false; } static void wp_variable_finish_post_plan(WpVariablePostComparePlan *plan) { if (plan == NULL) { return; } plan->extension_scan = (plan->flags & WP_VARIABLE_POST_EXTENSION_SCAN) != 0U; plan->refcount_adjust = (plan->flags & WP_VARIABLE_POST_REFCOUNT_ADJUST) != 0U; plan->refcount_increment = (plan->flags & WP_VARIABLE_POST_REFCOUNT_INCREMENT) != 0U; plan->refcount_decrement = plan->refcount_adjust && !plan->refcount_increment; } bool wp_variable_decode_post_compare_plan(const WpRecord *rec, WpVariablePostComparePlan *out_plan) { WpVariablePostComparePlan plan; const uint8_t *p; uint16_t len; if (out_plan != NULL) { memset(out_plan, 0, sizeof(*out_plan)); } if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH) { return false; } memset(&plan, 0, sizeof(plan)); p = rec->data; len = rec->data_length; /* Ported from layout_post_compare_record_touch / handle_escape_or_subcommand * at decompiled_wp_exe.c 1000:74ac. The original computes post-compare * action bits in uVar4: 0x100 repeat/dispatch, 0x200 extension scan, * 0x400 layout-refcount adjustment, 0x800 refcount increment. */ switch (rec->code) { case 0xDBU: if (len < 1U || p == NULL) { return false; } plan.flags = (p[0] == 0x03U) ? WP_VARIABLE_POST_REFCOUNT_ADJUST : (WP_VARIABLE_POST_REFCOUNT_ADJUST | WP_VARIABLE_POST_REFCOUNT_INCREMENT); break; case 0xD5U: if (len > 0x12U && p != NULL && p[10U] != 0U) { uint16_t count = wp_var_le16(p + 0x11U); if (count != 0U) { plan.flags = WP_VARIABLE_POST_REPEAT_DISPATCH; plan.has_repeat_count = true; plan.repeat_count = count; plan.repeat_count_offset = 0x11U; plan.repeat_count_offset_valid = true; } } break; case 0xD6U: if (len < 1U || p == NULL) { return false; } if (p[0] == 0U) { uint16_t off; plan.flags = WP_VARIABLE_POST_EXTENSION_SCAN; if (len > 6U) { off = (uint16_t)(((uint16_t)p[6U] + 1U) * 2U + 0x0CU); plan.repeat_count_offset = off; plan.repeat_count_offset_valid = true; if (off + 1U < len) { uint16_t count = wp_var_le16(p + off); if (count != 0U) { plan.flags |= WP_VARIABLE_POST_REPEAT_DISPATCH; plan.has_repeat_count = true; plan.repeat_count = count; } } } } else if (len >= 8U) { uint16_t count = wp_var_le16(p + 6U); plan.repeat_count_offset = 6U; plan.repeat_count_offset_valid = true; if (count != 0U) { plan.flags = WP_VARIABLE_POST_REPEAT_DISPATCH; plan.has_repeat_count = true; plan.repeat_count = count; } } break; case 0xDAU: if (len > 0x33U && p != NULL && p[0x33U] >= 0x40U) { plan.flags = WP_VARIABLE_POST_REPEAT_DISPATCH; plan.has_repeat_count = true; plan.repeat_count = 1U; } break; default: return false; } wp_variable_finish_post_plan(&plan); if (out_plan != NULL) { *out_plan = plan; } return true; } bool wp_variable_classify_record(const WpRecord *rec, WpVariableCommandInfo *out_info) { WpVariableCommandInfo info; if (out_info != NULL) { memset(out_info, 0, sizeof(*out_info)); } if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH) { return false; } memset(&info, 0, sizeof(info)); info.action = wp_variable_action(rec->code, rec->sub_code); info.has_initial_format_table = wp_format_table_decode_record(rec, &info.initial_table); info.scanner_bypass = (rec->code == 0xDEU && rec->sub_code == 0x31U); info.has_layout_state = wp_variable_decode_layout_state_record(rec, &info.layout_state); info.has_pending_span = wp_variable_decode_pending_span_record(rec, &info.pending_span); info.has_line_window = wp_variable_decode_line_window_record(rec, &info.line_window); info.has_line_metric = wp_variable_decode_line_metric_record(rec, &info.line_metric); info.has_extension_fragment = wp_variable_decode_extension_record(rec, &info.extension_fragment); info.has_line_build_checkpoint = wp_variable_decode_line_build_checkpoint_record(rec, &info.line_build_checkpoint); info.has_word_pair_checkpoint = wp_variable_decode_word_pair_checkpoint_record(rec, &info.word_pair_checkpoint); info.has_position_marker = wp_variable_decode_position_marker_record(rec, &info.position_marker); info.has_control_word = wp_variable_decode_control_word_record(rec, &info.control_word); info.has_compact_metric = wp_variable_decode_compact_metric_record(rec, &info.compact_metric); info.has_layout_anchor = wp_variable_decode_layout_anchor_record(rec, &info.layout_anchor); info.has_definition_payload = wp_variable_decode_definition_record(rec, &info.definition_payload); info.has_outline_payload = wp_variable_decode_outline_record(rec, &info.outline_payload); info.has_generated_text_payload = wp_variable_decode_generated_text_record(rec, &info.generated_text_payload); info.has_delayed_text_payload = wp_variable_decode_delayed_text_record(rec, &info.delayed_text_payload); info.has_repeat_group_payload = wp_variable_decode_repeat_group_record(rec, &info.repeat_group_payload); info.has_box_object_payload = wp_variable_decode_box_object_record(rec, &info.box_object_payload); info.has_table_layout_payload = wp_variable_decode_table_layout_record(rec, &info.table_layout_payload); info.has_system_command_payload = wp_variable_decode_system_command_record(rec, &info.system_command_payload); if (rec->code == 0xD5U || rec->code == 0xD6U || rec->code == 0xD9U) { info.has_nested_stream_hint = wp_variable_find_nested_stream_hint(rec->data, rec->data_length, &info.nested_stream_offset); } if (info.has_delayed_text_payload && info.has_nested_stream_hint) { info.delayed_text_payload.has_nested_stream_offset = true; info.delayed_text_payload.nested_stream_offset = info.nested_stream_offset; } info.has_post_compare_plan = wp_variable_decode_post_compare_plan(rec, &info.post_compare); if (out_info != NULL) { *out_info = info; } return true; } static void wp_variable_describe_d0_table(const WpVariableCommandInfo *info, char *out, size_t out_size) { if (info == NULL || !info->has_initial_format_table || !wp_format_table_describe(&info->initial_table, out, out_size)) { snprintf(out, out_size, "format-table unavailable"); } } static const char *wp_variable_post_flags_text(uint16_t flags) { switch (flags & (WP_VARIABLE_POST_REPEAT_DISPATCH | WP_VARIABLE_POST_EXTENSION_SCAN | WP_VARIABLE_POST_REFCOUNT_ADJUST | WP_VARIABLE_POST_REFCOUNT_INCREMENT)) { case WP_VARIABLE_POST_REPEAT_DISPATCH: return "repeat-dispatch"; case WP_VARIABLE_POST_REPEAT_DISPATCH | WP_VARIABLE_POST_EXTENSION_SCAN: return "repeat-dispatch+extension-scan"; case WP_VARIABLE_POST_EXTENSION_SCAN: return "extension-scan"; case WP_VARIABLE_POST_REFCOUNT_ADJUST: return "refcount-decrement"; case WP_VARIABLE_POST_REFCOUNT_ADJUST | WP_VARIABLE_POST_REFCOUNT_INCREMENT: return "refcount-increment"; default: return "none"; } } static void wp_variable_describe_pending_span(const WpD4PendingSpanPayload *s, char *out, size_t out_size) { snprintf(out, out_size, "pending-span type=0x%04X span-a=%u span-b=%u carry=%u total=%u", (unsigned)s->record_type, (unsigned)s->span_a, (unsigned)s->span_b, (unsigned)s->carry_width, (unsigned)((uint16_t)(s->span_a + s->span_b))); } static void wp_variable_describe_line_window(const WpD4LineWindowPayload *w, char *out, size_t out_size) { char suffix[128]; suffix[0] = '\0'; if (w->has_extension_payload) { snprintf(suffix, sizeof(suffix), " extension marker=%u size=%u bytes=%u trailing=%u", (unsigned)w->extension_marker, (unsigned)w->extension_size_hint, (unsigned)w->extension_payload_bytes, (unsigned)w->trailing_unparsed_bytes); } snprintf(out, out_size, "line-window type=0x%04X old=%u-%u new=%u-%u carry=%u%+d=>%u%s", (unsigned)w->record_type, (unsigned)w->old_line_start, (unsigned)w->old_line_extent, (unsigned)w->new_line_start, (unsigned)w->new_line_extent, (unsigned)w->carry_width_before, (int)w->carry_delta, (unsigned)w->carry_width_after, suffix); } static void wp_variable_describe_extension(const WpD4ExtensionPayload *e, char *out, size_t out_size) { if (e->has_inline_payload && e->has_block_list) { snprintf(out, out_size, "extension-fragment chunks=%u inline-bytes=%u blocks=%u block-bytes=%u bytes=%u trailing=%u", (unsigned)e->chunk_count, (unsigned)e->inline_payload_bytes, (unsigned)e->block_count, (unsigned)e->block_bytes, (unsigned)e->extension_payload_bytes, (unsigned)e->trailing_unparsed_bytes); } else if (e->is_block_list) { snprintf(out, out_size, "extension-fragment marker=%u length=%u chunks=%u blocks=%u bytes=%u trailing=%u", (unsigned)e->marker, (unsigned)e->length_word, (unsigned)e->chunk_count, (unsigned)e->block_count, (unsigned)e->block_bytes, (unsigned)e->trailing_unparsed_bytes); } else { snprintf(out, out_size, "extension-fragment marker=%u size=%u chunks=%u bytes=%u trailing=%u", (unsigned)e->marker, (unsigned)e->size_hint, (unsigned)e->chunk_count, (unsigned)e->extension_payload_bytes, (unsigned)e->trailing_unparsed_bytes); } } static void wp_variable_describe_line_metric(const WpD4LineMetricPayload *m, char *out, size_t out_size) { char suffix[160]; suffix[0] = '\0'; if (m->has_extension_payload) { if (m->extension.has_inline_payload && m->extension.has_block_list) { snprintf(suffix, sizeof(suffix), " extension chunks=%u inline-bytes=%u blocks=%u block-bytes=%u bytes=%u trailing=%u", (unsigned)m->extension.chunk_count, (unsigned)m->extension.inline_payload_bytes, (unsigned)m->extension.block_count, (unsigned)m->extension.block_bytes, (unsigned)m->extension.extension_payload_bytes, (unsigned)m->extension.trailing_unparsed_bytes); } else if (m->extension.is_block_list) { snprintf(suffix, sizeof(suffix), " extension marker=%u chunks=%u blocks=%u bytes=%u trailing=%u", (unsigned)m->extension.marker, (unsigned)m->extension.chunk_count, (unsigned)m->extension.block_count, (unsigned)m->extension.block_bytes, (unsigned)m->extension.trailing_unparsed_bytes); } else { snprintf(suffix, sizeof(suffix), " extension marker=%u size=%u chunks=%u bytes=%u trailing=%u", (unsigned)m->extension.marker, (unsigned)m->extension.size_hint, (unsigned)m->extension.chunk_count, (unsigned)m->extension.extension_payload_bytes, (unsigned)m->extension.trailing_unparsed_bytes); } } snprintf(out, out_size, "line-metric type=0x%04X pos=%u seq=%u flags=0x%04X gate=%u extents=%u/%u line-start=%u%s", (unsigned)m->record_type, (unsigned)m->position_word, (unsigned)m->sequence_word, (unsigned)m->flags_word, (unsigned)m->gate_word, (unsigned)m->extent_word_a, (unsigned)m->extent_word_b, (unsigned)m->line_start_word, suffix); } static void wp_variable_describe_line_build_checkpoint(const WpD4LineBuildCheckpointPayload *c, char *out, size_t out_size) { snprintf(out, out_size, "line-build-checkpoint word51f1=%u word51f3=%u", (unsigned)c->line_build_word_51f1, (unsigned)c->line_build_word_51f3); } static void wp_variable_describe_word_pair_checkpoint(const WpD4WordPairCheckpointPayload *c, char *out, size_t out_size) { snprintf(out, out_size, "word-pair-checkpoint word-a=%u word-b=%u", (unsigned)c->word_a, (unsigned)c->word_b); } static void wp_variable_describe_position_marker(const WpD4PositionMarkerPayload *m, char *out, size_t out_size) { snprintf(out, out_size, "position-marker type=0x%04X position=%u sequence=%u aux=%u/%u/%u tail=%u", (unsigned)m->record_type, (unsigned)m->position_word, (unsigned)m->sequence_word, (unsigned)m->aux_word_a, (unsigned)m->aux_word_b, (unsigned)m->aux_word_c, (unsigned)m->tail_byte); } static void wp_variable_describe_control_word(const WpD4ControlWordPayload *c, char *out, size_t out_size) { snprintf(out, out_size, "control-word value=%u", (unsigned)c->control_word); } static void wp_variable_describe_compact_metric(const WpD4CompactMetricPayload *m, char *out, size_t out_size) { snprintf(out, out_size, "compact-metric type=0x%04X words=%u/%u/%u/%u/%u", (unsigned)m->record_type, (unsigned)m->word_a, (unsigned)m->word_b, (unsigned)m->word_c, (unsigned)m->word_d, (unsigned)m->word_e); } static void wp_variable_describe_layout_anchor(const WpD4LayoutAnchorPayload *a, char *out, size_t out_size) { snprintf(out, out_size, "layout-anchor type=0x%04X anchor=%u sequence=%u flags=%u/%u group=%u spans=%u/%u/%u margins=%u/%u metric=%u advance=%u tail=%u", (unsigned)a->record_type, (unsigned)a->anchor_word, (unsigned)a->sequence_word, (unsigned)a->flags_word_a, (unsigned)a->flags_word_b, (unsigned)a->group_word, (unsigned)a->span_word_a, (unsigned)a->span_word_b, (unsigned)a->span_word_c, (unsigned)a->margin_word_a, (unsigned)a->margin_word_b, (unsigned)a->metric_word, (unsigned)a->line_advance_word, (unsigned)a->tail_word); } static void wp_variable_describe_layout_state(const WpLayoutStatePayload *s, char *out, size_t out_size) { char suffix[192]; suffix[0] = '\0'; if (s->has_variant_snapshot && s->has_extension_blocks) { snprintf(suffix, sizeof(suffix), " variant-snapshot limit=%u anchor=%u live=%u extension-blocks=%u extension-bytes=%u", (unsigned)s->variant_limit, (unsigned)s->variant_anchor, (unsigned)s->variant_live_limit, (unsigned)s->extension_block_count, (unsigned)s->extension_block_bytes); } else if (s->has_variant_snapshot) { snprintf(suffix, sizeof(suffix), " variant-snapshot limit=%u anchor=%u live=%u", (unsigned)s->variant_limit, (unsigned)s->variant_anchor, (unsigned)s->variant_live_limit); } else if (s->has_extension_blocks) { snprintf(suffix, sizeof(suffix), " extension-blocks=%u extension-bytes=%u", (unsigned)s->extension_block_count, (unsigned)s->extension_block_bytes); } else if (s->trailing_unparsed_bytes != 0U) { snprintf(suffix, sizeof(suffix), " trailing-unparsed=%u", (unsigned)s->trailing_unparsed_bytes); } snprintf(out, out_size, "layout-state type=0x%04X carry=%u wrap=%u pending=%u level=%u flags=%02X/%02X/%02X restore=%02X limits=%u/%u origins=%u/%u%s", (unsigned)s->record_type, (unsigned)s->carry_width, (unsigned)s->wrap_value, (unsigned)s->pending_offset, (unsigned)s->pending_level, (unsigned)s->state_flags, (unsigned)s->mode_flags, (unsigned)s->mode_flags_2, (unsigned)s->restore_flags, (unsigned)s->primary_limit, (unsigned)s->secondary_limit, (unsigned)s->primary_origin, (unsigned)s->secondary_origin, suffix); } static void wp_variable_describe_preview_suffix(const WpVariableTextPreview *text, char *out, size_t out_size) { if (out == NULL || out_size == 0U) { return; } out[0] = '\0'; if (text == NULL) { return; } if (text->preview_length != 0U && text->printable_bytes != 0U) { snprintf(out, out_size, " preview=\"%s%s\" printable=%u nul=%u", text->preview, text->preview_truncated ? "..." : "", (unsigned)text->printable_bytes, (unsigned)text->nul_bytes); } else if (text->nul_bytes != 0U) { snprintf(out, out_size, " nul=%u", (unsigned)text->nul_bytes); } } static void wp_variable_describe_definition(const WpD1DefinitionPayload *payload, char *out, size_t out_size) { char suffix[160]; wp_variable_describe_preview_suffix(&payload->text, suffix, sizeof(suffix)); snprintf(out, out_size, "definition id=0x%02X words=%u/%u/%u/%u flags=%02X/%02X bytes=%u%s", (unsigned)payload->definition_id, (unsigned)payload->word_a, (unsigned)payload->word_b, (unsigned)payload->word_c, (unsigned)payload->word_d, (unsigned)payload->flags_a, (unsigned)payload->flags_b, (unsigned)payload->text.bytes_seen, suffix); } static void wp_variable_describe_outline(const WpD2OutlinePayload *payload, char *out, size_t out_size) { char suffix[160]; wp_variable_describe_preview_suffix(&payload->text, suffix, sizeof(suffix)); snprintf(out, out_size, "outline/list family=0x%02X levels=%u words=%u/%u/%u/%u bytes=%u%s", (unsigned)payload->family, (unsigned)payload->level_count, (unsigned)payload->word_a, (unsigned)payload->word_b, (unsigned)payload->word_c, (unsigned)payload->word_d, (unsigned)payload->text.bytes_seen, suffix); } static void wp_variable_describe_generated_text(const WpD3GeneratedTextPayload *payload, char *out, size_t out_size) { char suffix[160]; wp_variable_describe_preview_suffix(&payload->text, suffix, sizeof(suffix)); snprintf(out, out_size, "generated-text selector=0x%02X words=%u/%u bytes=%u%s", (unsigned)payload->selector, (unsigned)payload->word_a, (unsigned)payload->word_b, (unsigned)payload->text.bytes_seen, suffix); } static void wp_variable_describe_delayed_text(const WpDelayedTextPayload *payload, char *out, size_t out_size) { char suffix[160]; char nested[64]; wp_variable_describe_preview_suffix(&payload->text, suffix, sizeof(suffix)); nested[0] = '\0'; if (payload->has_nested_stream_offset) { snprintf(nested, sizeof(nested), " nested-stream-offset=%u", (unsigned)payload->nested_stream_offset); } snprintf(out, out_size, "delayed/generated-text code=0x%02X sub=0x%02X prefix=%u selector=0x%02X bytes=%u%s%s", (unsigned)payload->code, (unsigned)payload->sub_code, (unsigned)payload->prefix_word, (unsigned)payload->selector, (unsigned)payload->text.bytes_seen, nested, suffix); } static void wp_variable_describe_repeat_group(const WpRepeatGroupPayload *payload, char *out, size_t out_size) { char words[128]; size_t used; uint8_t i; words[0] = '\0'; used = 0U; for (i = 0U; i < payload->preview_word_count; ++i) { int wrote = snprintf(words + used, sizeof(words) - used, "%s%u", (i == 0U) ? "" : "/", (unsigned)payload->preview_words[i]); if (wrote < 0) { break; } if ((size_t)wrote >= sizeof(words) - used) { used = sizeof(words) - 1U; break; } used += (size_t)wrote; } if (payload->has_odd_trailing_byte) { snprintf(out, out_size, "repeat/group code=0x%02X sub=0x%02X bytes=%u words=%s odd-tail=0x%02X", (unsigned)payload->code, (unsigned)payload->sub_code, (unsigned)payload->payload_bytes, words, (unsigned)payload->odd_trailing_byte); } else { snprintf(out, out_size, "repeat/group code=0x%02X sub=0x%02X bytes=%u words=%s", (unsigned)payload->code, (unsigned)payload->sub_code, (unsigned)payload->payload_bytes, words); } } static void wp_variable_describe_box_object(const WpVariableCommandInfo *info, char *out, size_t out_size) { const WpBoxObjectPayload *payload; char suffix[160]; char post[80]; payload = &info->box_object_payload; wp_variable_describe_preview_suffix(&payload->text, suffix, sizeof(suffix)); post[0] = '\0'; if (info->has_post_compare_plan && info->post_compare.flags != 0U) { snprintf(post, sizeof(post), " post=%s", wp_variable_post_flags_text(info->post_compare.flags)); } snprintf(out, out_size, "box/object id=0x%02X flags=%02X/%02X words=%u/%u/%u/%u bytes=%u%s%s", (unsigned)payload->object_id, (unsigned)payload->flags_a, (unsigned)payload->flags_b, (unsigned)payload->word_a, (unsigned)payload->word_b, (unsigned)payload->word_c, (unsigned)payload->word_d, (unsigned)payload->text.bytes_seen, post, suffix); } static void wp_variable_describe_table_layout(const WpTableLayoutPayload *payload, char *out, size_t out_size) { char suffix[160]; wp_variable_describe_preview_suffix(&payload->text, suffix, sizeof(suffix)); snprintf(out, out_size, "table/layout row=%u column=%u flags=%02X/%02X words=%u/%u/%u bytes=%u%s", (unsigned)payload->row, (unsigned)payload->column, (unsigned)payload->cell_flags, (unsigned)payload->layout_flags, (unsigned)payload->word_a, (unsigned)payload->word_b, (unsigned)payload->word_c, (unsigned)payload->text.bytes_seen, suffix); } static void wp_variable_describe_system_command(const WpSystemCommandPayload *payload, char *out, size_t out_size) { if (payload->has_word_a) { snprintf(out, out_size, "system/merge command sub=0x%02X bytes=%u word-a=%u", (unsigned)payload->sub_code, (unsigned)payload->payload_bytes, (unsigned)payload->word_a); } else { snprintf(out, out_size, "system/merge command sub=0x%02X bytes=%u", (unsigned)payload->sub_code, (unsigned)payload->payload_bytes); } } static bool wp_variable_describe_post_plan(const WpVariableCommandInfo *info, char *out, size_t out_size) { const WpVariablePostComparePlan *p; if (info == NULL || !info->has_post_compare_plan || info->post_compare.flags == 0U) { return false; } p = &info->post_compare; if (p->has_repeat_count) { if (p->repeat_count_offset_valid) { snprintf(out, out_size, "%s post=%s repeat=%u repeat-offset=%u", wp_variable_action_name(info->action), wp_variable_post_flags_text(p->flags), (unsigned)p->repeat_count, (unsigned)p->repeat_count_offset); } else { snprintf(out, out_size, "%s post=%s repeat=%u", wp_variable_action_name(info->action), wp_variable_post_flags_text(p->flags), (unsigned)p->repeat_count); } } else { snprintf(out, out_size, "%s post=%s", wp_variable_action_name(info->action), wp_variable_post_flags_text(p->flags)); } return true; } bool wp_variable_describe_payload(const WpRecord *rec, char *out, size_t out_size) { WpVariableCommandInfo info; if (out == NULL || out_size == 0U) { return false; } out[0] = '\0'; if (rec == NULL || rec->type != WP_CODE_VARIABLE_LENGTH) { return false; } if (!wp_variable_classify_record(rec, &info)) { return false; } if (info.has_layout_state) { wp_variable_describe_layout_state(&info.layout_state, out, out_size); return true; } if (info.has_pending_span) { wp_variable_describe_pending_span(&info.pending_span, out, out_size); return true; } if (info.has_line_window) { wp_variable_describe_line_window(&info.line_window, out, out_size); return true; } if (info.has_line_metric) { wp_variable_describe_line_metric(&info.line_metric, out, out_size); return true; } if (info.has_line_build_checkpoint) { wp_variable_describe_line_build_checkpoint(&info.line_build_checkpoint, out, out_size); return true; } if (info.has_word_pair_checkpoint) { wp_variable_describe_word_pair_checkpoint(&info.word_pair_checkpoint, out, out_size); return true; } if (info.has_position_marker) { wp_variable_describe_position_marker(&info.position_marker, out, out_size); return true; } if (info.has_control_word) { wp_variable_describe_control_word(&info.control_word, out, out_size); return true; } if (info.has_compact_metric) { wp_variable_describe_compact_metric(&info.compact_metric, out, out_size); return true; } if (info.has_layout_anchor) { wp_variable_describe_layout_anchor(&info.layout_anchor, out, out_size); return true; } if (info.has_repeat_group_payload) { wp_variable_describe_repeat_group(&info.repeat_group_payload, out, out_size); return true; } if (info.has_extension_fragment) { wp_variable_describe_extension(&info.extension_fragment, out, out_size); return true; } if (rec->code == 0xD0U) { wp_variable_describe_d0_table(&info, out, out_size); return true; } if (info.scanner_bypass) { snprintf(out, out_size, "scanner-bypass length=%u", (unsigned)rec->declared_length); return true; } if (info.has_definition_payload) { wp_variable_describe_definition(&info.definition_payload, out, out_size); return true; } if (info.has_outline_payload) { wp_variable_describe_outline(&info.outline_payload, out, out_size); return true; } if (info.has_generated_text_payload) { wp_variable_describe_generated_text(&info.generated_text_payload, out, out_size); return true; } if (info.has_delayed_text_payload) { wp_variable_describe_delayed_text(&info.delayed_text_payload, out, out_size); return true; } if (info.has_box_object_payload) { wp_variable_describe_box_object(&info, out, out_size); return true; } if (info.has_table_layout_payload) { wp_variable_describe_table_layout(&info.table_layout_payload, out, out_size); return true; } if (info.has_system_command_payload) { wp_variable_describe_system_command(&info.system_command_payload, out, out_size); return true; } if (wp_variable_describe_post_plan(&info, out, out_size)) { return true; } if (info.has_nested_stream_hint) { snprintf(out, out_size, "%s nested-stream-offset=%u", wp_variable_action_name(info.action), (unsigned)info.nested_stream_offset); return true; } snprintf(out, out_size, "%s", wp_variable_action_name(info.action)); return true; }
Commit message
This repository is read-only for this account.
Repository snapshot
Current branch
main
Visibility
public
Your access
Read
Remote
None
File activity
View file history