Skip to content

Commit 1364f41

Browse files
committed
Add initial implementation of Huffman coding
0 parents  commit 1364f41

File tree

6 files changed

+470
-0
lines changed

6 files changed

+470
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
target
2+
.idea/
3+
*.iml
4+
Cargo.lock

Cargo.toml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "huffman"
3+
version = "0.1.0"
4+
authors = ["WanzenBug <[email protected]>"]
5+
6+
[lib]
7+
name = "huffman"
8+
path = "src/lib.rs"
9+
10+
[[bin]]
11+
name = "encode"
12+
path = "src/bin/encode.rs"
13+
14+
[[bin]]
15+
name = "decode"
16+
path = "src/bin/decode.rs"
17+
18+
[dependencies]
19+
bitstream-rs = "0.1.2"
20+
bit-vec = "0.4.3"
21+
clap = "2.20.0"

src/bin/decode.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
extern crate huffman;
2+
extern crate clap;
3+
4+
mod util;
5+
6+
use std::fs::File;
7+
use std::io::{copy, BufReader, BufWriter, Write};
8+
use huffman::{HuffmanReader};
9+
use clap::{App, Arg};
10+
11+
fn main() {
12+
let matches = App::new("Huffman decoder")
13+
.version("0.1")
14+
.author("Moritz Wanzenböck <[email protected]>")
15+
.about("Decompress files using pure Huffman coding")
16+
.arg(Arg::with_name("INPUT")
17+
.required(true)
18+
.help("Sets the input file to use")
19+
.index(1))
20+
.arg(Arg::with_name("OUTPUT")
21+
.required(true)
22+
.help("Sets the output file to use")
23+
.index(2))
24+
.arg(Arg::with_name("verbose")
25+
.short("v")
26+
.help("Sets verbose output"))
27+
.get_matches();
28+
29+
let infile = matches.value_of("INPUT").and_then(|file| File::open(file).ok()).expect("Input: No such file");
30+
let outfile = matches.value_of("OUTPUT").and_then(|file| File::create(file).ok()).expect("Output: Could not create file");
31+
let mut read = util::StatsReader::new(BufReader::new(infile));
32+
let mut write = util::StatsWriter::new(BufWriter::new(outfile));
33+
{
34+
let mut reader = HuffmanReader::new(&mut read).expect("Could not read huffman table");
35+
copy(&mut reader, &mut write).expect("Something went wrong while encoding");
36+
}
37+
if matches.is_present("verbose") {
38+
write.flush().expect("Flush failed");
39+
let written = write.get_stats().processed;
40+
let read = read.get_stats().processed;
41+
42+
println!("Read: {} bytes", read);
43+
println!("Written: {} bytes", written);
44+
}
45+
}

src/bin/encode.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
extern crate huffman;
2+
extern crate clap;
3+
4+
mod util;
5+
6+
use std::fs::File;
7+
use std::io::{copy, BufReader, BufWriter, Write, Read, Cursor};
8+
use huffman::{HuffmanWriter, HuffmanTree};
9+
use clap::{App, Arg};
10+
11+
fn main() {
12+
let matches = App::new("Huffman encoder")
13+
.version("0.1")
14+
.author("Moritz Wanzenböck <[email protected]>")
15+
.about("Compresses files using pure Huffman coding")
16+
.arg(Arg::with_name("INPUT")
17+
.required(true)
18+
.help("Sets the input file to use")
19+
.index(1))
20+
.arg(Arg::with_name("OUTPUT")
21+
.required(true)
22+
.help("Sets the output file to use")
23+
.index(2))
24+
.arg(Arg::with_name("verbose")
25+
.short("v")
26+
.help("Sets verbose output"))
27+
.get_matches();
28+
29+
let infile = matches.value_of("INPUT").and_then(|file| File::open(file).ok()).expect("Input: No such file");
30+
let outfile = matches.value_of("OUTPUT").and_then(|file| File::create(file).ok()).expect("Output: Could not create file");
31+
let mut read = util::StatsReader::new(BufReader::new(infile));
32+
let mut write = util::StatsWriter::new(BufWriter::new(outfile));
33+
{
34+
let mut vec = Vec::new();
35+
read.read_to_end(&mut vec).expect("Error reading input");
36+
let tree = HuffmanTree::new(&vec[..]);
37+
let mut encoder = HuffmanWriter::new(&mut write, &tree).expect("Could not write huffman table");
38+
let mut read_vec = Cursor::new(vec);
39+
copy(&mut read_vec, &mut encoder).expect("Something went wrong while decoding");
40+
}
41+
if matches.is_present("verbose") {
42+
write.flush().expect("Flush failed");
43+
let written = write.get_stats().processed;
44+
let read = read.get_stats().processed;
45+
46+
println!("Read: {} bytes", read);
47+
println!("Written: {} bytes", written);
48+
}
49+
}

src/bin/util.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use std::io::{Read, Write, Result};
2+
3+
pub struct StatsReader<R> where R: Read {
4+
inner: R,
5+
read_bytes: usize,
6+
}
7+
8+
pub struct StatsWriter<W> where W: Write {
9+
inner: W,
10+
written_bytes: usize,
11+
}
12+
13+
pub struct Stats {
14+
pub processed: usize,
15+
}
16+
17+
impl<R> StatsReader<R> where R: Read {
18+
pub fn new(reader: R) -> Self {
19+
StatsReader {
20+
inner: reader,
21+
read_bytes: 0
22+
}
23+
}
24+
25+
pub fn get_stats(&self) -> Stats {
26+
Stats {
27+
processed: self.read_bytes
28+
}
29+
}
30+
}
31+
32+
impl<W> StatsWriter<W> where W: Write {
33+
pub fn new(writer: W) -> Self {
34+
StatsWriter {
35+
inner: writer,
36+
written_bytes: 0,
37+
}
38+
}
39+
40+
pub fn get_stats(&self) -> Stats {
41+
Stats {
42+
processed: self.written_bytes,
43+
}
44+
}
45+
}
46+
47+
impl<R> Read for StatsReader<R> where R: Read {
48+
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
49+
let n = self.inner.read(buf)?;
50+
self.read_bytes += n;
51+
Ok(n)
52+
}
53+
}
54+
55+
impl<W> Write for StatsWriter<W> where W: Write {
56+
fn write(&mut self, buf: &[u8]) -> Result<usize> {
57+
let n = self.inner.write(buf)?;
58+
self.written_bytes += n;
59+
Ok(n)
60+
}
61+
62+
fn flush(&mut self) -> Result<()> {
63+
self.inner.flush()
64+
}
65+
}

0 commit comments

Comments
 (0)