Skip to content

Commit

Permalink
Flag miniz_oxide as a #![no_std] library (#81)
Browse files Browse the repository at this point in the history
* Flag `miniz_oxide` as a `#![no_std]` library

This commit conversion the `miniz_oxide` crate to a `#![no_std]`
library, and is as a result a breaking change for the library. Currently
the only dependency on the `std` crate is the `std::io::Cursor` type,
which is pretty easily replaced with a `usize` parameter in a few
locations.

The goal of this commit is to eventually enable this library to be
included into the standard library itself. Dependencies of the standard
library can't depend on the standard library as well! The reason for
including this in the standard library is that the `backtrace` crate
wants to decompress DWARF information in executables, which can be
compressed with zlib.

* Update with annotations to build in libstd
  • Loading branch information
alexcrichton authored Jun 17, 2020
1 parent 5639cf6 commit 7f5aedd
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 123 deletions.
13 changes: 12 additions & 1 deletion miniz_oxide/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,15 @@ exclude = ["benches/*", "tests/*"]
name = "miniz_oxide"

[dependencies]
adler32 = "1.0.4"
adler32 = { version = "1.1.0", default-features = false }

# Internal feature, only used when building as part of libstd, not part of the
# stable interface of this crate.
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
alloc = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-alloc' }
compiler_builtins = { version = '0.1.2', optional = true }

[features]
# Internal feature, only used when building as part of libstd, not part of the
# stable interface of this crate.
rustc-dep-of-std = ['core', 'alloc', 'compiler_builtins', 'adler32/rustc-dep-of-std']
112 changes: 66 additions & 46 deletions miniz_oxide/src/deflate/core.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Streaming compression functionality.

use std::convert::TryInto;
use std::io::{self, Cursor, Seek, SeekFrom, Write};
use std::{cmp, mem};
use alloc::boxed::Box;
use core::convert::TryInto;
use core::{cmp, mem};

