/*	
 *	clippzl.h
 *
 *	P/ECE Zlib
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2004 Naoyuki Sawa
 *
 *	* Sat Mar 13 13:00:00 JST 2004 Naoyuki Sawa
 *	- 1st release.
 */
#ifndef __CLIP_PZL_H__
#define __CLIP_PZL_H__

/****************************************************************************
 *	バイトストリーム (出力)
 ****************************************************************************/

typedef struct _PBYTESTREAM {
	unsigned char* buffer;	/* バッファ先頭アドレス */
	int len;		/* バッファサイズ (byte単位) */
	int pos;		/* 書き込み位置   (byte単位) */
} PBYTESTREAM;

/* バイトストリームを初期化します。
 * [in]
 *	out		PBYTESTREAM構造体。
 *	buffer		バッファ先頭アドレス。
 *	len		バッファサイズ。(バイト単位)
 * [out]
 *	戻り値		成功ならば、0を返します。
 *			失敗ならば、負の値を返します。
 */
int pbytestream_init(PBYTESTREAM* out, void* buffer, int len);

/* バイトストリームに1バイト書き込みます。
 * [in]
 *	out		PBYTESTREAM構造体。
 *	value		書き込むバイト値。[7:0]
 *			[31:8]は捨てられます。
 * [out]
 *	戻り値		成功ならば、書き込んだバイト数(=1)を返します。
 *			失敗ならば、負の値を返します。
 */
int pbytestream_put(PBYTESTREAM* out, int value);

/****************************************************************************
 *	ビットストリーム (入力)
 ****************************************************************************/

typedef struct _PBITSTREAM {
	const unsigned char* data;	/* データ先頭アドレス */
	int len;			/* データサイズ (bit単位) */
	int pos;			/* 読み込み位置 (bit単位) */
} PBITSTREAM;

/* ビットストリームを初期化します。
 * [in]
 *	in		PBITSTREAM構造体。
 *	data		データ先頭アドレス。
 *	len		データサイズ。(バイト単位)
 * [out]
 *	戻り値		成功ならば、0を返します。
 *			失敗ならば、負の値を返します。
 */
int pbitstream_init(PBITSTREAM* in, const void* data, int len);

/* ビットストリームからビット列を読み込みます。
 * [in]
 *	in		PBITSTREAM構造体。
 *	out		読み込んだビット列を格納する変数へのポインタ。
 *			NULLを指定すると、読み込んだビット列は捨てられます。
 *	bits		読み込むビット数。(1〜32)
 * [out]
 *	戻り値		成功ならば、読み込んだビット数(=bits)を返します。
 *			失敗ならば、負の値を返します。
 *	*out		読み込んだビット列を格納します。
 *			NULLを指定すると、読み込んだビット列は捨てられます。
 */
int pbitstream_get(PBITSTREAM* in, int* out, int bits);

/* 読み込み位置を指定ビット幅の境界まで進めます。
 * [in]
 *	in		PBITSTREAM構造体。
 *	bits		ビット幅。(1〜)
 * [out]
 *	戻り値		成功ならば、0を返します。
 *			失敗ならば、負の値を返します。
 * [note]
 *	* 読み込み位置を      バイト境界まで進めるには、bitsに 8を指定します。
 *	  読み込み位置をハーフワード境界まで進めるには、bitsに16を指定します。
 *	  読み込み位置を      ワード境界まで進めるには、bitsに32を指定します。
 *	* bits>8を指定した場合、posがlenを超える場合がありますが、問題ありません。
 *	  pos>=lenならば、いずれにせよ次回のpbitstream_get()は失敗して0を返します。
 */
int pbitstream_align(PBITSTREAM* in, int bits);

/****************************************************************************
 *	ハフマン復号
 ****************************************************************************/

#define PHUFFTREE_MAX_BITS	 15	/* 符号の最大ビット長(仕様) */
#define PHUFFTREE_MAX_VALUE	287	/* 符号を割り当てる値の最大値(仕様)、286,287は無効値 */

typedef struct _PHUFFTREE {
	unsigned short next[2];	/* [0]:bit=0時の探査方向 / [1]:bit=1時の探査方向 */
} PHUFFTREE;

/* PHUFFTREE.next[bit] */
#define PHUFFTREE_BLANK		((1 << 16) - 1)	/* PHUFFTREE.next[bit]が空きであることを示します。 */
#define PHUFFTREE_LEAF		(1 << (16 - 1))	/* PHUFFTREE.next[bit]の最上位ビットが1ならば、それ以外のビットが値を示します。 */
						/* PHUFFTREE.next[bit]の最上位ビットが0ならば、次のノードインデクスを示します。 */

