static HEXCHARS: [char; 16] = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
];
static ENC_CHAR: char = '$';
static ENC_BYTE: u8 = b'$';
static ESCAPE_CHAR: char = '\\';
static ESCAPE_BYTE: u8 = b'\\';
pub fn from_hex_char(h: u8) -> Result<u8, ()> {
if h.is_ascii_digit() {
Ok(h - b'0')
} else if (b'a'..=b'f').contains(&h) {
Ok(h - b'a' + 10)
} else if (b'A'..=b'F').contains(&h) {
Ok(h - b'A' + 10)
} else {
Err(())
}
}
pub fn key_to_text(key: &[u8]) -> String {
let mut outlen: usize = 0;
for &x in key {
if (32..=126).contains(&x) && x != ENC_BYTE {
outlen += 1;
} else {
outlen += 3;
}
}
let mut out = String::with_capacity(outlen);
for &x in key {
if (32..=126).contains(&x) && x != ENC_BYTE {
out.push(char::from_u32(x as u32).unwrap());
} else {
out.push(ENC_CHAR);
out.push(HEXCHARS[((x >> 4) & 0x0F) as usize]);
out.push(HEXCHARS[(x & 0x0F) as usize]);
}
}
out
}
fn is_like_special(ch: u8) -> bool {
ch == b'_' || ch == b'%'
}
pub fn like_key_to_text(key: &[u8]) -> String {
let mut outlen: usize = 0;
for &x in key {
if (32..=126).contains(&x) && x != ENC_BYTE {
if is_like_special(x) || x == ESCAPE_BYTE {
outlen += 2;
} else {
outlen += 1;
}
} else {
outlen += 3;
}
}
let mut out = String::with_capacity(outlen);
for &x in key {
if (32..=126).contains(&x) && x != ENC_BYTE {
if is_like_special(x) || x == ESCAPE_BYTE {
out.push(ESCAPE_CHAR);
}
out.push(char::from_u32(x as u32).unwrap());
} else {
out.push(ENC_CHAR);
out.push(HEXCHARS[((x >> 4) & 0x0F) as usize]);
out.push(HEXCHARS[(x & 0x0F) as usize]);
}
}
out
}
pub fn text_to_key(text: &str) -> Result<Vec<u8>, ()> {
let mut outlen: usize = 0;
let bytes = text.as_bytes();
let mut i = 0usize;
while i < bytes.len() {
let x = bytes[i];
if x == ENC_BYTE {
i += 3;
} else {
i += 1;
}
outlen += 1;
}
let mut out: Vec<u8> = Vec::with_capacity(outlen);
i = 0;
while i < bytes.len() {
let x = bytes[i];
if x == ENC_BYTE {
let h1 = bytes.get(i + 1).ok_or(())?;
let h2 = bytes.get(i + 2).ok_or(())?;
let b: u8 = (from_hex_char(*h1)? << 4) | from_hex_char(*h2)?;
out.push(b);
i += 3;
} else {
out.push(x);
i += 1;
}
}
Ok(out)
}
pub fn get_column_table_name(column: u32) -> String {
format!("column_{}", column)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_key_text() {
assert_eq!(key_to_text(b"Test\xFFKey\x001!\xC3"), "Test$FFKey$001!$C3");
assert_eq!(
b"Test\xFFKey\x001!\xC3".to_vec(),
text_to_key("Test$FFKey$001!$C3").unwrap()
);
assert!(text_to_key("Test$FFKey$001!$C").is_err());
assert!(text_to_key("Test$FFKey$001!$G3").is_err());
assert!(text_to_key("Test$FFKey$001!$CG").is_err());
assert!(text_to_key("Test$FFKey$001!$").is_err());
assert_eq!(
like_key_to_text(b"Test_\xFFKey%\x001!\xC3"),
"Test\\_$FFKey\\%$001!$C3"
);
}
}