123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- #!/usr/bin/ruby
- # Encode and decode small files using LZ77 compression.
- define(
- CHUNK_SIZE = (1 << 16),
- SIGNATURE = ('LZ77' + 2.chr)
- )
- func lz77_compress (str) {
- var la = 0
- var compressed_data = []
- var prefix = ''
- var chars = str.chars
- var end = chars.end
- while (la <= end) {
- var n = 1
- var p = 0
- var token = chars[la]
- while ((n < 255) && (la+n <= end) && ((var tmp = prefix.index(token, p)) >= 0)) {
- p = tmp
- token += chars[la + n]
- ++n
- }
- --n
- compressed_data << (p, n, chars[la+n])
- la += n+1
- prefix += token
- }
- return pack('(SCa)*', compressed_data...)
- }
- # Compress file
- func lz77_compress_file(File input, File output) {
- var in_fh = input.open('<:raw') || die "Can't open file <<#{input}>> for reading"
- var out_fh = output.open('>:raw') || die "Can't open file <<#{output}>> for writing"
- var header = SIGNATURE
- # Print the header
- out_fh.print(header)
- # Compress data
- while (in_fh.read(\var chunk, CHUNK_SIZE)) {
- out_fh.print(lz77_compress(chunk))
- }
- # Close the files
- in_fh.close
- out_fh.close
- }
- # Decompress file
- func lz77_decompress_file(File input, File output) {
- var in_fh = input.open('<:raw') || die "Can't open file <<#{input}>> for reading"
- if (SIGNATURE.len.of { in_fh.getc }.join != SIGNATURE) {
- die "Not a LZ77 archive!\n"
- }
- var out_fh = output.open('>:raw') || die "Can't open file <<#{output}>> for writing"
- var chunk = ''
- while (in_fh.read(\var data, 4*CHUNK_SIZE)) {
- ['(SCa)*'.unpack(data)].each_slice(3, {|s,l,c|
- chunk += (chunk.substr(s, l) + c)
- if (chunk.len >= CHUNK_SIZE) {
- out_fh.print(chunk)
- chunk = ''
- }
- })
- }
- out_fh.print(chunk)
- in_fh.close
- out_fh.close
- }
- ARGV.getopt!('d', \var decode)
- var file = File(ARGV.shift) || do {
- say "usage: #{File(__MAIN__).basename} [-d] [input file]"
- Sys.exit(2)
- }
- if (decode || file.match(/\.lz77\.enc\z/)) {
- lz77_decompress_file(file, File("output.lz77.dec"))
- }
- else {
- lz77_compress_file(file, File("output.lz77.enc"))
- }
|