/* 0〜values-1の値に符号を割り当て、ハフマン木に{符号、値}のペアを追加します。
 * [in]
 *	pht		PHUFFTREE配列。
 *	len		PHUFFTREE配列の要素数。
 *	code_bits	0〜values-1の値に対応する符号のビット数を指定する配列。(0〜PHUFFCODE_MAX_BITS)
 *	values		code_bits配列の要素数。(0〜PHUFFCODE_MAX_VALUE+1)
 * [out]
 *	戻り値		使用したPHUFFTREE配列の要素数を返します。
 *			失敗ならば、負の値を返します。
 * [note]
 *	* 呼び出し側にて、code_bits配列の内容を設定しておいてください。
 */
int phufftree_init(PHUFFTREE pht[/*len*/], int len, const unsigned char code_bits[/*values*/], int values);

/* ハフマン木に{符号、値}のペアを追加します。
 * [in]
 *	pht		PHUFFTREE配列。
 *	len		PHUFFTREE配列の要素数。
 *	code		符号。
 *	code_bits	符号ビット数。(1〜PHUFFTREE_MAX_BITS)
 *	value		値。(0〜PHUFFTREE_INVALID_VALUE-1)
 * [out]
 *	戻り値		追加成功ならば、値を格納したノードのインデクスを返します。(0〜len-1)
 *			追加失敗ならば、負の値を返します。
 * [note]
 *	* phufftree_build()から利用します。
 *	  その他の関数やアプリケーションプログラムから直接呼び出すことはありません。
 */
int phufftree_add(PHUFFTREE pht[/*len*/], int len, int code, int code_bits, int value);

/* ハフマン木から符号に対応する値を検索します。
 * [in]
 *	pht		PHUFFTREE配列。
 *	len		PHUFFTREE配列の要素数。
 *	in		符号を読み込むビットストリーム。
 * [out]
 *	戻り値		見つかったならば、値を返します。(0〜INVALID_VALUE-1)
 *			見つからなかったならば、負の値を返します。
 */
int phufftree_lookup(PHUFFTREE pht[/*len*/], int len, PBITSTREAM* in);

/****************************************************************************
 *	Deflate形式
 ****************************************************************************/

/* Deflate形式の圧縮データを展開します。
 * [in]
 *	out		バイトストリーム。(出力)
 *	in		ビットストリーム。(入力)
 * [out]
 *	戻り値		展開成功ならば、出力データサイズを返します。(バイト単位)
 *			展開失敗ならば、負の値を返します。
 */
int pdeflate_uncompress(PBYTESTREAM* out, PBITSTREAM* in);

/****************************************************************************
 *	Zlib形式
 ****************************************************************************/

/* Zlib形式の圧縮データを展開します。
 * [in]
 *	outbuf		出力バッファ。
 *	outlen		出力バッファサイズ。(バイト単位)
 *	inbuf		入力データ。
 *	inlen		入力データサイズ。(バイト単位)
 * [out]
 *	戻り値		展開成功ならば、出力データサイズを返します。(バイト単位)
 *			展開失敗ならば、負の値を返します。
 */
int pzlib_uncompress(void* outbuf, int outlen, const void* inbuf, int inlen);

/* Adler-32チェックサムを計算します。
 * [in]
 *	data		データ先頭アドレス。
 *	len		データサイズ。(バイト単位)
 * [out]
 *	戻り値		Adler-32チェックサムを返します。
 * [note]
 *	* pzlib_uncompress()から利用します。
 *	  アプリケーションプログラムからも単独で利用可能です。
 */
int pzlib_adler32(const void* data, int len);

/* CRC-32を計算します。
 * [in]
 *	data		データ先頭アドレス。
 *	len		データサイズ。(バイト単位)
 * [out]
 *	戻り値		CRC-32を返します。
 * [note]
 *	* ※TODO:未使用※から利用します。
 *	  アプリケーションプログラムからも単独で利用可能です。
 */
int pzlib_crc32(const void* data, int len);

/****************************************************************************
 *	Zip形式
 ****************************************************************************/

