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_record_parser.c
File editor
#include "wp_record_parser.h" #include "wp_fixed_codes.h" #include "wp_record_stream.h" #include <stdlib.h> #include <string.h> static void wp_record_init(WpRecord *record) { memset(record, 0, sizeof(*record)); record->type = WP_CODE_CHAR; } static void wp_record_read_payload(WpLayoutGlobals *wl, WpRecord *record, uint16_t count) { uint16_t i; record->data_length = count; if (count > 0U) { record->data = (uint8_t *)malloc(count); } for (i = 0; i < count; ++i) { uint8_t b = (uint8_t)consume_byte_from_primary_buffer(wl); if (record->data != NULL) { record->data[i] = b; } } } static uint16_t wp_record_fixed_payload_bytes(const WpFixedCodeInfo *info) { if (info == NULL) { return 0U; } return info->payload_length; } static void wp_record_read_fixed_payload(WpLayoutGlobals *wl, WpRecord *record, uint8_t code, const WpFixedCodeInfo *info) { uint16_t payload = wp_record_fixed_payload_bytes(info); uint16_t trailer_bytes = (uint16_t)(info != NULL && info->mirrored_trailer ? 1U : 0U); record->declared_length = payload; if (info == NULL || payload == 0U) { return; } wp_record_read_payload(wl, record, payload); if (trailer_bytes != 0U) { uint8_t trailing_code = (uint8_t)consume_byte_from_primary_buffer(wl); record->trailer_present = true; record->trailer_matches = trailing_code == code; } else { record->trailer_present = false; record->trailer_matches = false; } } WpCodeType wp_parser_peek_record_type(WpLayoutGlobals *wl, uint8_t code) { (void)wl; if (code < 0x80) { return WP_CODE_CHAR; } else if (code < 0xC0) { return WP_CODE_SINGLE_BYTE; } else if (code < 0xD0) { return WP_CODE_FIXED_LENGTH; } else { return WP_CODE_VARIABLE_LENGTH; } } void wp_parser_consume_record(WpLayoutGlobals *wl, WpRecord *record) { uint8_t first_byte; int bytes_before; const WpFixedCodeInfo *fixed_code_info; uint16_t fixed_payload; uint16_t fixed_available; if (record == NULL) { return; } wp_record_init(record); if (wl == NULL || wl->record_used_bytes <= 0) { return; } bytes_before = wl->record_used_bytes; first_byte = (uint8_t)consume_byte_from_primary_buffer(wl); record->code = first_byte; if (first_byte < 0x80) { record->type = WP_CODE_CHAR; record->length = 1; record->is_complete = true; return; } if (first_byte < 0xC0) { record->type = WP_CODE_SINGLE_BYTE; record->length = 1; record->is_complete = true; return; } fixed_code_info = wp_fixed_code_info(first_byte); if (first_byte < 0xD0) { record->type = WP_CODE_FIXED_LENGTH; fixed_payload = wp_record_fixed_payload_bytes(fixed_code_info); fixed_available = wp_fixed_code_total_length(first_byte); if (fixed_available > 0U) { fixed_available -= 1U; } if (fixed_available == 0U) { fixed_available = fixed_payload; if (fixed_code_info != 0 && fixed_code_info->mirrored_trailer) { fixed_available = (uint16_t)(fixed_available + 1U); } } if (fixed_available == 0U) { if (fixed_code_info != 0) { /* Known fixed packet with zero payload and no mirrored trailer. */ record->declared_length = 0U; record->is_complete = true; record->length = 1U; return; } /* Unknown fixed packet shape is treated as a one-byte placeholder. */ record->is_complete = true; record->length = 1; return; } if (wl->record_used_bytes < fixed_available) { record->declared_length = fixed_payload; record->is_complete = false; wp_record_read_payload(wl, record, (uint16_t)wl->record_used_bytes); record->length = (uint16_t)(bytes_before - wl->record_used_bytes); return; } wp_record_read_fixed_payload(wl, record, first_byte, fixed_code_info); record->is_complete = fixed_code_info->mirrored_trailer ? record->trailer_matches : true; record->length = (uint16_t)(bytes_before - wl->record_used_bytes); return; } /* Multi-byte code (0xD0 - 0xFF) * WP 5.1 variable-length record structure: * [Code] [Sub-code] [Length-Word] [Data...] [Length-Word] [Sub-code] [Code] */ record->type = WP_CODE_VARIABLE_LENGTH; if (wl->record_used_bytes < 3) { /* We cannot even read sub-code + length. Consume the remainder as an * incomplete fragment so callers do not loop forever on corrupt input. */ uint16_t fragment = (uint16_t)(wl->record_used_bytes > 0 ? wl->record_used_bytes : 0); wp_record_read_payload(wl, record, fragment); record->length = (uint16_t)(bytes_before - wl->record_used_bytes); record->is_complete = false; return; } record->sub_code = (uint8_t)consume_byte_from_primary_buffer(wl); record->declared_length = (uint16_t)consume_word_from_primary_buffer(wl); if (wl->record_used_bytes < (int)record->declared_length) { /* Incomplete variable-length record payload. Copy whatever bytes are * available and leave them unvalidated; the next parser step will see * the first remaining byte. */ uint16_t available = (uint16_t)(wl->record_used_bytes > 0 ? wl->record_used_bytes : 0); wp_record_read_payload(wl, record, available); record->trailer_present = false; record->trailer_matches = false; record->length = (uint16_t)(bytes_before - wl->record_used_bytes); record->is_complete = false; return; } if (record->declared_length > 4U) { wp_record_read_payload(wl, record, (uint16_t)(record->declared_length - 4U)); } else { wp_record_read_payload(wl, record, 0U); } if (wl->record_used_bytes < 4) { /* Payload is complete, but there are not enough bytes for a * trailing mirror. Treat this as a valid weak/legacy variable packet. * Leave trailer fields unset so callers do not treat this as * structural corruption. */ record->trailer_present = false; record->trailer_matches = false; record->is_complete = true; } else { const uint8_t *tail = (const uint8_t *)wl->primary_record.as_record_p; uint16_t trailing_length; uint8_t trailing_sub; uint8_t trailing_code; bool matches; trailing_length = (uint16_t)(tail[-1] | ((uint16_t)tail[-2] << 8U)); trailing_sub = tail[-3]; trailing_code = tail[-4]; matches = (trailing_length == record->declared_length && trailing_sub == record->sub_code && trailing_code == first_byte); if (matches) { record->trailer_present = true; record->trailer_matches = true; (void)consume_word_from_primary_buffer(wl); (void)consume_byte_from_primary_buffer(wl); (void)consume_byte_from_primary_buffer(wl); record->is_complete = true; } else { record->trailer_present = true; record->trailer_matches = false; (void)consume_word_from_primary_buffer(wl); (void)consume_byte_from_primary_buffer(wl); (void)consume_byte_from_primary_buffer(wl); record->is_complete = false; } } record->length = (uint16_t)(bytes_before - wl->record_used_bytes); } void wp_record_free(WpRecord *record) { if (record == NULL) { return; } free(record->data); wp_record_init(record); }
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