mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-27 23:37:04 -05:00
patterns: Add terminfo pattern (#437)
* patterns/terminfo: Add pattern for compiled term info entry files. This adds support for the compiled (legacy and extended) term info entry files that are used for determining terminal capabilities. * Add .bin extension to the terminfo test file.
This commit is contained in:
348
patterns/terminfo.hexpat
Normal file
348
patterns/terminfo.hexpat
Normal file
@@ -0,0 +1,348 @@
|
||||
/* info */
|
||||
#pragma author Nightowl286
|
||||
#pragma description Compiled term info entry
|
||||
|
||||
#pragma endian little
|
||||
|
||||
#pragma magic [1e 02] @ 0x00
|
||||
#pragma MIME application/x-terminfo2
|
||||
|
||||
#pragma magic [1a 01] @ 0x00
|
||||
#pragma MIME application/x-terminfo
|
||||
|
||||
/*
|
||||
Format has been primarily taken from:
|
||||
https://www.man7.org/linux/man-pages/man5/term.5.html
|
||||
|
||||
Technically you can't count on the binary formats being compatible
|
||||
on different unix versions, however *(as I've been told)* those versions
|
||||
are pretty much dead nowadays so this format is common enough to work
|
||||
in like the majority of the cases.
|
||||
*/
|
||||
|
||||
/* imports */
|
||||
import std.array;
|
||||
import std.mem;
|
||||
import std.string;
|
||||
import std.ctype;
|
||||
|
||||
|
||||
/* utility */
|
||||
fn is_char(char ch) {
|
||||
char value = std::mem::read_unsigned($, 1);
|
||||
return value == ch;
|
||||
};
|
||||
|
||||
fn is_not_char(char ch) {
|
||||
char value = std::mem::read_unsigned($, 1);
|
||||
return value != ch;
|
||||
};
|
||||
|
||||
|
||||
/* types */
|
||||
enum number_format : s16 {
|
||||
legacy = 0o432,
|
||||
extended = 0o1036
|
||||
}
|
||||
[[format("number_format_to_string")]];
|
||||
|
||||
struct boolean_capability { s8 value; }
|
||||
[[
|
||||
sealed,
|
||||
format("boolean_capability_format"),
|
||||
comment("Indicates the presence of a boolean capability.\n\n(An empty value indicates that the capability is missing).")
|
||||
]];
|
||||
|
||||
struct numerical_capability {
|
||||
if (parent.header.format == number_format::extended)
|
||||
s32 value;
|
||||
else
|
||||
s16 value;
|
||||
}
|
||||
[[
|
||||
sealed,
|
||||
format("numerical_capability_format"),
|
||||
comment("Indicates the presence of a numerical capability.\n\n(An empty value indicates that the capability is missing).")
|
||||
]];
|
||||
|
||||
struct string_table_value_offset { s16 value; }
|
||||
[[
|
||||
sealed,
|
||||
format("string_table_value_offset_format"),
|
||||
comment("Indicates the offset of a string capability value in the string table.\n\n(An empty value indicates that the capability is missing).")
|
||||
]];
|
||||
|
||||
struct string_table_name_offset { s16 value; }
|
||||
[[
|
||||
sealed,
|
||||
format("string_table_name_offset_format"),
|
||||
comment("Indicates the offset of a name string in the string table.\n\n(This value is relative to the name portion of the string table).")
|
||||
]];
|
||||
|
||||
struct terminal_name {
|
||||
char name[while(is_not_char('|') && is_not_char(0x00))];
|
||||
padding[1];
|
||||
|
||||
if (is_char('|')) $ += 1;
|
||||
if (is_char(0)) break;
|
||||
}
|
||||
[[
|
||||
sealed,
|
||||
comment("Represents a terminal name/alias.")
|
||||
]];
|
||||
|
||||
struct table_string {
|
||||
char value[while(is_not_char(0x00))];
|
||||
if (is_char(0))
|
||||
$ += 1;
|
||||
|
||||
}
|
||||
[[
|
||||
sealed,
|
||||
format("string_table_value_format"),
|
||||
comment("A null-terminated string in the string table.")
|
||||
]];
|
||||
|
||||
struct string_table {
|
||||
std::ByteSizedArray<table_string, parent.header.string_table_size> array [[inline]];
|
||||
};
|
||||
|
||||
struct legacy_header {
|
||||
number_format format
|
||||
[[comment("The number format of the terminfo entry.")]];
|
||||
|
||||
s16 name_size
|
||||
[[
|
||||
name("name size"),
|
||||
comment("The size of the terminal names in bytes.")
|
||||
]];
|
||||
|
||||
s16 boolean_count
|
||||
[[
|
||||
name("boolean capability count"),
|
||||
comment("The amount of known boolean capabilities in the file.")
|
||||
]];
|
||||
|
||||
s16 numerical_count
|
||||
[[
|
||||
name("numerical capability count"),
|
||||
comment("The amount of known numerical capabilities in the file.")
|
||||
]];
|
||||
|
||||
s16 string_count
|
||||
[[
|
||||
name("string capability count"),
|
||||
comment("The amount of known string capabilities in the file.")
|
||||
]];
|
||||
|
||||
s16 string_table_size
|
||||
[[
|
||||
name("string table size"),
|
||||
comment("The size of the string table (in bytes).")
|
||||
]];
|
||||
};
|
||||
|
||||
struct extended_header {
|
||||
s16 boolean_count
|
||||
[[
|
||||
name("boolean capability count"),
|
||||
comment("The amount of extended boolean capabilities in the file.")
|
||||
]];
|
||||
|
||||
s16 numerical_count
|
||||
[[
|
||||
name("numerical capability count"),
|
||||
comment("The amount of extended numerical capabilities in the file.")
|
||||
]];
|
||||
|
||||
s16 string_count
|
||||
[[
|
||||
name("string capability count"),
|
||||
comment("The amount of extended string capabilities in the file.")
|
||||
]];
|
||||
|
||||
s16 table_item_count
|
||||
[[
|
||||
name("table item count"),
|
||||
comment("The amount of items in the string table.")
|
||||
]];
|
||||
|
||||
s16 string_table_size
|
||||
[[
|
||||
name("string table size"),
|
||||
comment("The size of the extended string table (in bytes).")
|
||||
]];
|
||||
};
|
||||
|
||||
struct extended_data {
|
||||
extended_header header
|
||||
[[comment("The metadata about the extended section of the file.")]];
|
||||
|
||||
boolean_capability booleans[header.boolean_count]
|
||||
[[
|
||||
name("boolean capabilities"),
|
||||
comment("The extended boolean capabilities.")
|
||||
]];
|
||||
|
||||
if ($ % 2 != 0) $ += 1; // align to even boundary before numerical capabilities are read;
|
||||
|
||||
numerical_capability numerical[header.numerical_count]
|
||||
[[
|
||||
name("numerical capabilities"),
|
||||
comment("The extended numerical capabilities.")
|
||||
]];
|
||||
|
||||
string_table_value_offset string_offsets[header.string_count]
|
||||
[[
|
||||
name("string table value offsets"),
|
||||
comment("The string table offsets for the extended string capability values.")
|
||||
]];
|
||||
|
||||
string_table_name_offset name_offsets[header.table_item_count - header.string_count]
|
||||
[[
|
||||
name("string table name offsets"),
|
||||
comment("The string table offsets for all of the extended capability names.\n\n(These values are relative to the name portion of the string table).")
|
||||
]];
|
||||
|
||||
string_table string_table
|
||||
[[
|
||||
name("string table"),
|
||||
comment("Contains all of the string values used in the extended section of the file.")
|
||||
]];
|
||||
};
|
||||
|
||||
struct file {
|
||||
legacy_header header
|
||||
[[comment("The metadata about the file.")]];
|
||||
|
||||
terminal_name terminal_names[1000]
|
||||
[[
|
||||
format_entries("terminal_name_format"),
|
||||
name("terminal names"),
|
||||
comment("The names and aliases that the terminfo file is describing.")
|
||||
]];
|
||||
|
||||
boolean_capability booleans[header.boolean_count]
|
||||
[[
|
||||
name("boolean capabilities"),
|
||||
comment("The known boolean capabilities.")
|
||||
]];
|
||||
|
||||
if ($ % 2 != 0) $ += 1; // align to even boundary before numerical capabilities are read;
|
||||
|
||||
numerical_capability numerical[header.numerical_count]
|
||||
[[
|
||||
name("numerical capabilities"),
|
||||
comment("The known numerical capabilities.")
|
||||
]];
|
||||
|
||||
string_table_value_offset string_offsets[header.string_count]
|
||||
[[
|
||||
name("string table value offsets"),
|
||||
comment("The string table offsets for the known string capability values.")
|
||||
]];
|
||||
|
||||
string_table string_table
|
||||
[[
|
||||
name("string table"),
|
||||
comment("Contains all of the string values used in the (legacy storage format section of) file.")
|
||||
]];
|
||||
|
||||
if (std::mem::eof() == false) {
|
||||
extended_data extended
|
||||
[[comment("Contains the information from extended storage format section.")]];
|
||||
}
|
||||
|
||||
} [[inline]];
|
||||
|
||||
|
||||
/* formatting */
|
||||
fn terminal_name_format(terminal_name name) {
|
||||
return '"' + name.name + '"';
|
||||
};
|
||||
|
||||
fn boolean_capability_format(boolean_capability value) {
|
||||
match (value.value) {
|
||||
(-2): return "cancelled";
|
||||
(-1 | 0): return "";
|
||||
(1): return "present";
|
||||
(_): return value.value;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
fn numerical_capability_format(numerical_capability value) {
|
||||
match (value.value) {
|
||||
(-2): return "cancelled";
|
||||
(-1): return "";
|
||||
(_): return value.value;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
fn string_table_value_offset_format(string_table_value_offset value) {
|
||||
match (value.value) {
|
||||
(-2): return "cancelled";
|
||||
(-1): return "";
|
||||
(_): return value.value;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
fn string_table_name_offset_format(string_table_name_offset value) {
|
||||
return value.value;
|
||||
};
|
||||
|
||||
fn string_table_value_format(ref table_string value) {
|
||||
str view = "\"";
|
||||
|
||||
for (s16 i = 0, i < sizeof(value.value), i += 1) {
|
||||
char ch = value.value[i];
|
||||
if (ch == '\\') view += "\\\\";
|
||||
else if (ch == '"') view += "\\\"";
|
||||
else if (std::ctype::isgraph(ch)) view += ch;
|
||||
else view += to_hex_ch(ch);
|
||||
}
|
||||
|
||||
view += "\"";
|
||||
return view;
|
||||
};
|
||||
|
||||
fn to_hex_ch(char ch) {
|
||||
if (ch == '\x1b') return "\\e";
|
||||
if (ch == ' ') return " ";
|
||||
if (ch == '\r') return "\\r";
|
||||
if (ch == '\n') return "\\n";
|
||||
if (ch == '\a') return "\\a";
|
||||
if (ch == '\b') return "\\b";
|
||||
if (ch == '\t') return "\\t";
|
||||
if (ch == 11) return "\\v";
|
||||
if (ch == '\f') return "\\f";
|
||||
|
||||
s8 second = ch % 16;
|
||||
s8 first = ch / 16;
|
||||
|
||||
return "\\x" + to_hex_digit(first) + to_hex_digit(second);
|
||||
};
|
||||
|
||||
fn to_hex_digit(u8 num) {
|
||||
if (num == 10) return 'A';
|
||||
if (num == 11) return 'B';
|
||||
if (num == 12) return 'C';
|
||||
if (num == 13) return 'D';
|
||||
if (num == 14) return 'E';
|
||||
if (num == 15) return 'F';
|
||||
|
||||
return std::string::to_string(num);
|
||||
};
|
||||
|
||||
fn number_format_to_string(number_format format) {
|
||||
if (format == number_format::extended) return "extended";
|
||||
if (format == number_format::legacy) return "legacy";
|
||||
|
||||
return "unknown (" + std::string::to_string(s16(format)) + ")";
|
||||
};
|
||||
|
||||
|
||||
/* actual data */
|
||||
file file @ 0x00;
|
||||
Reference in New Issue
Block a user