Skip to content

Commit 34660f0

Browse files
committed
Merge pull request #2798 from erickt/incoming
adding base64 and to_bytes to stdlib
2 parents 10fd195 + 2f9c011 commit 34660f0

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed

src/libcore/to_bytes.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
iface to_bytes {
2+
fn to_bytes() -> ~[u8];
3+
}
4+
5+
impl of to_bytes for ~[u8] {
6+
fn to_bytes() -> ~[u8] { copy self }
7+
}
8+
9+
impl of to_bytes for @~[u8] {
10+
fn to_bytes() -> ~[u8] { copy *self }
11+
}
12+
13+
impl of to_bytes for str {
14+
fn to_bytes() -> ~[u8] { str::bytes(self) }
15+
}
16+
17+
impl of to_bytes for @str {
18+
fn to_bytes() -> ~[u8] { str::bytes(*self) }
19+
}

src/libstd/base64.rs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import io::{reader, reader_util};
2+
3+
iface to_base64 {
4+
fn to_base64() -> str;
5+
}
6+
7+
impl of to_base64 for ~[u8] {
8+
fn to_base64() -> str {
9+
let chars = str::chars(
10+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
11+
);
12+
13+
let len = self.len();
14+
let mut s = "";
15+
str::reserve(s, ((len + 3u) / 4u) * 3u);
16+
17+
let mut i = 0u;
18+
19+
while i < len - (len % 3u) {
20+
let n = (self[i] as uint) << 16u |
21+
(self[i + 1u] as uint) << 8u |
22+
(self[i + 2u] as uint);
23+
24+
// This 24-bit number gets separated into four 6-bit numbers.
25+
str::push_char(s, chars[(n >> 18u) & 63u]);
26+
str::push_char(s, chars[(n >> 12u) & 63u]);
27+
str::push_char(s, chars[(n >> 6u) & 63u]);
28+
str::push_char(s, chars[n & 63u]);
29+
30+
i += 3u;
31+
}
32+
33+
alt check len % 3u {
34+
0u { }
35+
1u {
36+
let n = (self[i] as uint) << 16u;
37+
str::push_char(s, chars[(n >> 18u) & 63u]);
38+
str::push_char(s, chars[(n >> 12u) & 63u]);
39+
str::push_char(s, '=');
40+
str::push_char(s, '=');
41+
}
42+
2u {
43+
let n = (self[i] as uint) << 16u | (self[i + 1u] as uint) << 8u;
44+
str::push_char(s, chars[(n >> 18u) & 63u]);
45+
str::push_char(s, chars[(n >> 12u) & 63u]);
46+
str::push_char(s, chars[(n >> 6u) & 63u]);
47+
str::push_char(s, '=');
48+
}
49+
}
50+
51+
s
52+
}
53+
}
54+
55+
impl of to_base64 for str {
56+
fn to_base64() -> str {
57+
str::bytes(self).to_base64()
58+
}
59+
}
60+
61+
iface from_base64 {
62+
fn from_base64() -> ~[u8];
63+
}
64+
65+
impl of from_base64 for ~[u8] {
66+
fn from_base64() -> ~[u8] {
67+
if self.len() % 4u != 0u { fail "invalid base64 length"; }
68+
69+
let len = self.len();
70+
let mut padding = 0u;
71+
72+
if len != 0u {
73+
if self[len - 1u] == '=' as u8 { padding += 1u; }
74+
if self[len - 2u] == '=' as u8 { padding += 1u; }
75+
}
76+
77+
let mut r = ~[];
78+
vec::reserve(r, (len / 4u) * 3u - padding);
79+
80+
let mut i = 0u;
81+
while i < len {
82+
let mut n = 0u;
83+
84+
for iter::repeat(4u) {
85+
let ch = self[i] as char;
86+
n <<= 6u;
87+
88+
if ch >= 'A' && ch <= 'Z' {
89+
n |= (ch as uint) - 0x41u;
90+
} else if ch >= 'a' && ch <= 'z' {
91+
n |= (ch as uint) - 0x47u;
92+
} else if ch >= '0' && ch <= '9' {
93+
n |= (ch as uint) + 0x04u;
94+
} else if ch == '+' {
95+
n |= 0x3Eu;
96+
} else if ch == '/' {
97+
n |= 0x3Fu;
98+
} else if ch == '=' {
99+
alt len - i {
100+
1u {
101+
vec::push(r, ((n >> 16u) & 0xFFu) as u8);
102+
vec::push(r, ((n >> 8u ) & 0xFFu) as u8);
103+
ret copy r;
104+
}
105+
2u {
106+
vec::push(r, ((n >> 10u) & 0xFFu) as u8);
107+
ret copy r;
108+
}
109+
_ {
110+
fail "invalid base64 padding";
111+
}
112+
}
113+
} else {
114+
fail "invalid base64 character";
115+
}
116+
117+
i += 1u;
118+
};
119+
120+
vec::push(r, ((n >> 16u) & 0xFFu) as u8);
121+
vec::push(r, ((n >> 8u ) & 0xFFu) as u8);
122+
vec::push(r, ((n ) & 0xFFu) as u8);
123+
}
124+
125+
r
126+
}
127+
}
128+
129+
impl of from_base64 for str {
130+
fn from_base64() -> ~[u8] {
131+
str::bytes(self).from_base64()
132+
}
133+
}
134+
135+
#[cfg(test)]
136+
mod tests {
137+
#[test]
138+
fn test_to_base64() {
139+
assert "".to_base64() == "";
140+
assert "f".to_base64() == "Zg==";
141+
assert "fo".to_base64() == "Zm8=";
142+
assert "foo".to_base64() == "Zm9v";
143+
assert "foob".to_base64() == "Zm9vYg==";
144+
assert "fooba".to_base64() == "Zm9vYmE=";
145+
assert "foobar".to_base64() == "Zm9vYmFy";
146+
}
147+
148+
#[test]
149+
fn test_from_base64() {
150+
assert "".from_base64() == str::bytes("");
151+
assert "Zg==".from_base64() == str::bytes("f");
152+
assert "Zm8=".from_base64() == str::bytes("fo");
153+
assert "Zm9v".from_base64() == str::bytes("foo");
154+
assert "Zm9vYg==".from_base64() == str::bytes("foob");
155+
assert "Zm9vYmE=".from_base64() == str::bytes("fooba");
156+
assert "Zm9vYmFy".from_base64() == str::bytes("foobar");
157+
}
158+
}

0 commit comments

Comments
 (0)