diff --git a/src/decode.rs b/src/decode.rs index fb9b5b1..2bc384f 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -134,12 +134,16 @@ where } } } - if let Some(expected_size) = metadata.size { - if expected_size != num_bytes { - return Err(DecodeError::IncompleteData { - expected_size, - actual_size: num_bytes, - }); + + if let Some(end) = metadata.end { + if let Some(begin) = metadata.begin { + let expected_size = end - begin + 1; + if expected_size != num_bytes { + return Err(DecodeError::IncompleteData { + expected_size, + actual_size: num_bytes, + }); + } } } } @@ -205,6 +209,8 @@ fn parse_header_line(line_buf: &[u8]) -> Result { }); } + let is_yend = header_line.starts_with("=yend "); + let offset = match line_buf.iter().position(|&c| c == b' ') { Some(pos) => pos + 1, None => { @@ -311,6 +317,17 @@ fn parse_header_line(line_buf: &[u8]) -> Result { keyword_start_idx = None; value_start_idx = None; } + LF | CR if is_yend => { + metadata.size = match String::from_utf8_lossy(value).parse::() { + Ok(size) => Some(size), + Err(_) => { + return Err(DecodeError::InvalidHeader { + line: header_line, + position, + }) + } + }; + } _ => { return Err(DecodeError::InvalidHeader { line: header_line, @@ -430,6 +447,19 @@ fn parse_header_line(line_buf: &[u8]) -> Result { keyword_start_idx = None; value_start_idx = None; } + LF | CR if is_yend && keyword == b"part" => { + let number = match String::from_utf8_lossy(value).parse::() { + Ok(size) => Some(size), + Err(_) => { + return Err(DecodeError::InvalidHeader { + line: header_line, + position, + }) + } + }; + + metadata.part = number; + } _ => { return Err(DecodeError::InvalidHeader { line: header_line, @@ -535,6 +565,25 @@ mod tests { assert_eq!(Some(0xae05_2b48), metadata.pcrc32); } + #[test] + fn parse_valid_footer_end_space_no_checksums() { + let parse_result = parse_header_line(b"=yend size=26624 part=1\n"); + assert!(parse_result.is_ok()); + let metadata = parse_result.unwrap(); + assert_eq!(Some(1), metadata.part); + assert_eq!(Some(26624), metadata.size); + assert_eq!(None, metadata.pcrc32); + assert_eq!(None, metadata.crc32); + + let parse_result = parse_header_line(b"=yend size=26624 part=1\r\n"); + assert!(parse_result.is_ok()); + let metadata = parse_result.unwrap(); + assert_eq!(Some(1), metadata.part); + assert_eq!(Some(26624), metadata.size); + assert_eq!(None, metadata.pcrc32); + assert_eq!(None, metadata.crc32); + } + #[test] fn parse_valid_header_begin() { let parse_result = parse_header_line( diff --git a/testdata/yenc.org/testfile_no_checksums.txt.yenc b/testdata/yenc.org/testfile_no_checksums.txt.yenc new file mode 100644 index 0000000..041eab6 --- /dev/null +++ b/testdata/yenc.org/testfile_no_checksums.txt.yenc @@ -0,0 +1,7 @@ +=ybegin line=128 size=584 name=testfile.txt +oJWJ~JR[S74k}mssdJ\__XXZ74)('&%$#"! =M =J =@ +~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQ +PONMLKJIHGFEDCBA@?>=}<;:9876543210/.-,+*74k}mssdJZXX\__74*+,-./0123456789:;<=}>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmno +pqrstuvwxyz{|}~ +=@ =J =M !"#$%&'()74oJJ~74 +=yend size=584 diff --git a/tests/singlepart.rs b/tests/singlepart.rs index 84562db..76f9061 100644 --- a/tests/singlepart.rs +++ b/tests/singlepart.rs @@ -34,3 +34,22 @@ fn decode() { .unwrap(); assert_eq!(decoded.as_slice(), &expected_decoded[..]); } + +#[test] +fn decode_no_checksums() { + let data = include_bytes!("../testdata/yenc.org/testfile_no_checksums.txt.yenc"); + let expected_decoded = include_bytes!("../testdata/yenc.org/testfile.txt"); + let mut decoded = Vec::::new(); + let mut c = std::io::Cursor::new(&data[..]); + let tmpdir = temp_dir(); + let mut tmpfile = tmpdir.clone(); + tmpfile.push("testfile.txt"); + let decode_options = yenc::DecodeOptions::new(tmpdir); + decode_options.decode_stream(&mut c).unwrap(); + File::open(&tmpfile) + .unwrap() + .read_to_end(&mut decoded) + .unwrap(); + + assert_eq!(decoded.as_slice(), &expected_decoded[..]); +}