9
9
// except according to those terms.
10
10
11
11
//! Base64 binary-to-text encoding
12
+ use std:: str;
12
13
13
14
/// Available encoding character sets
14
15
pub enum CharacterSet {
@@ -40,21 +41,13 @@ pub static URL_SAFE: Config =
40
41
pub static MIME : Config =
41
42
Config { char_set : Standard , pad : true , line_length : Some ( 76 ) } ;
42
43
43
- static STANDARD_CHARS : [ char , ..64 ] = [
44
- 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 'M' ,
45
- 'N' , 'O' , 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z' ,
46
- 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' ,
47
- 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' ,
48
- '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , '+' , '/'
49
- ] ;
50
-
51
- static URLSAFE_CHARS : [ char , ..64 ] = [
52
- 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 'M' ,
53
- 'N' , 'O' , 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z' ,
54
- 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' ,
55
- 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' ,
56
- '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , '-' , '_'
57
- ] ;
44
+ static STANDARD_CHARS : & ' static [ u8 ] = bytes ! ( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ,
45
+ "abcdefghijklmnopqrstuvwxyz" ,
46
+ "0123456789+/" ) ;
47
+
48
+ static URLSAFE_CHARS : & ' static [ u8 ] = bytes ! ( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ,
49
+ "abcdefghijklmnopqrstuvwxyz" ,
50
+ "0123456789-_" ) ;
58
51
59
52
/// A trait for converting a value to base64 encoding.
60
53
pub trait ToBase64 {
@@ -80,20 +73,21 @@ impl<'self> ToBase64 for &'self [u8] {
80
73
* ~~~
81
74
*/
82
75
fn to_base64 ( & self , config : Config ) -> ~str {
83
- let chars = match config. char_set {
76
+ let bytes = match config. char_set {
84
77
Standard => STANDARD_CHARS ,
85
78
UrlSafe => URLSAFE_CHARS
86
79
} ;
87
80
88
- let mut s = ~"" ;
81
+ let mut v : ~ [ u8 ] = ~[ ] ;
89
82
let mut i = 0 ;
90
83
let mut cur_length = 0 ;
91
84
let len = self . len ( ) ;
92
85
while i < len - ( len % 3 ) {
93
86
match config. line_length {
94
87
Some ( line_length) =>
95
88
if cur_length >= line_length {
96
- s. push_str ( "\r \n " ) ;
89
+ v. push ( '\r' as u8 ) ;
90
+ v. push ( '\n' as u8 ) ;
97
91
cur_length = 0 ;
98
92
} ,
99
93
None => ( )
@@ -104,10 +98,10 @@ impl<'self> ToBase64 for &'self [u8] {
104
98
( self [ i + 2 ] as u32 ) ;
105
99
106
100
// This 24-bit number gets separated into four 6-bit numbers.
107
- s . push_char ( chars [ ( n >> 18 ) & 63 ] ) ;
108
- s . push_char ( chars [ ( n >> 12 ) & 63 ] ) ;
109
- s . push_char ( chars [ ( n >> 6 ) & 63 ] ) ;
110
- s . push_char ( chars [ n & 63 ] ) ;
101
+ v . push ( bytes [ ( n >> 18 ) & 63 ] ) ;
102
+ v . push ( bytes [ ( n >> 12 ) & 63 ] ) ;
103
+ v . push ( bytes [ ( n >> 6 ) & 63 ] ) ;
104
+ v . push ( bytes [ n & 63 ] ) ;
111
105
112
106
cur_length += 4 ;
113
107
i += 3 ;
@@ -117,7 +111,8 @@ impl<'self> ToBase64 for &'self [u8] {
117
111
match config. line_length {
118
112
Some ( line_length) =>
119
113
if cur_length >= line_length {
120
- s. push_str ( "\r \n " ) ;
114
+ v. push ( '\r' as u8 ) ;
115
+ v. push ( '\n' as u8 ) ;
121
116
} ,
122
117
None => ( )
123
118
}
@@ -129,48 +124,29 @@ impl<'self> ToBase64 for &'self [u8] {
129
124
0 => ( ) ,
130
125
1 => {
131
126
let n = ( self [ i] as u32 ) << 16 ;
132
- s . push_char ( chars [ ( n >> 18 ) & 63 ] ) ;
133
- s . push_char ( chars [ ( n >> 12 ) & 63 ] ) ;
127
+ v . push ( bytes [ ( n >> 18 ) & 63 ] ) ;
128
+ v . push ( bytes [ ( n >> 12 ) & 63 ] ) ;
134
129
if config. pad {
135
- s. push_str ( "==" ) ;
130
+ v. push ( '=' as u8 ) ;
131
+ v. push ( '=' as u8 ) ;
136
132
}
137
133
}
138
134
2 => {
139
135
let n = ( self [ i] as u32 ) << 16 |
140
136
( self [ i + 1 u] as u32 ) << 8 ;
141
- s . push_char ( chars [ ( n >> 18 ) & 63 ] ) ;
142
- s . push_char ( chars [ ( n >> 12 ) & 63 ] ) ;
143
- s . push_char ( chars [ ( n >> 6 ) & 63 ] ) ;
137
+ v . push ( bytes [ ( n >> 18 ) & 63 ] ) ;
138
+ v . push ( bytes [ ( n >> 12 ) & 63 ] ) ;
139
+ v . push ( bytes [ ( n >> 6 ) & 63 ] ) ;
144
140
if config. pad {
145
- s . push_char ( '=' ) ;
141
+ v . push ( '=' as u8 ) ;
146
142
}
147
143
}
148
144
_ => fail ! ( "Algebra is broken, please alert the math police" )
149
145
}
150
- s
151
- }
152
- }
153
146
154
- impl < ' self > ToBase64 for & ' self str {
155
- /**
156
- * Convert any string (literal, `@`, `&`, or `~`) to base64 encoding.
157
- *
158
- *
159
- * # Example
160
- *
161
- * ~~~ {.rust}
162
- * extern mod extra;
163
- * use extra::base64::{ToBase64, standard};
164
- *
165
- * fn main () {
166
- * let str = "Hello, World".to_base64(standard);
167
- * printfln!("%s", str);
168
- * }
169
- * ~~~
170
- *
171
- */
172
- fn to_base64 ( & self , config : Config ) -> ~str {
173
- self . as_bytes ( ) . to_base64 ( config)
147
+ unsafe {
148
+ str:: raw:: from_bytes_owned ( v)
149
+ }
174
150
}
175
151
}
176
152
@@ -181,22 +157,31 @@ pub trait FromBase64 {
181
157
fn from_base64 ( & self ) -> Result < ~[ u8 ] , ~str > ;
182
158
}
183
159
184
- impl < ' self > FromBase64 for & ' self [ u8 ] {
160
+ impl < ' self > FromBase64 for & ' self str {
185
161
/**
186
- * Convert base64 `u8` vector into u8 byte values.
187
- * Every 4 encoded characters is converted into 3 octets, modulo padding.
162
+ * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
163
+ * to the byte values it encodes.
164
+ *
165
+ * You can use the `from_bytes` function in `std::str`
166
+ * to turn a `[u8]` into a string with characters corresponding to those
167
+ * values.
188
168
*
189
169
* # Example
190
170
*
171
+ * This converts a string literal to base64 and back.
172
+ *
191
173
* ~~~ {.rust}
192
174
* extern mod extra;
193
175
* use extra::base64::{ToBase64, FromBase64, standard};
176
+ * use std::str;
194
177
*
195
178
* fn main () {
196
- * let str = [52,32] .to_base64(standard);
197
- * printfln!("%s", str );
198
- * let bytes = str .from_base64();
179
+ * let hello_str = "Hello, World" .to_base64(standard);
180
+ * printfln!("%s", hello_str );
181
+ * let bytes = hello_str .from_base64();
199
182
* printfln!("%?", bytes);
183
+ * let result_str = str::from_bytes(bytes);
184
+ * printfln!("%s", result_str);
200
185
* }
201
186
* ~~~
202
187
*/
@@ -205,20 +190,20 @@ impl<'self> FromBase64 for &'self [u8] {
205
190
let mut buf: u32 = 0 ;
206
191
let mut modulus = 0 ;
207
192
208
- let mut it = self . iter ( ) ;
209
- for & byte in it {
210
- let ch = byte as char ;
193
+ let mut it = self . byte_iter ( ) . enumerate ( ) ;
194
+ for ( idx, byte) in it {
211
195
let val = byte as u32 ;
212
196
213
- match ch {
197
+ match byte as char {
214
198
'A' ..'Z' => buf |= val - 0x41 ,
215
199
'a' ..'z' => buf |= val - 0x47 ,
216
200
'0' ..'9' => buf |= val + 0x04 ,
217
201
'+' |'-' => buf |= 0x3E ,
218
202
'/' |'_' => buf |= 0x3F ,
219
203
'\r' |'\n' => loop ,
220
204
'=' => break ,
221
- _ => return Err ( ~"Invalid Base64 character")
205
+ _ => return Err ( fmt ! ( "Invalid character '%c' at position %u" ,
206
+ self . char_at( idx) , idx) )
222
207
}
223
208
224
209
buf <<= 6 ;
@@ -231,8 +216,11 @@ impl<'self> FromBase64 for &'self [u8] {
231
216
}
232
217
}
233
218
234
- if !it. all ( |& byte| { byte as char == '=' } ) {
235
- return Err ( ~"Invalid Base64 character") ;
219
+ for ( idx, byte) in it {
220
+ if ( byte as char ) != '=' {
221
+ return Err ( fmt ! ( "Invalid character '%c' at position %u" ,
222
+ self . char_at( idx) , idx) ) ;
223
+ }
236
224
}
237
225
238
226
match modulus {
@@ -251,67 +239,35 @@ impl<'self> FromBase64 for &'self [u8] {
251
239
}
252
240
}
253
241
254
- impl < ' self > FromBase64 for & ' self str {
255
- /**
256
- * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
257
- * to the byte values it encodes.
258
- *
259
- * You can use the `from_bytes` function in `std::str`
260
- * to turn a `[u8]` into a string with characters corresponding to those
261
- * values.
262
- *
263
- * # Example
264
- *
265
- * This converts a string literal to base64 and back.
266
- *
267
- * ~~~ {.rust}
268
- * extern mod extra;
269
- * use extra::base64::{ToBase64, FromBase64, standard};
270
- * use std::str;
271
- *
272
- * fn main () {
273
- * let hello_str = "Hello, World".to_base64(standard);
274
- * printfln!("%s", hello_str);
275
- * let bytes = hello_str.from_base64();
276
- * printfln!("%?", bytes);
277
- * let result_str = str::from_bytes(bytes);
278
- * printfln!("%s", result_str);
279
- * }
280
- * ~~~
281
- */
282
- fn from_base64 ( & self ) -> Result < ~[ u8 ] , ~str > {
283
- self . as_bytes ( ) . from_base64 ( )
284
- }
285
- }
286
-
287
242
#[ cfg( test) ]
288
243
mod test {
289
244
use test:: BenchHarness ;
290
245
use base64:: * ;
291
246
292
247
#[ test]
293
248
fn test_to_base64_basic ( ) {
294
- assert_eq ! ( "" . to_base64( STANDARD ) , ~"") ;
295
- assert_eq ! ( "f" . to_base64( STANDARD ) , ~"Zg ==");
296
- assert_eq!(" fo".to_base64(STANDARD), ~" Zm8 =");
297
- assert_eq!(" foo".to_base64(STANDARD), ~" Zm9v ");
298
- assert_eq!(" foob".to_base64(STANDARD), ~" Zm9vYg ==");
299
- assert_eq!(" fooba".to_base64(STANDARD), ~" Zm9vYmE =");
300
- assert_eq!(" foobar".to_base64(STANDARD), ~" Zm9vYmFy ");
249
+ assert_eq ! ( "" . as_bytes ( ) . to_base64( STANDARD ) , ~"") ;
250
+ assert_eq ! ( "f" . as_bytes ( ) . to_base64( STANDARD ) , ~"Zg ==");
251
+ assert_eq!(" fo".as_bytes(). to_base64(STANDARD), ~" Zm8 =");
252
+ assert_eq!(" foo".as_bytes(). to_base64(STANDARD), ~" Zm9v ");
253
+ assert_eq!(" foob".as_bytes(). to_base64(STANDARD), ~" Zm9vYg ==");
254
+ assert_eq!(" fooba".as_bytes(). to_base64(STANDARD), ~" Zm9vYmE =");
255
+ assert_eq!(" foobar".as_bytes(). to_base64(STANDARD), ~" Zm9vYmFy ");
301
256
}
302
257
303
258
#[test]
304
259
fn test_to_base64_line_break() {
305
260
assert!(![0u8, 1000].to_base64(Config {line_length: None, ..STANDARD})
306
261
.contains("\r \n " ) ) ;
307
- assert_eq ! ( "foobar" . to_base64( Config { line_length: Some ( 4 ) , ..STANDARD } ) ,
262
+ assert_eq ! ( "foobar" . as_bytes( ) . to_base64( Config { line_length: Some ( 4 ) ,
263
+ ..STANDARD } ) ,
308
264
~"Zm9v \r \n YmFy ");
309
265
}
310
266
311
267
#[test]
312
268
fn test_to_base64_padding() {
313
- assert_eq!(" f".to_base64(Config {pad: false, ..STANDARD}), ~" Zg ");
314
- assert_eq!(" fo".to_base64(Config {pad: false, ..STANDARD}), ~" Zm8 ");
269
+ assert_eq!(" f".as_bytes(). to_base64(Config {pad: false, ..STANDARD}), ~" Zg ");
270
+ assert_eq!(" fo".as_bytes(). to_base64(Config {pad: false, ..STANDARD}), ~" Zm8 ");
315
271
}
316
272
317
273
#[test]
@@ -345,7 +301,7 @@ mod test {
345
301
#[test]
346
302
fn test_from_base64_invalid_char() {
347
303
assert!(" Zm $=".from_base64().is_err())
348
- assert!(" Zg ==$".from_base64().is_err());
304
+ assert!(" Zg ==$".from_base64().is_err());
349
305
}
350
306
351
307
#[test]
@@ -369,20 +325,20 @@ mod test {
369
325
}
370
326
371
327
#[bench]
372
- pub fn to_base64 (bh: & mut BenchHarness) {
328
+ pub fn bench_to_base64 (bh: & mut BenchHarness) {
373
329
let s = " イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
374
330
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン";
375
331
do bh.iter {
376
- s.to_base64(STANDARD);
332
+ s.as_bytes(). to_base64(STANDARD);
377
333
}
378
334
bh.bytes = s.len() as u64;
379
335
}
380
336
381
337
#[bench]
382
- pub fn from_base64 (bh: & mut BenchHarness) {
338
+ pub fn bench_from_base64 (bh: & mut BenchHarness) {
383
339
let s = " イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム \
384
340
ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン" ;
385
- let b = s. to_base64( STANDARD ) ;
341
+ let b = s. as_bytes ( ) . to_base64( STANDARD ) ;
386
342
do bh. iter {
387
343
b. from_base64( ) ;
388
344
}
0 commit comments