commit 5556aa64bbea0da9e3b46ec492a90c8f2225b446
parent b1fcd99ec975069313fc7bbee2fe56c0298e2586
Author: Robert Russell <robert@rr3.xyz>
Date: Sat, 28 Dec 2024 13:54:32 -0800
Fix handling of binary data
Diffstat:
| M | cembed.c | | | 43 | +++++++++++++++++++++++++++++-------------- |
1 file changed, 29 insertions(+), 14 deletions(-)
diff --git a/cembed.c b/cembed.c
@@ -6,10 +6,9 @@
#define USAGE "usage: %s [-h|--help] NAME PATH\n"
usize
-format_char(char *buf, char c) {
- // Escape specials
- switch (c) {
- case '\0': strcpy(buf, "\\0"); return 2;
+format_char(char *buf, uchar curr, uchar next) {
+ // Escape specials.
+ switch (curr) {
case '\a': strcpy(buf, "\\a"); return 2;
case '\b': strcpy(buf, "\\b"); return 2;
case '\t': strcpy(buf, "\\t"); return 2;
@@ -22,20 +21,34 @@ format_char(char *buf, char c) {
case '\\': strcpy(buf, "\\\\"); return 2;
}
- // Keep non-special printable ASCII as-is
- if (' ' <= c && c <= '~') {
- buf[0] = c;
+ // Keep non-special printable ASCII as-is.
+ if (' ' <= curr && curr <= '~') {
+ buf[0] = curr;
buf[1] = '\0';
return 1;
}
- // Hex-encode rest
+ // Octal-encode rest. We can't hex-encode, because C hex encoding is
+ // variable length.
+ char octal[4] = {
+ "01234567"[(curr >> 6) & 0x3],
+ "01234567"[(curr >> 3) & 0x7],
+ "01234567"[(curr >> 0) & 0x7],
+ '\0',
+ };
buf[0] = '\\';
- buf[1] = 'x';
- buf[2] = "0123456789abcdef"[((uchar)c >> 0) & 0xf];
- buf[3] = "0123456789abcdef"[((uchar)c >> 4) & 0xf];
- buf[4] = '\0';
- return 4;
+ // We want the encoding to be as small as possible, but if the next
+ // character is an octal digit, than we must pad to 3 digits.
+ if (('0' <= next && next <= '7') || curr >= 64) {
+ strcpy(&buf[1], &octal[0]);
+ return 4;
+ } else if (curr >= 8) {
+ strcpy(&buf[1], &octal[1]);
+ return 3;
+ } else {
+ strcpy(&buf[1], &octal[2]);
+ return 2;
+ }
}
int
@@ -73,7 +86,9 @@ main(int argc, char **argv) {
}
char buf[5];
- line_len += format_char(buf, data[i]);
+ uchar curr = data[i];
+ uchar next = i + 1 < size ? data[i + 1] : '\0';
+ line_len += format_char(buf, curr, next);
fputs(buf, stdout);
}