172 lines
5.7 KiB
Rust
172 lines
5.7 KiB
Rust
// Copyright (C) 2020 "Maxime “pep” Buquet <pep@bouah.net>"
|
||
//
|
||
// This program is free software: you can redistribute it and/or modify it
|
||
// under the terms of the GNU Affero General Public License as published by the
|
||
// Free Software Foundation, either version 3 of the License, or (at your
|
||
// option) any later version.
|
||
//
|
||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
||
// for more details.
|
||
//
|
||
// You should have received a copy of the GNU Affero General Public License
|
||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
||
use std::fmt;
|
||
use std::ops::Deref;
|
||
use std::convert::TryFrom;
|
||
use std::collections::HashMap;
|
||
use lazy_static::lazy_static;
|
||
|
||
lazy_static! {
|
||
static ref STRTOHEX: HashMap<char, u8> = {
|
||
let tmp = [
|
||
('A', 0x80), ('B', 0x81), ('C', 0x82), ('D', 0x83),
|
||
('E', 0x84), ('F', 0x85), ('G', 0x86), ('H', 0x87),
|
||
('I', 0x88), ('J', 0x89), ('K', 0x8a), ('L', 0x8b),
|
||
('M', 0x8c), ('N', 0x8d), ('O', 0x8e), ('P', 0x8f),
|
||
('Q', 0x90), ('R', 0x91), ('S', 0x92), ('T', 0x93),
|
||
('U', 0x94), ('V', 0x95), ('W', 0x96), ('X', 0x97),
|
||
('Y', 0x98), ('Z', 0x99), ('(', 0x9a), (')', 0x9b),
|
||
(':', 0x9c), (';', 0x9d), ('[', 0x9e), (']', 0x9f),
|
||
('a', 0xa0), ('b', 0xa1), ('c', 0xa2), ('d', 0xa3),
|
||
('e', 0xa4), ('f', 0xa5), ('g', 0xa6), ('h', 0xa7),
|
||
('i', 0xa8), ('j', 0xa9), ('k', 0xaa), ('l', 0xab),
|
||
('m', 0xac), ('n', 0xad), ('o', 0xae), ('p', 0xaf),
|
||
('q', 0xb0), ('r', 0xb1), ('s', 0xb2), ('t', 0xb3),
|
||
('u', 0xb4), ('v', 0xb5), ('w', 0xb6), ('x', 0xb7),
|
||
('y', 0xb8), ('z', 0xb9), ('\'', 0xe0), ('-', 0xe3),
|
||
('?', 0xe6), ('!', 0xe7), ('.', 0xe8), ('▷', 0xec),
|
||
('▶', 0xed), ('▼', 0xee), ('♂', 0xef), ('×', 0xf1),
|
||
('.', 0xf2), ('/', 0xf3), (',', 0xf4), ('♀', 0xf5),
|
||
('0', 0xf6), ('1', 0xf7), ('2', 0xf8), ('3', 0xf9),
|
||
('4', 0xfa), ('5', 0xfb), ('6', 0xfc), ('7', 0xfd),
|
||
('8', 0xfe), ('9', 0xff), (' ', 0x7f), ('@', 0x50),
|
||
];
|
||
|
||
let mut map = HashMap::new();
|
||
for (k, v) in tmp.iter() {
|
||
map.insert(*k, *v);
|
||
}
|
||
map
|
||
};
|
||
|
||
static ref HEXTOSTR: HashMap<u8, char> = {
|
||
let tmp = [
|
||
(0x80, 'A'), (0x81, 'B'), (0x82, 'C'), (0x83, 'D'),
|
||
(0x84, 'E'), (0x85, 'F'), (0x86, 'G'), (0x87, 'H'),
|
||
(0x88, 'I'), (0x89, 'J'), (0x8a, 'K'), (0x8b, 'L'),
|
||
(0x8c, 'M'), (0x8d, 'N'), (0x8e, 'O'), (0x8f, 'P'),
|
||
(0x90, 'Q'), (0x91, 'R'), (0x92, 'S'), (0x93, 'T'),
|
||
(0x94, 'U'), (0x95, 'V'), (0x96, 'W'), (0x97, 'X'),
|
||
(0x98, 'Y'), (0x99, 'Z'), (0x9a, '('), (0x9b, ')'),
|
||
(0x9c, ':'), (0x9d, ';'), (0x9e, '['), (0x9f, ']'),
|
||
(0xa0, 'a'), (0xa1, 'b'), (0xa2, 'c'), (0xa3, 'd'),
|
||
(0xa4, 'e'), (0xa5, 'f'), (0xa6, 'g'), (0xa7, 'h'),
|
||
(0xa8, 'i'), (0xa9, 'j'), (0xaa, 'k'), (0xab, 'l'),
|
||
(0xac, 'm'), (0xad, 'n'), (0xae, 'o'), (0xaf, 'p'),
|
||
(0xb0, 'q'), (0xb1, 'r'), (0xb2, 's'), (0xb3, 't'),
|
||
(0xb4, 'u'), (0xb5, 'v'), (0xb6, 'w'), (0xb7, 'x'),
|
||
(0xb8, 'y'), (0xb9, 'z'), (0xe0, '\''), (0xe3, '-'),
|
||
(0xe6, '?'), (0xe7, '!'), (0xe8, '.'), (0xec, '▷'),
|
||
(0xed, '▶'), (0xee, '▼'), (0xef, '♂'), (0xf1, '×'),
|
||
(0xf2, '.'), (0xf3, '/'), (0xf4, ','), (0xf5, '♀'),
|
||
(0xf6, '0'), (0xf7, '1'), (0xf8, '2'), (0xf9, '3'),
|
||
(0xfa, '4'), (0xfb, '5'), (0xfc, '6'), (0xfd, '7'),
|
||
(0xfe, '8'), (0xff, '9'), (0x7f, ' '), (0x50, '@'),
|
||
];
|
||
|
||
let mut map = HashMap::new();
|
||
for (k, v) in tmp.iter() {
|
||
map.insert(*k, *v);
|
||
}
|
||
map
|
||
};
|
||
}
|
||
|
||
#[derive(Debug, Eq, PartialEq)]
|
||
pub enum Error {
|
||
InvalidCharacter,
|
||
}
|
||
|
||
#[derive(Debug, Eq, PartialEq)]
|
||
pub struct PKString(String);
|
||
|
||
impl Deref for PKString {
|
||
type Target = String;
|
||
|
||
fn deref(&self) -> &Self::Target {
|
||
&self.0
|
||
}
|
||
}
|
||
|
||
impl fmt::Display for PKString {
|
||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
f.write_fmt(format_args!("{}", &self.0))
|
||
}
|
||
}
|
||
|
||
impl TryFrom<&[u8]> for PKString {
|
||
type Error = Error;
|
||
|
||
fn try_from(data: &[u8]) -> Result<PKString, Error> {
|
||
let mut buf = String::with_capacity(data.len());
|
||
let placeholder = '_';
|
||
|
||
for ord in data {
|
||
if let Some(chr) = HEXTOSTR.get(&ord) {
|
||
buf.push(*chr);
|
||
} else {
|
||
buf.push(placeholder);
|
||
}
|
||
}
|
||
|
||
Ok(PKString(buf))
|
||
}
|
||
}
|
||
|
||
impl Into<Vec<u8>> for PKString {
|
||
fn into(self) -> Vec<u8> {
|
||
let mut vec = Vec::with_capacity(self.len());
|
||
|
||
for chr in self.0.chars() {
|
||
if let Some(ord) = STRTOHEX.get(&chr) {
|
||
vec.push(*ord);
|
||
} else {
|
||
// TODO: Change this.
|
||
panic!();
|
||
}
|
||
}
|
||
|
||
vec
|
||
}
|
||
}
|
||
|
||
impl TryFrom<&str> for PKString {
|
||
type Error = Error;
|
||
|
||
fn try_from(data: &str) -> Result<PKString, Error> {
|
||
for chr in data.chars() {
|
||
if ! STRTOHEX.contains_key(&chr) {
|
||
return Err(Error::InvalidCharacter);
|
||
}
|
||
}
|
||
|
||
Ok(PKString(String::from(data)))
|
||
}
|
||
}
|
||
|
||
impl TryFrom<String> for PKString {
|
||
type Error = Error;
|
||
|
||
fn try_from(data: String) -> Result<PKString, Error> {
|
||
for chr in data.chars() {
|
||
if ! STRTOHEX.contains_key(&chr) {
|
||
return Err(Error::InvalidCharacter);
|
||
}
|
||
}
|
||
|
||
Ok(PKString(data))
|
||
}
|
||
}
|