helpers.rs

  1// Copyright (c) 2017 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
  2//
  3// This Source Code Form is subject to the terms of the Mozilla Public
  4// License, v. 2.0. If a copy of the MPL was not distributed with this
  5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6
  7use crate::util::error::Error;
  8use base64::{engine::general_purpose::STANDARD as Base64Engine, Engine};
  9use jid::Jid;
 10use std::str::FromStr;
 11
 12/// Codec for text content.
 13pub struct Text;
 14
 15impl Text {
 16    pub fn decode(s: &str) -> Result<String, Error> {
 17        Ok(s.to_owned())
 18    }
 19
 20    pub fn encode(string: &str) -> Option<String> {
 21        Some(string.to_owned())
 22    }
 23}
 24
 25/// Codec for plain text content.
 26pub struct PlainText;
 27
 28impl PlainText {
 29    pub fn decode(s: &str) -> Result<Option<String>, Error> {
 30        Ok(match s {
 31            "" => None,
 32            text => Some(text.to_owned()),
 33        })
 34    }
 35
 36    pub fn encode(string: &Option<String>) -> Option<String> {
 37        string.as_ref().map(ToOwned::to_owned)
 38    }
 39}
 40
 41/// Codec for trimmed plain text content.
 42pub struct TrimmedPlainText;
 43
 44impl TrimmedPlainText {
 45    pub fn decode(s: &str) -> Result<String, Error> {
 46        Ok(match s.trim() {
 47            "" => return Err(Error::ParseError("URI missing in uri.")),
 48            text => text.to_owned(),
 49        })
 50    }
 51
 52    pub fn encode(string: &str) -> Option<String> {
 53        Some(string.to_owned())
 54    }
 55}
 56
 57/// Codec wrapping base64 encode/decode.
 58pub struct Base64;
 59
 60impl Base64 {
 61    pub fn decode(s: &str) -> Result<Vec<u8>, Error> {
 62        Ok(Base64Engine.decode(s)?)
 63    }
 64
 65    pub fn encode(b: &[u8]) -> Option<String> {
 66        Some(Base64Engine.encode(b))
 67    }
 68}
 69
 70/// Codec wrapping base64 encode/decode, while ignoring whitespace characters.
 71pub struct WhitespaceAwareBase64;
 72
 73impl WhitespaceAwareBase64 {
 74    pub fn decode(s: &str) -> Result<Vec<u8>, Error> {
 75        let s: String = s
 76            .chars()
 77            .filter(|ch| *ch != ' ' && *ch != '\n' && *ch != '\t')
 78            .collect();
 79        Ok(Base64Engine.decode(&s)?)
 80    }
 81
 82    pub fn encode(b: &[u8]) -> Option<String> {
 83        Some(Base64Engine.encode(b))
 84    }
 85}
 86
 87/// Codec for colon-separated bytes of uppercase hexadecimal.
 88pub struct ColonSeparatedHex;
 89
 90impl ColonSeparatedHex {
 91    pub fn decode(s: &str) -> Result<Vec<u8>, Error> {
 92        let mut bytes = vec![];
 93        for i in 0..(1 + s.len()) / 3 {
 94            let byte = u8::from_str_radix(&s[3 * i..3 * i + 2], 16)?;
 95            if 3 * i + 2 < s.len() {
 96                assert_eq!(&s[3 * i + 2..3 * i + 3], ":");
 97            }
 98            bytes.push(byte);
 99        }
100        Ok(bytes)
101    }
102
103    pub fn encode(b: &[u8]) -> Option<String> {
104        let mut bytes = vec![];
105        for byte in b {
106            bytes.push(format!("{:02X}", byte));
107        }
108        Some(bytes.join(":"))
109    }
110}
111
112/// Codec for a JID.
113pub struct JidCodec;
114
115impl JidCodec {
116    pub fn decode(s: &str) -> Result<Jid, Error> {
117        Ok(Jid::from_str(s)?)
118    }
119
120    pub fn encode(jid: &Jid) -> Option<String> {
121        Some(jid.to_string())
122    }
123}