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()
    }
}