#![cfg(test)]
use core;
use super::{s16, v8};
extern crate alloc_no_stdlib;
extern crate brotli_decompressor;
use super::cluster::HistogramPair;
use super::ZopfliNode;
use super::encode::{BrotliEncoderCreateInstance, BrotliEncoderSetParameter,
BrotliEncoderDestroyInstance, BrotliEncoderIsFinished,
BrotliEncoderCompressStream, BrotliEncoderParameter, BrotliEncoderOperation};
use super::histogram::{ContextType, HistogramLiteral, HistogramCommand, HistogramDistance};
use super::super::alloc::{AllocatedStackMemory, Allocator, SliceWrapper, SliceWrapperMut,
StackAllocator, bzero};
use enc::util::brotli_min_size_t;
use super::StaticCommand;
extern "C" {
fn calloc(n_elem: usize, el_size: usize) -> *mut u8;
}
extern "C" {
fn free(ptr: *mut u8);
}
use super::pdf::PDF;
use super::command::Command;
use super::entropy_encode::HuffmanTree;
use super::combined_alloc::CombiningAllocator;
pub use super::super::{BrotliDecompressStream, BrotliResult, BrotliState};
use brotli_decompressor::HuffmanCode;
use core::ops;
use super::interface;
declare_stack_allocator_struct!(MemPool, 128, stack);
declare_stack_allocator_struct!(CallocatedFreelist4096, 128, calloc);
declare_stack_allocator_struct!(CallocatedFreelist2048, 64, calloc);
declare_stack_allocator_struct!(CallocatedFreelist1024, 32, calloc);
fn oneshot_compress(input: &[u8],
output: &mut [u8],
quality: u32,
lgwin: u32,
magic: bool,
in_batch_size: usize,
out_batch_size: usize)
-> (i32, usize) {
let stack_u8_buffer =
unsafe { define_allocator_memory_pool!(96, u8, [0; 24 * 1024 * 1024], calloc) };
let stack_u16_buffer =
unsafe { define_allocator_memory_pool!(96, u16, [0; 128 * 1024], calloc) };
let stack_i32_buffer =
unsafe { define_allocator_memory_pool!(96, i32, [0; 128 * 1024], calloc) };
let stack_u32_buffer =
unsafe { define_allocator_memory_pool!(96, u32, [0; 32 * 1024 * 1024], calloc) };
let stack_u64_buffer =
unsafe { define_allocator_memory_pool!(96, u64, [0; 32 * 1024], calloc) };
let stack_f64_buffer =
unsafe { define_allocator_memory_pool!(48, super::util::floatX, [0; 128 * 1024], calloc) };
let stack_f8_buffer =
unsafe { define_allocator_memory_pool!(48, v8, [0; 128 * 1024], calloc) };
let stack_16x16_buffer =
unsafe { define_allocator_memory_pool!(48, s16, [0; 128 * 1024], calloc) };
let stack_hl_buffer =
unsafe { define_allocator_memory_pool!(48, HistogramLiteral, [0; 128 * 1024], calloc) };
let stack_hc_buffer =
unsafe { define_allocator_memory_pool!(48, HistogramCommand, [0; 128 * 1024], calloc) };
let stack_hd_buffer =
unsafe { define_allocator_memory_pool!(48, HistogramDistance, [0; 128 * 1024], calloc) };
let stack_hp_buffer =
unsafe { define_allocator_memory_pool!(48, HistogramPair, [0; 128 * 1024], calloc) };
let stack_ct_buffer =
unsafe { define_allocator_memory_pool!(48, ContextType, [0; 128 * 1024], calloc) };
let stack_ht_buffer =
unsafe { define_allocator_memory_pool!(48, HuffmanTree, [0; 128 * 1024], calloc) };
let stack_zn_buffer =
unsafe { define_allocator_memory_pool!(48, ZopfliNode, [0; 1024], calloc) };
let stack_mc_buffer =
unsafe { define_allocator_memory_pool!(48, Command, [0; 128 * 1024], calloc) };
let stack_pdf_buffer =
unsafe { define_allocator_memory_pool!(48, PDF, [0; 1], calloc) };
let stack_sc_buffer =
unsafe { define_allocator_memory_pool!(48, StaticCommand, [0; 100], calloc) };
let stack_u8_allocator = CallocatedFreelist4096::<u8>::new_allocator(stack_u8_buffer.data, bzero);
let stack_u16_allocator = CallocatedFreelist4096::<u16>::new_allocator(stack_u16_buffer.data,
bzero);
let stack_i32_allocator = CallocatedFreelist1024::<i32>::new_allocator(stack_i32_buffer.data,
bzero);
let stack_u32_allocator = CallocatedFreelist4096::<u32>::new_allocator(stack_u32_buffer.data,
bzero);
let stack_u64_allocator = CallocatedFreelist1024::<u64>::new_allocator(stack_u64_buffer.data,
bzero);
let stack_zn_allocator = CallocatedFreelist1024::<ZopfliNode>::new_allocator(stack_zn_buffer.data,
bzero);
let mf64 = CallocatedFreelist2048::<super::util::floatX>::new_allocator(stack_f64_buffer.data, bzero);
let mf8 = CallocatedFreelist2048::<v8>::new_allocator(stack_f8_buffer.data, bzero);
let m16x16 = CallocatedFreelist2048::<s16>::new_allocator(stack_16x16_buffer.data, bzero);
let mpdf = CallocatedFreelist2048::<PDF>::new_allocator(stack_pdf_buffer.data, bzero);
let msc = CallocatedFreelist2048::<StaticCommand>::new_allocator(stack_sc_buffer.data, bzero);
let stack_mc_allocator = CallocatedFreelist2048::<Command>::new_allocator(stack_mc_buffer.data,
bzero);
let mhl = CallocatedFreelist2048::<HistogramLiteral>::new_allocator(stack_hl_buffer.data,
bzero);
let mhc = CallocatedFreelist2048::<HistogramCommand>::new_allocator(stack_hc_buffer.data,
bzero);
let mhd = CallocatedFreelist2048::<HistogramDistance>::new_allocator(stack_hd_buffer.data,
bzero);
let mhp = CallocatedFreelist2048::<HistogramPair>::new_allocator(stack_hp_buffer.data, bzero);
let mct = CallocatedFreelist2048::<ContextType>::new_allocator(stack_ct_buffer.data, bzero);
let mht = CallocatedFreelist2048::<HuffmanTree>::new_allocator(stack_ht_buffer.data, bzero);
let mut s_orig = BrotliEncoderCreateInstance(CombiningAllocator::new(
stack_u8_allocator,
stack_u16_allocator,
stack_i32_allocator,
stack_u32_allocator,
stack_u64_allocator,
stack_mc_allocator,
mf64,
mf8,
m16x16,
mpdf,
msc,
mhl,
mhc,
mhd,
mhp,
mct,
mht,
stack_zn_allocator,
));
let mut next_in_offset: usize = 0;
let mut next_out_offset: usize = 0;
{
let s = &mut s_orig;
BrotliEncoderSetParameter(s,
BrotliEncoderParameter::BROTLI_PARAM_QUALITY,
quality as (u32));
if magic {
BrotliEncoderSetParameter(s,
BrotliEncoderParameter::BROTLI_PARAM_MAGIC_NUMBER,
magic as (u32));
}
if quality >= 10 {
BrotliEncoderSetParameter(s,
BrotliEncoderParameter::BROTLI_PARAM_Q9_5,
1);
}
BrotliEncoderSetParameter(s,
BrotliEncoderParameter::BROTLI_PARAM_LGWIN,
lgwin as (u32));
BrotliEncoderSetParameter(s, BrotliEncoderParameter::BROTLI_PARAM_MODE, 0 as (u32)); BrotliEncoderSetParameter(s,
BrotliEncoderParameter::BROTLI_PARAM_SIZE_HINT,
input.len() as (u32));
loop {
let mut available_in: usize = brotli_min_size_t(input.len() - next_in_offset, in_batch_size);
let mut available_out: usize = brotli_min_size_t(output.len() - next_out_offset,
out_batch_size);
if available_out == 0 {
panic!("No output buffer space");
}
let mut total_out = Some(0usize);
let op: BrotliEncoderOperation;
if available_in == input.len() - next_in_offset {
op = BrotliEncoderOperation::BROTLI_OPERATION_FINISH;
} else {
op = BrotliEncoderOperation::BROTLI_OPERATION_PROCESS;
}
let mut nop_callback = |_data:&mut interface::PredictionModeContextMap<interface::InputReferenceMut>,
_cmds: &mut [interface::StaticCommand],
_mb: interface::InputPair,
_mfv:&mut CombiningAllocator<_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_>|();
let result = BrotliEncoderCompressStream(s,
op,
&mut available_in,
input,
&mut next_in_offset,
&mut available_out,
output,
&mut next_out_offset,
&mut total_out,
&mut nop_callback);
if result <= 0 {
return (result, next_out_offset);
}
if BrotliEncoderIsFinished(s) != 0 {
break;
}
}
BrotliEncoderDestroyInstance(s);
}
return (1, next_out_offset);
}
fn oneshot_decompress(compressed: &[u8], mut output: &mut [u8]) -> (BrotliResult, usize, usize) {
let mut available_in: usize = compressed.len();
let mut available_out: usize = output.len();
let mut stack_u8_buffer = define_allocator_memory_pool!(128, u8, [0; 100 * 1024], stack);
let mut stack_u32_buffer = define_allocator_memory_pool!(128, u32, [0; 36 * 1024], stack);
let mut stack_hc_buffer = define_allocator_memory_pool!(128,
HuffmanCode,
[HuffmanCode::default(); 116 * 1024],
stack);
let stack_u8_allocator = MemPool::<u8>::new_allocator(&mut stack_u8_buffer, bzero);
let stack_u32_allocator = MemPool::<u32>::new_allocator(&mut stack_u32_buffer, bzero);
let stack_hc_allocator = MemPool::<HuffmanCode>::new_allocator(&mut stack_hc_buffer, bzero);
let mut input_offset: usize = 0;
let mut output_offset: usize = 0;
let mut written: usize = 0;
let mut brotli_state =
BrotliState::new(stack_u8_allocator, stack_u32_allocator, stack_hc_allocator);
let result = BrotliDecompressStream(&mut available_in,
&mut input_offset,
&compressed[..],
&mut available_out,
&mut output_offset,
&mut output,
&mut written,
&mut brotli_state);
brotli_state.BrotliStateCleanup();
return (result, input_offset, output_offset);
}
fn oneshot(input: &[u8],
compressed: &mut [u8],
output: &mut [u8],
q: u32,
lg: u32,
magic: bool,
in_buffer_size: usize,
out_buffer_size: usize)
-> (BrotliResult, usize, usize) {
let (success, mut available_in) =
oneshot_compress(input, compressed, q, lg, magic, in_buffer_size, out_buffer_size);
if success == 0 {
available_in = compressed.len();
}
return oneshot_decompress(&mut compressed[..available_in], output);
}
#[test]
fn test_roundtrip_10x10y() {
const BUFFER_SIZE: usize = 128;
let mut compressed: [u8; 13] = [0; 13];
let mut output = [0u8; BUFFER_SIZE];
let mut input = ['x' as u8, 'x' as u8, 'x' as u8, 'x' as u8, 'x' as u8, 'x' as u8, 'x' as u8,
'x' as u8, 'x' as u8, 'x' as u8, 'y' as u8, 'y' as u8, 'y' as u8, 'y' as u8,
'y' as u8, 'y' as u8, 'y' as u8, 'y' as u8, 'y' as u8, 'y' as u8];
let (result, compressed_offset, output_offset) = oneshot(&mut input[..],
&mut compressed,
&mut output[..],
9,
10,
false,
1,
1);
match result {
BrotliResult::ResultSuccess => {}
_ => assert!(false),
}
let mut i: usize = 0;
while i < 10 {
assert_eq!(output[i], 'x' as u8);
assert_eq!(output[i + 10], 'y' as u8);
i += 1;
}
assert_eq!(output_offset, 20);
assert_eq!(compressed_offset, compressed.len());
}
macro_rules! test_roundtrip_file {
($filedata : expr, $bufsize: expr, $quality: expr, $lgwin: expr, $magic: expr, $in_buf:expr, $out_buf:expr) => {{
let stack_u8_buffer = unsafe{define_allocator_memory_pool!(4096, u8, [0; 18 * 1024 * 1024], calloc)};
let mut stack_u8_allocator = CallocatedFreelist4096::<u8>::new_allocator(stack_u8_buffer.data, bzero);
let mut compressed = stack_u8_allocator.alloc_cell($bufsize);
let inp = $filedata;
let mut output = stack_u8_allocator.alloc_cell(inp.len() + 16);
let (result, compressed_offset, output_offset) = oneshot(&inp[..],
compressed.slice_mut(),
output.slice_mut(),
$quality,
$lgwin,
$magic,
$in_buf,
$out_buf);
match result {
BrotliResult::ResultSuccess => {}
_ => assert!(false),
}
for i in 0..inp.len() {
if inp[i] != output[i] {
assert_eq!((i,inp[i]), (i,output[i]));
}
assert_eq!(inp[i], output[i]);
}
assert!(compressed_offset <= compressed.slice().len());
assert_eq!(output_offset, inp.len());
stack_u8_allocator.free_cell(output);
stack_u8_allocator.free_cell(compressed);
}};
}
#[test]
fn test_roundtrip_64x() {
test_roundtrip_file!(include_bytes!("../../testdata/64x"), 72, 9, 10, false, 3, 2);
}
#[test]
fn test_roundtrip_ukkonooa() {
test_roundtrip_file!(include_bytes!("../../testdata/ukkonooa"), 82, 9, 10, true, 3, 2);
}
#[test]
fn test_roundtrip_backward65536() {
test_roundtrip_file!(include_bytes!("../../testdata/backward65536"), 72000, 9, 10, false, 3, 2);
}
#[test]
fn test_roundtrip_aaabaaaa() {
test_roundtrip_file!(include_bytes!("../../testdata/aaabaaaa"), 72000, 9, 10, true, 3, 2);
}
#[test]
fn test_roundtrip_monkey() {
test_roundtrip_file!(include_bytes!("../../testdata/monkey"), 72000, 9, 10, false, 16, 15);
}
#[test]
fn test_roundtrip_quickfox_repeated() {
test_roundtrip_file!(include_bytes!("../../testdata/quickfox_repeated"), 16384, 9, 10, true, 257, 255);
}
#[test]
fn test_roundtrip_asyoulik() {
test_roundtrip_file!(include_bytes!("../../testdata/asyoulik.txt"), 64384, 9, 15, false, 513, 511);
}
#[test]
fn test_roundtrip_asyoulik9_5() {
test_roundtrip_file!(include_bytes!("../../testdata/asyoulik.txt"), 62384, 10, 15, true, 513, 511);
}
#[test]
fn test_roundtrip_compressed() {
test_roundtrip_file!(include_bytes!("../../testdata/compressed_file"), 50400, 9, 10, false, 1025, 1024);
}
#[test]
fn test_roundtrip_compressed_repeated() {
test_roundtrip_file!(include_bytes!("../../testdata/compressed_repeated"),
120000,
9,
16,
false,
2049,
2047);
}
#[test]
fn test_roundtrip_first_58_bytes_alice() {
test_roundtrip_file!(&include_bytes!("../../testdata/alice29.txt")[..58], 50400, 2, 10, true, 1, 2);
}
#[test]
fn test_roundtrip_first_2_bytes_alice() {
test_roundtrip_file!(&include_bytes!("../../testdata/alice29.txt")[..2], 50400, 2, 10, true, 1, 2);
}
#[test]
fn test_roundtrip_quickfox() {
test_roundtrip_file!(include_bytes!("../../testdata/quickfox"), 256, 9, 10, false, 1, 2);
}
#[test]
fn test_roundtrip_x() {
const BUFFER_SIZE: usize = 16384;
let mut compressed: [u8; 6] = [0x0b, 0x00, 0x80, 0x58, 0x03, 0];
let mut output = [0u8; BUFFER_SIZE];
let mut input = ['X' as u8];
let (result, compressed_offset, output_offset) = oneshot(&mut input[..],
&mut compressed[..],
&mut output[..],
9,
10,
false,
1,
2);
match result {
BrotliResult::ResultSuccess => {}
_ => assert!(false),
}
assert_eq!(output[0], 'X' as u8);
assert_eq!(output_offset, 1);
assert_eq!(compressed_offset, compressed.len());
}
#[test]
fn test_roundtrip_empty() {
let mut compressed: [u8; 2] = [0x06, 0];
let mut output = [0u8; 1];
let (result, compressed_offset, output_offset) =
oneshot(&mut [], &mut compressed[..], &mut output[..], 9, 10, false, 2, 3);
match result {
BrotliResult::ResultSuccess => {}
_ => assert!(false),
}
assert_eq!(output_offset, 0);
assert_eq!(compressed_offset, compressed.len());
}