@@ -83,6 +83,110 @@ impl<R: Read> Read for Crc32Reader<R> {
83
83
}
84
84
}
85
85
86
+ pub ( crate ) mod non_crypto {
87
+ use std:: io;
88
+ use std:: io:: prelude:: * ;
89
+
90
+ use crc32fast:: Hasher ;
91
+
92
+ /// Reader that validates the CRC32 when it reaches the EOF.
93
+ pub struct Crc32Reader < R > {
94
+ inner : R ,
95
+ hasher : Hasher ,
96
+ check : u32 ,
97
+ }
98
+
99
+ impl < R > Crc32Reader < R > {
100
+ /// Get a new Crc32Reader which checks the inner reader against checksum.
101
+ pub ( crate ) fn new ( inner : R , checksum : u32 ) -> Self {
102
+ Crc32Reader {
103
+ inner,
104
+ hasher : Hasher :: new ( ) ,
105
+ check : checksum,
106
+ }
107
+ }
108
+
109
+ fn check_matches ( & self ) -> Result < ( ) , & ' static str > {
110
+ let res = self . hasher . clone ( ) . finalize ( ) ;
111
+ if self . check == res {
112
+ Ok ( ( ) )
113
+ } else {
114
+ /* TODO: make this into our own Crc32Error error type! */
115
+ Err ( "Invalid checksum" )
116
+ }
117
+ }
118
+ }
119
+
120
+ impl < R : Read > Read for Crc32Reader < R > {
121
+ fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
122
+ /* We want to make sure we only check the hash when the input stream is exhausted. */
123
+ if buf. is_empty ( ) {
124
+ /* If the input buf is empty (this shouldn't happen, but isn't guaranteed), we
125
+ * still want to "pull" from the source in case it surfaces an i/o error. This will
126
+ * always return a count of Ok(0) if successful. */
127
+ return self . inner . read ( buf) ;
128
+ }
129
+
130
+ let count = self . inner . read ( buf) ?;
131
+ if count == 0 {
132
+ return self
133
+ . check_matches ( )
134
+ . map ( |( ) | 0 )
135
+ /* TODO: use io::Error::other for MSRV >=1.74 */
136
+ . map_err ( |e| io:: Error :: new ( io:: ErrorKind :: Other , e) ) ;
137
+ }
138
+ self . hasher . update ( & buf[ ..count] ) ;
139
+ Ok ( count)
140
+ }
141
+ }
142
+
143
+ #[ cfg( test) ]
144
+ mod test {
145
+ use super :: * ;
146
+
147
+ #[ test]
148
+ fn test_empty_reader ( ) {
149
+ let data: & [ u8 ] = b"" ;
150
+ let mut buf = [ 0 ; 1 ] ;
151
+
152
+ let mut reader = Crc32Reader :: new ( data, 0 ) ;
153
+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 0 ) ;
154
+
155
+ let mut reader = Crc32Reader :: new ( data, 1 ) ;
156
+ assert ! ( reader
157
+ . read( & mut buf)
158
+ . unwrap_err( )
159
+ . to_string( )
160
+ . contains( "Invalid checksum" ) ) ;
161
+ }
162
+
163
+ #[ test]
164
+ fn test_byte_by_byte ( ) {
165
+ let data: & [ u8 ] = b"1234" ;
166
+ let mut buf = [ 0 ; 1 ] ;
167
+
168
+ let mut reader = Crc32Reader :: new ( data, 0x9be3e0a3 ) ;
169
+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
170
+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
171
+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
172
+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 1 ) ;
173
+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 0 ) ;
174
+ // Can keep reading 0 bytes after the end
175
+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 0 ) ;
176
+ }
177
+
178
+ #[ test]
179
+ fn test_zero_read ( ) {
180
+ let data: & [ u8 ] = b"1234" ;
181
+ let mut buf = [ 0 ; 5 ] ;
182
+
183
+ let mut reader = Crc32Reader :: new ( data, 0x9be3e0a3 ) ;
184
+ assert_eq ! ( reader. read( & mut buf[ ..0 ] ) . unwrap( ) , 0 ) ;
185
+ assert_eq ! ( reader. read( & mut buf) . unwrap( ) , 4 ) ;
186
+ }
187
+ }
188
+ }
189
+
86
190
#[ cfg( test) ]
87
191
mod test {
88
192
use super :: * ;
0 commit comments