#!/usr/bin/env python
#
# Copyright (c) 2011, 2012, Simon Howard
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
#
# Convert -lz5- compressed data into -lzs- compressed data.
# -lzs- is generated by old versions of LArc, but I can't find
# any of these versions that actually generate it. This script
# therefore generates some -lzs- compressed data that can be
# used for testing purposes.
#

import sys

output_buffer = 0x00
output_buffer_bits = 0
output_pos = 2048 - 17

def output_bit(bit):
	global output_buffer, output_buffer_bits

	if bit != 0:
		output_buffer |= 1 << (7 - output_buffer_bits)

	output_buffer_bits += 1

	if output_buffer_bits >= 8:
		sys.stdout.write("%c" % output_buffer)
		output_buffer = 0
		output_buffer_bits = 0

def output_bits(val, bits):
	for i in range(bits):
		output_bit(val & (1 << (bits - 1 - i)))

def output_cmd_byte(b):
	global output_pos
	output_bit(1)
	output_bits(b, 8)
	output_pos += 1

def output_cmd_copy(distance, count):
	global output_pos

	pos = (output_pos - distance + 2048) % 2048
	output_bit(0)
	output_bits(pos, 11)
	output_bits(count - 2, 4)

	output_pos += count

history = [ ' ' ] * 4096
history_pos = 4096 - 18

def process_run():
	global history, history_pos

	bitmap = ord(sys.stdin.read(1))

	for i in range(8):
		if (bitmap & (1 << i)) != 0:
			b = sys.stdin.read(1)
			print >>sys.stderr, "byte: %s" % b
			history[history_pos] = b
			history_pos = (history_pos + 1) % 4096

			output_cmd_byte(ord(b))
		else:
			c = sys.stdin.read(2)
			pos = ord(c[0]) | ((ord(c[1]) & 0xf0) << 4)
			count = (ord(c[1]) & 0xf) + 3
			distance = history_pos - pos

			if pos > history_pos:
				distance = history_pos + 4096 - pos

			print >>sys.stderr, "copy: %i, %i" % (distance, count)

			for i in range(count):
				b = history[(pos + i) % 4096]
				print >> sys.stderr, "\t%s" % b
				history[history_pos] = b
				history_pos = (history_pos + 1) % 4096

			# Normally we can translate this to a -lzs- copy
			# command; however, if the distance to the copy
			# point is outside the -lzs- buffer size (> 2048),
			# translate the copy into a sequence of byte output
			# commands instead.

			if distance >= 2048:
				for i in range(count):
					b = history[(pos + i) % 4096]
					output_cmd_byte(ord(b))

			# Maximum size of a copy for -lz5- is 18 bytes, but
			# maximum for -lzs- is 17 bytes. If we get an 18
			# byte copy we therefore need to convert to 17
			# byte copy + single byte output.

			elif count == 18:

				b = history[(pos + 17) % 4096]
				print >>sys.stderr, "\tcopy too long (%i, %i): last char %s" % (pos, count, b)
				output_cmd_copy(distance, 17)
				output_cmd_byte(ord(b))
			else:
				output_cmd_copy(distance, count)


while True:
	try:
		process_run()
	except:
		break

# Flush out remaining bits.
output_bits(0, 7)

