Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
sile committed Oct 5, 2016
0 parents commit 42d3f22
Show file tree
Hide file tree
Showing 9 changed files with 508 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target
Cargo.lock
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "libflate"
version = "0.1.0"
authors = ["Takeru Ohta <[email protected]>"]

[dependencies]
byteorder = "*"
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
libflate
========

A Rust implementation of [DEFLATE](https://tools.ietf.org/html/rfc1951) algorithm.
69 changes: 69 additions & 0 deletions examples/gz_dec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
extern crate byteorder;
extern crate libflate;

use std::io;
use std::io::Read;
use byteorder::ReadBytesExt;
use byteorder::LittleEndian;

fn main() {
let mut reader = io::stdin();
let id1 = reader.read_u8().unwrap();
let id2 = reader.read_u8().unwrap();
let mode = reader.read_u8().unwrap();
let flag = reader.read_u8().unwrap();
let mtime = reader.read_u32::<LittleEndian>().unwrap();
let xfl = reader.read_u8().unwrap();
let os = reader.read_u8().unwrap();
if flag & 0b0001 != 0 {
panic!();
}
if flag & 0b0010 != 0 {
panic!();
}
if flag & 0b0100 != 0 {
panic!();
}
if flag & 0b1000 != 0 {
// FNAME
let mut name = String::new();
loop {
let b = reader.read_u8().unwrap();
if b == 0 {
break;
}
name.push(b as char);
}
println!("NAME: {}\n", name);
}
if flag & 0b10000 != 0 {
panic!();
}

println!("
# HEADER
- id1: {}
- id2: {}
- mode: {}
- flag: {}
- mtime: {}
- xfl: {}
- os: {}
",
id1,
id2,
mode,
flag,
mtime,
xfl,
os);

let mut dec = libflate::deflate::Decoder::new(reader);
let mut buf = Vec::new();
dec.read_to_end(&mut buf).unwrap();
println!("
# BODY
{}
",
String::from_utf8_lossy(&buf));
}
188 changes: 188 additions & 0 deletions src/deflate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
use std::io;
use std::io::Read;
use std::cmp;
use std::iter;
use byteorder::ReadBytesExt;

use huffman;

pub struct Decoder<R> {
reader: BitReader<R>,
block_buf: Vec<u8>,
block_offset: usize,
eos: bool,
}
impl<R> Decoder<R>
where R: Read
{
pub fn new(reader: R) -> Self {
Decoder {
reader: BitReader::new(reader),
block_buf: Vec::new(),
block_offset: 0,
eos: false,
}
}
pub fn into_reader(self) -> R {
self.reader.into_byte_reader()
}
fn read_non_compressed_block(&mut self) -> io::Result<()> {
let len = try!(self.reader.read_byte_aligned_u16());
let nlen = try!(self.reader.read_byte_aligned_u16());
if !len != nlen {
Err(io::Error::new(io::ErrorKind::InvalidData,
format!("LEN={} is not the one's complement of NLEN={}", len, nlen)))
} else {
self.block_buf.resize(len as usize, 0);
self.block_offset = 0;
try!(self.reader.byte_reader.read_exact(&mut self.block_buf));
Ok(())
}
}
fn read_compressed_block(&mut self, is_dynamic: bool) -> io::Result<()> {
let mut huffman = if is_dynamic {
let hlit = try!(self.reader.read_bits_u8(5)) as u16 + 257;
let hdist = try!(self.reader.read_bits_u8(5)) + 1;
let hclen = try!(self.reader.read_bits_u8(4)) + 4;

let mut hc = [0; 19];
let indices = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
for &i in indices.iter().take(hclen as usize) {
hc[i] = try!(self.reader.read_bits_u8(3));
}
println!("{:?}", hc);
let mut code_length_codes = huffman::Decoder2::from_lens(&hc[..]);

let mut lit_lens = Vec::with_capacity(hlit as usize);
while lit_lens.len() < hlit as usize {
let c = try!(code_length_codes.decode(&mut self.reader));
match c {
0...15 => {
lit_lens.push(c as u8);
}
16 => {
let count = try!(self.reader.read_bits_u8(2)) + 3;
let last = lit_lens.last().cloned().unwrap();
lit_lens.extend(iter::repeat(last).take(count as usize));
}
17 => {
let zeros = try!(self.reader.read_bits_u8(3)) + 3;
lit_lens.extend(iter::repeat(0).take(zeros as usize));
}
18 => {
let zeros = try!(self.reader.read_bits_u8(7)) + 11;
lit_lens.extend(iter::repeat(0).take(zeros as usize));
}
_ => unreachable!(),
}
}
println!("{:?}", lit_lens);
let mut lite_codes = huffman::Decoder2::from_lens(&lit_lens[..]);

panic!("# {}, {}, {}", hlit, hdist, hclen);
} else {
huffman::Decoder::new_fixed()
};
loop {
let s = try!(huffman.decode_one(&mut self.reader));
println!("SYM: {:?}", s);
}
panic!()
}
}
impl<R> Read for Decoder<R>
where R: Read
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.block_offset < self.block_buf.len() {
let copy_size = cmp::min(buf.len(), self.block_buf.len() - self.block_offset);
buf[..copy_size].copy_from_slice(&self.block_buf[self.block_offset..][..copy_size]);
self.block_offset += copy_size;
Ok(copy_size)
} else if self.eos {
Ok(0)
} else {
let bfinal = try!(self.reader.read_bit());
let btype = try!(self.reader.read_bits_u8(2));
println!("BFINAL: {}", bfinal);
self.eos = bfinal;
match btype {
0b00 => {
try!(self.read_non_compressed_block());
self.read(buf)
}
0b01 => {
try!(self.read_compressed_block(false));
self.read(buf)
}
0b10 => {
try!(self.read_compressed_block(true));
self.read(buf)
}
0b11 => {
Err(io::Error::new(io::ErrorKind::InvalidData,
"btype 0x11 of DEFLATE is reserved(error) value"))
}
_ => unreachable!(),
}
}
}
}

