chromaprint/codec/
base64.rs1use crate::error::{Error, Result};
2
3const ENCODE_TABLE: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
4
5#[rustfmt::skip]
6static DECODE_TABLE: [u8; 256] = {
7 let mut table = [0u8; 256];
8 table[b'A' as usize] = 0; table[b'B' as usize] = 1; table[b'C' as usize] = 2;
9 table[b'D' as usize] = 3; table[b'E' as usize] = 4; table[b'F' as usize] = 5;
10 table[b'G' as usize] = 6; table[b'H' as usize] = 7; table[b'I' as usize] = 8;
11 table[b'J' as usize] = 9; table[b'K' as usize] = 10; table[b'L' as usize] = 11;
12 table[b'M' as usize] = 12; table[b'N' as usize] = 13; table[b'O' as usize] = 14;
13 table[b'P' as usize] = 15; table[b'Q' as usize] = 16; table[b'R' as usize] = 17;
14 table[b'S' as usize] = 18; table[b'T' as usize] = 19; table[b'U' as usize] = 20;
15 table[b'V' as usize] = 21; table[b'W' as usize] = 22; table[b'X' as usize] = 23;
16 table[b'Y' as usize] = 24; table[b'Z' as usize] = 25;
17 table[b'a' as usize] = 26; table[b'b' as usize] = 27; table[b'c' as usize] = 28;
18 table[b'd' as usize] = 29; table[b'e' as usize] = 30; table[b'f' as usize] = 31;
19 table[b'g' as usize] = 32; table[b'h' as usize] = 33; table[b'i' as usize] = 34;
20 table[b'j' as usize] = 35; table[b'k' as usize] = 36; table[b'l' as usize] = 37;
21 table[b'm' as usize] = 38; table[b'n' as usize] = 39; table[b'o' as usize] = 40;
22 table[b'p' as usize] = 41; table[b'q' as usize] = 42; table[b'r' as usize] = 43;
23 table[b's' as usize] = 44; table[b't' as usize] = 45; table[b'u' as usize] = 46;
24 table[b'v' as usize] = 47; table[b'w' as usize] = 48; table[b'x' as usize] = 49;
25 table[b'y' as usize] = 50; table[b'z' as usize] = 51;
26 table[b'0' as usize] = 52; table[b'1' as usize] = 53; table[b'2' as usize] = 54;
27 table[b'3' as usize] = 55; table[b'4' as usize] = 56; table[b'5' as usize] = 57;
28 table[b'6' as usize] = 58; table[b'7' as usize] = 59; table[b'8' as usize] = 60;
29 table[b'9' as usize] = 61;
30 table[b'-' as usize] = 62;
31 table[b'_' as usize] = 63;
32 table
33};
34
35pub fn encode(data: &[u8]) -> String {
37 let mut result = String::with_capacity((data.len() * 4 + 2) / 3);
38 let mut i = 0;
39 let size = data.len();
40
41 while i + 3 <= size {
42 let s0 = data[i];
43 let s1 = data[i + 1];
44 let s2 = data[i + 2];
45 result.push(ENCODE_TABLE[((s0 >> 2) & 63) as usize] as char);
46 result.push(ENCODE_TABLE[(((s0 << 4) | (s1 >> 4)) & 63) as usize] as char);
47 result.push(ENCODE_TABLE[(((s1 << 2) | (s2 >> 6)) & 63) as usize] as char);
48 result.push(ENCODE_TABLE[(s2 & 63) as usize] as char);
49 i += 3;
50 }
51
52 let remaining = size - i;
53 if remaining == 2 {
54 let s0 = data[i];
55 let s1 = data[i + 1];
56 result.push(ENCODE_TABLE[((s0 >> 2) & 63) as usize] as char);
57 result.push(ENCODE_TABLE[(((s0 << 4) | (s1 >> 4)) & 63) as usize] as char);
58 result.push(ENCODE_TABLE[((s1 << 2) & 63) as usize] as char);
59 } else if remaining == 1 {
60 let s0 = data[i];
61 result.push(ENCODE_TABLE[((s0 >> 2) & 63) as usize] as char);
62 result.push(ENCODE_TABLE[((s0 << 4) & 63) as usize] as char);
63 }
64
65 result
66}
67
68pub fn decode(input: &str) -> Result<Vec<u8>> {
70 let bytes = input.as_bytes();
71 let size = bytes.len();
72 let mut result = Vec::with_capacity(size * 3 / 4);
73 let mut i = 0;
74
75 while i + 4 <= size {
76 let b0 = DECODE_TABLE[bytes[i] as usize];
77 let b1 = DECODE_TABLE[bytes[i + 1] as usize];
78 let b2 = DECODE_TABLE[bytes[i + 2] as usize];
79 let b3 = DECODE_TABLE[bytes[i + 3] as usize];
80 result.push((b0 << 2) | (b1 >> 4));
81 result.push((b1 << 4) | (b2 >> 2));
82 result.push((b2 << 6) | b3);
83 i += 4;
84 }
85
86 let remaining = size - i;
87 if remaining == 3 {
88 let b0 = DECODE_TABLE[bytes[i] as usize];
89 let b1 = DECODE_TABLE[bytes[i + 1] as usize];
90 let b2 = DECODE_TABLE[bytes[i + 2] as usize];
91 result.push((b0 << 2) | (b1 >> 4));
92 result.push((b1 << 4) | (b2 >> 2));
93 } else if remaining == 2 {
94 let b0 = DECODE_TABLE[bytes[i] as usize];
95 let b1 = DECODE_TABLE[bytes[i + 1] as usize];
96 result.push((b0 << 2) | (b1 >> 4));
97 } else if remaining == 1 {
98 return Err(Error::InvalidFingerprint);
99 }
100
101 Ok(result)
102}