1use crate::checksum;
23use crate::deflate;
24use crate::finish::{Complete, Finish};
25use crate::lz77;
26use alloc::{ffi::CString, vec::Vec};
27use no_std_io2::io;
28#[cfg(feature = "std")]
29use std::time;
30
31const GZIP_ID: [u8; 2] = [31, 139];
32const COMPRESSION_METHOD_DEFLATE: u8 = 8;
33
34const OS_FAT: u8 = 0;
35const OS_AMIGA: u8 = 1;
36const OS_VMS: u8 = 2;
37const OS_UNIX: u8 = 3;
38const OS_VM_CMS: u8 = 4;
39const OS_ATARI_TOS: u8 = 5;
40const OS_HPFS: u8 = 6;
41const OS_MACINTOSH: u8 = 7;
42const OS_Z_SYSTEM: u8 = 8;
43const OS_CPM: u8 = 9;
44const OS_TOPS20: u8 = 10;
45const OS_NTFS: u8 = 11;
46const OS_QDOS: u8 = 12;
47const OS_ACORN_RISCOS: u8 = 13;
48const OS_UNKNOWN: u8 = 255;
49
50const F_TEXT: u8 = 0b00_0001;
51const F_HCRC: u8 = 0b00_0010;
52const F_EXTRA: u8 = 0b00_0100;
53const F_NAME: u8 = 0b00_1000;
54const F_COMMENT: u8 = 0b01_0000;
55
56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
58pub enum CompressionLevel {
59 Fastest,
61
62 Slowest,
64
65 Unknown,
67}
68impl CompressionLevel {
69 fn to_u8(&self) -> u8 {
70 match *self {
71 CompressionLevel::Fastest => 4,
72 CompressionLevel::Slowest => 2,
73 CompressionLevel::Unknown => 0,
74 }
75 }
76 fn from_u8(x: u8) -> Self {
77 match x {
78 4 => CompressionLevel::Fastest,
79 2 => CompressionLevel::Slowest,
80 _ => CompressionLevel::Unknown,
81 }
82 }
83}
84impl From<lz77::CompressionLevel> for CompressionLevel {
85 fn from(f: lz77::CompressionLevel) -> Self {
86 match f {
87 lz77::CompressionLevel::Fast => CompressionLevel::Fastest,
88 lz77::CompressionLevel::Best => CompressionLevel::Slowest,
89 _ => CompressionLevel::Unknown,
90 }
91 }
92}
93
94#[derive(Debug, Clone)]
95pub(crate) struct Trailer {
96 crc32: u32,
97 input_size: u32,
98}
99impl Trailer {
100 pub fn crc32(&self) -> u32 {
101 self.crc32
102 }
103 pub fn read_from<R>(mut reader: R) -> io::Result<Self>
104 where
105 R: io::Read,
106 {
107 let mut buf = [0; 4];
108 reader.read_exact(&mut buf)?;
109 let crc32 = u32::from_le_bytes(buf);
110 reader.read_exact(&mut buf)?;
111 let input_size = u32::from_le_bytes(buf);
112 Ok(Trailer { crc32, input_size })
113 }
114 fn write_to<W>(&self, mut writer: W) -> io::Result<()>
115 where
116 W: io::Write,
117 {
118 writer.write_all(&self.crc32.to_le_bytes())?;
119 writer.write_all(&self.input_size.to_le_bytes())?;
120 Ok(())
121 }
122}
123
124#[derive(Debug, Clone)]
126pub struct HeaderBuilder {
127 header: Header,
128}
129impl HeaderBuilder {
130 pub fn new() -> Self {
146 #[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
148 let modification_time = time::UNIX_EPOCH
149 .elapsed()
150 .map(|d| d.as_secs() as u32)
151 .unwrap_or(0);
152 #[cfg(any(target_arch = "wasm32", not(feature = "std")))]
153 let modification_time = 0;
154
155 let header = Header {
156 modification_time,
157 compression_level: CompressionLevel::Unknown,
158 os: Os::Unix,
159 is_text: false,
160 is_verified: false,
161 extra_field: None,
162 filename: None,
163 comment: None,
164 };
165 HeaderBuilder { header }
166 }
167
168 pub fn modification_time(&mut self, modification_time: u32) -> &mut Self {
178 self.header.modification_time = modification_time;
179 self
180 }
181
182 pub fn os(&mut self, os: Os) -> &mut Self {
191 self.header.os = os;
192 self
193 }
194
195 pub fn text(&mut self) -> &mut Self {
205 self.header.is_text = true;
206 self
207 }
208
209 pub fn verify(&mut self) -> &mut Self {
219 self.header.is_verified = true;
220 self
221 }
222
223 pub fn extra_field(&mut self, extra: ExtraField) -> &mut Self {
235 self.header.extra_field = Some(extra);
236 self
237 }
238
239 pub fn filename(&mut self, filename: CString) -> &mut Self {
255 self.header.filename = Some(filename);
256 self
257 }
258
259 pub fn comment(&mut self, comment: CString) -> &mut Self {
275 self.header.comment = Some(comment);
276 self
277 }
278
279 pub fn finish(&self) -> Header {
281 self.header.clone()
282 }
283}
284impl Default for HeaderBuilder {
285 fn default() -> Self {
286 Self::new()
287 }
288}
289
290#[derive(Debug, Clone)]
292pub struct Header {
293 modification_time: u32,
294 compression_level: CompressionLevel,
295 os: Os,
296 is_text: bool,
297 is_verified: bool,
298 extra_field: Option<ExtraField>,
299 filename: Option<CString>,
300 comment: Option<CString>,
301}
302impl Header {
303 pub fn modification_time(&self) -> u32 {
305 self.modification_time
306 }
307
308 pub fn compression_level(&self) -> CompressionLevel {
310 self.compression_level.clone()
311 }
312
313 pub fn os(&self) -> Os {
315 self.os.clone()
316 }
317
318 pub fn is_text(&self) -> bool {
320 self.is_text
321 }
322
323 pub fn is_verified(&self) -> bool {
325 self.is_verified
326 }
327
328 pub fn extra_field(&self) -> Option<&ExtraField> {
330 self.extra_field.as_ref()
331 }
332
333 pub fn filename(&self) -> Option<&CString> {
335 self.filename.as_ref()
336 }
337
338 pub fn comment(&self) -> Option<&CString> {
340 self.comment.as_ref()
341 }
342
343 fn flags(&self) -> u8 {
344 [
345 (F_TEXT, self.is_text),
346 (F_HCRC, self.is_verified),
347 (F_EXTRA, self.extra_field.is_some()),
348 (F_NAME, self.filename.is_some()),
349 (F_COMMENT, self.comment.is_some()),
350 ]
351 .iter()
352 .filter(|e| e.1)
353 .map(|e| e.0)
354 .sum()
355 }
356 fn crc16(&self) -> u16 {
357 let mut crc = checksum::Crc32::new();
358 let mut buf = Vec::new();
359 Header {
360 is_verified: false,
361 ..self.clone()
362 }
363 .write_to(&mut buf)
364 .unwrap();
365 crc.update(&buf);
366 crc.value() as u16
367 }
368 fn write_to<W>(&self, mut writer: W) -> io::Result<()>
369 where
370 W: io::Write,
371 {
372 writer.write_all(&GZIP_ID)?;
373 writer.write_all(&[COMPRESSION_METHOD_DEFLATE, self.flags()])?;
374 writer.write_all(&self.modification_time.to_le_bytes())?;
375 writer.write_all(&[self.compression_level.to_u8(), self.os.to_u8()])?;
376 if let Some(ref x) = self.extra_field {
377 x.write_to(&mut writer)?;
378 }
379 if let Some(ref x) = self.filename {
380 writer.write_all(x.as_bytes_with_nul())?;
381 }
382 if let Some(ref x) = self.comment {
383 writer.write_all(x.as_bytes_with_nul())?;
384 }
385 if self.is_verified {
386 writer.write_all(&self.crc16().to_le_bytes())?;
387 }
388 Ok(())
389 }
390 pub(crate) fn read_from<R>(mut reader: R) -> io::Result<Self>
391 where
392 R: io::Read,
393 {
394 let mut this = HeaderBuilder::new().finish();
395 let mut buf = [0; 2 + 1 + 1 + 4 + 1 + 1];
396 reader.read_exact(&mut buf)?;
397 let id = &buf[0..2];
398 if id != GZIP_ID {
399 return Err(invalid_data_error!(
400 "Unexpected GZIP ID: value={:?}, \
401 expected={:?}",
402 id,
403 GZIP_ID
404 ));
405 }
406 let compression_method = buf[2];
407 if compression_method != COMPRESSION_METHOD_DEFLATE {
408 return Err(invalid_data_error!(
409 "Compression methods other than DEFLATE(8) are \
410 unsupported: method={}",
411 compression_method
412 ));
413 }
414 let flags = buf[3];
415 this.modification_time = u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]);
416 this.compression_level = CompressionLevel::from_u8(buf[8]);
417 this.os = Os::from_u8(buf[9]);
418 if flags & F_EXTRA != 0 {
419 this.extra_field = Some(ExtraField::read_from(&mut reader)?);
420 }
421 if flags & F_NAME != 0 {
422 this.filename = Some(read_cstring(&mut reader)?);
423 }
424 if flags & F_COMMENT != 0 {
425 this.comment = Some(read_cstring(&mut reader)?);
426 }
427 if flags & F_HCRC != 0 && cfg!(not(fuzzing)) {
431 let mut buf = [0; 2];
432 reader.read_exact(&mut buf)?;
433 let crc = u16::from_le_bytes(buf);
434 let expected = this.crc16();
435 if crc != expected {
436 return Err(invalid_data_error!(
437 "CRC16 of GZIP header mismatched: value={}, \
438 expected={}",
439 crc,
440 expected
441 ));
442 }
443 this.is_verified = true;
444 }
445 Ok(this)
446 }
447}
448
449fn read_cstring<R>(mut reader: R) -> io::Result<CString>
450where
451 R: io::Read,
452{
453 let mut buf = Vec::new();
454 loop {
455 let mut cbuf = [0; 1];
456 reader.read_exact(&mut cbuf)?;
457 if cbuf[0] == 0 {
458 return Ok(CString::new(buf).unwrap());
459 }
460 buf.push(cbuf[0]);
461 }
462}
463
464#[derive(Debug, Clone, PartialEq, Eq, Hash)]
466pub struct ExtraField {
467 pub subfields: Vec<ExtraSubField>,
469}
470impl ExtraField {
471 fn read_from<R>(mut reader: R) -> io::Result<Self>
472 where
473 R: io::Read,
474 {
475 let mut subfields = Vec::new();
476 let mut buf = [0; 2];
477 reader.read_exact(&mut buf)?;
478 let data_size = u16::from_le_bytes(buf) as usize;
479 let mut reader = reader.take(data_size as u64);
480 while reader.limit() > 0 {
481 subfields.push(ExtraSubField::read_from(&mut reader)?);
482 }
483 Ok(ExtraField { subfields })
484 }
485 fn write_to<W>(&self, mut writer: W) -> io::Result<()>
486 where
487 W: io::Write,
488 {
489 let len = self.subfields.iter().map(|f| f.write_len()).sum::<usize>();
490 if len > 0xFFFF {
491 return Err(invalid_data_error!("extra field too long: {}", len));
492 }
493 writer.write_all(&(len as u16).to_le_bytes())?;
494 for f in &self.subfields {
495 f.write_to(&mut writer)?;
496 }
497 Ok(())
498 }
499}
500
501#[derive(Debug, Clone, PartialEq, Eq, Hash)]
503pub struct ExtraSubField {
504 pub id: [u8; 2],
506
507 pub data: Vec<u8>,
509}
510impl ExtraSubField {
511 fn read_from<R>(mut reader: R) -> io::Result<Self>
512 where
513 R: io::Read,
514 {
515 let mut field = ExtraSubField {
516 id: [0; 2],
517 data: Vec::new(),
518 };
519
520 reader.read_exact(&mut field.id)?;
521 let mut buf = [0; 2];
522 reader.read_exact(&mut buf)?;
523 let data_size = u16::from_le_bytes(buf) as usize;
524 field.data.resize(data_size, 0);
525 reader.read_exact(&mut field.data)?;
526
527 Ok(field)
528 }
529 fn write_to<W>(&self, mut writer: W) -> io::Result<()>
530 where
531 W: io::Write,
532 {
533 writer.write_all(&self.id)?;
534 writer.write_all(&(self.data.len() as u16).to_le_bytes())?;
535 writer.write_all(&self.data)?;
536 Ok(())
537 }
538 fn write_len(&self) -> usize {
539 4 + self.data.len()
540 }
541}
542
543#[derive(Debug, Clone, PartialEq, Eq, Hash)]
545pub enum Os {
546 Fat,
548
549 Amiga,
551
552 Vms,
554
555 Unix,
557
558 VmCms,
560
561 AtariTos,
563
564 Hpfs,
566
567 Macintosh,
569
570 ZSystem,
572
573 CpM,
575
576 Tops20,
578
579 Ntfs,
581
582 Qdos,
584
585 AcornRiscos,
587
588 Unknown,
590
591 Undefined(u8),
593}
594impl Os {
595 fn to_u8(&self) -> u8 {
596 match *self {
597 Os::Fat => OS_FAT,
598 Os::Amiga => OS_AMIGA,
599 Os::Vms => OS_VMS,
600 Os::Unix => OS_UNIX,
601 Os::VmCms => OS_VM_CMS,
602 Os::AtariTos => OS_ATARI_TOS,
603 Os::Hpfs => OS_HPFS,
604 Os::Macintosh => OS_MACINTOSH,
605 Os::ZSystem => OS_Z_SYSTEM,
606 Os::CpM => OS_CPM,
607 Os::Tops20 => OS_TOPS20,
608 Os::Ntfs => OS_NTFS,
609 Os::Qdos => OS_QDOS,
610 Os::AcornRiscos => OS_ACORN_RISCOS,
611 Os::Unknown => OS_UNKNOWN,
612 Os::Undefined(os) => os,
613 }
614 }
615 fn from_u8(x: u8) -> Self {
616 match x {
617 OS_FAT => Os::Fat,
618 OS_AMIGA => Os::Amiga,
619 OS_VMS => Os::Vms,
620 OS_UNIX => Os::Unix,
621 OS_VM_CMS => Os::VmCms,
622 OS_ATARI_TOS => Os::AtariTos,
623 OS_HPFS => Os::Hpfs,
624 OS_MACINTOSH => Os::Macintosh,
625 OS_Z_SYSTEM => Os::ZSystem,
626 OS_CPM => Os::CpM,
627 OS_TOPS20 => Os::Tops20,
628 OS_NTFS => Os::Ntfs,
629 OS_QDOS => Os::Qdos,
630 OS_ACORN_RISCOS => Os::AcornRiscos,
631 OS_UNKNOWN => Os::Unknown,
632 os => Os::Undefined(os),
633 }
634 }
635}
636
637#[derive(Debug)]
639pub struct EncodeOptions<E>
640where
641 E: lz77::Lz77Encode,
642{
643 header: Header,
644 options: deflate::EncodeOptions<E>,
645}
646impl Default for EncodeOptions<lz77::DefaultLz77Encoder> {
647 fn default() -> Self {
648 EncodeOptions {
649 header: HeaderBuilder::new().finish(),
650 options: Default::default(),
651 }
652 }
653}
654impl EncodeOptions<lz77::DefaultLz77Encoder> {
655 pub fn new() -> Self {
665 Self::default()
666 }
667}
668impl<E> EncodeOptions<E>
669where
670 E: lz77::Lz77Encode,
671{
672 pub fn with_lz77(lz77: E) -> Self {
683 let mut header = HeaderBuilder::new().finish();
684 header.compression_level = From::from(lz77.compression_level());
685 EncodeOptions {
686 header,
687 options: deflate::EncodeOptions::with_lz77(lz77),
688 }
689 }
690
691 pub fn no_compression(mut self) -> Self {
702 self.options = self.options.no_compression();
703 self.header.compression_level = CompressionLevel::Unknown;
704 self
705 }
706
707 pub fn header(mut self, header: Header) -> Self {
718 self.header = header;
719 self
720 }
721
722 pub fn block_size(mut self, size: usize) -> Self {
734 self.options = self.options.block_size(size);
735 self
736 }
737
738 pub fn fixed_huffman_codes(mut self) -> Self {
748 self.options = self.options.fixed_huffman_codes();
749 self
750 }
751}
752
753pub struct Encoder<W, E = lz77::DefaultLz77Encoder> {
755 header: Header,
756 crc32: checksum::Crc32,
757 input_size: u32,
758 writer: deflate::Encoder<W, E>,
759}
760impl<W> Encoder<W, lz77::DefaultLz77Encoder>
761where
762 W: io::Write,
763{
764 pub fn new(inner: W) -> io::Result<Self> {
778 Self::with_options(inner, EncodeOptions::new())
779 }
780}
781impl<W, E> Encoder<W, E>
782where
783 W: io::Write,
784 E: lz77::Lz77Encode,
785{
786 pub fn with_options(mut inner: W, options: EncodeOptions<E>) -> io::Result<Self> {
805 options.header.write_to(&mut inner)?;
806 Ok(Encoder {
807 header: options.header.clone(),
808 crc32: checksum::Crc32::new(),
809 input_size: 0,
810 writer: deflate::Encoder::with_options(inner, options.options),
811 })
812 }
813
814 pub fn header(&self) -> &Header {
824 &self.header
825 }
826
827 pub fn finish(self) -> Finish<W, io::Error> {
859 let trailer = Trailer {
860 crc32: self.crc32.value(),
861 input_size: self.input_size,
862 };
863 let mut inner = finish_try!(self.writer.finish());
864 match trailer.write_to(&mut inner).and_then(|_| inner.flush()) {
865 Ok(_) => Finish::new(inner, None),
866 Err(e) => Finish::new(inner, Some(e)),
867 }
868 }
869
870 pub fn as_inner_ref(&self) -> &W {
872 self.writer.as_inner_ref()
873 }
874
875 pub fn as_inner_mut(&mut self) -> &mut W {
877 self.writer.as_inner_mut()
878 }
879
880 pub fn into_inner(self) -> W {
882 self.writer.into_inner()
883 }
884}
885impl<W, E> io::Write for Encoder<W, E>
886where
887 W: io::Write,
888 E: lz77::Lz77Encode,
889{
890 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
891 let written_size = self.writer.write(buf)?;
892 self.crc32.update(&buf[..written_size]);
893 self.input_size = self.input_size.wrapping_add(written_size as u32);
894 Ok(written_size)
895 }
896 fn flush(&mut self) -> io::Result<()> {
897 self.writer.flush()
898 }
899}
900impl<W, E> Complete for Encoder<W, E>
901where
902 W: io::Write,
903 E: lz77::Lz77Encode,
904{
905 fn complete(self) -> io::Result<()> {
906 self.finish().into_result().map(|_| ())
907 }
908}
909
910#[derive(Debug)]
912pub struct Decoder<R> {
913 header: Header,
914 reader: deflate::Decoder<R>,
915 crc32: checksum::Crc32,
916 eos: bool,
917}
918impl<R> Decoder<R>
919where
920 R: io::Read,
921{
922 pub fn new(mut inner: R) -> io::Result<Self> {
942 let header = Header::read_from(&mut inner)?;
943 Ok(Self::with_header(inner, header))
944 }
945
946 pub fn header(&self) -> &Header {
960 &self.header
961 }
962
963 pub fn as_inner_ref(&self) -> &R {
965 self.reader.as_inner_ref()
966 }
967
968 pub fn as_inner_mut(&mut self) -> &mut R {
970 self.reader.as_inner_mut()
971 }
972
973 pub fn into_inner(self) -> R {
988 self.reader.into_inner()
989 }
990
991 pub fn unread_decoded_data(&self) -> &[u8] {
995 self.reader.unread_decoded_data()
996 }
997
998 fn with_header(inner: R, header: Header) -> Self {
999 Decoder {
1000 header,
1001 reader: deflate::Decoder::new(inner),
1002 crc32: checksum::Crc32::new(),
1003 eos: false,
1004 }
1005 }
1006
1007 fn reset(&mut self, header: Header) {
1008 self.header = header;
1009 self.reader.reset();
1010 self.crc32 = checksum::Crc32::new();
1011 self.eos = false;
1012 }
1013}
1014impl<R> io::Read for Decoder<R>
1015where
1016 R: io::Read,
1017{
1018 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1019 if self.eos {
1020 Ok(0)
1021 } else {
1022 let read_size = self.reader.read(buf)?;
1023 self.crc32.update(&buf[..read_size]);
1024 if read_size == 0 {
1025 if buf.is_empty() {
1026 return Ok(0);
1027 }
1028
1029 self.eos = true;
1030 let trailer = Trailer::read_from(self.reader.as_inner_mut())?;
1031 if cfg!(not(fuzzing)) && trailer.crc32 != self.crc32.value() {
1035 Err(invalid_data_error!(
1036 "CRC32 mismatched: value={}, expected={}",
1037 self.crc32.value(),
1038 trailer.crc32
1039 ))
1040 } else {
1041 Ok(0)
1042 }
1043 } else {
1044 Ok(read_size)
1045 }
1046 }
1047 }
1048}
1049
1050#[derive(Debug)]
1052pub struct MultiDecoder<R> {
1053 decoder: Decoder<R>,
1054 eos: bool,
1055}
1056impl<R> MultiDecoder<R>
1057where
1058 R: io::Read,
1059{
1060 pub fn new(inner: R) -> io::Result<Self> {
1086 let decoder = Decoder::new(inner)?;
1087 Ok(MultiDecoder {
1088 decoder,
1089 eos: false,
1090 })
1091 }
1092
1093 pub fn header(&self) -> &Header {
1107 self.decoder.header()
1108 }
1109
1110 pub fn as_inner_ref(&self) -> &R {
1112 self.decoder.as_inner_ref()
1113 }
1114
1115 pub fn as_inner_mut(&mut self) -> &mut R {
1117 self.decoder.as_inner_mut()
1118 }
1119
1120 pub fn into_inner(self) -> R {
1135 self.decoder.into_inner()
1136 }
1137}
1138impl<R> io::Read for MultiDecoder<R>
1139where
1140 R: io::Read,
1141{
1142 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1143 if self.eos {
1144 return Ok(0);
1145 }
1146
1147 let read_size = self.decoder.read(buf)?;
1148 if read_size == 0 {
1149 match Header::read_from(self.as_inner_mut()) {
1150 Err(e) => {
1151 if e.kind() == io::ErrorKind::UnexpectedEof {
1152 self.eos = true;
1153 Ok(0)
1154 } else {
1155 Err(e)
1156 }
1157 }
1158 Ok(header) => {
1159 self.decoder.reset(header);
1160 self.read(buf)
1161 }
1162 }
1163 } else {
1164 Ok(read_size)
1165 }
1166 }
1167}
1168
1169#[cfg(test)]
1170mod tests {
1171 use super::*;
1172 use crate::finish::AutoFinish;
1173 use alloc::{vec, vec::Vec};
1174 use no_std_io2::io::{Read, Write};
1175
1176 fn decode(buf: &[u8]) -> io::Result<Vec<u8>> {
1177 let mut decoder = Decoder::new(buf).unwrap();
1178 let mut buf = Vec::with_capacity(buf.len());
1179 decoder.read_to_end(&mut buf)?;
1180 Ok(buf)
1181 }
1182
1183 fn decode_multi(buf: &[u8]) -> io::Result<Vec<u8>> {
1184 let mut decoder = MultiDecoder::new(buf).unwrap();
1185 let mut buf = Vec::with_capacity(buf.len());
1186 decoder.read_to_end(&mut buf).unwrap();
1187 Ok(buf)
1188 }
1189
1190 fn encode(text: &[u8]) -> io::Result<Vec<u8>> {
1191 let mut encoder = Encoder::new(Vec::new()).unwrap();
1192 encoder.write_all(text).unwrap();
1193 encoder.finish().into_result()
1194 }
1195
1196 #[test]
1197 fn encode_works() {
1198 let plain = b"Hello World! Hello GZIP!!";
1199 let mut encoder = Encoder::new(Vec::new()).unwrap();
1200 encoder.write_all(plain.as_ref()).unwrap();
1201 let encoded = encoder.finish().into_result().unwrap();
1202 assert_eq!(decode(&encoded).unwrap(), plain);
1203 }
1204
1205 #[test]
1206 fn encoder_auto_finish_works() {
1207 let plain = b"Hello World! Hello GZIP!!";
1208 let mut buf = Vec::new();
1209 {
1210 let mut encoder = AutoFinish::new(Encoder::new(&mut buf).unwrap());
1211 encoder.write_all(plain.as_ref()).unwrap();
1212 }
1213 assert_eq!(decode(&buf).unwrap(), plain);
1214 }
1215
1216 #[test]
1217 fn multi_decode_works() {
1218 use core::iter;
1219 let text = b"Hello World!";
1220 let encoded: Vec<u8> = iter::repeat(encode(text).unwrap())
1221 .take(2)
1222 .flat_map(|b| b)
1223 .collect();
1224 assert_eq!(decode(&encoded).unwrap(), b"Hello World!");
1225 assert_eq!(decode_multi(&encoded).unwrap(), b"Hello World!Hello World!");
1226 }
1227
1228 #[test]
1229 fn issue_15_1() {
1231 let data = b"\x1F\x8B\x08\xC1\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x7B\x80\x80\x80\x80\x7B\x7B\x7B\x7B\x7B\x7B\x97\x7B\x7B\x7B\x86\x27\xEB\x60\xA7\xA8\x46\x6E\x1F\x33\x51\x5C\x34\xE0\xD2\x2E\xE8\x0C\x19\x1D\x3D\x3C\xFD\x3B\x6A\xFA\x63\xDF\x28\x87\x86\xF2\xA6\xAC\x87\x86\xF2\xA6\xAC\xD5";
1232 assert!(decode(&data[..]).is_err());
1233 }
1234
1235 #[test]
1236 fn issue_15_2() {
1238 let data = b"\x1F\x8B\x08\xC1\x7B\x7B\x7B\x7B\x7B\xFC\x5D\x2D\xDC\x08\xC1\x7B\x7B\x7B\x7B\x7B\xFC\x5D\x2D\xDC\x08\xC1\x7B\x7F\x7B\x7B\x7B\xFC\x5D\x2D\xDC\x69\x32\x48\x22\x5A\x81\x81\x42\x42\x81\x7E\x81\x81\x81\x81\xF2\x17";
1239 assert!(decode(&data[..]).is_err());
1240 }
1241
1242 #[test]
1243 fn issue_15_3() {
1245 let data = b"\x1F\x8B\x08\xC1\x91\x28\x71\xDC\xF2\x2D\x34\x35\x31\x35\x34\x30\x70\x6E\x60\x35\x31\x32\x32\x33\x32\x33\x37\x32\x36\x38\xDD\x1C\xE5\x2A\xDD\xDD\xDD\x22\xDD\xDD\xDD\xDC\x88\x13\xC9\x40\x60\xA7";
1246 assert!(decode(&data[..]).is_err());
1247 }
1248
1249 #[test]
1250 fn issue_61() {
1252 let data = encode(b"Hello World").unwrap();
1253 let mut decoder = Decoder::new(&data[..]).unwrap();
1254 let mut buf = Vec::new();
1255 decoder.read(&mut buf).unwrap();
1256 decoder.read_to_end(&mut buf).unwrap();
1257 assert_eq!(buf, b"Hello World");
1258 }
1259
1260 #[test]
1261 fn extra_field() {
1262 let f = ExtraField {
1263 subfields: vec![ExtraSubField {
1264 id: [0, 0x42],
1265 data: "abc".into(),
1266 }],
1267 };
1268
1269 let mut buf = Vec::new();
1270 f.write_to(&mut buf).unwrap();
1271
1272 assert_eq!(ExtraField::read_from(&buf[..]).unwrap(), f);
1273 }
1274
1275 #[test]
1276 #[cfg(feature = "std")]
1277 fn encode_with_extra_field() {
1278 use std::io;
1279
1280 let mut buf = Vec::new();
1281 let extra_field = ExtraField {
1282 subfields: vec![ExtraSubField {
1283 id: [0, 0x42],
1284 data: "abc".into(),
1285 }],
1286 };
1287 {
1288 let header = HeaderBuilder::new()
1290 .extra_field(extra_field.clone())
1291 .finish();
1292
1293 let ops = EncodeOptions::new().header(header);
1294 let mut encoder = Encoder::with_options(&mut buf, ops).unwrap();
1295 write!(encoder, "hello world").unwrap();
1296 encoder.finish().as_result().unwrap();
1297 }
1298 {
1299 let mut decoder = Decoder::new(&buf[..]).unwrap();
1301 io::copy(&mut decoder, &mut io::sink()).unwrap();
1302 assert_eq!(decoder.header().extra_field(), Some(&extra_field));
1303 }
1304 }
1305}