1use std::io::{self, Write};
23use lzma_sys::*;
24use std;
25use error::LzmaError;
26use ::Direction;
27use lzma_stream_wrapper::{LzmaStreamWrapper, LzmaCodeResult};
28
29
30const DEFAULT_BUF_SIZE: usize = 4 * 1024;
31
32
33pub struct LzmaWriter<T> {
34 inner: T,
35 stream: LzmaStreamWrapper,
36 buffer: Vec<u8>,
37 direction: Direction,
38}
39
40
41impl<T: Write> LzmaWriter<T> {
42 pub fn new_compressor(inner: T, preset: u32) -> Result<LzmaWriter<T>, LzmaError> {
43 LzmaWriter::with_capacity(DEFAULT_BUF_SIZE, inner, Direction::Compress, preset)
44 }
45
46 pub fn new_decompressor(inner: T) -> Result<LzmaWriter<T>, LzmaError> {
47 LzmaWriter::with_capacity(DEFAULT_BUF_SIZE, inner, Direction::Decompress, 0)
48 }
49
50 pub fn with_capacity(capacity: usize, inner: T, direction: Direction, preset: u32) -> Result<LzmaWriter<T>, LzmaError> {
51 let mut writer = LzmaWriter {
52 inner,
53 stream: LzmaStreamWrapper::new(),
54 buffer: vec![0; capacity],
55 direction,
56 };
57
58 match writer.direction {
59 Direction::Compress => {
60 writer.stream.easy_encoder(preset, lzma_check::LzmaCheckCrc64)?
61 },
62 Direction::Decompress => {
63 writer.stream.stream_decoder(std::u64::MAX, 0)?
64 },
65 }
66
67 Ok(writer)
68 }
69}
70
71impl<W: Write> LzmaWriter<W> {
72 pub fn finish(mut self) -> Result<W, LzmaError> {
77 loop {
78 match self.lzma_code_and_write(&[], lzma_action::LzmaFinish) {
79 Ok(LzmaCodeResult {
80 ret: Ok(lzma_ret::LzmaStreamEnd),
81 bytes_read: _,
82 bytes_written: _,
83 }) => break,
84 Ok(_) => continue,
85 Err(err) => return Err(err),
86 }
87 }
88
89 Ok(self.inner)
90 }
91
92 #[allow(clippy::question_mark)]
93 fn lzma_code_and_write(&mut self, input: &[u8], action: lzma_action) -> Result<LzmaCodeResult, LzmaError> {
94 let result = self.stream.code(input, &mut self.buffer, action);
95 if let Err(err) = result.ret {
96 return Err(err);
97 }
98
99 if result.bytes_written > 0 {
100 Write::write_all(&mut self.inner, &self.buffer[..result.bytes_written])?;
101 }
102
103 Ok(result)
104 }
105}
106
107
108impl<W: Write> Write for LzmaWriter<W> {
109 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
110 loop {
113 match self.lzma_code_and_write(buf, lzma_action::LzmaRun) {
114 Ok(result) => if result.bytes_read == 0 && result.bytes_written > 0 {
115 continue
116 } else {
117 return Ok(result.bytes_read)
120 },
121 Err(LzmaError::Io(err)) => return Err(err),
122 Err(err) => return Err(io::Error::new(io::ErrorKind::Other, err)),
123 }
124 }
125 }
126
127 fn flush(&mut self) -> io::Result<()> {
128 self.inner.flush()
129 }
130}