#![allow(unknown_lints)]
#![allow(bare_trait_objects)]
use codec::helpers::codecs::FilteredDecoder;
use codec::helpers::codecs::StatelessEncoder;
use codec::Codec;
use codec::CodecSettings;
use codec::CodecTransform;
use codec::Direction;
use codec::Error;
use codec::FlushState;
use codec::Status;
use codec::TransformableCodec;
use std::cmp;
use std::collections::BTreeMap;
use std::io;
#[derive(Default)]
pub struct TransformFactory {}
#[derive(Default)]
pub struct ModHexTransformFactory {}
pub const LOWER: [u8; 16] = [
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
];
pub const UPPER: [u8; 16] = [
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
];
pub const MODHEX: [u8; 16] = *b"cbdefghijklnrtuv";
pub const REV: [i8; 256] = [
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10,
11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
];
pub const MODHEXREV: [i8; 256] = [
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 11, -1, -1, -1, 12, -1, 13, 14, 15, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
];
fn forward_transform(inp: &[u8], outp: &mut [u8], arr: &[u8; 16]) -> (usize, usize) {
let n = cmp::min(inp.len(), outp.len() / 2);
for (i, j) in (0..n).map(|x| (x, x * 2)) {
outp[j..j + 2]
.copy_from_slice(&[arr[(inp[i] >> 4) as usize], arr[(inp[i] & 0xf) as usize]]);
}
(n, n * 2)
}
impl TransformFactory {
pub fn new() -> Self {
TransformFactory {}
}
}
impl CodecTransform for TransformFactory {
fn factory(&self, r: Box<io::BufRead>, s: CodecSettings) -> Result<Box<io::BufRead>, Error> {
match s.dir {
Direction::Forward => {
let arr = if s.bool_arg("upper")? { &UPPER } else { &LOWER };
Ok(
StatelessEncoder::new(move |inp, out| forward_transform(inp, out, arr), 2)
.into_bufread(r, s.bufsize),
)
}
Direction::Reverse => Ok(Decoder::new(s.strict, &REV).into_bufread(r, s.bufsize)),
}
}
fn options(&self) -> BTreeMap<String, String> {
let mut map = BTreeMap::new();
map.insert("lower".to_string(), tr!("use lowercase letters"));
map.insert("upper".to_string(), tr!("use uppercase letters"));
map
}
fn can_reverse(&self) -> bool {
true
}
fn name(&self) -> &'static str {
"hex"
}
}
impl ModHexTransformFactory {
pub fn new() -> Self {
ModHexTransformFactory {}
}
}
impl CodecTransform for ModHexTransformFactory {
fn factory(&self, r: Box<io::BufRead>, s: CodecSettings) -> Result<Box<io::BufRead>, Error> {
match s.dir {
Direction::Forward => Ok(StatelessEncoder::new(
move |inp, out| forward_transform(inp, out, &MODHEX),
2,
)
.into_bufread(r, s.bufsize)),
Direction::Reverse => Ok(Decoder::new(s.strict, &MODHEXREV).into_bufread(r, s.bufsize)),
}
}
fn options(&self) -> BTreeMap<String, String> {
BTreeMap::new()
}
fn can_reverse(&self) -> bool {
true
}
fn name(&self) -> &'static str {
"modhex"
}
}
pub struct Decoder {
strict: bool,
rev: &'static [i8; 256],
}
impl Decoder {
fn new(strict: bool, rev: &'static [i8; 256]) -> Self {
Decoder { strict, rev }
}
}
impl FilteredDecoder for Decoder {
fn strict(&self) -> bool {
self.strict
}
fn filter_byte(&self, b: u8) -> bool {
self.rev[b as usize] != -1
}
fn internal_transform(
&mut self,
src: &[u8],
dst: &mut [u8],
f: FlushState,
) -> Result<Status, Error> {
match f {
FlushState::None if src.len() < 2 => {
return Ok(Status::SeqError(0, 0));
}
FlushState::Finish if src.is_empty() => {
return Ok(Status::StreamEnd(0, 0));
}
_ => (),
}
let bytes = cmp::min(src.len() / 2, dst.len());
let mut consumed = 0;
for (i, j) in (0..bytes).map(|x| (x * 2, x)) {
let (x, y) = (src[i], src[i + 1]);
let v: i16 = (i16::from(self.rev[x as usize]) << 4) | i16::from(self.rev[y as usize]);
if v < 0 {
return Err(Error::InvalidSequence("hex".to_string(), vec![x, y]));
}
dst[j] = (v & 0xff) as u8;
consumed = i + 2;
}
match f {
FlushState::Finish if consumed == src.len() => Ok(Status::StreamEnd(consumed, bytes)),
_ => Ok(Status::Ok(consumed, bytes)),
}
}
}
impl Codec for Decoder {
fn transform(&mut self, src: &[u8], dst: &mut [u8], f: FlushState) -> Result<Status, Error> {
self.wrap_transform(src, dst, f)
}
fn chunk_size(&self) -> usize {
2
}
fn buffer_size(&self) -> usize {
1
}
}
#[cfg(test)]
mod tests {
use chain::Chain;
use codec::registry::CodecRegistry;
use codec::tests;
fn check(inp: &[u8], lower: &[u8], upper: &[u8], modhex: &[u8]) {
let reg = CodecRegistry::new();
for i in vec![5, 6, 7, 8, 512] {
let c = Chain::new(®, "hex", i, true);
assert_eq!(c.transform(inp.to_vec()).unwrap(), lower);
let c = Chain::new(®, "hex,lower", i, true);
assert_eq!(c.transform(inp.to_vec()).unwrap(), lower);
let c = Chain::new(®, "hex,upper", i, true);
assert_eq!(c.transform(inp.to_vec()).unwrap(), upper);
let c = Chain::new(®, "-hex", i, true);
assert_eq!(c.transform(upper.to_vec()).unwrap(), inp);
let c = Chain::new(®, "-hex", i, true);
assert_eq!(c.transform(lower.to_vec()).unwrap(), inp);
let c = Chain::new(®, "-hex", i, false);
assert_eq!(c.transform(upper.to_vec()).unwrap(), inp);
let c = Chain::new(®, "modhex", i, true);
assert_eq!(c.transform(inp.to_vec()).unwrap(), modhex);
let c = Chain::new(®, "-modhex", i, true);
assert_eq!(c.transform(modhex.to_vec()).unwrap(), inp);
let c = Chain::new(®, "-modhex", i, false);
assert_eq!(c.transform(modhex.to_vec()).unwrap(), inp);
}
}
#[test]
fn encodes_bytes() {
check(b"abc", b"616263", b"616263", b"hbhdhe");
check(b"\x00\xff", b"00ff", b"00FF", b"ccvv");
check(b"\xc2\xa9", b"c2a9", b"C2A9", b"rdlk");
check(
b"\x01\x23\x45\x67\x89\xab\xcd\xef",
b"0123456789abcdef",
b"0123456789ABCDEF",
b"cbdefghijklnrtuv",
);
check(b"\xfe\xdc\xba", b"fedcba", b"FEDCBA", b"vutrnl");
}
#[test]
fn default_tests() {
tests::round_trip("hex");
tests::round_trip("hex,upper");
tests::round_trip("hex,lower");
tests::round_trip_stripped_whitespace("hex");
tests::round_trip_stripped_whitespace("hex,upper");
tests::round_trip_stripped_whitespace("hex,lower");
tests::basic_configuration("hex");
tests::invalid_data("hex");
tests::round_trip("modhex");
tests::basic_configuration("modhex");
tests::round_trip_stripped_whitespace("modhex");
tests::invalid_data("modhex");
}
#[test]
fn known_values() {
check(tests::BYTE_SEQ, b"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", b"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF", b"cccbcdcecfcgchcicjckclcncrctcucvbcbbbdbebfbgbhbibjbkblbnbrbtbubvdcdbdddedfdgdhdidjdkdldndrdtdudvecebedeeefegeheiejekelenereteuevfcfbfdfefffgfhfifjfkflfnfrftfufvgcgbgdgegfggghgigjgkglgngrgtgugvhchbhdhehfhghhhihjhkhlhnhrhthuhvicibidieifigihiiijikiliniritiuivjcjbjdjejfjgjhjijjjkjljnjrjtjujvkckbkdkekfkgkhkikjkkklknkrktkukvlclbldlelflglhliljlklllnlrltlulvncnbndnenfngnhninjnknlnnnrntnunvrcrbrdrerfrgrhrirjrkrlrnrrrtrurvtctbtdtetftgthtitjtktltntrtttutvucubudueufuguhuiujukulunurutuuuvvcvbvdvevfvgvhvivjvkvlvnvrvtvuvv");
}
}