1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
//! Rust binding to the [zstd library][zstd].
//!
//! This crate provides:
//!
//! * An [encoder](struct.Encoder.html) to compress data using zstd
//!   and send the output to another write.
//! * A [decoder](struct.Decoder.html) to read input data from a `Read`
//!   and decompress it.
//!
//! # Example
//!
//! ```rust
//! extern crate zstd;
//!
//! use std::io;
//!
//! fn main() {
//! 	// Uncompress input and print the result.
//! 	let mut decoder = zstd::Decoder::new(io::stdin()).unwrap();
//! 	io::copy(&mut decoder, &mut io::stdout()).unwrap();
//! }
//! ```
//!
//! [zstd]: https://github.com/Cyan4973/zstd
extern crate libc;

mod ll;
mod encoder;
mod decoder;
pub mod dict;

pub use encoder::Encoder;
pub use decoder::Decoder;

use std::io;


/// Compress a single block of data to the given destination buffer.
///
/// Returns the number of bytes written, or an error if something happened
/// (for instance if the destination buffer was too small).
pub fn compress(destination: &mut [u8], source: &[u8], level: i32) -> io::Result<usize> {
    let code = unsafe {
        ll::ZSTD_compress(destination.as_mut_ptr(),
                          destination.len(),
                          source.as_ptr(),
                          source.len(),
                          level)
    };
    ll::parse_code(code)
}

/// Compress a block of data, and return the compressed result in a `Vec<u8>`.
pub fn compress_to_vec(data: &[u8], level: i32) -> io::Result<Vec<u8>> {
    let buffer_len = unsafe { ll::ZSTD_compressBound(data.len()) };
    let mut buffer = Vec::with_capacity(buffer_len);

    unsafe {
        // Use all capacity. Memory may not be initialized, but we won't read it.
        buffer.set_len(buffer_len);
        let len = try!(compress(&mut buffer[..], data, level));
        buffer.set_len(len);
    }
    Ok(buffer)
}

/// Deompress a single block of data to the given destination buffer.
///
/// Returns the number of bytes written, or an error if something happened
/// (for instance if the destination buffer was too small).
pub fn decompress(destination: &mut [u8], source: &[u8]) -> io::Result<usize> {
    let code = unsafe {
        ll::ZSTD_decompress(destination.as_mut_ptr(),
                            destination.len(),
                            source.as_ptr(),
                            source.len())
    };
    ll::parse_code(code)
}

/// Decompress a block of data, and return the decompressed result in a `Vec<u8>`.
///
/// The decompressed data should be less than `capacity` bytes,
/// or an error will be returned.
pub fn decompress_to_vec(data: &[u8], capacity: usize) -> io::Result<Vec<u8>> {
    let mut buffer = Vec::with_capacity(capacity);
    unsafe {
        buffer.set_len(capacity);
        let len = try!(decompress(&mut buffer[..], data));
        buffer.set_len(len);
    }
    Ok(buffer)
}

#[test]
fn test_cycle() {
    use std::io::{Read, Write};
    let text = "This is a sample text. It is not meant to be interesting or anything. Just text, \
                nothing more. Don't expect too much from it.";

    let buffer: Vec<u8> = Vec::new();

    let mut encoder = Encoder::new(buffer, 1).unwrap();
    encoder.write_all(text.as_bytes()).unwrap();
    let buffer = encoder.finish().unwrap();

    let mut decoder = Decoder::new(&buffer[..]).unwrap();
    let mut result = String::new();
    decoder.read_to_string(&mut result).unwrap();

    assert_eq!(text, &result);
}

#[test]
fn test_direct() {
    let text = "Pork belly art party wolf XOXO, neutra scenester ugh thundercats tattooed squid \
                skateboard beard readymade kogi. VHS cardigan schlitz, meditation chartreuse kogi \
                tilde church-key. Actually direct trade hammock, aesthetic VHS semiotics organic \
                narwhal lo-fi heirloom flexitarian master cleanse polaroid man bun. Flannel \
                helvetica mustache, bicycle rights small batch slow-carb neutra tilde \
                williamsburg meh poutine humblebrag. Four dollar toast butcher actually franzen, \
                gastropub mustache tofu cardigan. 90's fingerstache forage brooklyn meditation \
                single-origin coffee tofu actually, ramps pabst farm-to-table art party kombucha \
                artisan fanny pack. Flannel salvia ennui viral leggings selfies.";

    let compressed = compress_to_vec(text.as_bytes(), 1).unwrap();

    let uncompressed = decompress_to_vec(&compressed, text.len()).unwrap();

    assert_eq!(text.as_bytes(), &uncompressed[..]);
}