pub struct BitReader<R> {
byte_reader: R,
last_byte: u8,
offset: usize,
}
impl<R> BitReader<R>
where R: Read
{
pub fn new(byte_reader: R) -> Self {
BitReader {
byte_reader: byte_reader,
last_byte: 0,
offset: 8,
}
}
pub fn into_byte_reader(self) -> R {
self.byte_reader
}
pub fn read_bit(&mut self) -> io::Result<bool> {
if self.offset == 8 {
self.last_byte = try!(self.byte_reader.read_u8());
self.offset = 0;
}
let bit = (self.last_byte & (1 << self.offset)) != 0;
self.offset += 1;
Ok(bit)
}
pub fn read_bits_u8(&mut self, bits: usize) -> io::Result<u8> {
assert!(bits <= 8);
// TODO: optimize
let mut n = 0;
for i in 0..bits {
let bit = try!(self.read_bit());
n |= (bit as u8) << i;
}
Ok(n)
}
pub fn read_bits_u16(&mut self, bits: usize) -> io::Result<u16> {
assert!(bits <= 16);
// TODO: optimize
let mut n = 0;
for i in 0..bits {
let bit = try!(self.read_bit());
n |= (bit as u16) << i;
}
Ok(n)
}
pub fn read_byte_aligned_u16(&mut self) -> io::Result<u16> {
if self.offset != 0 {
self.last_byte = try!(self.byte_reader.read_u8());
}
self.offset = 8;
let low = self.last_byte as u16;
let high = try!(self.byte_reader.read_u8()) as u16;
Ok((high << 8) | low)
}
}
1 change: 1 addition & 0 deletions src/gzip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading

0 comments on commit 42d3f22

Please sign in to comment.