diff options
Diffstat (limited to 'third_party/rust/base64/examples')
-rw-r--r-- | third_party/rust/base64/examples/base64.rs | 89 | ||||
-rw-r--r-- | third_party/rust/base64/examples/make_tables.rs | 179 |
2 files changed, 268 insertions, 0 deletions
diff --git a/third_party/rust/base64/examples/base64.rs b/third_party/rust/base64/examples/base64.rs new file mode 100644 index 0000000000..cba745b05e --- /dev/null +++ b/third_party/rust/base64/examples/base64.rs @@ -0,0 +1,89 @@ +use std::fs::File; +use std::io::{self, Read}; +use std::path::PathBuf; +use std::process; +use std::str::FromStr; + +use base64::{read, write}; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +enum CharacterSet { + Standard, + UrlSafe, +} + +impl Default for CharacterSet { + fn default() -> Self { + CharacterSet::Standard + } +} + +impl Into<base64::Config> for CharacterSet { + fn into(self) -> base64::Config { + match self { + CharacterSet::Standard => base64::STANDARD, + CharacterSet::UrlSafe => base64::URL_SAFE, + } + } +} + +impl FromStr for CharacterSet { + type Err = String; + fn from_str(s: &str) -> Result<CharacterSet, String> { + match s { + "standard" => Ok(CharacterSet::Standard), + "urlsafe" => Ok(CharacterSet::UrlSafe), + _ => Err(format!("charset '{}' unrecognized", s)), + } + } +} + +/// Base64 encode or decode FILE (or standard input), to standard output. +#[derive(Debug, StructOpt)] +struct Opt { + /// decode data + #[structopt(short = "d", long = "decode")] + decode: bool, + /// The character set to choose. Defaults to the standard base64 character set. + /// Supported character sets include "standard" and "urlsafe". + #[structopt(long = "charset")] + charset: Option<CharacterSet>, + /// The file to encode/decode. + #[structopt(parse(from_os_str))] + file: Option<PathBuf>, +} + +fn main() { + let opt = Opt::from_args(); + let stdin; + let mut input: Box<dyn Read> = match opt.file { + None => { + stdin = io::stdin(); + Box::new(stdin.lock()) + } + Some(ref f) if f.as_os_str() == "-" => { + stdin = io::stdin(); + Box::new(stdin.lock()) + } + Some(f) => Box::new(File::open(f).unwrap()), + }; + let config = opt.charset.unwrap_or_default().into(); + let stdout = io::stdout(); + let mut stdout = stdout.lock(); + let r = if opt.decode { + let mut decoder = read::DecoderReader::new(&mut input, config); + io::copy(&mut decoder, &mut stdout) + } else { + let mut encoder = write::EncoderWriter::new(&mut stdout, config); + io::copy(&mut input, &mut encoder) + }; + if let Err(e) = r { + eprintln!( + "Base64 {} failed with {}", + if opt.decode { "decode" } else { "encode" }, + e + ); + process::exit(1); + } +} diff --git a/third_party/rust/base64/examples/make_tables.rs b/third_party/rust/base64/examples/make_tables.rs new file mode 100644 index 0000000000..2f27c0eb95 --- /dev/null +++ b/third_party/rust/base64/examples/make_tables.rs @@ -0,0 +1,179 @@ +use std::collections::{HashMap, HashSet}; +use std::iter::Iterator; + +fn main() { + println!("pub const INVALID_VALUE: u8 = 255;"); + + // A-Z + let standard_alphabet: Vec<u8> = (0x41..0x5B) + // a-z + .chain(0x61..0x7B) + // 0-9 + .chain(0x30..0x3A) + // + + .chain(0x2B..0x2C) + // / + .chain(0x2F..0x30) + .collect(); + print_encode_table(&standard_alphabet, "STANDARD_ENCODE", 0); + print_decode_table(&standard_alphabet, "STANDARD_DECODE", 0); + + // A-Z + let url_alphabet: Vec<u8> = (0x41..0x5B) + // a-z + .chain(0x61..0x7B) + // 0-9 + .chain(0x30..0x3A) + // - + .chain(0x2D..0x2E) + // _ + .chain(0x5F..0x60) + .collect(); + print_encode_table(&url_alphabet, "URL_SAFE_ENCODE", 0); + print_decode_table(&url_alphabet, "URL_SAFE_DECODE", 0); + + // ./0123456789 + let crypt_alphabet: Vec<u8> = (b'.'..(b'9' + 1)) + // A-Z + .chain(b'A'..(b'Z' + 1)) + // a-z + .chain(b'a'..(b'z' + 1)) + .collect(); + print_encode_table(&crypt_alphabet, "CRYPT_ENCODE", 0); + print_decode_table(&crypt_alphabet, "CRYPT_DECODE", 0); + + // ./ + let bcrypt_alphabet: Vec<u8> = (b'.'..(b'/' + 1)) + // A-Z + .chain(b'A'..(b'Z' + 1)) + // a-z + .chain(b'a'..(b'z' + 1)) + // 0-9 + .chain(b'0'..(b'9' + 1)) + .collect(); + print_encode_table(&bcrypt_alphabet, "BCRYPT_ENCODE", 0); + print_decode_table(&bcrypt_alphabet, "BCRYPT_DECODE", 0); + + // A-Z + let imap_alphabet: Vec<u8> = (0x41..0x5B) + // a-z + .chain(0x61..0x7B) + // 0-9 + .chain(0x30..0x3A) + // + + .chain(0x2B..0x2C) + // , + .chain(0x2C..0x2D) + .collect(); + print_encode_table(&imap_alphabet, "IMAP_MUTF7_ENCODE", 0); + print_decode_table(&imap_alphabet, "IMAP_MUTF7_DECODE", 0); + + // '!' - '-' + let binhex_alphabet: Vec<u8> = (0x21..0x2E) + // 0-9 + .chain(0x30..0x3A) + // @-N + .chain(0x40..0x4F) + // P-V + .chain(0x50..0x57) + // X-[ + .chain(0x58..0x5C) + // `-f + .chain(0x60..0x66) + // h-m + .chain(0x68..0x6E) + // p-r + .chain(0x70..0x73) + .collect(); + print_encode_table(&binhex_alphabet, "BINHEX_ENCODE", 0); + print_decode_table(&binhex_alphabet, "BINHEX_DECODE", 0); +} + +fn print_encode_table(alphabet: &[u8], const_name: &str, indent_depth: usize) { + check_alphabet(alphabet); + println!("#[rustfmt::skip]"); + println!( + "{:width$}pub const {}: &[u8; 64] = &[", + "", + const_name, + width = indent_depth + ); + + for (i, b) in alphabet.iter().enumerate() { + println!( + "{:width$}{}, // input {} (0x{:X}) => '{}' (0x{:X})", + "", + b, + i, + i, + String::from_utf8(vec![*b as u8]).unwrap(), + b, + width = indent_depth + 4 + ); + } + + println!("{:width$}];", "", width = indent_depth); +} + +fn print_decode_table(alphabet: &[u8], const_name: &str, indent_depth: usize) { + check_alphabet(alphabet); + // map of alphabet bytes to 6-bit morsels + let mut input_to_morsel = HashMap::<u8, u8>::new(); + + // standard base64 alphabet bytes, in order + for (morsel, ascii_byte) in alphabet.iter().enumerate() { + // truncation cast is fine here + let _ = input_to_morsel.insert(*ascii_byte, morsel as u8); + } + + println!("#[rustfmt::skip]"); + println!( + "{:width$}pub const {}: &[u8; 256] = &[", + "", + const_name, + width = indent_depth + ); + for ascii_byte in 0..256 { + let (value, comment) = match input_to_morsel.get(&(ascii_byte as u8)) { + None => ( + "INVALID_VALUE".to_string(), + format!("input {} (0x{:X})", ascii_byte, ascii_byte), + ), + Some(v) => ( + format!("{}", *v), + format!( + "input {} (0x{:X} char '{}') => {} (0x{:X})", + ascii_byte, + ascii_byte, + String::from_utf8(vec![ascii_byte as u8]).unwrap(), + *v, + *v + ), + ), + }; + + println!( + "{:width$}{}, // {}", + "", + value, + comment, + width = indent_depth + 4 + ); + } + println!("{:width$}];", "", width = indent_depth); +} + +fn check_alphabet(alphabet: &[u8]) { + // ensure all characters are distinct + assert_eq!(64, alphabet.len()); + let mut set: HashSet<u8> = HashSet::new(); + set.extend(alphabet); + assert_eq!(64, set.len()); + + // must be ASCII to be valid as single UTF-8 bytes + for &b in alphabet { + assert!(b <= 0x7F_u8); + // = is assumed to be padding, so cannot be used as a symbol + assert_ne!(b'=', b); + } +} |