1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2024 Orange
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *          http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
use crate::reader::Reader;
19

            
20
/// <https://en.wikipedia.org/wiki/Base64>
21
/// Test padding/no-padding
22
///
23
/// Encoded
24
/// YW55IGNhcm5hbCBwbGVhcw==    any carnal pleas   # [97, 110, 121, 32, 99, 97, 114, 110, 97, 108, 32, 112, 108, 101, 97, 115]
25

            
26
320
pub fn parse(reader: &mut Reader) -> Vec<u8> {
27
320
    let mut bytes = vec![];
28
320
    let mut buf = vec![]; // base64 text
29
    loop {
30
6335
        let pad = padding(reader);
31
6335
        if !pad.is_empty() {
32
70
            break;
33
        }
34
6265
        let save = reader.cursor();
35
6265
        match reader.read() {
36
            None => {
37
                break;
38
            }
39
            Some(' ') | Some('\n') | Some('\t') => {}
40
6265
            Some(c) => match value(c) {
41
                None => {
42
250
                    reader.seek(save);
43
250
                    break;
44
                }
45
6015
                Some(v) => {
46
6015
                    buf.push(v);
47
6015
                    if buf.len() == 4 {
48
1475
                        let bs = decode_four_chars(
49
1475
                            *buf.first().unwrap(),
50
1475
                            *buf.get(1).unwrap(),
51
1475
                            *buf.get(2).unwrap(),
52
1475
                            *buf.get(3).unwrap(),
53
1475
                        );
54
5900
                        for b in bs {
55
4425
                            bytes.push(b);
56
                        }
57
1475
                        buf = vec![];
58
                    }
59
                }
60
            },
61
        }
62
    }
63
320
    match buf.as_slice() {
64
55
        [c1, c2] => bytes.append(&mut decode_two_chars(*c1, *c2)),
65
        [c1, c2, c3] => bytes.append(&mut decode_three_chars(*c1, *c2, *c3)),
66
265
        _ => {}
67
    }
68
320
    bytes
69
}
70

            
71
6265
fn value(c: char) -> Option<i32> {
72
6265
    match c {
73
55
        'A' => Some(0),
74
15
        'B' => Some(1),
75
125
        'C' => Some(2),
76
55
        'D' => Some(3),
77
90
        'E' => Some(4),
78
15
        'F' => Some(5),
79
740
        'G' => Some(6),
80
15
        'H' => Some(7),
81
130
        'I' => Some(8),
82
15
        'J' => Some(9),
83
130
        'K' => Some(10),
84
15
        'L' => Some(11),
85
35
        'M' => Some(12),
86
70
        'N' => Some(13),
87
15
        'O' => Some(14),
88
15
        'P' => Some(15),
89
240
        'Q' => Some(16),
90
15
        'R' => Some(17),
91
200
        'S' => Some(18),
92
185
        'T' => Some(19),
93
70
        'U' => Some(20),
94
385
        'V' => Some(21),
95
15
        'W' => Some(22),
96
15
        'X' => Some(23),
97
15
        'Y' => Some(24),
98
185
        'Z' => Some(25),
99
40
        'a' => Some(26),
100
610
        'b' => Some(27),
101
15
        'c' => Some(28),
102
15
        'd' => Some(29),
103
15
        'e' => Some(30),
104
15
        'f' => Some(31),
105
255
        'g' => Some(32),
106
200
        'h' => Some(33),
107
15
        'i' => Some(34),
108
15
        'j' => Some(35),
109
15
        'k' => Some(36),
110
185
        'l' => Some(37),
111
125
        'm' => Some(38),
112
15
        'n' => Some(39),
113
15
        'o' => Some(40),
114
70
        'p' => Some(41),
115
15
        'q' => Some(42),
116
15
        'r' => Some(43),
117
200
        's' => Some(44),
118
15
        't' => Some(45),
119
185
        'u' => Some(46),
120
15
        'v' => Some(47),
121
15
        'w' => Some(48),
122
70
        'x' => Some(49),
123
200
        'y' => Some(50),
124
70
        'z' => Some(51),
125
15
        '0' => Some(52),
126
15
        '1' => Some(53),
127
200
        '2' => Some(54),
128
15
        '3' => Some(55),
129
15
        '4' => Some(56),
130
15
        '5' => Some(57),
131
15
        '6' => Some(58),
132
15
        '7' => Some(59),
133
200
        '8' => Some(60),
134
200
        '9' => Some(61),
135
15
        '+' => Some(62),
136
15
        '/' => Some(63),
137
250
        _ => None,
138
    }
139
}
140

            
141
6335
fn padding(reader: &mut Reader) -> String {
142
6335
    // consume padding can not fail
143
6335
    let mut buf = String::new();
144
    loop {
145
6475
        let save = reader.cursor();
146
6475
        match reader.read() {
147
140
            Some('=') => {
148
140
                buf.push('=');
149
            }
150
            _ => {
151
6335
                reader.seek(save);
152
6335
                break;
153
            }
154
        }
155
    }
156
6335
    buf
157
}
158

            
159
55
fn decode_two_chars(c1: i32, c2: i32) -> Vec<u8> {
160
55
    vec![((c1 << 2 & 255) + (c2 >> 4)) as u8]
161
}
162

            
163
fn decode_three_chars(c1: i32, c2: i32, c3: i32) -> Vec<u8> {
164
    vec![
165
        ((c1 << 2 & 255) + (c2 >> 4)) as u8,
166
        ((c2 << 4 & 255) + (c3 >> 2)) as u8,
167
    ]
168
}
169

            
170
1475
fn decode_four_chars(c1: i32, c2: i32, c3: i32, c4: i32) -> Vec<u8> {
171
1475
    vec![
172
1475
        ((c1 << 2 & 255) + (c2 >> 4)) as u8,
173
1475
        ((c2 << 4 & 255) + (c3 >> 2)) as u8,
174
1475
        (((c3 << 6) & 255) + c4) as u8,
175
1475
    ]
176
}
177

            
178
#[cfg(test)]
179
mod tests {
180
    use super::*;
181

            
182
    #[test]
183
    fn test_decode_one_block() {
184
        let mut reader = Reader::new("");
185
        assert_eq!(parse(&mut reader), vec![] as Vec<u8>);
186
        assert_eq!(reader.cursor().index, 0);
187

            
188
        let mut reader = Reader::new("AA==;");
189
        assert_eq!(parse(&mut reader), vec![0]);
190
        assert_eq!(reader.cursor().index, 4);
191

            
192
        let mut reader = Reader::new("AA");
193
        assert_eq!(parse(&mut reader), vec![0]);
194
        assert_eq!(reader.cursor().index, 2);
195

            
196
        let mut reader = Reader::new("AA;");
197
        assert_eq!(parse(&mut reader), vec![0]);
198
        assert_eq!(reader.cursor().index, 2);
199

            
200
        let mut reader = Reader::new("TWE=;");
201
        assert_eq!(parse(&mut reader), vec![77, 97]);
202
        assert_eq!(reader.cursor().index, 4);
203

            
204
        let mut reader = Reader::new("TWFu;");
205
        assert_eq!(parse(&mut reader), vec![77, 97, 110]);
206
        assert_eq!(reader.cursor().index, 4);
207
    }
208

            
209
    /*
210
    |   Y       |     W     |     5     |     5     |
211
    |     24    |    22     |      57   |     57    |
212
    |0|1|1|0|0|0|0|1|0|1|1|0|1|1|1|0|0|1|1|1|1|0|0|1|
213
    |      97       |     110       |      121      |
214
    */
215

            
216
    /*
217
    |   Y       |     W     |     5     |     5     |
218
    |     24    |    22     |      57   |     57    |
219
    |0|1|1|0|0|0|0|1|0|1|1|0|1|1|1|0|0|1|1|1|1|0|0|1|
220
    |      97       |     110       |      121      |
221
    */
222

            
223
    #[test]
224
    fn test_decode_with_padding() {
225
        let mut reader = Reader::new("YW55IGNhcm5hbCBwbGVhcw==;");
226
        let decoded = parse(&mut reader);
227
        assert_eq!(decoded, b"any carnal pleas");
228

            
229
        let mut reader = Reader::new("YW55IGNhcm5hbCBwbGVhc3U=;");
230
        assert_eq!(parse(&mut reader), b"any carnal pleasu");
231

            
232
        let mut reader = Reader::new("YW55IGNhcm5hbCBwbGVhc3Vy;");
233
        assert_eq!(parse(&mut reader), b"any carnal pleasur");
234
    }
235

            
236
    #[test]
237
    fn test_decode_without_padding() {
238
        let mut reader = Reader::new("YW55IGNhcm5hbCBwbGVhcw;");
239
        assert_eq!(parse(&mut reader), b"any carnal pleas");
240

            
241
        let mut reader = Reader::new("YW55IGNhcm5hbCBwbGVhc3U;");
242
        assert_eq!(parse(&mut reader), b"any carnal pleasu");
243
    }
244

            
245
    #[test]
246
    fn test_decode_with_whitespace() {
247
        let mut reader = Reader::new("TW E=\n;");
248
        assert_eq!(parse(&mut reader), vec![77, 97]);
249
        assert_eq!(reader.cursor().index, 5);
250
    }
251

            
252
    #[test]
253
    fn test_decode_two_chars() {
254
        assert_eq!(
255
            decode_two_chars(value('A').unwrap(), value('A').unwrap()),
256
            vec![0]
257
        );
258
        assert_eq!(
259
            decode_two_chars(value('A').unwrap(), value('Q').unwrap()),
260
            vec![1]
261
        );
262
        assert_eq!(
263
            decode_two_chars(value('T').unwrap(), value('Q').unwrap()),
264
            vec![77]
265
        );
266
    }
267

            
268
    #[test]
269
    fn test_decode_three_chars() {
270
        assert_eq!(
271
            decode_three_chars(
272
                value('T').unwrap(),
273
                value('W').unwrap(),
274
                value('E').unwrap(),
275
            ),
276
            vec![77, 97]
277
        );
278
    }
279

            
280
    #[test]
281
    fn test_decode_four_chars() {
282
        assert_eq!(
283
            decode_four_chars(
284
                value('Y').unwrap(),
285
                value('W').unwrap(),
286
                value('5').unwrap(),
287
                value('5').unwrap(),
288
            ),
289
            vec![97, 110, 121]
290
        );
291
        assert_eq!(
292
            decode_four_chars(
293
                value('T').unwrap(),
294
                value('W').unwrap(),
295
                value('F').unwrap(),
296
                value('u').unwrap(),
297
            ),
298
            vec![77, 97, 110]
299
        );
300
    }
301
}