1
- // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
1
+ // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2
2
// file at the top-level directory of this distribution and at
3
3
// http://rust-lang.org/COPYRIGHT.
4
4
//
14
14
15
15
pub use self :: FromBase64Error :: * ;
16
16
pub use self :: CharacterSet :: * ;
17
+ pub use self :: Newline :: * ;
17
18
18
19
use std:: fmt;
19
20
use std:: error;
@@ -28,10 +29,22 @@ pub enum CharacterSet {
28
29
29
30
impl Copy for CharacterSet { }
30
31
32
+ /// Available newline types
33
+ pub enum Newline {
34
+ /// A linefeed (i.e. Unix-style newline)
35
+ LF ,
36
+ /// A carriage return and a linefeed (i.e. Windows-style newline)
37
+ CRLF
38
+ }
39
+
40
+ impl Copy for Newline { }
41
+
31
42
/// Contains configuration parameters for `to_base64`.
32
43
pub struct Config {
33
44
/// Character set to use
34
45
pub char_set : CharacterSet ,
46
+ /// Newline to use
47
+ pub newline : Newline ,
35
48
/// True to pad output with `=` characters
36
49
pub pad : bool ,
37
50
/// `Some(len)` to wrap lines at `len`, `None` to disable line wrapping
@@ -42,15 +55,15 @@ impl Copy for Config {}
42
55
43
56
/// Configuration for RFC 4648 standard base64 encoding
44
57
pub static STANDARD : Config =
45
- Config { char_set : Standard , pad : true , line_length : None } ;
58
+ Config { char_set : Standard , newline : CRLF , pad : true , line_length : None } ;
46
59
47
60
/// Configuration for RFC 4648 base64url encoding
48
61
pub static URL_SAFE : Config =
49
- Config { char_set : UrlSafe , pad : false , line_length : None } ;
62
+ Config { char_set : UrlSafe , newline : CRLF , pad : false , line_length : None } ;
50
63
51
64
/// Configuration for RFC 2045 MIME base64 encoding
52
65
pub static MIME : Config =
53
- Config { char_set : Standard , pad : true , line_length : Some ( 76 ) } ;
66
+ Config { char_set : Standard , newline : CRLF , pad : true , line_length : Some ( 76 ) } ;
54
67
55
68
static STANDARD_CHARS : & ' static [ u8 ] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
56
69
abcdefghijklmnopqrstuvwxyz\
@@ -87,24 +100,29 @@ impl ToBase64 for [u8] {
87
100
UrlSafe => URLSAFE_CHARS
88
101
} ;
89
102
90
- let mut v = Vec :: new ( ) ;
103
+ // In general, this Vec only needs (4/3) * self.len() memory, but
104
+ // addition is faster than multiplication and division.
105
+ let mut v = Vec :: with_capacity ( self . len ( ) + self . len ( ) ) ;
91
106
let mut i = 0 ;
92
107
let mut cur_length = 0 ;
93
108
let len = self . len ( ) ;
94
- while i < len - ( len % 3 ) {
95
- match config. line_length {
96
- Some ( line_length) =>
97
- if cur_length >= line_length {
98
- v. push ( b'\r' ) ;
99
- v. push ( b'\n' ) ;
100
- cur_length = 0 ;
101
- } ,
102
- None => ( )
109
+ let mod_len = len % 3 ;
110
+ let cond_len = len - mod_len;
111
+ while i < cond_len {
112
+ let ( first, second, third) = ( self [ i] , self [ i + 1 ] , self [ i + 2 ] ) ;
113
+ if let Some ( line_length) = config. line_length {
114
+ if cur_length >= line_length {
115
+ v. push_all ( match config. newline {
116
+ LF => b"\n " ,
117
+ CRLF => b"\r \n "
118
+ } ) ;
119
+ cur_length = 0 ;
120
+ }
103
121
}
104
122
105
- let n = ( self [ i ] as u32 ) << 16 |
106
- ( self [ i + 1 ] as u32 ) << 8 |
107
- ( self [ i + 2 ] as u32 ) ;
123
+ let n = ( first as u32 ) << 16 |
124
+ ( second as u32 ) << 8 |
125
+ ( third as u32 ) ;
108
126
109
127
// This 24-bit number gets separated into four 6-bit numbers.
110
128
v. push ( bytes[ ( ( n >> 18 ) & 63 ) as uint ] ) ;
@@ -116,20 +134,20 @@ impl ToBase64 for [u8] {
116
134
i += 3 ;
117
135
}
118
136
119
- if len % 3 != 0 {
120
- match config. line_length {
121
- Some ( line_length ) =>
122
- if cur_length >= line_length {
123
- v . push ( b'\r' ) ;
124
- v . push ( b'\n' ) ;
125
- } ,
126
- None => ( )
137
+ if mod_len != 0 {
138
+ if let Some ( line_length ) = config. line_length {
139
+ if cur_length >= line_length {
140
+ v . push_all ( match config . newline {
141
+ LF => b" \n " ,
142
+ CRLF => b" \r \n "
143
+ } ) ;
144
+ }
127
145
}
128
146
}
129
147
130
148
// Heh, would be cool if we knew this was exhaustive
131
149
// (the dream of bounded integer types)
132
- match len % 3 {
150
+ match mod_len {
133
151
0 => ( ) ,
134
152
1 => {
135
153
let n = ( self [ i] as u32 ) << 16 ;
@@ -232,7 +250,7 @@ impl FromBase64 for str {
232
250
233
251
impl FromBase64 for [ u8 ] {
234
252
fn from_base64 ( & self ) -> Result < Vec < u8 > , FromBase64Error > {
235
- let mut r = Vec :: new ( ) ;
253
+ let mut r = Vec :: with_capacity ( self . len ( ) ) ;
236
254
let mut buf: u32 = 0 ;
237
255
let mut modulus = 0 i;
238
256
@@ -288,7 +306,7 @@ impl FromBase64 for [u8] {
288
306
mod tests {
289
307
extern crate test;
290
308
use self :: test:: Bencher ;
291
- use base64:: { Config , FromBase64 , ToBase64 , STANDARD , URL_SAFE } ;
309
+ use base64:: { Config , FromBase64 , ToBase64 , STANDARD , URL_SAFE , LF } ;
292
310
293
311
#[ test]
294
312
fn test_to_base64_basic ( ) {
@@ -302,14 +320,26 @@ mod tests {
302
320
}
303
321
304
322
#[ test]
305
- fn test_to_base64_line_break ( ) {
323
+ fn test_to_base64_crlf_line_break ( ) {
306
324
assert ! ( ![ 0u8 , ..1000 ] . to_base64( Config { line_length: None , ..STANDARD } )
307
325
. contains( "\r \n " ) ) ;
308
326
assert_eq ! ( "foobar" . as_bytes( ) . to_base64( Config { line_length: Some ( 4 ) ,
309
327
..STANDARD } ) ,
310
328
"Zm9v\r \n YmFy" ) ;
311
329
}
312
330
331
+ #[ test]
332
+ fn test_to_base64_lf_line_break ( ) {
333
+ assert ! ( ![ 0u8 , ..1000 ] . to_base64( Config { line_length: None , newline: LF ,
334
+ ..STANDARD } )
335
+ . as_slice( )
336
+ . contains( "\n " ) ) ;
337
+ assert_eq ! ( "foobar" . as_bytes( ) . to_base64( Config { line_length: Some ( 4 ) ,
338
+ newline: LF ,
339
+ ..STANDARD } ) ,
340
+ "Zm9v\n YmFy" . to_string( ) ) ;
341
+ }
342
+
313
343
#[ test]
314
344
fn test_to_base64_padding ( ) {
315
345
assert_eq ! ( "f" . as_bytes( ) . to_base64( Config { pad: false , ..STANDARD } ) , "Zg" ) ;
@@ -344,6 +374,10 @@ mod tests {
344
374
b"foobar" ) ;
345
375
assert_eq ! ( "Zm9vYg==\r \n " . from_base64( ) . unwrap( ) ,
346
376
b"foob" ) ;
377
+ assert_eq ! ( "Zm9v\n YmFy" . from_base64( ) . unwrap( ) ,
378
+ b"foobar" ) ;
379
+ assert_eq ! ( "Zm9vYg==\n " . from_base64( ) . unwrap( ) ,
380
+ b"foob" ) ;
347
381
}
348
382
349
383
#[ test]
0 commit comments