/*	
 *	cliplzss.c
 *
 *	LZSS展開ルーチン
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2009 Naoyuki Sawa
 *
 *	* Thu Sep 10 00:42:56 JST 2009 Naoyuki Sawa
 *	- 新規作成。
 */
#include "clip.h"

/****************************************************************************
 *	
 ****************************************************************************/

int
lzss_uncompress1(void* _dst_data/*[dst_lim]*/, int dst_lim, const void* _src_data/*[src_len]*/, int src_len)
{
	      unsigned char* dst_data = _dst_data;
	const unsigned char* src_data = _src_data;

	/*{{この範囲は、lzss_uncompress1とlzss_uncompress2とで、ほぼ共通の処理*/
	int flag_mask = 0;
	int flag = 0;
	int dst_len = 0;
	int src_pos = 0;
	int hdr;
	int len;
	int dist;
	int pos;
	while(src_pos < src_len) {
		/* フラグを取得する */
		if(!flag_mask) {
			flag_mask = 1 << 7;	/*{{lzss_uncompress1とlzss_uncompress2とで、違うのはここだけ}}*/
			flag = src_data[src_pos++];
		}
		/* 圧縮コードの場合 */
		if(!(flag & flag_mask)) {
			/* 圧縮コード {(match_dist-1),(match_len-2)} を取得する */
			hdr = src_data[src_pos++];
			len = (hdr & 15) + 2;
			dist = (hdr >> 4) + 1;
			/* 圧縮コードを展開する */
			pos = dst_len - dist;
			do {
				if(dst_len < dst_lim) {
					dst_data[dst_len] = dst_data[pos];
				}
				dst_len++;
				pos++;
			} while(--len);
		/* 無圧縮コードの場合 */
		} else {
			/* 無圧縮コードを出力する */
			if(dst_len < dst_lim) {
				dst_data[dst_len] = src_data[src_pos];
			}
			dst_len++;
			src_pos++;
		}
		/* フラグビット位置を進める */
		flag_mask >>= 1;
	}
	/*}}この範囲は、lzss_uncompress1とlzss_uncompress2とで、ほぼ共通の処理*/

	return dst_len;
}

/*--------------------------------------------------------------------------*/

int
lzss_uncompress2(void* _dst_data/*[dst_lim]*/, int _dst_lim, const void* _src_data/*[src_len]*/, int _src_len)
{
	      unsigned short* dst_data = _dst_data;
	const unsigned short* src_data = _src_data;
	int dst_lim = _dst_lim >> 1; /* ハーフワード単位に変換。奇数だった場合は、一時的に端数を切り捨てておく */
	int src_len = _src_len >> 1; /* ハーフワード単位に変換。奇数だった場合は、一時的に端数を切り捨てておく */

	/*{{この範囲は、lzss_uncompress1とlzss_uncompress2とで、ほぼ共通の処理*/
	int flag_mask = 0;
	int flag = 0;
	int dst_len = 0;
	int src_pos = 0;
	int hdr;
	int len;
	int dist;
	int pos;
	while(src_pos < src_len) {
		/* フラグを取得する */
		if(!flag_mask) {
			flag_mask = 1 << 15;	/*{{lzss_uncompress1とlzss_uncompress2とで、違うのはここだけ}}*/
			flag = src_data[src_pos++];
		}
		/* 圧縮コードの場合 */
		if(!(flag & flag_mask)) {
			/* 圧縮コード {(match_dist-1),(match_len-2)} を取得する */
			hdr = src_data[src_pos++];
			len = (hdr & 15) + 2;
			dist = (hdr >> 4) + 1;
			/* 圧縮コードを展開する */
			pos = dst_len - dist;
			do {
				if(dst_len < dst_lim) {
					dst_data[dst_len] = dst_data[pos];
				}
				dst_len++;
				pos++;
			} while(--len);
		/* 無圧縮コードの場合 */
		} else {
			/* 無圧縮コードを出力する */
			if(dst_len < dst_lim) {
				dst_data[dst_len] = src_data[src_pos];
			}
			dst_len++;
			src_pos++;
		}
		/* フラグビット位置を進める */
		flag_mask >>= 1;
	}
	/*}}この範囲は、lzss_uncompress1とlzss_uncompress2とで、ほぼ共通の処理*/

	/* 入力データバイト数が奇数だった場合は、入力データの端数バイトを、そのまま出力データの末尾に追加する */
	dst_len <<= 1; /* バイト単位に変換 */
	if(_src_len/*バイト単位*/ & 1) {
		if(dst_len/*バイト単位*/ < _dst_lim/*バイト単位*/) {
			((unsigned char*)_dst_data)[dst_len/*バイト単位*/] = ((const unsigned char*)_src_data)[_src_len/*バイト単位*/ - 1];
		}
		dst_len++; /* バイト単位 */
	}
	return dst_len; /* バイト単位 */
}

