1use std::borrow::Cow;
6use std::convert::TryFrom;
7use std::fmt;
8use std::io::{BufReader, Error, Read, Result, Write};
9use std::str::FromStr;
10
11mod lz4_standard;
12use self::lz4_standard::*;
13
14#[cfg(feature = "zran")]
15pub mod zlib_random;
16
17const COMPRESSION_MINIMUM_RATIO: usize = 100;
18
19#[repr(u32)]
21#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
22pub enum Algorithm {
23 #[default]
24 None = 0,
25 Lz4Block = 1,
26 GZip = 2,
27 Zstd = 3,
28}
29
30impl fmt::Display for Algorithm {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 let output = match self {
33 Algorithm::None => "none",
34 Algorithm::Lz4Block => "lz4_block",
35 Algorithm::GZip => "gzip",
36 Algorithm::Zstd => "zstd",
37 };
38 write!(f, "{}", output)
39 }
40}
41
42impl FromStr for Algorithm {
43 type Err = Error;
44
45 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
46 match s {
47 "none" => Ok(Self::None),
48 "lz4_block" => Ok(Self::Lz4Block),
49 "gzip" => Ok(Self::GZip),
50 "zstd" => Ok(Self::Zstd),
51 _ => Err(einval!("compression algorithm should be none or lz4_block")),
52 }
53 }
54}
55
56impl TryFrom<u32> for Algorithm {
57 type Error = ();
58
59 fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
60 if value == Algorithm::None as u32 {
61 Ok(Algorithm::None)
62 } else if value == Algorithm::Lz4Block as u32 {
63 Ok(Algorithm::Lz4Block)
64 } else if value == Algorithm::GZip as u32 {
65 Ok(Algorithm::GZip)
66 } else if value == Algorithm::Zstd as u32 {
67 Ok(Algorithm::Zstd)
68 } else {
69 Err(())
70 }
71 }
72}
73
74impl TryFrom<u64> for Algorithm {
75 type Error = ();
76
77 fn try_from(value: u64) -> std::result::Result<Self, Self::Error> {
78 if value == Algorithm::None as u64 {
79 Ok(Algorithm::None)
80 } else if value == Algorithm::Lz4Block as u64 {
81 Ok(Algorithm::Lz4Block)
82 } else if value == Algorithm::GZip as u64 {
83 Ok(Algorithm::GZip)
84 } else if value == Algorithm::Zstd as u64 {
85 Ok(Algorithm::Zstd)
86 } else {
87 Err(())
88 }
89 }
90}
91
92impl Algorithm {
93 pub fn is_none(self) -> bool {
95 self == Self::None
96 }
97}
98
99pub fn compress(src: &[u8], algorithm: Algorithm) -> Result<(Cow<[u8]>, bool)> {
101 let src_size = src.len();
102 if src_size == 0 {
103 return Ok((Cow::Borrowed(src), false));
104 }
105
106 let compressed = match algorithm {
107 Algorithm::None => return Ok((Cow::Borrowed(src), false)),
108 Algorithm::Lz4Block => lz4_compress(src)?,
109 Algorithm::GZip => {
110 let dst: Vec<u8> = Vec::new();
111 let mut gz = flate2::write::GzEncoder::new(dst, flate2::Compression::default());
112 gz.write_all(src)?;
113 gz.finish()?
114 }
115 Algorithm::Zstd => zstd_compress(src)?,
116 };
117
118 if (COMPRESSION_MINIMUM_RATIO == 100 && compressed.len() >= src_size)
120 || ((100 * compressed.len() / src_size) >= COMPRESSION_MINIMUM_RATIO)
121 {
122 Ok((Cow::Borrowed(src), false))
123 } else {
124 Ok((Cow::Owned(compressed), true))
125 }
126}
127
128pub fn decompress(src: &[u8], dst: &mut [u8], algorithm: Algorithm) -> Result<usize> {
131 match algorithm {
132 Algorithm::None => {
133 assert_eq!(src.len(), dst.len());
134 dst.copy_from_slice(src);
135 Ok(dst.len())
136 }
137 Algorithm::Lz4Block => lz4_decompress(src, dst),
138 Algorithm::GZip => {
139 let mut gz = flate2::bufread::GzDecoder::new(src);
140 gz.read_exact(dst)?;
141 Ok(dst.len())
142 }
143 Algorithm::Zstd => zstd::bulk::decompress_to_buffer(src, dst),
144 }
145}
146
147#[allow(clippy::large_enum_variant)]
148pub enum Decoder<'a, R: Read> {
150 None(R),
151 Gzip(flate2::bufread::MultiGzDecoder<BufReader<R>>),
152 Zstd(zstd::stream::Decoder<'a, BufReader<R>>),
153}
154
155impl<R: Read> Decoder<'_, R> {
156 pub fn new(reader: R, algorithm: Algorithm) -> Result<Self> {
158 let decoder = match algorithm {
159 Algorithm::None => Decoder::None(reader),
160 Algorithm::GZip => {
161 Decoder::Gzip(flate2::bufread::MultiGzDecoder::new(BufReader::new(reader)))
162 }
163 Algorithm::Lz4Block => panic!("Decoder doesn't support lz4_block"),
164 Algorithm::Zstd => Decoder::Zstd(zstd::stream::Decoder::new(reader)?),
165 };
166 Ok(decoder)
167 }
168}
169
170impl<R: Read> Read for Decoder<'_, R> {
171 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
172 match self {
173 Decoder::None(r) => r.read(buf),
174 Decoder::Gzip(r) => r.read(buf),
175 Decoder::Zstd(r) => r.read(buf),
176 }
177 }
178}
179
180pub struct ZlibDecoder<R> {
182 stream: flate2::bufread::MultiGzDecoder<BufReader<R>>,
183}
184
185impl<R: Read> ZlibDecoder<R> {
186 pub fn new(reader: R) -> Self {
188 ZlibDecoder {
189 stream: flate2::bufread::MultiGzDecoder::new(BufReader::new(reader)),
190 }
191 }
192}
193
194impl<R: Read> Read for ZlibDecoder<R> {
195 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
196 self.stream.read(buf)
197 }
198}
199
200pub fn compute_compressed_gzip_size(size: usize, max_size: usize) -> usize {
244 let size = size + 10 + 8 + 5 + (size / (16 << 10)) * 5 + 128;
245
246 std::cmp::min(size, max_size)
247}
248
249fn zstd_compress(src: &[u8]) -> Result<Vec<u8>> {
250 zstd::bulk::compress(src, zstd::DEFAULT_COMPRESSION_LEVEL)
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256 use std::fs::OpenOptions;
257 use std::io::{Seek, SeekFrom};
258 use std::path::Path;
259 use std::str::FromStr;
260 use vmm_sys_util::tempfile::TempFile;
261
262 #[test]
263 fn test_compress_algorithm_gzip() {
264 let buf = vec![0x2u8; 4095];
265 let compressed = compress(&buf, Algorithm::GZip).unwrap();
266 assert!(compressed.1);
267 let (compressed, _) = compressed;
268 assert_ne!(compressed.len(), 0);
269
270 let mut decompressed = vec![0; buf.len()];
271 let sz = decompress(&compressed, decompressed.as_mut_slice(), Algorithm::GZip).unwrap();
272 assert_eq!(sz, 4095);
273 assert_eq!(buf, decompressed);
274
275 let mut tmp_file = TempFile::new().unwrap().into_file();
276 tmp_file.write_all(&compressed).unwrap();
277 tmp_file.seek(SeekFrom::Start(0)).unwrap();
278
279 let mut decompressed = vec![0; buf.len()];
280 let mut decoder = Decoder::new(tmp_file, Algorithm::GZip).unwrap();
281 decoder.read_exact(decompressed.as_mut_slice()).unwrap();
282 assert_eq!(sz, 4095);
283 assert_eq!(buf, decompressed);
284 }
285
286 #[test]
287 fn test_compress_algorithm_none() {
288 let buf = [
289 0x1u8, 0x2u8, 0x3u8, 0x4u8, 0x1u8, 0x2u8, 0x3u8, 0x4u8, 0x1u8, 0x2u8, 0x3u8, 0x4u8,
290 0x1u8, 0x2u8, 0x3u8, 0x4u8,
291 ];
292 let mut dst = [0x0u8; 16];
293 let (compressed, _) = compress(&buf, Algorithm::None).unwrap();
294 assert_eq!(buf.to_vec(), compressed.to_vec());
295 let _len = decompress(&buf, &mut dst, Algorithm::None).unwrap();
296 assert_eq!(dst.to_vec(), compressed.to_vec());
297 }
298
299 #[test]
300 fn test_compress_algorithm_ztsd() {
301 let buf = vec![0x2u8; 4097];
302 let mut decompressed = vec![0; buf.len()];
303 let (compressed, _) = compress(&buf, Algorithm::Zstd).unwrap();
304 let sz = decompress(&compressed, decompressed.as_mut_slice(), Algorithm::Zstd).unwrap();
305 assert_eq!(sz, 4097);
306 assert_eq!(buf, decompressed);
307 }
308
309 #[test]
310 fn test_compress_algorithm_lz4() {
311 let buf = [
312 0x1u8, 0x2u8, 0x3u8, 0x4u8, 0x1u8, 0x2u8, 0x3u8, 0x4u8, 0x1u8, 0x2u8, 0x3u8, 0x4u8,
313 0x1u8, 0x2u8, 0x3u8, 0x4u8,
314 ];
315 let mut decompressed = vec![0; buf.len()];
316 let (compressed, _) = compress(&buf, Algorithm::Lz4Block).unwrap();
317 let _len = decompress(
318 &compressed,
319 decompressed.as_mut_slice(),
320 Algorithm::Lz4Block,
321 )
322 .unwrap();
323 assert_eq!(decompressed.to_vec(), buf.to_vec());
324 }
325
326 #[test]
327 fn test_lz4_compress_decompress_1_byte() {
328 let buf = vec![0x1u8];
329 let compressed = lz4_compress(&buf).unwrap();
330 let mut decompressed = vec![0; buf.len()];
331 let sz = decompress(
332 &compressed,
333 decompressed.as_mut_slice(),
334 Algorithm::Lz4Block,
335 )
336 .unwrap();
337
338 assert_eq!(sz, 1);
339 assert_eq!(buf, decompressed);
340 }
341
342 #[test]
343 fn test_lz4_compress_decompress_2_bytes() {
344 let buf = vec![0x2u8, 0x3u8];
345 let compressed = lz4_compress(&buf).unwrap();
346 let mut decompressed = vec![0; buf.len()];
347 let sz = decompress(
348 &compressed,
349 decompressed.as_mut_slice(),
350 Algorithm::Lz4Block,
351 )
352 .unwrap();
353
354 assert_eq!(sz, 2);
355 assert_eq!(buf, decompressed);
356 }
357
358 #[test]
359 fn test_lz4_compress_decompress_16_bytes() {
360 let buf = [
361 0x1u8, 0x2u8, 0x3u8, 0x4u8, 0x1u8, 0x2u8, 0x3u8, 0x4u8, 0x1u8, 0x2u8, 0x3u8, 0x4u8,
362 0x1u8, 0x2u8, 0x3u8, 0x4u8,
363 ];
364 let compressed = lz4_compress(&buf).unwrap();
365 let mut decompressed = vec![0; buf.len()];
366 let sz = decompress(
367 &compressed,
368 decompressed.as_mut_slice(),
369 Algorithm::Lz4Block,
370 )
371 .unwrap();
372
373 assert_eq!(sz, 16);
374 assert_eq!(&buf, decompressed.as_slice());
375 }
376
377 #[test]
378 fn test_lz4_compress_decompress_4095_bytes() {
379 let buf = vec![0x2u8; 4095];
380 let compressed = lz4_compress(&buf).unwrap();
381 let mut decompressed = vec![0; buf.len()];
382 let sz = decompress(
383 &compressed,
384 decompressed.as_mut_slice(),
385 Algorithm::Lz4Block,
386 )
387 .unwrap();
388
389 assert_eq!(sz, 4095);
390 assert_eq!(buf, decompressed);
391 }
392
393 #[test]
394 fn test_lz4_compress_decompress_4096_bytes() {
395 let buf = vec![0x2u8; 4096];
396 let compressed = lz4_compress(&buf).unwrap();
397 let mut decompressed = vec![0; buf.len()];
398 let sz = decompress(
399 &compressed,
400 decompressed.as_mut_slice(),
401 Algorithm::Lz4Block,
402 )
403 .unwrap();
404
405 assert_eq!(sz, 4096);
406 assert_eq!(buf, decompressed);
407 }
408
409 #[test]
410 fn test_lz4_compress_decompress_4097_bytes() {
411 let buf = vec![0x2u8; 4097];
412 let compressed = lz4_compress(&buf).unwrap();
413 let mut decompressed = vec![0; buf.len()];
414 let sz = decompress(
415 &compressed,
416 decompressed.as_mut_slice(),
417 Algorithm::Lz4Block,
418 )
419 .unwrap();
420
421 assert_eq!(sz, 4097);
422 assert_eq!(buf, decompressed);
423 }
424
425 #[test]
426 fn test_zstd_compress_decompress_1_byte() {
427 let buf = vec![0x1u8];
428 let compressed = zstd_compress(&buf).unwrap();
429 let mut decompressed = vec![0; buf.len()];
430 let sz = decompress(&compressed, decompressed.as_mut_slice(), Algorithm::Zstd).unwrap();
431
432 assert_eq!(sz, 1);
433 assert_eq!(buf, decompressed);
434 }
435
436 #[test]
437 fn test_zstd_compress_decompress_2_bytes() {
438 let buf = vec![0x2u8, 0x3u8];
439 let compressed = zstd_compress(&buf).unwrap();
440 let mut decompressed = vec![0; buf.len()];
441 let sz = decompress(&compressed, decompressed.as_mut_slice(), Algorithm::Zstd).unwrap();
442
443 assert_eq!(sz, 2);
444 assert_eq!(buf, decompressed);
445 }
446
447 #[test]
448 fn test_zstd_compress_decompress_16_bytes() {
449 let buf = [
450 0x1u8, 0x2u8, 0x3u8, 0x4u8, 0x1u8, 0x2u8, 0x3u8, 0x4u8, 0x1u8, 0x2u8, 0x3u8, 0x4u8,
451 0x1u8, 0x2u8, 0x3u8, 0x4u8,
452 ];
453 let compressed = zstd_compress(&buf).unwrap();
454 let mut decompressed = vec![0; buf.len()];
455 let sz = decompress(&compressed, decompressed.as_mut_slice(), Algorithm::Zstd).unwrap();
456
457 assert_eq!(sz, 16);
458 assert_eq!(&buf, decompressed.as_slice());
459 }
460
461 #[test]
462 fn test_zstd_compress_decompress_4095_bytes() {
463 let buf = vec![0x2u8; 4095];
464 let compressed = zstd_compress(&buf).unwrap();
465 let mut decompressed = vec![0; buf.len()];
466 let sz = decompress(&compressed, decompressed.as_mut_slice(), Algorithm::Zstd).unwrap();
467
468 assert_eq!(sz, 4095);
469 assert_eq!(buf, decompressed);
470 }
471
472 #[test]
473 fn test_zstd_compress_decompress_4096_bytes() {
474 let buf = vec![0x2u8; 4096];
475 let compressed = zstd_compress(&buf).unwrap();
476 let mut decompressed = vec![0; buf.len()];
477 let sz = decompress(&compressed, decompressed.as_mut_slice(), Algorithm::Zstd).unwrap();
478
479 assert_eq!(sz, 4096);
480 assert_eq!(buf, decompressed);
481 }
482
483 #[test]
484 fn test_zstd_compress_decompress_4097_bytes() {
485 let buf = vec![0x2u8; 4097];
486 let compressed = zstd_compress(&buf).unwrap();
487 let mut decompressed = vec![0; buf.len()];
488 let sz = decompress(&compressed, decompressed.as_mut_slice(), Algorithm::Zstd).unwrap();
489
490 assert_eq!(sz, 4097);
491 assert_eq!(buf, decompressed);
492 }
493
494 #[test]
495 fn test_new_decoder_none() {
496 let buf = b"This is a test";
497 let mut decoder = Decoder::new(buf.as_slice(), Algorithm::None).unwrap();
498 let mut buf2 = vec![0u8; 1024];
499 let res = decoder.read(&mut buf2).unwrap();
500 assert_eq!(res, 14);
501 assert_eq!(&buf2[0..14], buf.as_slice());
502 }
503
504 #[test]
505 fn test_gzip_decoder() {
506 let root_dir = &std::env::var("CARGO_MANIFEST_DIR").expect("$CARGO_MANIFEST_DIR");
507 let path = Path::new(root_dir).join("../tests/texture/zran/zlib_sample.txt.gz");
508 let file = OpenOptions::new().read(true).open(path).unwrap();
509 let mut decoder = Decoder::new(file, Algorithm::GZip).unwrap();
510 let mut buf = [0u8; 8];
511
512 decoder.read_exact(&mut buf).unwrap();
513 assert_eq!(&String::from_utf8_lossy(&buf), "This is ");
514 decoder.read_exact(&mut buf).unwrap();
515 assert_eq!(&String::from_utf8_lossy(&buf), "a test f");
516 decoder.read_exact(&mut buf).unwrap();
517 assert_eq!(&String::from_utf8_lossy(&buf), "ile for ");
518 let ret = decoder.read(&mut buf).unwrap();
519 assert_eq!(ret, 6);
520 assert_eq!(&String::from_utf8_lossy(&buf[0..6]), "zlib.\n");
521 let ret = decoder.read(&mut buf).unwrap();
522 assert_eq!(ret, 0);
523 }
524
525 #[test]
526 fn test_zlib_decoder() {
527 let root_dir = &std::env::var("CARGO_MANIFEST_DIR").expect("$CARGO_MANIFEST_DIR");
528 let path = Path::new(root_dir).join("../tests/texture/zran/zlib_sample.txt.gz");
529 let file = OpenOptions::new().read(true).open(path).unwrap();
530 let mut decoder = ZlibDecoder::new(file);
531 let mut buf = [0u8; 8];
532
533 decoder.read_exact(&mut buf).unwrap();
534 assert_eq!(&String::from_utf8_lossy(&buf), "This is ");
535 decoder.read_exact(&mut buf).unwrap();
536 assert_eq!(&String::from_utf8_lossy(&buf), "a test f");
537 decoder.read_exact(&mut buf).unwrap();
538 assert_eq!(&String::from_utf8_lossy(&buf), "ile for ");
539 let ret = decoder.read(&mut buf).unwrap();
540 assert_eq!(ret, 6);
541 assert_eq!(&String::from_utf8_lossy(&buf[0..6]), "zlib.\n");
542 let ret = decoder.read(&mut buf).unwrap();
543 assert_eq!(ret, 0);
544 print!(
545 "{:?}, {:?}, {:?}, {:?},",
546 Algorithm::GZip,
547 Algorithm::Lz4Block,
548 Algorithm::Zstd,
549 Algorithm::None
550 )
551 }
552
553 #[test]
554 fn test_algorithm_from() {
555 assert_eq!(Algorithm::from_str("none").unwrap(), Algorithm::None);
556 assert_eq!(
557 Algorithm::from_str("lz4_block").unwrap(),
558 Algorithm::Lz4Block
559 );
560 assert_eq!(Algorithm::from_str("gzip").unwrap(), Algorithm::GZip);
561 assert_eq!(Algorithm::from_str("zstd").unwrap(), Algorithm::Zstd);
562 assert!(Algorithm::from_str("foo").is_err());
563 assert_eq!(
564 Algorithm::try_from(Algorithm::None as u32).unwrap(),
565 Algorithm::None
566 );
567 assert_eq!(
568 Algorithm::try_from(Algorithm::Lz4Block as u32).unwrap(),
569 Algorithm::Lz4Block
570 );
571 assert_eq!(
572 Algorithm::try_from(Algorithm::GZip as u32).unwrap(),
573 Algorithm::GZip
574 );
575 assert_eq!(
576 Algorithm::try_from(Algorithm::Zstd as u32).unwrap(),
577 Algorithm::Zstd
578 );
579 assert!(Algorithm::try_from(u32::MAX).is_err());
580
581 assert_eq!(
582 Algorithm::try_from(Algorithm::None as u64).unwrap(),
583 Algorithm::None
584 );
585 assert_eq!(
586 Algorithm::try_from(Algorithm::Lz4Block as u64).unwrap(),
587 Algorithm::Lz4Block
588 );
589 assert_eq!(
590 Algorithm::try_from(Algorithm::GZip as u64).unwrap(),
591 Algorithm::GZip
592 );
593 assert_eq!(
594 Algorithm::try_from(Algorithm::Zstd as u64).unwrap(),
595 Algorithm::Zstd
596 );
597 assert!(Algorithm::try_from(u64::MAX).is_err());
598 assert!(Algorithm::None.is_none());
599 assert!(!Algorithm::Lz4Block.is_none());
600 assert!(!Algorithm::GZip.is_none());
601 assert!(!Algorithm::Zstd.is_none());
602 }
603
604 #[test]
605 fn test_algorithm_to_string() {
606 assert_eq!(Algorithm::None.to_string(), "none");
607 assert_eq!(Algorithm::Lz4Block.to_string(), "lz4_block");
608 assert_eq!(Algorithm::GZip.to_string(), "gzip");
609 assert_eq!(Algorithm::Zstd.to_string(), "zstd");
610 }
611
612 #[test]
613 fn test_algorithm_from_str() {
614 assert_eq!(Algorithm::from_str("none").unwrap(), Algorithm::None);
615 assert_eq!(
616 Algorithm::from_str("lz4_block").unwrap(),
617 Algorithm::Lz4Block
618 );
619 assert_eq!(Algorithm::from_str("gzip").unwrap(), Algorithm::GZip);
620 assert_eq!(Algorithm::from_str("zstd").unwrap(), Algorithm::Zstd);
621 }
622
623 #[test]
624 fn test_algorithm_to_string_and_from_str_consistency() {
625 let algorithms = vec![
626 Algorithm::None,
627 Algorithm::Lz4Block,
628 Algorithm::GZip,
629 Algorithm::Zstd,
630 ];
631
632 for algo in algorithms {
633 let stringified = algo.to_string();
634 let parsed = Algorithm::from_str(&stringified).unwrap();
635 assert_eq!(algo, parsed, "Mismatch for algorithm: {:?}", algo);
636 }
637 }
638
639 #[test]
640 fn test_algorithm_from_str_invalid_input() {
641 assert!(Algorithm::from_str("invalid_algorithm").is_err());
642 assert!(Algorithm::from_str("GZIP").is_err());
643 assert!(Algorithm::from_str("LZ4_BLOCK").is_err());
644 }
645}