1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
use super::{base64_char_to_decimal, config::Config, error::Base64Error, Base64};
impl<'a> Base64<'a> {
/// Decode a Base64 value to it's a Vector of u8
///
/// # Return:
/// The vector of u8 corresponding to the data that was encoded into base64
///
/// # Example:
/// ```
/// extern crate lb64;
/// use lb64::{Base64, config::STANDARD};
///
/// fn main() {
/// let word: &str = "Hello";
/// let mut b64 = Base64::new_encode_bytes(word.as_bytes(), STANDARD);
/// let decoded_word = match String::from_utf8(b64.decode_to_bytes()) {
/// Ok(value) => value,
/// Err(e) => panic!("{}", e),
/// };
/// println!("Before = {}\nAfter = {}", word, decoded_word);
/// }
/// ```
pub fn decode_to_bytes(&self) -> Vec<u8> {
decode_bytes(self.conf, &self.to_string())
}
/// Loop over Base64 number convert each value to it's corresponding unsigned value and sum all
/// of those
///
/// # Return:
/// Result with either the u128 or
/// [Base64Error::OverflowError](error/enum.Base64Error.html#variant.OverflowError)
///
/// # Example:
/// ```
/// extern crate lb64;
/// use lb64::{Base64, config::STANDARD};
///
/// fn main() {
/// let mut b64 = Base64::new_encode_unsigned(&8, STANDARD);
/// match b64.decode_to_unsigned() {
/// Ok(value) => println!("{}", value),
/// Err(e) => println!("{}", e),
/// }
/// }
/// ```
pub fn decode_to_unsigned(&self) -> Result<u128, Base64Error> {
let mut dec: u128 = 0;
// Strip padding from self.value
let stripped_vec = remove_padding(self.conf.get_padding(), &self.value);
for (i, ch) in stripped_vec.iter().enumerate() {
match convert_char_to_decimal(&self.conf, *ch, (stripped_vec.len() - (i + 1)) as u32) {
Some(val) => match dec.checked_add(val) {
// Check possible addition overflow
Some(val) => {
dec = val;
}
None => {
return Err(Base64Error::OverflowError);
}
},
None => {
return Err(Base64Error::OverflowError);
}
}
}
Ok(dec)
}
}
/// Decodes a &str to a Base64 String
fn decode_bytes<'a>(conf: &'a Config, s: &str) -> Vec<u8> {
//let mut binary: String = String::new();
let mut binary: Vec<char> = Vec::new();
for i in s.chars() {
if conf.get_padding().is_some() && i == conf.get_padding().unwrap() {
// Skip padding characters
} else if i != ' ' && i != '\n' {
// Skip newlines and spaces
binary.append(
convert_decimal_to_binary(base64_char_to_decimal(conf.get_character_set(), i))
.as_mut(),
);
}
}
// Add additional 0s to make sure it's divisible by 8
while binary.len() % 8 != 0 {
binary.push('0');
}
let mut v: Vec<u8> = Vec::new();
for i in (0..binary.len()).step_by(8) {
if !is_8bit_all_0s(&binary[i..i + 8]) {
//Skip padding
v.push(convert_8bit_to_u8(&binary[i..i + 8]));
}
}
v
}
/// Converts a character in Base64 to it's decimal equivalent which is val * 64^place
/// Param: val, the character value
/// Param: place, the place
/// Return: Either None if any value isn't in the proper bounds or u128
fn convert_char_to_decimal(conf: &Config, val: char, place: u32) -> Option<u128> {
match 64u128.checked_pow(place) {
// Check pow overflow
Some(value) => {
match (base64_char_to_decimal(conf.get_character_set(), val)).checked_mul(value) {
Some(val) => Some(val),
None => None,
}
}
None => None,
}
}
/// Converts a decimal to binary by getting value % 2 then dividing by 2 until the value is 0
/// Prepend 0s until the binary is of length 6. This is in the reverse order so reverse it.
fn convert_decimal_to_binary(value: u128) -> Vec<char> {
let mut v = value;
let mut vec: Vec<char> = Vec::new();
while v != 0 {
match v % 2 {
0 => vec.push('0'),
1 => vec.push('1'),
_ => vec.push('0'), // Impossible case
}
v /= 2;
}
// Prepend 0s so that it's of length 6
while vec.len() < 6 {
vec.push('0');
}
vec.reverse(); // Flip vector to proper order
vec
}
/// Converts a 6 bit binary value to a u128
fn convert_8bit_to_u8(s: &[char]) -> u8 {
let mut value: u8 = 0;
for (i, c) in s.iter().enumerate() {
// if it's 1 add 2^place
if *c == '1' {
value += 2u8.pow(((s.len() - 1) - i) as u32);
}
}
value
}
/// Checks if all 8 bits (represented as a slice of chars) are all 0s
fn is_8bit_all_0s(s: &[char]) -> bool {
for c in s {
if *c != '0' {
return false;
}
}
true
}
fn remove_padding(pad: Option<char>, v: &[char]) -> Vec<char> {
if pad.is_some() {
let mut new_v: Vec<char> = Vec::new();
for i in v {
if *i != pad.unwrap() {
new_v.push(*i);
}
}
new_v
} else {
v.to_vec()
}
}