use super::super::*;
use super::deflate_flags::*;
Expand All @@ -14,6 +14,11 @@ use crate::deflate::buffer::{
use crate::shared::{update_adler32, HUFFMAN_LENGTH_ORDER, MZ_ADLER32_INIT};
use crate::DataFormat;

// Currently not bubbled up outside this module, so can fill in with more
// context eventually if needed.
type Result<T, E = Error> = core::result::Result<T, E>;
struct Error {}

const MAX_PROBES_MASK: i32 = 0xFFF;

const MAX_SUPPORTED_HUFF_CODESIZE: usize = 32;
Expand Down Expand Up @@ -549,12 +554,12 @@ impl<'a> CallbackBuf<'a> {
.copy_from_slice(&params.local_buf.b[..n]);

params.out_buf_ofs += n;
if saved_output.pos != n as u64 {
if saved_output.pos != n {
params.flush_ofs = n as u32;
params.flush_remaining = (saved_output.pos - n as u64) as u32;
params.flush_remaining = (saved_output.pos - n) as u32;
}
} else {
params.out_buf_ofs += saved_output.pos as usize;
params.out_buf_ofs += saved_output.pos;
}

params.flush_remaining as i32
Expand Down Expand Up @@ -585,9 +590,9 @@ impl<'a> CallbackOut<'a> {
}
};

let cursor = Cursor::new(chosen_buffer);
OutputBufferOxide {
inner: cursor,
inner: chosen_buffer,
inner_pos: 0,
local: is_local,
bit_buffer: 0,
bits_in: 0,
Expand Down Expand Up @@ -649,7 +654,8 @@ impl<'a> CallbackOxide<'a> {
}

struct OutputBufferOxide<'a> {
pub inner: Cursor<&'a mut [u8]>,
pub inner: &'a mut [u8],
pub inner_pos: usize,
pub local: bool,

pub bit_buffer: u32,
Expand All @@ -662,25 +668,24 @@ impl<'a> OutputBufferOxide<'a> {
self.bit_buffer |= bits << self.bits_in;
self.bits_in += len;
while self.bits_in >= 8 {
let pos = self.inner.position();
self.inner.get_mut()[pos as usize] = self.bit_buffer as u8;
self.inner.set_position(pos + 1);
self.inner[self.inner_pos] = self.bit_buffer as u8;
self.inner_pos += 1;
self.bit_buffer >>= 8;
self.bits_in -= 8;
}
}

fn save(&self) -> SavedOutputBufferOxide {
SavedOutputBufferOxide {
pos: self.inner.position(),
pos: self.inner_pos,
bit_buffer: self.bit_buffer,
bits_in: self.bits_in,
local: self.local,
}
}

fn load(&mut self, saved: SavedOutputBufferOxide) {
self.inner.set_position(saved.pos);
self.inner_pos = saved.pos;
self.bit_buffer = saved.bit_buffer;
self.bits_in = saved.bits_in;
self.local = saved.local;
Expand All @@ -695,7 +700,7 @@ impl<'a> OutputBufferOxide<'a> {
}

struct SavedOutputBufferOxide {
pub pos: u64,
pub pos: usize,
pub bit_buffer: u32,
pub bits_in: u32,
pub local: bool,
Expand All @@ -712,17 +717,18 @@ impl BitBuffer {
self.bits_in += len;
}

fn flush(&mut self, output: &mut OutputBufferOxide) -> io::Result<()> {
let pos = output.inner.position() as usize;
fn flush(&mut self, output: &mut OutputBufferOxide) -> Result<()> {
let pos = output.inner_pos;
{
// isolation to please borrow checker
let inner = &mut (*output.inner.get_mut())[pos..pos + 8];
let inner = &mut output.inner[pos..pos + 8];
let bytes = u64::to_le_bytes(self.bit_buffer);
inner.copy_from_slice(&bytes);
}
output
.inner
.seek(SeekFrom::Current(i64::from(self.bits_in >> 3)))?;
match output.inner_pos.checked_add((self.bits_in >> 3) as usize) {
Some(n) if n <= output.inner.len() => output.inner_pos = n,
_ => return Err(Error {}),
}
self.bit_buffer >>= self.bits_in & !7;
self.bits_in &= 7;
Ok(())
Expand Down Expand Up @@ -760,19 +766,21 @@ struct RLE {
impl RLE {
fn prev_code_size(
&mut self,
packed_code_sizes: &mut Cursor<&mut [u8]>,
packed_code_sizes: &mut [u8],
packed_pos: &mut usize,
h: &mut HuffmanOxide,
) -> io::Result<()> {
) -> Result<()> {
let mut write = |buf| write(buf, packed_code_sizes, packed_pos);
let counts = &mut h.count[HUFF_CODES_TABLE];
if self.repeat_count != 0 {
if self.repeat_count < 3 {
counts[self.prev_code_size as usize] =
counts[self.prev_code_size as usize].wrapping_add(self.repeat_count as u16);
let code = self.prev_code_size;
packed_code_sizes.write_all(&[code, code, code][..self.repeat_count as usize])?;
write(&[code, code, code][..self.repeat_count as usize])?;
} else {
counts[16] = counts[16].wrapping_add(1);
packed_code_sizes.write_all(&[16, (self.repeat_count - 3) as u8][..])?;
write(&[16, (self.repeat_count - 3) as u8][..])?;
}
self.repeat_count = 0;
}
Expand All @@ -782,20 +790,22 @@ impl RLE {

fn zero_code_size(
&mut self,
packed_code_sizes: &mut Cursor<&mut [u8]>,
packed_code_sizes: &mut [u8],
packed_pos: &mut usize,
h: &mut HuffmanOxide,
) -> io::Result<()> {
) -> Result<()> {
let mut write = |buf| write(buf, packed_code_sizes, packed_pos);
let counts = &mut h.count[HUFF_CODES_TABLE];
if self.z_count != 0 {
if self.z_count < 3 {
counts[0] = counts[0].wrapping_add(self.z_count as u16);
packed_code_sizes.write_all(&[0, 0, 0][..self.z_count as usize])?;
write(&[0, 0, 0][..self.z_count as usize])?;
} else if self.z_count <= 10 {
counts[17] = counts[17].wrapping_add(1);
packed_code_sizes.write_all(&[17, (self.z_count - 3) as u8][..])?;
write(&[17, (self.z_count - 3) as u8][..])?;
} else {
counts[18] = counts[18].wrapping_add(1);
packed_code_sizes.write_all(&[18, (self.z_count - 11) as u8][..])?;
write(&[18, (self.z_count - 11) as u8][..])?;
}
self.z_count = 0;
}
Expand All @@ -804,6 +814,15 @@ impl RLE {
}
}

fn write(src: &[u8], dst: &mut [u8], dst_pos: &mut usize) -> Result<()> {
match dst.get_mut(*dst_pos..*dst_pos + src.len()) {
Some(s) => s.copy_from_slice(src),
None => return Err(Error {}),
}
*dst_pos += src.len();
Ok(())
}

impl Default for HuffmanOxide {
fn default() -> Self {
HuffmanOxide {
Expand Down Expand Up @@ -1036,7 +1055,7 @@ impl HuffmanOxide {
output.put_bits(0b01, 2)
}

fn start_dynamic_block(&mut self, output: &mut OutputBufferOxide) -> io::Result<()> {
fn start_dynamic_block(&mut self, output: &mut OutputBufferOxide) -> Result<()> {
// There will always be one, and only one end of block code.
self.count[0][256] = 1;

Expand Down Expand Up @@ -1075,35 +1094,35 @@ impl HuffmanOxide {

memset(&mut self.count[HUFF_CODES_TABLE][..MAX_HUFF_SYMBOLS_2], 0);

let mut packed_code_sizes_cursor = Cursor::new(&mut packed_code_sizes[..]);
let mut packed_pos = 0;
for &code_size in &code_sizes_to_pack[..total_code_sizes_to_pack] {
if code_size == 0 {
rle.prev_code_size(&mut packed_code_sizes_cursor, self)?;
rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
rle.z_count += 1;
if rle.z_count == 138 {
rle.zero_code_size(&mut packed_code_sizes_cursor, self)?;
rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
}
} else {
rle.zero_code_size(&mut packed_code_sizes_cursor, self)?;
rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
if code_size != rle.prev_code_size {
rle.prev_code_size(&mut packed_code_sizes_cursor, self)?;
rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
self.count[HUFF_CODES_TABLE][code_size as usize] =
self.count[HUFF_CODES_TABLE][code_size as usize].wrapping_add(1);
packed_code_sizes_cursor.write_all(&[code_size][..])?;
write(&[code_size], &mut packed_code_sizes, &mut packed_pos)?;
} else {
rle.repeat_count += 1;
if rle.repeat_count == 6 {
rle.prev_code_size(&mut packed_code_sizes_cursor, self)?;
rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
}
}
}
rle.prev_code_size = code_size;
}

if rle.repeat_count != 0 {
rle.prev_code_size(&mut packed_code_sizes_cursor, self)?;
rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
} else {
rle.zero_code_size(&mut packed_code_sizes_cursor, self)?;
rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?;
}

self.optimize_table(2, MAX_HUFF_SYMBOLS_2, 7, false);
Expand All @@ -1130,8 +1149,7 @@ impl HuffmanOxide {
}

let mut packed_code_size_index = 0 as usize;
let packed_code_sizes = packed_code_sizes_cursor.get_ref();
while packed_code_size_index < packed_code_sizes_cursor.position() as usize {
while packed_code_size_index < packed_pos {
let code = packed_code_sizes[packed_code_size_index] as usize;
packed_code_size_index += 1;
assert!(code < MAX_HUFF_SYMBOLS_2);
Expand Down Expand Up @@ -1474,7 +1492,7 @@ fn compress_lz_codes(
huff: &HuffmanOxide,
output: &mut OutputBufferOxide,
lz_code_buf: &[u8],
) -> io::Result<bool> {
) -> Result<bool> {
let mut flags = 1;
let mut bb = BitBuffer {
bit_buffer: u64::from(output.bit_buffer),
Expand Down Expand Up @@ -1573,7 +1591,7 @@ fn compress_block(
output: &mut OutputBufferOxide,
lz: &LZOxide,
static_block: bool,
) -> io::Result<bool> {
) -> Result<bool> {
if static_block {
huff.start_static_block(output);
} else {
Expand All @@ -1587,7 +1605,7 @@ fn flush_block(
d: &mut CompressorOxide,
callback: &mut CallbackOxide,
flush: TDEFLFlush,
) -> io::Result<i32> {
) -> Result<i32> {
let mut saved_buffer;
{
let mut output = callback
Expand Down Expand Up @@ -1635,7 +1653,7 @@ fn flush_block(
// (as literals are either 8 or 9 bytes), a raw block will
// never take up less space if the number of input bytes are less than 32.
let expanded = (d.lz.total_bytes > 32)
&& (output.inner.position() - saved_buffer.pos + 1 >= u64::from(d.lz.total_bytes))
&& (output.inner_pos - saved_buffer.pos + 1 >= (d.lz.total_bytes as usize))
&& (d.dict.lookahead_pos - d.dict.code_buf_dict_pos <= d.dict.size);

if use_raw_block || expanded {
Expand Down Expand Up @@ -2339,6 +2357,8 @@ mod test {
MZ_DEFAULT_WINDOW_BITS,
};
use crate::inflate::decompress_to_vec;
use std::prelude::v1::*;
use std::vec;

#[test]
fn u16_to_slice() {
Expand Down
6 changes: 5 additions & 1 deletion miniz_oxide/src/deflate/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! This module contains functionality for compression.

use alloc::vec;
use alloc::vec::Vec;

mod buffer;
pub mod core;
pub mod stream;
Expand Down Expand Up @@ -119,7 +122,7 @@ fn compress_to_vec_inner(input: &[u8], level: u8, window_bits: i32, strategy: i3
// The comp flags function sets the zlib flag if the window_bits parameter is > 0.
let flags = create_comp_flags_from_zip_params(level.into(), window_bits, strategy);
let mut compressor = CompressorOxide::new(flags);
let mut output = vec![0; std::cmp::max(input.len() / 2, 2)];
let mut output = vec![0; ::core::cmp::max(input.len() / 2, 2)];

let mut in_pos = 0;
let mut out_pos = 0;
Expand Down Expand Up @@ -157,6 +160,7 @@ fn compress_to_vec_inner(input: &[u8], level: u8, window_bits: i32, strategy: i3
mod test {
use super::{compress_to_vec, compress_to_vec_inner, CompressionStrategy};
use crate::inflate::decompress_to_vec;
use std::vec;

/// Test deflate example.
///
Expand Down
5 changes: 4 additions & 1 deletion miniz_oxide/src/deflate/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! As of now this is mainly inteded for use to build a higher-level wrapper.
//!
//! There is no DeflateState as the needed state is contained in the compressor struct itself.
use std::convert::{AsMut, AsRef};
use core::convert::{AsMut, AsRef};

use crate::deflate::core::{compress, CompressorOxide, TDEFLFlush, TDEFLStatus};
use crate::{MZError, MZFlush, MZStatus, StreamResult};
Expand Down Expand Up @@ -100,6 +100,9 @@ mod test {
use crate::deflate::CompressorOxide;
use crate::inflate::decompress_to_vec_zlib;
use crate::{MZFlush, MZStatus};
use std::prelude::v1::*;
use std::vec;

#[test]
fn test_state() {
let data = b"Hello zlib!";
Expand Down
Loading

0 comments on commit 7f5aedd

Please sign in to comment.