ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
rle.c File Reference

ANSI RLE (REP) sequence compression and expansion. More...

Go to the source code of this file.

Functions

char * ansi_expand_rle (const char *input, size_t input_len)
 
char * ansi_compress_rle (const char *input, size_t input_len)
 

Detailed Description

ANSI RLE (REP) sequence compression and expansion.

Definition in file rle.c.

Function Documentation

◆ ansi_compress_rle()

char * ansi_compress_rle ( const char *  input,
size_t  input_len 
)

Definition at line 98 of file rle.c.

98 {
99 if (!input || input_len == 0) {
100 return NULL;
101 }
102
103 outbuf_t ob = {0};
104 ob_reserve(&ob, input_len);
105
106 size_t i = 0;
107 while (i < input_len) {
108 // Check for ESC character (start of ANSI sequence)
109 if (input[i] == '\x1b' && i + 1 < input_len && input[i + 1] == '[') {
110 size_t seq_start = i;
111 i += 2; // Skip ESC[
112
113 // Skip parameter bytes
114 while (i < input_len && ((input[i] >= '0' && input[i] <= '9') || input[i] == ';')) {
115 i++;
116 }
117
118 // Skip final byte
119 if (i < input_len) {
120 i++;
121 }
122
123 // Copy entire escape sequence as-is
124 ob_write(&ob, input + seq_start, i - seq_start);
125 } else {
126 // Regular character - check for runs
127 char c = input[i];
128
129 // Only compress printable characters (not newlines, not control chars)
130 if (c >= 0x20 && c != 0x7F) {
131 // Count run length
132 size_t run_len = 1;
133 i++;
134
135 while (i < input_len && input[i] == c) {
136 run_len++;
137 i++;
138 }
139
140 // Emit first character
141 ob_putc(&ob, c);
142
143 // Use RLE if profitable (run > overhead of ESC[Nb)
144 if (run_len > 1 && rep_is_profitable((uint32_t)run_len)) {
145 emit_rep(&ob, (uint32_t)(run_len - 1));
146 } else {
147 // Emit remaining characters directly
148 for (size_t k = 1; k < run_len; k++) {
149 ob_putc(&ob, c);
150 }
151 }
152 } else {
153 // Non-compressible character (newline, etc.)
154 ob_putc(&ob, c);
155 i++;
156 }
157 }
158 }
159
160 ob_term(&ob);
161 return ob.buf;
162}
void ob_term(outbuf_t *ob)
void ob_putc(outbuf_t *ob, char c)
bool rep_is_profitable(uint32_t runlen)
void ob_reserve(outbuf_t *ob, size_t need)
void emit_rep(outbuf_t *ob, uint32_t extra)
void ob_write(outbuf_t *ob, const char *s, size_t n)

References emit_rep(), ob_putc(), ob_reserve(), ob_term(), ob_write(), and rep_is_profitable().

◆ ansi_expand_rle()

char * ansi_expand_rle ( const char *  input,
size_t  input_len 
)

Definition at line 13 of file rle.c.

13 {
14 if (!input || input_len == 0) {
15 return NULL;
16 }
17
18 // RLE expansion can make output larger than input, start with 2x capacity
19 outbuf_t ob = {0};
20 ob_reserve(&ob, input_len * 2);
21
22 // Track the last character/grapheme for RLE expansion
23 // UTF-8 characters can be up to 4 bytes
24 char last_char[5] = " ";
25 size_t last_char_len = 1;
26
27 size_t i = 0;
28 while (i < input_len) {
29 // Check for ESC character (start of ANSI sequence)
30 if (input[i] == '\x1b' && i + 1 < input_len && input[i + 1] == '[') {
31 size_t seq_start = i;
32 i += 2; // Skip ESC[
33
34 // Parse parameter bytes (digits and semicolons)
35 uint32_t param = 0;
36 while (i < input_len && ((input[i] >= '0' && input[i] <= '9') || input[i] == ';')) {
37 if (input[i] >= '0' && input[i] <= '9') {
38 param = param * 10 + (uint32_t)(input[i] - '0');
39 } else if (input[i] == ';') {
40 param = 0; // Reset for next parameter
41 }
42 i++;
43 }
44
45 // Check for final byte
46 if (i < input_len) {
47 char final_byte = input[i];
48 i++;
49
50 // Handle RLE: ESC[Nb repeats previous character N times
51 if (final_byte == 'b' && param > 0) {
52 for (uint32_t r = 0; r < param; r++) {
53 ob_write(&ob, last_char, last_char_len);
54 }
55 } else {
56 // Not RLE - copy the entire escape sequence as-is
57 ob_write(&ob, input + seq_start, i - seq_start);
58 }
59 }
60 } else {
61 // Regular character - copy to output and track for RLE
62 unsigned char c = (unsigned char)input[i];
63 size_t char_len = 1;
64
65 // Determine UTF-8 character length from first byte
66 if ((c & 0x80) == 0) {
67 char_len = 1; // ASCII
68 } else if ((c & 0xE0) == 0xC0) {
69 char_len = 2; // 2-byte UTF-8
70 } else if ((c & 0xF0) == 0xE0) {
71 char_len = 3; // 3-byte UTF-8
72 } else if ((c & 0xF8) == 0xF0) {
73 char_len = 4; // 4-byte UTF-8
74 }
75
76 // Make sure we don't read past end of input
77 if (i + char_len > input_len) {
78 char_len = input_len - i;
79 }
80
81 // Copy full UTF-8 character to output
82 ob_write(&ob, input + i, char_len);
83
84 // Track last printable character for RLE (skip control chars)
85 if (c >= 0x20 && c != 0x7F) {
86 SAFE_MEMCPY(last_char, sizeof(last_char), input + i, char_len);
87 last_char[char_len] = '\0';
88 last_char_len = char_len;
89 }
90 i += char_len;
91 }
92 }
93
94 ob_term(&ob);
95 return ob.buf;
96}

References ob_reserve(), ob_term(), and ob_write().