1 use std::fs::File;
2 use std::io::{self, Read};
3 use std::path::PathBuf;
4 use std::process;
5 use std::str::FromStr;
6
7 use base64::{read, write};
8 use structopt::StructOpt;
9
10 #[derive(Debug, StructOpt)]
11 enum CharacterSet {
12 Standard,
13 UrlSafe,
14 }
15
16 impl Default for CharacterSet {
default() -> Self17 fn default() -> Self {
18 CharacterSet::Standard
19 }
20 }
21
22 impl Into<base64::Config> for CharacterSet {
into(self) -> base64::Config23 fn into(self) -> base64::Config {
24 match self {
25 CharacterSet::Standard => base64::STANDARD,
26 CharacterSet::UrlSafe => base64::URL_SAFE,
27 }
28 }
29 }
30
31 impl FromStr for CharacterSet {
32 type Err = String;
from_str(s: &str) -> Result<CharacterSet, String>33 fn from_str(s: &str) -> Result<CharacterSet, String> {
34 match s {
35 "standard" => Ok(CharacterSet::Standard),
36 "urlsafe" => Ok(CharacterSet::UrlSafe),
37 _ => Err(format!("charset '{}' unrecognized", s)),
38 }
39 }
40 }
41
42 /// Base64 encode or decode FILE (or standard input), to standard output.
43 #[derive(Debug, StructOpt)]
44 struct Opt {
45 /// decode data
46 #[structopt(short = "d", long = "decode")]
47 decode: bool,
48 /// The character set to choose. Defaults to the standard base64 character set.
49 /// Supported character sets include "standard" and "urlsafe".
50 #[structopt(long = "charset")]
51 charset: Option<CharacterSet>,
52 /// The file to encode/decode.
53 #[structopt(parse(from_os_str))]
54 file: Option<PathBuf>,
55 }
56
main()57 fn main() {
58 let opt = Opt::from_args();
59 let stdin;
60 let mut input: Box<dyn Read> = match opt.file {
61 None => {
62 stdin = io::stdin();
63 Box::new(stdin.lock())
64 }
65 Some(ref f) if f.as_os_str() == "-" => {
66 stdin = io::stdin();
67 Box::new(stdin.lock())
68 }
69 Some(f) => Box::new(File::open(f).unwrap()),
70 };
71 let config = opt.charset.unwrap_or_default().into();
72 let stdout = io::stdout();
73 let mut stdout = stdout.lock();
74 let r = if opt.decode {
75 let mut decoder = read::DecoderReader::new(&mut input, config);
76 io::copy(&mut decoder, &mut stdout)
77 } else {
78 let mut encoder = write::EncoderWriter::new(&mut stdout, config);
79 io::copy(&mut input, &mut encoder)
80 };
81 if let Err(e) = r {
82 eprintln!(
83 "Base64 {} failed with {}",
84 if opt.decode { "decode" } else { "encode" },
85 e
86 );
87 process::exit(1);
88 }
89 }
90