From abee1589451c513bb0b77bb7001a0ea592dc67c3 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 3 Jul 2012 21:29:45 -0700 Subject: [PATCH 1/2] Add a basic base64 module --- src/libstd/base64.rs | 158 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 src/libstd/base64.rs diff --git a/src/libstd/base64.rs b/src/libstd/base64.rs new file mode 100644 index 0000000000000..3ca34c4b75697 --- /dev/null +++ b/src/libstd/base64.rs @@ -0,0 +1,158 @@ +import io::{reader, reader_util}; + +iface to_base64 { + fn to_base64() -> str; +} + +impl of to_base64 for ~[u8] { + fn to_base64() -> str { + let chars = str::chars( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + ); + + let len = self.len(); + let mut s = ""; + str::reserve(s, ((len + 3u) / 4u) * 3u); + + let mut i = 0u; + + while i < len - (len % 3u) { + let n = (self[i] as uint) << 16u | + (self[i + 1u] as uint) << 8u | + (self[i + 2u] as uint); + + // This 24-bit number gets separated into four 6-bit numbers. + str::push_char(s, chars[(n >> 18u) & 63u]); + str::push_char(s, chars[(n >> 12u) & 63u]); + str::push_char(s, chars[(n >> 6u) & 63u]); + str::push_char(s, chars[n & 63u]); + + i += 3u; + } + + alt check len % 3u { + 0u { } + 1u { + let n = (self[i] as uint) << 16u; + str::push_char(s, chars[(n >> 18u) & 63u]); + str::push_char(s, chars[(n >> 12u) & 63u]); + str::push_char(s, '='); + str::push_char(s, '='); + } + 2u { + let n = (self[i] as uint) << 16u | (self[i + 1u] as uint) << 8u; + str::push_char(s, chars[(n >> 18u) & 63u]); + str::push_char(s, chars[(n >> 12u) & 63u]); + str::push_char(s, chars[(n >> 6u) & 63u]); + str::push_char(s, '='); + } + } + + s + } +} + +impl of to_base64 for str { + fn to_base64() -> str { + str::bytes(self).to_base64() + } +} + +iface from_base64 { + fn from_base64() -> ~[u8]; +} + +impl of from_base64 for ~[u8] { + fn from_base64() -> ~[u8] { + if self.len() % 4u != 0u { fail "invalid base64 length"; } + + let len = self.len(); + let mut padding = 0u; + + if len != 0u { + if self[len - 1u] == '=' as u8 { padding += 1u; } + if self[len - 2u] == '=' as u8 { padding += 1u; } + } + + let mut r = ~[]; + vec::reserve(r, (len / 4u) * 3u - padding); + + let mut i = 0u; + while i < len { + let mut n = 0u; + + for iter::repeat(4u) { + let ch = self[i] as char; + n <<= 6u; + + if ch >= 'A' && ch <= 'Z' { + n |= (ch as uint) - 0x41u; + } else if ch >= 'a' && ch <= 'z' { + n |= (ch as uint) - 0x47u; + } else if ch >= '0' && ch <= '9' { + n |= (ch as uint) + 0x04u; + } else if ch == '+' { + n |= 0x3Eu; + } else if ch == '/' { + n |= 0x3Fu; + } else if ch == '=' { + alt len - i { + 1u { + vec::push(r, ((n >> 16u) & 0xFFu) as u8); + vec::push(r, ((n >> 8u ) & 0xFFu) as u8); + ret copy r; + } + 2u { + vec::push(r, ((n >> 10u) & 0xFFu) as u8); + ret copy r; + } + _ { + fail "invalid base64 padding"; + } + } + } else { + fail "invalid base64 character"; + } + + i += 1u; + }; + + vec::push(r, ((n >> 16u) & 0xFFu) as u8); + vec::push(r, ((n >> 8u ) & 0xFFu) as u8); + vec::push(r, ((n ) & 0xFFu) as u8); + } + + r + } +} + +impl of from_base64 for str { + fn from_base64() -> ~[u8] { + str::bytes(self).from_base64() + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_to_base64() { + assert "".to_base64() == ""; + assert "f".to_base64() == "Zg=="; + assert "fo".to_base64() == "Zm8="; + assert "foo".to_base64() == "Zm9v"; + assert "foob".to_base64() == "Zm9vYg=="; + assert "fooba".to_base64() == "Zm9vYmE="; + assert "foobar".to_base64() == "Zm9vYmFy"; + } + + #[test] + fn test_from_base64() { + assert "".from_base64() == str::bytes(""); + assert "Zg==".from_base64() == str::bytes("f"); + assert "Zm8=".from_base64() == str::bytes("fo"); + assert "Zm9v".from_base64() == str::bytes("foo"); + assert "Zm9vYg==".from_base64() == str::bytes("foob"); + assert "Zm9vYmE=".from_base64() == str::bytes("fooba"); + assert "Zm9vYmFy".from_base64() == str::bytes("foobar"); + } +} From 2f9c0114fa0b0d3b018b37dcfd0eafaf01d6c48a Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 3 Jul 2012 21:30:09 -0700 Subject: [PATCH 2/2] Add a to_bytes iface and a handful of impls --- src/libcore/to_bytes.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/libcore/to_bytes.rs diff --git a/src/libcore/to_bytes.rs b/src/libcore/to_bytes.rs new file mode 100644 index 0000000000000..4bfd16344cbd5 --- /dev/null +++ b/src/libcore/to_bytes.rs @@ -0,0 +1,19 @@ +iface to_bytes { + fn to_bytes() -> ~[u8]; +} + +impl of to_bytes for ~[u8] { + fn to_bytes() -> ~[u8] { copy self } +} + +impl of to_bytes for @~[u8] { + fn to_bytes() -> ~[u8] { copy *self } +} + +impl of to_bytes for str { + fn to_bytes() -> ~[u8] { str::bytes(self) } +} + +impl of to_bytes for @str { + fn to_bytes() -> ~[u8] { str::bytes(*self) } +}