1#![forbid(unsafe_code)]
24
25use bouncycastle_utils::ct::Condition;
26
27#[derive(Debug)]
28pub enum HexError {
29 InvalidHexCharacter(usize),
30 OddLengthInput,
31 InsufficientOutputBufferSize,
32}
33
34pub fn encode<T: AsRef<[u8]>>(input: T) -> String {
36 let mut out = vec![0u8; input.as_ref().len() * 2];
37 encode_out(input.as_ref(), &mut out).unwrap();
38
39 String::from_utf8(out).unwrap()
40}
41
42pub fn encode_out<T: AsRef<[u8]>>(input: T, out: &mut [u8]) -> Result<usize, HexError> {
45 let inref = input.as_ref();
46 if out.len() < inref.len() * 2 {
47 return Err(HexError::InsufficientOutputBufferSize);
48 }
49
50 for i in 0..inref.len() {
51 out[2 * i] = ct_word_to_hex(inref[i] >> 4);
52 out[2 * i + 1] = ct_word_to_hex(inref[i] & 0x0F);
53 }
54 return Ok(inref.len() * 2);
55
56 fn ct_word_to_hex(mut c: u8) -> u8 {
58 c &= 0x0F;
60
61 let in_af = Condition::<i64>::is_within_range(c as i64, 10, 15);
63
64 let c_09: i64 = '0' as i64 + (c as i64);
67 let c_az: i64 = 'a' as i64 + (c as i64 - 10);
68
69 let mut ret: i64 = c_09 as i64;
70 ret = in_af.select(c_az as i64, ret);
71 ret as u8
72 }
73}
74
75pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, HexError> {
78 let inref = input.as_ref();
79 let mut out: Vec<u8> = vec![0u8; inref.len() / 2];
80 let bytes_written = decode_out(inref, &mut out)?;
81 out.truncate(bytes_written);
82 Ok(out)
83}
84
85pub fn decode_out<T: AsRef<[u8]>>(input: T, out: &mut [u8]) -> Result<usize, HexError> {
88 let inref = input.as_ref();
89 if out.len() < inref.len() / 2 {
90 return Err(HexError::InsufficientOutputBufferSize);
91 }
92
93 let mut b = 0u8;
94 let mut b_i = 0u8;
95 let mut out_i = 0_usize;
96 let mut i = 0_usize;
97 while i < inref.len() {
98 let c = inref[i];
99
100 match c {
102 b' ' | b'\t' | b'\n' | b'\r' | 0 => {
103 i += 1;
104 continue;
105 }
106 b'\\' => {
107 if inref[i + 1] == b'x' {
108 i += 2;
109 continue;
110 }
111 }
112 _ => {}
113 }
114
115 b |= match ct_hex_to_word(c) {
118 0xFF => return Err(HexError::InvalidHexCharacter(i)),
119 c => c,
120 } << (4 * (1 - b_i));
121
122 if b_i == 1 {
123 out[out_i] = b;
124 out_i += 1;
125 b = 0;
126 b_i = 0;
127 } else {
128 b_i = 1;
129 }
130 i += 1;
131 }
132 if b_i != 0 {
134 return Err(HexError::OddLengthInput);
135 }
136
137 return Ok(out_i);
138
139 fn ct_hex_to_word(b: u8) -> u8 {
140 let in_09 = Condition::<i64>::is_within_range(b as i64, 48, 57);
141 let in_af = Condition::<i64>::is_within_range(b as i64, 97, 102);
142 #[allow(non_snake_case)]
143 let in_AF = Condition::<i64>::is_within_range(b as i64, 65, 70);
144
145 let c_09: i64 = b as i64 - ('0' as i64);
148 #[allow(non_snake_case)]
149 let c_AF: i64 = b as i64 - ('A' as i64) + 10;
150 let c_af: i64 = b as i64 - ('a' as i64) + 10;
151
152 let mut ret: i64 = 0xFFi64;
153
154 ret = in_09.select(c_09, ret);
155 ret = in_AF.select(c_AF, ret);
156 ret = in_af.select(c_af, ret);
157
158 ret as u8
159 }
160}