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