Skip to content

Commit 62923d3

Browse files
committed
new file: Encoding/lzih_file_compression.sf
1 parent 0d92178 commit 62923d3

7 files changed

+398
-264
lines changed

Encoding/huffman_coding.sf

+18-10
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,37 @@
22

33
# https://rosettacode.org/wiki/huffman_coding
44

5-
func walk(n, s, h) {
5+
func walk(Hash n, String s, Hash h) {
66
if (n.has(:a)) {
77
h{n{:a}} = s
88
printf("%3s: %s\n", n{:a}, s)
99
return nil
1010
}
11-
walk(n{:0}, s+'0', h)
12-
walk(n{:1}, s+'1', h)
11+
walk(n{:0}, s+'0', h) if n.has(:0)
12+
walk(n{:1}, s+'1', h) if n.has(:1)
1313
}
1414

15-
func make_tree(bytes) {
15+
func make_tree(Array bytes) {
1616

17-
var nodes = bytes.freq.kv.map_2d { |b,f|
17+
var nodes = bytes.freq.sort.map_2d { |b,f|
1818
Hash(a => b, freq => f)
1919
}
2020

21-
var n = Hash()
22-
while (nodes.sort_by!{|h| h{:freq} }.len > 1) {
23-
n = Hash(:0 => nodes.shift, :1 => nodes.shift)
24-
n{:freq} = (n{:0}{:freq} + n{:1}{:freq})
25-
nodes << n
21+
loop {
22+
nodes.sort_by!{|h| h{:freq} }
23+
var(x, y) = (nodes.shift, nodes.shift)
24+
if (defined(x)) {
25+
if (defined(y)) {
26+
nodes << Hash(:0 => x, :1 => y, :freq => x{:freq}+y{:freq})
27+
}
28+
else {
29+
nodes << Hash(:0 => x, :freq => x{:freq})
30+
}
31+
}
32+
nodes.len > 1 || break
2633
}
2734

35+
var n = nodes.first
2836
walk(n, '', n{:tree} = Hash())
2937
return n
3038
}

Encoding/huffman_file_compression.sf

+15-7
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ func walk(Hash n, String s, Hash h) {
1212
h{n{:a}} = s
1313
return nil
1414
}
15-
walk(n{:0}, s+'0', h)
16-
walk(n{:1}, s+'1', h)
15+
walk(n{:0}, s+'0', h) if n.has(:0)
16+
walk(n{:1}, s+'1', h) if n.has(:1)
1717
}
1818

1919
func make_tree(Array bytes) {
@@ -22,13 +22,21 @@ func make_tree(Array bytes) {
2222
Hash(a => b, freq => f)
2323
}
2424

25-
var n = Hash()
26-
while (nodes.sort_by!{|h| h{:freq} }.len > 1) {
27-
n = Hash(:0 => nodes.shift, :1 => nodes.shift)
28-
n{:freq} = (n{:0}{:freq} + n{:1}{:freq})
29-
nodes << n
25+
loop {
26+
nodes.sort_by!{|h| h{:freq} }
27+
var(x, y) = (nodes.shift, nodes.shift)
28+
if (defined(x)) {
29+
if (defined(y)) {
30+
nodes << Hash(:0 => x, :1 => y, :freq => x{:freq}+y{:freq})
31+
}
32+
else {
33+
nodes << Hash(:0 => x, :freq => x{:freq})
34+
}
35+
}
36+
nodes.len > 1 || break
3037
}
3138

39+
var n = nodes.first
3240
walk(n, '', n{:tree} = Hash())
3341
return n
3442
}

Encoding/lz77h_file_compression_v2.sf

-222
This file was deleted.

Encoding/lz77h_file_compression.sf renamed to Encoding/lzh_file_compression.sf

+21-13
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
#!/usr/bin/ruby
22

3-
# Encode and decode small files using LZ77 compression + Huffman coding.
3+
# Compress/decompress files using LZ77 compression + Huffman coding.
44

55
define(
66
CHUNK_SIZE = (1 << 16),
7-
SIGNATURE = ('LZ77H' + 1.chr)
7+
SIGNATURE = ('LZH' + 1.chr)
88
)
99

1010
func walk(Hash n, String s, Hash h) {
1111
if (n.has(:a)) {
1212
h{n{:a}} = s
1313
return nil
1414
}
15-
walk(n{:0}, s+'0', h)
16-
walk(n{:1}, s+'1', h)
15+
walk(n{:0}, s+'0', h) if n.has(:0)
16+
walk(n{:1}, s+'1', h) if n.has(:1)
1717
}
1818

1919
func make_tree(Array bytes) {
@@ -22,13 +22,21 @@ func make_tree(Array bytes) {
2222
Hash(a => b, freq => f)
2323
}
2424

25-
var n = Hash()
26-
while (nodes.sort_by!{|h| h{:freq} }.len > 1) {
27-
n = Hash(:0 => nodes.shift, :1 => nodes.shift)
28-
n{:freq} = (n{:0}{:freq} + n{:1}{:freq})
29-
nodes << n
25+
loop {
26+
nodes.sort_by!{|h| h{:freq} }
27+
var(x, y) = (nodes.shift, nodes.shift)
28+
if (defined(x)) {
29+
if (defined(y)) {
30+
nodes << Hash(:0 => x, :1 => y, :freq => x{:freq}+y{:freq})
31+
}
32+
else {
33+
nodes << Hash(:0 => x, :freq => x{:freq})
34+
}
35+
}
36+
nodes.len > 1 || break
3037
}
3138

39+
var n = nodes.first
3240
walk(n, '', n{:tree} = Hash())
3341
return n
3442
}
@@ -179,7 +187,7 @@ func lz77h_decompress_file(File input, File output) {
179187
var in_fh = input.open('<:raw') || die "Can't open file <<#{input}>> for reading"
180188

181189
if (SIGNATURE.len.of { in_fh.getc }.join != SIGNATURE) {
182-
die "Not a LZ77H archive!\n"
190+
die "Not a LZH archive!\n"
183191
}
184192

185193
var out_fh = output.open('>:raw') || die "Can't open file <<#{output}>> for writing"
@@ -212,9 +220,9 @@ var file = File(ARGV.shift) || do {
212220
Sys.exit(2)
213221
}
214222

215-
if (decode || file.match(/\.lz77h\.enc\z/)) {
216-
lz77h_decompress_file(file, File("output.lz77h.dec"))
223+
if (decode || file.match(/\.lzh\.enc\z/)) {
224+
lz77h_decompress_file(file, File("output.lzh.dec"))
217225
}
218226
else {
219-
lz77h_compress_file(file, File("output.lz77h.enc"))
227+
lz77h_compress_file(file, File("output.lzh.enc"))
220228
}

0 commit comments

Comments
 (0)