/*{{ZIPファイル仕様*/
#define PUNZIPLOCALFILEHEADER_SIGNATURE	0x04034b50
typedef struct _PUNZIPLOCALFILEHEADER {
	unsigned char local_file_header_signature[4];	/* + 0,4 */
	unsigned char version_needed_to_extract[2];	/* + 4,2 */
	unsigned char general_purpose_bit_flag[2];	/* + 6,2 */
	unsigned char compression_method[2];		/* + 8,2 */
	unsigned char last_mod_file_time[2];		/* +10,2 */
	unsigned char last_mod_file_date[2];		/* +12,2 */
	unsigned char crc32[4];				/* +14,4 */
	unsigned char compressed_size[4];		/* +18,4 */
	unsigned char uncompressed_size[4];		/* +22,4 */
	unsigned char filename_length[2];		/* +26,2 */
	unsigned char extra_field_length[2];		/* +28,2 */
	//filename[/*filename_length*/];
	//extra_field[/*extra_field_length*/];
	//file_data[/*compressed_size*/];
} PUNZIPLOCALFILEHEADER;				/* =30+n */
/*}}ZIPファイル仕様*/

typedef struct _PUNZIP {
	const unsigned char* data;	/* Zipデータ先頭アドレス */
	int len;			/* Zipデータサイズ */
	/* punzip_dir() */
	int dir_pos;			/* ファイル情報走査位置 */
} PUNZIP;

/* PUNZIPLOCALFILEHEADERから、必要な部分だけを取り出しました。 */
typedef struct _PUNZIPDIR {
	char filename[44];		/* + 0,44: ファイル名 */
	int compression_method;		/* +44, 4: 圧縮形式 */
	int compressed_size;		/* +48, 4: 圧縮データサイズ */
	int uncompressed_size;		/* +52, 4: 展開データサイズ */
	int crc32;			/* +56, 4: CRC-32 */
	const void* file_data;		/* +60, 4: 圧縮データアドレス */
} PUNZIPDIR;				/* =64 */

/* Zipデータを開きます。
 * [in]
 *	puz		PUNZIP構造体。
 *	data		Zipデータ先頭アドレス。
 *	len		Zipデータサイズ。(バイト単位)
 * [out]
 *	戻り値		成功ならば、0を返します。
 *			失敗ならば、負の値を返します。
 */
int punzip_init(PUNZIP* puz, const void* data, int len);

/* ファイル情報を読み込みます。
 * [in]
 *	puz		PUNZIP構造体。
 *	dir		NULLを指定すると、ファイル情報走査位置を先頭へ戻します。
 *			NULL以外を指定すると、ファイル情報を読み込んで格納し、走査位置を次へ進めます。
 * [out]
 *	戻り値		dirにNULLを指定した場合、常に0を返します。
 *			dirにNULL以外を指定した場合、ファイル情報読み込み成功ならば、0を返します。
 *			                             ファイル情報読み込み失敗ならば、負の値を返します。
 * [note]
 *	* ファイル名一覧を表示するプログラム例を示します。
 *		punzip_init(&zip, data, len);
 *		punzip_dir(&zip, NULL);
 *		while(punzip_dir(&zip, &dir) == 0) {
 *			puts(dir.filename);
 *		}
 */
int punzip_dir(PUNZIP* puz, PUNZIPDIR* dir);

/* 指定ファイル名に一致するファイル情報を読み込みます。
 * [in]
 *	puz		PUNZIP構造体。
 *	filename	ファイル名。
 *	dir		ファイル情報を格納するための変数へのポインタ。
 * [out]
 *	戻り値		指定ファイル名に一致するファイル情報が見つかったら、0を返します。
 *			指定ファイル名に一致するファイル情報が見つからなければ、負の値を返します。
 * [note]
 *	* ファイル名の大文字と小文字は区別しません。
 *	  また、パス名の"/"と"\"は区別しません。
 */
int punzip_find(PUNZIP* puz, const char* filename, PUNZIPDIR* dir);

/* 指定ファイル名に一致するファイルを展開します。
 * [in]
 *	puz		PUNZIP構造体。
 *	filename	ファイル名。
 *	outbuf		出力バッファ。
 *	outlen		出力バッファサイズ。(バイト単位)
 * [out]
 *	戻り値		成功ならば、0を返します。
 *			失敗ならば、負の値を返します。
 * [note]
 *	* 失敗の要因は、次のようなものがあります。
 *	  ・指定ファイル名に一致するファイルが見つからない。
 *	  ・出力バッファサイズが不足している。
 *	  ・展開データのCRCが一致しない。(Zipデータが破損している)
 */
int punzip_uncompress(PUNZIP* puz, const char* filename, void* outbuf, int outlen);

#endif /*__CLIP_PZL_H__*/

