/*	
 *	clipzip.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.
 *	* Sun Dec 19 20:21:00 JST 2004 Naoyuki Sawa
 *	- clippzl.hからclipzip.hへ名前変更しました。
 *	- 関数名のプレフィクスをp〜からzlib〜へ変更しました。
 *	  関数名のプレフィクスをpunzip〜からzip〜へ変更しました。
 *	  構造体名のプレフィクスをP〜からZLIB〜へ変更しました。
 *	  構造体名のプレフィクスをPUNZIP〜ZIP〜へ変更しました。
 *	  これまで、本物のZlibとの名前衝突を恐れてp〜等の名前を付けていたのですが、
 *	  上記のように名前変更しても、本物のZlibとの名前衝突は起こらないようなので、
 *	  わかりやすさを優先してzlib〜、zip〜等の名前に変更することにしました。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 */
#ifndef __CLIP_ZIP_H__
#define __CLIP_ZIP_H__

#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/*{{ZIPファイル仕様*/
#define ZIPLOCALFILEHEADER_SIGNATURE	0x04034b50
typedef struct _ZIPLOCALFILEHEADER {
	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*/];
} ZIPLOCALFILEHEADER;				/* =30+n */
/*}}ZIPファイル仕様*/

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

/* ZIPLOCALFILEHEADERから、必要な部分だけを取り出しました。 */
typedef struct _ZIPDIR {
	char filename[128];		/* ファイル名 */
	int compression_method;		/* 圧縮形式 */
	int compressed_size;		/* 圧縮データサイズ */
	int uncompressed_size;		/* 展開データサイズ */
	int crc32;			/* CRC-32 */
	const void* file_data;		/* 圧縮データアドレス */
} ZIPDIR;

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

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

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

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

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

#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus

#endif /*__CLIP_ZIP_H__*/
