///|
fn char_at(s : String, index : Int) -> Char {
s.get_char(index).unwrap()
}
///|
fn is_hex(c : Char) -> Bool {
c.is_ascii_hexdigit()
}
///|
fn hex_value(c : Char) -> Int {
if c >= '0' && c <= '9' {
c.to_int() - '0'.to_int()
} else if c >= 'A' && c <= 'F' {
c.to_int() - 'A'.to_int() + 10
} else if c >= 'a' && c <= 'f' {
c.to_int() - 'a'.to_int() + 10
} else {
-1
}
}
///|
fn is_hex_separator(c : Char) -> Bool {
c == ' ' ||
c == '\t' ||
c == '\n' ||
c == '\r' ||
c == ':' ||
c == '-' ||
c == '_' ||
c == ','
}
///|
pub fn parse_hex_bytes(input : String) -> Result[Array[Int], EdidError] {
let nibbles : Array[Int] = []
let mut index = 0
while index < input.length() {
let c = char_at(input, index)
if is_hex_separator(c) {
index = index + c.utf16_len()
continue
}
if !is_hex(c) {
return Err(
EdidError::make(
InvalidHexCharacter,
"Input contains a non-hexadecimal character",
Some(index),
),
)
}
nibbles.push(hex_value(c))
index = index + c.utf16_len()
}
if nibbles.length() % 2 != 0 {
return Err(
EdidError::make(
InvalidHexLength,
"Hexadecimal EDID input must contain an even number of digits",
None,
),
)
}
let bytes : Array[Int] = []
let mut i = 0
while i < nibbles.length() {
bytes.push((nibbles[i] << 4) + nibbles[i + 1])
i = i + 2
}
Ok(bytes)
}
///|
fn byte_at(data : Array[Int], index : Int) -> Int {
data[index] & 0xFF
}
///|
fn u16_le(data : Array[Int], index : Int) -> Int {
byte_at(data, index) + (byte_at(data, index + 1) << 8)
}
///|
fn u16_be(data : Array[Int], index : Int) -> Int {
(byte_at(data, index) << 8) + byte_at(data, index + 1)
}
///|
fn u32_le(data : Array[Int], index : Int) -> Int {
byte_at(data, index) +
(byte_at(data, index + 1) << 8) +
(byte_at(data, index + 2) << 16) +
(byte_at(data, index + 3) << 24)
}
///|
fn bit_set(value : Int, mask : Int) -> Bool {
(value & mask) != 0
}
///|
fn edid_block_checksum(data : Array[Int], offset : Int) -> Int {
let mut sum = 0
let mut i = 0
while i < 128 {
sum = (sum + byte_at(data, offset + i)) & 0xFF
i = i + 1
}
sum
}
///|
fn checksum_valid(data : Array[Int], offset : Int) -> Bool {
edid_block_checksum(data, offset) == 0
}
///|
fn has_edid_header(data : Array[Int]) -> Bool {
data.length() >= 8 &&
byte_at(data, 0) == 0x00 &&
byte_at(data, 1) == 0xFF &&
byte_at(data, 2) == 0xFF &&
byte_at(data, 3) == 0xFF &&
byte_at(data, 4) == 0xFF &&
byte_at(data, 5) == 0xFF &&
byte_at(data, 6) == 0xFF &&
byte_at(data, 7) == 0x00
}
///|
fn ascii_from_byte(value : Int) -> Char {
if value >= 32 && value <= 126 {
value.to_char().unwrap()
} else {
' '
}
}
///|
fn descriptor_text(data : Array[Int], offset : Int) -> String {
let chars : Array[Char] = []
let mut i = 5
while i < 18 {
let b = byte_at(data, offset + i)
if b == 0x0A || b == 0x0D {
break
}
chars.push(ascii_from_byte(b))
i = i + 1
}
String::from_array(chars).trim(chars=" \t\r\n").to_owned()
}