summaryrefslogtreecommitdiffstats
path: root/rust/vendor/lzma-rs/src/encode/xz.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/vendor/lzma-rs/src/encode/xz.rs')
-rw-r--r--rust/vendor/lzma-rs/src/encode/xz.rs163
1 files changed, 163 insertions, 0 deletions
diff --git a/rust/vendor/lzma-rs/src/encode/xz.rs b/rust/vendor/lzma-rs/src/encode/xz.rs
new file mode 100644
index 0000000..15eca80
--- /dev/null
+++ b/rust/vendor/lzma-rs/src/encode/xz.rs
@@ -0,0 +1,163 @@
+use crate::decode;
+use crate::encode::lzma2;
+use crate::encode::util;
+use crate::xz::{footer, header, CheckMethod, StreamFlags};
+use byteorder::{LittleEndian, WriteBytesExt};
+use crc::{crc32, Hasher32};
+use std::io;
+use std::io::Write;
+
+pub fn encode_stream<R, W>(input: &mut R, output: &mut W) -> io::Result<()>
+where
+ R: io::BufRead,
+ W: io::Write,
+{
+ let stream_flags = StreamFlags {
+ check_method: CheckMethod::None,
+ };
+
+ // Header
+ write_header(output, stream_flags)?;
+
+ // Block
+ let (unpadded_size, unpacked_size) = write_block(input, output)?;
+
+ // Index
+ let index_size = write_index(output, unpadded_size, unpacked_size)?;
+
+ // Footer
+ write_footer(output, stream_flags, index_size)
+}
+
+fn write_header<W>(output: &mut W, stream_flags: StreamFlags) -> io::Result<()>
+where
+ W: io::Write,
+{
+ output.write_all(header::XZ_MAGIC)?;
+ let mut digest = crc32::Digest::new(crc32::IEEE);
+ {
+ let mut digested = util::HasherWrite::new(output, &mut digest);
+ stream_flags.serialize(&mut digested)?;
+ }
+ let crc32 = digest.sum32();
+ output.write_u32::<LittleEndian>(crc32)?;
+ Ok(())
+}
+
+fn write_footer<W>(output: &mut W, stream_flags: StreamFlags, index_size: usize) -> io::Result<()>
+where
+ W: io::Write,
+{
+ let mut digest = crc32::Digest::new(crc32::IEEE);
+ let mut footer_buf: Vec<u8> = Vec::new();
+ {
+ let mut digested = util::HasherWrite::new(&mut footer_buf, &mut digest);
+
+ let backward_size = (index_size >> 2) - 1;
+ digested.write_u32::<LittleEndian>(backward_size as u32)?;
+ stream_flags.serialize(&mut digested)?;
+ }
+ let crc32 = digest.sum32();
+ output.write_u32::<LittleEndian>(crc32)?;
+ output.write_all(footer_buf.as_slice())?;
+
+ output.write_all(footer::XZ_MAGIC_FOOTER)?;
+ Ok(())
+}
+
+fn write_block<R, W>(input: &mut R, output: &mut W) -> io::Result<(usize, usize)>
+where
+ R: io::BufRead,
+ W: io::Write,
+{
+ let (unpadded_size, unpacked_size) = {
+ let mut count_output = util::CountWrite::new(output);
+
+ // Block header
+ let mut digest = crc32::Digest::new(crc32::IEEE);
+ {
+ let mut digested = util::HasherWrite::new(&mut count_output, &mut digest);
+ let header_size = 8;
+ digested.write_u8((header_size >> 2) as u8)?;
+ let flags = 0x00; // 1 filter, no (un)packed size provided
+ digested.write_u8(flags)?;
+ let filter_id = 0x21; // LZMA2
+ digested.write_u8(filter_id)?;
+ let size_of_properties = 1;
+ digested.write_u8(size_of_properties)?;
+ let properties = 22; // TODO
+ digested.write_u8(properties)?;
+ let padding = [0, 0, 0];
+ digested.write_all(&padding)?;
+ }
+ let crc32 = digest.sum32();
+ count_output.write_u32::<LittleEndian>(crc32)?;
+
+ // Block
+ let mut count_input = decode::util::CountBufRead::new(input);
+ lzma2::encode_stream(&mut count_input, &mut count_output)?;
+ (count_output.count(), count_input.count())
+ };
+ lzma_info!(
+ "Unpadded size = {}, unpacked_size = {}",
+ unpadded_size,
+ unpacked_size
+ );
+
+ let padding_size = ((unpadded_size ^ 0x03) + 1) & 0x03;
+ let padding = vec![0; padding_size];
+ output.write_all(padding.as_slice())?;
+ // Checksum = None (cf. above)
+
+ Ok((unpadded_size, unpacked_size))
+}
+
+fn write_index<W>(output: &mut W, unpadded_size: usize, unpacked_size: usize) -> io::Result<usize>
+where
+ W: io::Write,
+{
+ let mut count_output = util::CountWrite::new(output);
+
+ let mut digest = crc32::Digest::new(crc32::IEEE);
+ {
+ let mut digested = util::HasherWrite::new(&mut count_output, &mut digest);
+ digested.write_u8(0)?; // No more block
+ let num_records = 1;
+ write_multibyte(&mut digested, num_records)?;
+
+ write_multibyte(&mut digested, unpadded_size as u64)?;
+ write_multibyte(&mut digested, unpacked_size as u64)?;
+ }
+
+ // Padding
+ let count = count_output.count();
+ let padding_size = ((count ^ 0x03) + 1) & 0x03;
+ {
+ let mut digested = util::HasherWrite::new(&mut count_output, &mut digest);
+ let padding = vec![0; padding_size];
+ digested.write_all(padding.as_slice())?;
+ }
+
+ let crc32 = digest.sum32();
+ count_output.write_u32::<LittleEndian>(crc32)?;
+
+ Ok(count_output.count())
+}
+
+fn write_multibyte<W>(output: &mut W, mut value: u64) -> io::Result<()>
+where
+ W: io::Write,
+{
+ loop {
+ let byte = (value & 0x7F) as u8;
+ value >>= 7;
+ if value == 0 {
+ output.write_u8(byte)?;
+ break;
+ } else {
+ output.write_u8(0x80 | byte)?;
+ }
+ }
+
+ Ok(())
+}