Skip to content

Commit

Permalink
Implement FromBase64 for &[u8].
Browse files Browse the repository at this point in the history
The algorithm was already based on bytes internally.

Also use byte literals instead of casting u8 to char for matching.
  • Loading branch information
SimonSapin committed Jul 19, 2014
1 parent e0a6e2b commit 56218f5
Showing 1 changed file with 29 additions and 17 deletions.
46 changes: 29 additions & 17 deletions src/libserialize/base64.rs
Expand Up @@ -161,15 +161,15 @@ pub trait FromBase64 {
/// Errors that can occur when decoding a base64 encoded string
pub enum FromBase64Error {
/// The input contained a character not part of the base64 format
InvalidBase64Character(char, uint),
InvalidBase64Byte(u8, uint),
/// The input had an invalid length
InvalidBase64Length,
}

impl fmt::Show for FromBase64Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
InvalidBase64Character(ch, idx) =>
InvalidBase64Byte(ch, idx) =>
write!(f, "Invalid character '{}' at position {}", ch, idx),
InvalidBase64Length => write!(f, "Invalid length"),
}
Expand Down Expand Up @@ -205,24 +205,31 @@ impl<'a> FromBase64 for &'a str {
* }
* ```
*/
#[inline]
fn from_base64(&self) -> Result<Vec<u8>, FromBase64Error> {
self.as_bytes().from_base64()
}
}

impl<'a> FromBase64 for &'a [u8] {
fn from_base64(&self) -> Result<Vec<u8>, FromBase64Error> {
let mut r = Vec::new();
let mut buf: u32 = 0;
let mut modulus = 0i;

let mut it = self.bytes().enumerate();
for (idx, byte) in it {
let mut it = self.iter().enumerate();
for (idx, &byte) in it {
let val = byte as u32;

match byte as char {
'A'..'Z' => buf |= val - 0x41,
'a'..'z' => buf |= val - 0x47,
'0'..'9' => buf |= val + 0x04,
'+'|'-' => buf |= 0x3E,
'/'|'_' => buf |= 0x3F,
'\r'|'\n' => continue,
'=' => break,
_ => return Err(InvalidBase64Character(self.char_at(idx), idx)),
match byte {
b'A'..b'Z' => buf |= val - 0x41,
b'a'..b'z' => buf |= val - 0x47,
b'0'..b'9' => buf |= val + 0x04,
b'+' | b'-' => buf |= 0x3E,
b'/' | b'_' => buf |= 0x3F,
b'\r' | b'\n' => continue,
b'=' => break,
_ => return Err(InvalidBase64Byte(self[idx], idx)),
}

buf <<= 6;
Expand All @@ -235,10 +242,10 @@ impl<'a> FromBase64 for &'a str {
}
}

for (idx, byte) in it {
match byte as char {
'='|'\r'|'\n' => continue,
_ => return Err(InvalidBase64Character(self.char_at(idx), idx)),
for (idx, &byte) in it {
match byte {
b'=' | b'\r' | b'\n' => continue,
_ => return Err(InvalidBase64Byte(self[idx], idx)),
}
}

Expand Down Expand Up @@ -308,6 +315,11 @@ mod tests {
assert_eq!("Zm9vYmFy".from_base64().unwrap().as_slice(), "foobar".as_bytes());
}

#[test]
fn test_from_base64_bytes() {
assert_eq!(b"Zm9vYmFy".from_base64().unwrap().as_slice(), "foobar".as_bytes());
}

#[test]
fn test_from_base64_newlines() {
assert_eq!("Zm9v\r\nYmFy".from_base64().unwrap().as_slice(),
Expand Down

5 comments on commit 56218f5

@bors
Copy link
Contributor

@bors bors commented on 56218f5 Jul 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from alexcrichton
at SimonSapin@56218f5

@bors
Copy link
Contributor

@bors bors commented on 56218f5 Jul 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging SimonSapin/rust/base64-from-bytes = 56218f5 into auto

@bors
Copy link
Contributor

@bors bors commented on 56218f5 Jul 20, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SimonSapin/rust/base64-from-bytes = 56218f5 merged ok, testing candidate = f15d6d2

@bors
Copy link
Contributor

@bors bors commented on 56218f5 Jul 21, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = f15d6d2

Please sign in to comment.