1use byteorder::{BigEndian, ByteOrder};
2
3use ::{chunked_encoder, Config, STANDARD};
4
5pub fn encode<T: ?Sized + AsRef<[u8]>>(input: &T) -> String {
20 encode_config(input, STANDARD)
21}
22
23pub fn encode_config<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config) -> String {
40 let mut buf = match encoded_size(input.as_ref().len(), config) {
41 Some(n) => vec![0; n],
42 None => panic!("integer overflow when calculating buffer size"),
43 };
44
45 let encoded_len = encode_config_slice(input.as_ref(), config, &mut buf[..]);
46 debug_assert_eq!(encoded_len, buf.len());
47
48 String::from_utf8(buf).expect("Invalid UTF8")
49}
50
51pub fn encode_config_buf<T: ?Sized + AsRef<[u8]>>(input: &T, config: Config, buf: &mut String) {
70 let input_bytes = input.as_ref();
71
72 {
73 let mut sink = chunked_encoder::StringSink::new(buf);
74 let encoder = chunked_encoder::ChunkedEncoder::new(config);
75
76 encoder
77 .encode(input_bytes, &mut sink)
78 .expect("Writing to a String shouldn't fail")
79 }
80}
81
82pub fn encode_config_slice<T: ?Sized + AsRef<[u8]>>(
113 input: &T,
114 config: Config,
115 output: &mut [u8],
116) -> usize {
117 let input_bytes = input.as_ref();
118
119 let encoded_size = encoded_size(input_bytes.len(), config)
120 .expect("usize overflow when calculating buffer size");
121
122 let mut b64_output = &mut output[0..encoded_size];
123
124 encode_with_padding(&input_bytes, config, encoded_size, &mut b64_output);
125
126 encoded_size
127}
128
129fn encode_with_padding(input: &[u8], config: Config, encoded_size: usize, output: &mut [u8]) {
140 debug_assert_eq!(encoded_size, output.len());
141
142 let b64_bytes_written = encode_to_slice(input, output, config.char_set.encode_table());
143
144 let padding_bytes = if config.pad {
145 add_padding(input.len(), &mut output[b64_bytes_written..])
146 } else {
147 0
148 };
149
150 let encoded_bytes = b64_bytes_written
151 .checked_add(padding_bytes)
152 .expect("usize overflow when calculating b64 length");
153
154 debug_assert_eq!(encoded_size, encoded_bytes);
155}
156
157#[inline]
161pub fn encode_to_slice(input: &[u8], output: &mut [u8], encode_table: &[u8; 64]) -> usize {
162 let mut input_index: usize = 0;
163
164 const BLOCKS_PER_FAST_LOOP: usize = 4;
165 const LOW_SIX_BITS: u64 = 0x3F;
166
167 let last_fast_index = input.len().saturating_sub(BLOCKS_PER_FAST_LOOP * 6 + 2);
170 let mut output_index = 0;
171
172 if last_fast_index > 0 {
173 while input_index <= last_fast_index {
174 let input_chunk = &input[input_index..(input_index + (BLOCKS_PER_FAST_LOOP * 6 + 2))];
177 let output_chunk = &mut output[output_index..(output_index + BLOCKS_PER_FAST_LOOP * 8)];
178
179 let input_u64 = BigEndian::read_u64(&input_chunk[0..]);
188
189 output_chunk[0] = encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize];
190 output_chunk[1] = encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize];
191 output_chunk[2] = encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize];
192 output_chunk[3] = encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize];
193 output_chunk[4] = encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize];
194 output_chunk[5] = encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize];
195 output_chunk[6] = encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize];
196 output_chunk[7] = encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize];
197
198 let input_u64 = BigEndian::read_u64(&input_chunk[6..]);
199
200 output_chunk[8] = encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize];
201 output_chunk[9] = encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize];
202 output_chunk[10] = encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize];
203 output_chunk[11] = encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize];
204 output_chunk[12] = encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize];
205 output_chunk[13] = encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize];
206 output_chunk[14] = encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize];
207 output_chunk[15] = encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize];
208
209 let input_u64 = BigEndian::read_u64(&input_chunk[12..]);
210
211 output_chunk[16] = encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize];
212 output_chunk[17] = encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize];
213 output_chunk[18] = encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize];
214 output_chunk[19] = encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize];
215 output_chunk[20] = encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize];
216 output_chunk[21] = encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize];
217 output_chunk[22] = encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize];
218 output_chunk[23] = encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize];
219
220 let input_u64 = BigEndian::read_u64(&input_chunk[18..]);
221
222 output_chunk[24] = encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize];
223 output_chunk[25] = encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize];
224 output_chunk[26] = encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize];
225 output_chunk[27] = encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize];
226 output_chunk[28] = encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize];
227 output_chunk[29] = encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize];
228 output_chunk[30] = encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize];
229 output_chunk[31] = encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize];
230
231 output_index += BLOCKS_PER_FAST_LOOP * 8;
232 input_index += BLOCKS_PER_FAST_LOOP * 6;
233 }
234 }
235
236 const LOW_SIX_BITS_U8: u8 = 0x3F;
239
240 let rem = input.len() % 3;
241 let start_of_rem = input.len() - rem;
242
243 while input_index < start_of_rem {
246 let input_chunk = &input[input_index..(input_index + 3)];
247 let output_chunk = &mut output[output_index..(output_index + 4)];
248
249 output_chunk[0] = encode_table[(input_chunk[0] >> 2) as usize];
250 output_chunk[1] =
251 encode_table[((input_chunk[0] << 4 | input_chunk[1] >> 4) & LOW_SIX_BITS_U8) as usize];
252 output_chunk[2] =
253 encode_table[((input_chunk[1] << 2 | input_chunk[2] >> 6) & LOW_SIX_BITS_U8) as usize];
254 output_chunk[3] = encode_table[(input_chunk[2] & LOW_SIX_BITS_U8) as usize];
255
256 input_index += 3;
257 output_index += 4;
258 }
259
260 if rem == 2 {
261 output[output_index] = encode_table[(input[start_of_rem] >> 2) as usize];
262 output[output_index + 1] = encode_table[((input[start_of_rem] << 4
263 | input[start_of_rem + 1] >> 4)
264 & LOW_SIX_BITS_U8) as usize];
265 output[output_index + 2] =
266 encode_table[((input[start_of_rem + 1] << 2) & LOW_SIX_BITS_U8) as usize];
267 output_index += 3;
268 } else if rem == 1 {
269 output[output_index] = encode_table[(input[start_of_rem] >> 2) as usize];
270 output[output_index + 1] =
271 encode_table[((input[start_of_rem] << 4) & LOW_SIX_BITS_U8) as usize];
272 output_index += 2;
273 }
274
275 output_index
276}
277
278pub fn encoded_size(bytes_len: usize, config: Config) -> Option<usize> {
280 let rem = bytes_len % 3;
281
282 let complete_input_chunks = bytes_len / 3;
283 let complete_chunk_output = complete_input_chunks.checked_mul(4);
284
285 if rem > 0 {
286 if config.pad {
287 complete_chunk_output.and_then(|c| c.checked_add(4))
288 } else {
289 let encoded_rem = match rem {
290 1 => 2,
291 2 => 3,
292 _ => unreachable!("Impossible remainder"),
293 };
294 complete_chunk_output.and_then(|c| c.checked_add(encoded_rem))
295 }
296 } else {
297 complete_chunk_output
298 }
299}
300
301pub fn add_padding(input_len: usize, output: &mut [u8]) -> usize {
306 let rem = input_len % 3;
307 let mut bytes_written = 0;
308 for _ in 0..((3 - rem) % 3) {
309 output[bytes_written] = b'=';
310 bytes_written += 1;
311 }
312
313 bytes_written
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 use std;
321 use std::str;
322
323 use rand::{FromEntropy, Rng};
324 use rand::distributions::{Distribution, Uniform};
325
326 use ::{Config, STANDARD, URL_SAFE_NO_PAD};
327 use decode::decode_config_buf;
328 use tests::{assert_encode_sanity, random_config};
329
330 #[test]
331 fn encoded_size_correct_standard() {
332 assert_encoded_length(0, 0, STANDARD);
333
334 assert_encoded_length(1, 4, STANDARD);
335 assert_encoded_length(2, 4, STANDARD);
336 assert_encoded_length(3, 4, STANDARD);
337
338 assert_encoded_length(4, 8, STANDARD);
339 assert_encoded_length(5, 8, STANDARD);
340 assert_encoded_length(6, 8, STANDARD);
341
342 assert_encoded_length(7, 12, STANDARD);
343 assert_encoded_length(8, 12, STANDARD);
344 assert_encoded_length(9, 12, STANDARD);
345
346 assert_encoded_length(54, 72, STANDARD);
347
348 assert_encoded_length(55, 76, STANDARD);
349 assert_encoded_length(56, 76, STANDARD);
350 assert_encoded_length(57, 76, STANDARD);
351
352 assert_encoded_length(58, 80, STANDARD);
353 }
354
355 #[test]
356 fn encoded_size_correct_no_pad() {
357 assert_encoded_length(0, 0, URL_SAFE_NO_PAD);
358
359 assert_encoded_length(1, 2, URL_SAFE_NO_PAD);
360 assert_encoded_length(2, 3, URL_SAFE_NO_PAD);
361 assert_encoded_length(3, 4, URL_SAFE_NO_PAD);
362
363 assert_encoded_length(4, 6, URL_SAFE_NO_PAD);
364 assert_encoded_length(5, 7, URL_SAFE_NO_PAD);
365 assert_encoded_length(6, 8, URL_SAFE_NO_PAD);
366
367 assert_encoded_length(7, 10, URL_SAFE_NO_PAD);
368 assert_encoded_length(8, 11, URL_SAFE_NO_PAD);
369 assert_encoded_length(9, 12, URL_SAFE_NO_PAD);
370
371 assert_encoded_length(54, 72, URL_SAFE_NO_PAD);
372
373 assert_encoded_length(55, 74, URL_SAFE_NO_PAD);
374 assert_encoded_length(56, 75, URL_SAFE_NO_PAD);
375 assert_encoded_length(57, 76, URL_SAFE_NO_PAD);
376
377 assert_encoded_length(58, 78, URL_SAFE_NO_PAD);
378 }
379
380 #[test]
381 fn encoded_size_overflow() {
382 assert_eq!(None, encoded_size(std::usize::MAX, STANDARD));
383 }
384
385 #[test]
386 fn encode_config_buf_into_nonempty_buffer_doesnt_clobber_prefix() {
387 let mut orig_data = Vec::new();
388 let mut prefix = String::new();
389 let mut encoded_data_no_prefix = String::new();
390 let mut encoded_data_with_prefix = String::new();
391 let mut decoded = Vec::new();
392
393 let prefix_len_range = Uniform::new(0, 1000);
394 let input_len_range = Uniform::new(0, 1000);
395
396 let mut rng = rand::rngs::SmallRng::from_entropy();
397
398 for _ in 0..10_000 {
399 orig_data.clear();
400 prefix.clear();
401 encoded_data_no_prefix.clear();
402 encoded_data_with_prefix.clear();
403 decoded.clear();
404
405 let input_len = input_len_range.sample(&mut rng);
406
407 for _ in 0..input_len {
408 orig_data.push(rng.gen());
409 }
410
411 let prefix_len = prefix_len_range.sample(&mut rng);
412 for _ in 0..prefix_len {
413 prefix.push('#');
416 }
417 encoded_data_with_prefix.push_str(&prefix);
418
419 let config = random_config(&mut rng);
420 encode_config_buf(&orig_data, config, &mut encoded_data_no_prefix);
421 encode_config_buf(&orig_data, config, &mut encoded_data_with_prefix);
422
423 assert_eq!(
424 encoded_data_no_prefix.len() + prefix_len,
425 encoded_data_with_prefix.len()
426 );
427 assert_encode_sanity(&encoded_data_no_prefix, config, input_len);
428 assert_encode_sanity(&encoded_data_with_prefix[prefix_len..], config, input_len);
429
430 prefix.push_str(&mut encoded_data_no_prefix);
432
433 assert_eq!(prefix, encoded_data_with_prefix);
434
435 decode_config_buf(&encoded_data_no_prefix, config, &mut decoded).unwrap();
436 assert_eq!(orig_data, decoded);
437 }
438 }
439
440 #[test]
441 fn encode_config_slice_into_nonempty_buffer_doesnt_clobber_suffix() {
442 let mut orig_data = Vec::new();
443 let mut encoded_data = Vec::new();
444 let mut encoded_data_original_state = Vec::new();
445 let mut decoded = Vec::new();
446
447 let input_len_range = Uniform::new(0, 1000);
448
449 let mut rng = rand::rngs::SmallRng::from_entropy();
450
451 for _ in 0..10_000 {
452 orig_data.clear();
453 encoded_data.clear();
454 encoded_data_original_state.clear();
455 decoded.clear();
456
457 let input_len = input_len_range.sample(&mut rng);
458
459 for _ in 0..input_len {
460 orig_data.push(rng.gen());
461 }
462
463 for _ in 0..10 * input_len {
465 encoded_data.push(rng.gen());
466 }
467
468 encoded_data_original_state.extend_from_slice(&encoded_data);
469
470 let config = random_config(&mut rng);
471
472 let encoded_size = encoded_size(input_len, config).unwrap();
473
474 assert_eq!(
475 encoded_size,
476 encode_config_slice(&orig_data, config, &mut encoded_data)
477 );
478
479 assert_encode_sanity(
480 std::str::from_utf8(&encoded_data[0..encoded_size]).unwrap(),
481 config,
482 input_len,
483 );
484
485 assert_eq!(
486 &encoded_data[encoded_size..],
487 &encoded_data_original_state[encoded_size..]
488 );
489
490 decode_config_buf(&encoded_data[0..encoded_size], config, &mut decoded).unwrap();
491 assert_eq!(orig_data, decoded);
492 }
493 }
494
495 #[test]
496 fn encode_config_slice_fits_into_precisely_sized_slice() {
497 let mut orig_data = Vec::new();
498 let mut encoded_data = Vec::new();
499 let mut decoded = Vec::new();
500
501 let input_len_range = Uniform::new(0, 1000);
502
503 let mut rng = rand::rngs::SmallRng::from_entropy();
504
505 for _ in 0..10_000 {
506 orig_data.clear();
507 encoded_data.clear();
508 decoded.clear();
509
510 let input_len = input_len_range.sample(&mut rng);
511
512 for _ in 0..input_len {
513 orig_data.push(rng.gen());
514 }
515
516 let config = random_config(&mut rng);
517
518 let encoded_size = encoded_size(input_len, config).unwrap();
519
520 encoded_data.resize(encoded_size, 0);
521
522 assert_eq!(
523 encoded_size,
524 encode_config_slice(&orig_data, config, &mut encoded_data)
525 );
526
527 assert_encode_sanity(
528 std::str::from_utf8(&encoded_data[0..encoded_size]).unwrap(),
529 config,
530 input_len,
531 );
532
533 decode_config_buf(&encoded_data[0..encoded_size], config, &mut decoded).unwrap();
534 assert_eq!(orig_data, decoded);
535 }
536 }
537
538 #[test]
539 fn encode_to_slice_random_valid_utf8() {
540 let mut input = Vec::new();
541 let mut output = Vec::new();
542
543 let input_len_range = Uniform::new(0, 1000);
544
545 let mut rng = rand::rngs::SmallRng::from_entropy();
546
547 for _ in 0..10_000 {
548 input.clear();
549 output.clear();
550
551 let input_len = input_len_range.sample(&mut rng);
552
553 for _ in 0..input_len {
554 input.push(rng.gen());
555 }
556
557 let config = random_config(&mut rng);
558
559 let encoded_size = encoded_size(input_len, config).unwrap();
561 for _ in 0..encoded_size {
562 output.push(rng.gen());
563 }
564
565 let orig_output_buf = output.to_vec();
566
567 let bytes_written =
568 encode_to_slice(&input, &mut output, config.char_set.encode_table());
569
570 assert_eq!(orig_output_buf[bytes_written..], output[bytes_written..]);
572
573 let _ = str::from_utf8(&output[0..bytes_written]).unwrap();
575 }
576 }
577
578 #[test]
579 fn encode_with_padding_random_valid_utf8() {
580 let mut input = Vec::new();
581 let mut output = Vec::new();
582
583 let input_len_range = Uniform::new(0, 1000);
584
585 let mut rng = rand::rngs::SmallRng::from_entropy();
586
587 for _ in 0..10_000 {
588 input.clear();
589 output.clear();
590
591 let input_len = input_len_range.sample(&mut rng);
592
593 for _ in 0..input_len {
594 input.push(rng.gen());
595 }
596
597 let config = random_config(&mut rng);
598
599 let encoded_size = encoded_size(input_len, config).unwrap();
601 for _ in 0..encoded_size + 1000 {
602 output.push(rng.gen());
603 }
604
605 let orig_output_buf = output.to_vec();
606
607 encode_with_padding(&input, config, encoded_size, &mut output[0..encoded_size]);
608
609 assert_eq!(orig_output_buf[encoded_size..], output[encoded_size..]);
611
612 let _ = str::from_utf8(&output[0..encoded_size]).unwrap();
614 }
615 }
616
617 #[test]
618 fn add_padding_random_valid_utf8() {
619 let mut output = Vec::new();
620
621 let mut rng = rand::rngs::SmallRng::from_entropy();
622
623 for input_len in 0..10 {
625 output.clear();
626
627 for _ in 0..10 {
629 output.push(rng.gen());
630 }
631
632 let orig_output_buf = output.to_vec();
633
634 let bytes_written = add_padding(input_len, &mut output);
635
636 assert_eq!(orig_output_buf[bytes_written..], output[bytes_written..]);
638
639 let _ = str::from_utf8(&output[0..bytes_written]).unwrap();
641 }
642 }
643
644 fn assert_encoded_length(input_len: usize, encoded_len: usize, config: Config) {
645 assert_eq!(encoded_len, encoded_size(input_len, config).unwrap());
646
647 let mut bytes: Vec<u8> = Vec::new();
648 let mut rng = rand::rngs::SmallRng::from_entropy();
649
650 for _ in 0..input_len {
651 bytes.push(rng.gen());
652 }
653
654 let encoded = encode_config(&bytes, config);
655 assert_encode_sanity(&encoded, config, input_len);
656
657 assert_eq!(encoded_len, encoded.len());
658 }
659
660}