
#include	"stdafx.h"
#include	"../Image.h"
#include	"LZSS.h"

//////////////////////////////////////////////////////////////////////////////////////////
//	デコード

BOOL	CLZSS::Decode(
	CArcFile*			pclArc							// アーカイブ
	)
{
	SFileInfo*			pstFileInfo = pclArc->GetOpenFileInfo();

	if( pstFileInfo->format != _T("LZ") )
	{
		return	FALSE;
	}

	return	Decomp( pclArc, 4096, 4078, 3 );
}

//////////////////////////////////////////////////////////////////////////////////////////
//	ファイルに解凍

BOOL	CLZSS::Decomp(
	CArcFile*			pclArc,							// アーカイブ
	DWORD				dwDicSize,						// 辞書サイズ
	DWORD				dwDicPtr,						// 辞書初期参照位置
	DWORD				dwLengthOffset					// 一致長のオフセット
	)
{
	SFileInfo*			pstFileInfo = pclArc->GetOpenFileInfo();

	// 読み込み

	DWORD				dwSrcSize = pstFileInfo->sizeCmp;

	YCMemory<BYTE>		clmSrc( dwSrcSize );

	pclArc->Read( &clmSrc[0], dwSrcSize );

	// 解凍用バッファの確保

	DWORD				dwDstSize = pstFileInfo->sizeOrg;

	YCMemory<BYTE>		clmDst( dwDstSize );

	// 解凍

	Decomp( &clmDst[0], dwDstSize, &clmSrc[0], dwSrcSize, dwDicSize, dwDicPtr, dwLengthOffset );

	if( lstrcmp( PathFindExtension( pstFileInfo->name ), _T(".bmp") ) == 0 )
	{
		// ビットマップ

		CImage				clImage;

		clImage.Init( pclArc, &clmDst[0] );
		clImage.Write( dwDstSize );
		clImage.Close();
	}
	else
	{
		// その他

		pclArc->OpenFile();
		pclArc->WriteFile( &clmDst[0], dwDstSize );
		pclArc->CloseFile();
	}

	return	TRUE;
}

//////////////////////////////////////////////////////////////////////////////////////////
//	メモリに解凍

BOOL	CLZSS::Decomp(
	void*				pvDst,							// 格納先
	DWORD				dwDstSize,						// 格納先サイズ
	const void*			pvSrc,							// 圧縮データ
	DWORD				dwSrcSize,						// 圧縮データサイズ
	DWORD				dwDicSize,						// 辞書サイズ
	DWORD				dwDicPtr,						// 辞書初期参照位置
	DWORD				dwLengthOffset					// 一致長のオフセット
	)
{
	BYTE*				pbtDst = (BYTE*) pvDst;
	const BYTE*			pbtSrc = (const BYTE*) pvSrc;

	// 辞書バッファの確保

	YCMemory<BYTE>		clmbtDic( dwDicSize );

	ZeroMemory( &clmbtDic[0], dwDicSize );

	// 解凍

	DWORD				dwSrcPtr = 0;
	DWORD				dwDstPtr = 0;
	BYTE				btFlags;
	DWORD				dwBitCount = 0;

	while( (dwSrcPtr < dwSrcSize) && (dwDstPtr < dwDstSize) )
	{
		if( dwBitCount == 0 )
		{
			// 8bit読み切った

			btFlags = pbtSrc[dwSrcPtr++];
			dwBitCount = 8;
		}

		if( btFlags & 1 )
		{
			// 無圧縮データ

			pbtDst[dwDstPtr] = clmbtDic[dwDicPtr] = pbtSrc[dwSrcPtr];

			dwDstPtr++;
			dwSrcPtr++;
			dwDicPtr++;

			dwDicPtr &= (dwDicSize - 1);
		}
		else
		{
			// 圧縮データ

			BYTE				btLow = pbtSrc[dwSrcPtr++];
			BYTE				btHigh = pbtSrc[dwSrcPtr++];

			DWORD				dwBack = (((btHigh & 0xF0) << 4) | btLow);
			DWORD				dwLength = ((btHigh & 0x0F) + dwLengthOffset);

			if( (dwDstPtr + dwLength) > dwDstSize )
			{
				// 出力バッファを超えてしまう

				dwLength = (dwDstSize - dwDstPtr);
			}

			for( DWORD j = 0 ; j < dwLength ; j++ )
			{
				pbtDst[dwDstPtr] = clmbtDic[dwDicPtr] = clmbtDic[dwBack];

				dwDstPtr++;
				dwDicPtr++;
				dwBack++;

				dwDicPtr &= (dwDicSize - 1);
				dwBack &= (dwDicSize - 1);
			}
		}

		btFlags >>= 1;
		dwBitCount--;


/*
		for( DWORD i = 0 ; (i < 8) && (dwSrcPtr < dwSrcSize) && (dwDstPtr < dwDstSize) ; i++ )
		{
			if( btFlags & 1 )
			{
				// 無圧縮データ

				pbtDst[dwDstPtr] = clmbtDic[dwDicPtr] = pbtSrc[dwSrcPtr];

				dwDstPtr++;
				dwSrcPtr++;
				dwDicPtr++;

				dwDicPtr &= (dwDicSize - 1);
			}
			else
			{
				// 圧縮データ

				BYTE				btLow = pbtSrc[dwSrcPtr++];
				BYTE				btHigh = pbtSrc[dwSrcPtr++];

				DWORD				dwBack = (((btHigh & 0xF0) << 4) | btLow);
				DWORD				dwLength = ((btHigh & 0x0F) + dwOffset);

				if( (dwDstPtr + dwLength) > dwDstSize )
				{
					// 出力バッファを超えてしまう

					dwLength = (dwDstSize - dwDstPtr);
				}

				for( DWORD j = 0 ; j < dwLength ; j++ )
				{
					pbtDst[dwDstPtr] = clmbtDic[dwDicPtr] = clmbtDic[dwBack];

					dwDstPtr++;
					dwDicPtr++;
					dwBack++;

					dwDicPtr &= (dwDicSize - 1);
					dwBack &= (dwDicSize - 1);
				}
			}

			btFlags >>= 1;
		}*/
	}

	return	TRUE;
}
