/****************************************************************************
[名称]
	SUSIE32 '00IN' Plug-in for Hidden
	HiddenDecoderクラス インプリメンテーションファイル
[備考]
	フォルダ内にあるSusie-Pluginを列挙し、適当に選択して画像ファイルを開く。
[履歴]
	2001.04.12	01.00.00	Bitlearner(Toofect Arts)
	2003.02.25	---			したらびあん用に必要な関数を抽出・コメント付加(moralog)
*****************************************************************************/

#include "stdafx.h"

#include "resource.h"
#include <stdio.h>
#include <io.h>
#include <time.h>
#include <afxcoll.h>

#include "HiddenDecoder.h"
#define		BUFF_SIZE		128
#define		HEADBUF_SIZE	2048
#define		NULL_STRING		_T("")

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CHiddenDecoder::CHiddenDecoder()
{
	m_bEnumlated = FALSE;
	m_strPluginFolder.Empty();
}

CHiddenDecoder::~CHiddenDecoder()
{
}

//////////////////////////////////////////////////////////////////////
// インタフェース関数の実装部分
//////////////////////////////////////////////////////////////////////

void CHiddenDecoder::PluginFolder(
	CString		strPluginFolder
){
	m_strPluginFolder = strPluginFolder +"\\";
}

/****************************************************************************
[名称]
	対応フォーマット確認
[概要]
	ヘッダを見て対応フォーマットか確認する。
[引数]
	pImageFileName	<I> - 画像ファイルパス名 [-] ( - )
	dw				<I> - ファイルハンドルもしくはヘッダを読み込んだバッファ [-] (-)
[戻り値]
	BOOL - 対応有無 [-] （TRUE:有、FALSE:無）
[備考]
	filnameはファイル名で、NULLが入っていることもある。
	dwは上位バイトが0のとき、ファイルハンドル。
	そうでなければファイルのヘッダを格納したバッファ。サイズは2000バイト以上。
****************************************************************************/
BOOL CHiddenDecoder::IsSupportedCore(
	char*		pImageFileName,
	DWORD		dw
){
	// warning C4100:警告の無視
	pImageFileName;

	char	pBuffer[ HEADBUF_SIZE ];

	if ( dw & 0xFFFF0000 )
	{
	// バッファ
		// バッファからローカルなバッファへコピー
		BOOL bSuccess;
		bSuccess = GetImageHeader(
			(char*)dw,
			HEADBUF_SIZE,
			1,
			pBuffer,
			HEADBUF_SIZE
		);
	}
	else
	{
	// ハンドル
		// ファイルからバッファへ読み込み
		DWORD ReadBytes;
		ReadBytes = fread( pBuffer, 1, HEADBUF_SIZE, (FILE*)dw);
	}

	// Spiが列挙済みか
	if ( !m_bEnumlated )
	{
		// 使用可能なSpiの列挙
		EnumlateSpiz();
	}

	// サポート可能を返すプラグインを見つけるまでループ
	long		idxPlugIn;
	for ( idxPlugIn=0 ; idxPlugIn<m_aPlugInNamez.GetSize() ; idxPlugIn++ )
	{
		BOOL	bSupported;
		bSupported = IsSupportedPlugIn(
			m_aPlugInNamez[ idxPlugIn ],
			pBuffer
		);
		if ( bSupported )
		{
			return( TRUE );
		}
	}

	return( FALSE );
}



/****************************************************************************
[名称]
	画像情報取得
[概要]
	画像情報を返す。
[引数]
	buf			<I>
	len			<I>
	flag		<I>
	lpInfo		<O>
[戻り値]
	BOOL - 対応有無 [-] （TRUE:有、FALSE:無）
[備考]
	Susie 32bit Plug-in 仕様 rev4 抜粋

    Parameter:
      LPSTR buf : 入力がファイルの場合 ファイル名
                        メモリーの場合 ファイルイメージへのポインタ
      long len  : 入力がファイルの場合 読込み開始オフセット(MacBin対応のため)
                        メモリーの場合 データサイズ
      unsigned int flag : 追加情報 xxxx xxxx xxxx xSSS
                  SSS : 入力形式
                        0 : ディスクファイル
                        1 : メモリ上のイメージ
      struct PictureInfo *lpInfo :
                  struct PictureInfo
                  {
                    long left,top;    画像を展開する位置
                    long width;       画像の幅(pixel)
                    long height;      画像の高さ(pixel)
                    WORD x_density;   画素の水平方向密度
                    WORD y_density;   画素の垂直方向密度
                    short colorDepth; １画素当たりのbit数
                    HLOCAL hInfo;    画像内のテキスト情報
                  };
                  hInfoには必要に応じてPlug-inが確保したGlobalメモリーの
                  ハンドルが格納される。
****************************************************************************/
int CHiddenDecoder::GetPictureInfoCore(
	LPSTR			buf,
	long			len,
	unsigned int	flag,
	struct PictureInfo *lpInfo
){
	// Spiが列挙済みか
	if ( !m_bEnumlated )
	{
		// 使用可能なSpiの列挙
		EnumlateSpiz();
	}

	// デコード可能画像を探す
	long		idxPlugIn;
	for ( idxPlugIn=0 ; idxPlugIn<m_aPlugInNamez.GetSize() ; idxPlugIn++ )
	{
		HINSTANCE	hPlugIn;
		hPlugIn = AfxLoadLibrary(  m_strPluginFolder+m_aPlugInNamez[ idxPlugIn ] );
		if ( hPlugIn != NULL )
		{
		// サポートしているかを検査
			// IsSupported()のエントリポイントを得る
			GETPICTUREINFO	GetPictureInfo;
			GetPictureInfo = (GETPICTUREINFO)GetProcAddress(
				hPlugIn,
				"GetPictureInfo"
			);
			if ( GetPictureInfo == NULL )
			{
				// GetPictureInfo()が存在しない
				AfxFreeLibrary( hPlugIn );
				continue;
			}

			int		iResult;
			iResult = GetPictureInfo(
				buf,
				len,
				flag,
				lpInfo
			);
			return( iResult );
		}
	}
	return( SPI_NO_FUNCTION );
}


/****************************************************************************
[名称]
	画像取得
[概要]
	画像を返す。
[引数]
	buf					<I>
	len					<I>
	flag				<I>
	pHBInfo				<O>
	pHBm				<O>
	lpPrgressCallback	<I>
	lData				<O>
[戻り値]
	int - 処理結果 [結果コード] （-）
[備考]
	Susie 32bit Plug-in 仕様 rev4 抜粋

    Parameter:
      LPSTR buf : 入力がファイルの場合 ファイル名
                        メモリーの場合 ファイルイメージへのポインタ
      long len  : 入力がファイルの場合 読込み開始オフセット(MacBin対応のため)
                        メモリーの場合 データサイズ
      unsigned int flag : 追加情報 xxxx xxxx xxxx xSSS
                  SSS : 入力形式
                        0 : ディスクファイル
                        1 : メモリ上のイメージ
      HLOCAL *pHBm    : ビットマップデータ本体のメモリハンドルが返される
      HLOCAL *pHBInfo : BITMAPINFO 構造体が納められたメモリハンドルが
                             返される。
      FARPROC lpPrgressCallback :
                途中経過を表示するコールバック関数へのポインタ。
                MakeProcInstance を用いて求める。
                NULLの場合、plug-inは処理が終了するまでプロセスを占有し、
                中断も出来ません。
                コールバック関数のprototype:
                  int PASCAL ProgressCallback(
                                        int nNum,int nDenom,long lData);
                  まず nNum==0 でコールされ、nNum==nDenom になるまで
                  定期的に呼ばれる。
                  戻値が 非0 の時、Plug-inは処理を中断する。
      long lData : コールバック関数に渡すlongデータ。
                  ポインタ等を必要に応じて受け渡せる。
****************************************************************************/
int CHiddenDecoder::GetPictureCore(
	LPSTR			buf,
	long			len,
	unsigned int	flag, 
	HANDLE			*pHBInfo,
	HANDLE			*pHBm,
	SPI_PROGRESS	lpPrgressCallback,
	long			lData
){

	// Spiが列挙済みか
	if ( !m_bEnumlated )
	{
		// 使用可能なSpiの列挙
		EnumlateSpiz();
	}

	// 画像ヘッダを取得
	char	pImageHeader[ HEADBUF_SIZE ];
	GetImageHeader(
		buf,
		len,
		flag,
		pImageHeader,
		HEADBUF_SIZE
	);

	// デコード可能画像を探す
	long		idxPlugIn;
	for ( idxPlugIn=0 ; idxPlugIn<m_aPlugInNamez.GetSize() ; idxPlugIn++ )
	{
		BOOL	bSupported;

		bSupported = IsSupportedPlugIn(
			m_aPlugInNamez[ idxPlugIn ],
			pImageHeader
		);
		if ( bSupported != TRUE )
		{
			continue;
		}

		HINSTANCE	hPlugIn;
		hPlugIn = AfxLoadLibrary( m_strPluginFolder+m_aPlugInNamez[ idxPlugIn ] );
		if ( hPlugIn != NULL )
		{
			// GetPicture()のエントリポイントを得る
			GETPICTURE	GetPicture;
			GetPicture = (GETPICTURE)GetProcAddress(
				hPlugIn,
				"GetPicture"
			);
			if ( GetPicture == NULL )
			{
				// GetPicture()が存在しない
				AfxFreeLibrary( hPlugIn );
				continue;
			}

			int		iResult;
			iResult = GetPicture(
				buf,
				len,
				flag,
				pHBInfo,
				pHBm,
				lpPrgressCallback,
				lData
			);

			// ここでHiddenの真価を見せる
			if ( iResult == SPI_ALL_RIGHT )
			{
				return( iResult );
			}
			// 画像の読込みに失敗したので、次に賭ける
		}
	}
	return( SPI_NO_FUNCTION );
}


/****************************************************************************
[名称]
	サムネイル画像取得
[概要]
	サムネイル画像を返す。
[引数]
	buf					<I>
	len					<I>
	flag				<I>
	pHBInfo				<O>
	pHBm				<O>
	lpPrgressCallback	<I>
	lData				<O>
[戻り値]
	int - 処理結果 [結果コード] （-）
[備考]
	GetPictureCore()参照。
****************************************************************************/
int CHiddenDecoder::GetPreviewCore(
	LPSTR			buf,
	long			len,
	unsigned int	flag,
	HANDLE			*pHBInfo,
	HANDLE			*pHBm,
	SPI_PROGRESS	lpPrgressCallback,
	long			lData
){

	if ( !m_bEnumlated )
	{
		// 使用可能なSpiの列挙
		EnumlateSpiz();
	}

	long		idxPlugIn;
	for ( idxPlugIn=0 ; idxPlugIn<m_aPlugInNamez.GetSize() ; idxPlugIn++ )
	{
		HINSTANCE	hPlugIn;
		hPlugIn = AfxLoadLibrary( m_strPluginFolder+m_aPlugInNamez[ idxPlugIn ] );
		if ( hPlugIn != NULL )
		{
		// サポートしているかを検査
			// GetPicture()のエントリポイントを得る
			GETPREVIEW	GetPreviewCore;
			GetPreviewCore = (GETPREVIEW)GetProcAddress(
				hPlugIn,
				"GetPreviewCore"
			);
			if ( GetPreviewCore == NULL )
			{
				// GetPreviewCore()が存在しない
				AfxFreeLibrary( hPlugIn );
				continue;
			}

			int		iResult;
			iResult = GetPreviewCore(
				buf,
				len,
				flag, 
				pHBInfo,
				pHBm,
				lpPrgressCallback,
				lData
			);
			return( iResult );
		}
	}
	return( SPI_NO_FUNCTION );
}



//////////////////////////////////////////////////////////////////////
// 些末な関数
//////////////////////////////////////////////////////////////////////

/****************************************************************************
[名称]
	SPI列挙
[概要]
	使用可能なSpiを列挙し、SPIファイル名称をアレイに格納する。
[引数]
	なし
[戻り値]
	なし
[備考]
	BOOL			m_bEnumlated;
	CStringArray	m_aPluginInfoz;			全拡張子・全ファイル形式名
	CStringArray	m_aPlugInNamez;			全Pluginファイル名（Hidden除く）
	に内容を格納する。
****************************************************************************/
void CHiddenDecoder::EnumlateSpiz()
{
	// この関数を通ればSpiは列挙済み
	m_bEnumlated = TRUE;

	m_aPluginInfoz.RemoveAll();
	m_aPlugInNamez.RemoveAll();

	// プラグインの列挙
    struct _finddata_t c_file;
    long hFile;

    // カレント ディレクトリ内の最初の .spi ファイルを探す
    if( (hFile = _findfirst( m_strPluginFolder+"*.spi", &c_file )) == -1L )
	{
		return;
	}
	else
	{
		BOOL	bEnd = FALSE;
        while( bEnd != TRUE )
		{
			// continue条件が多いのでwhileを使用してswitch文風に記述する
			while(1)
			{
			// Plug-Inのロード
				HINSTANCE	hPlugIn;
				hPlugIn = AfxLoadLibrary( m_strPluginFolder+c_file.name );
				if ( hPlugIn == NULL )
				{
					// ロードできなければ次へ
					break;
				}

			// GetPluginInfo()のエントリポイントを得る
				GETPLUGININFO	GetPluginInfo;
				GetPluginInfo = (GETPLUGININFO)GetProcAddress(
					hPlugIn,
					"GetPluginInfo"
				);
				if ( GetPluginInfo == NULL )
				{
					// GetPluginInfo()が存在しない
					AfxFreeLibrary( hPlugIn );
					break;
				}

			// プラグイン情報を得る
				// 拡張子とファイル形式名をずるっと読む
				long	idxExt;
				for ( idxExt=0 ; TRUE ; idxExt++ )
				{
					char	aBuff[ BUFF_SIZE+1 ];

					int		iResult;

					iResult = GetPluginInfo(
						idxExt*2 +2 +1,
						aBuff,
						BUFF_SIZE
					);
					if ( iResult == 0 )
					{
						break;
					}
					m_aPluginInfoz.Add( aBuff );

					iResult = GetPluginInfo(
						idxExt*2 +2,
						aBuff,
						BUFF_SIZE
					);
					if ( iResult == 0 )
					{
						m_aPluginInfoz.Add( NULL_STRING );
						break;
					}
					m_aPluginInfoz.Add( aBuff );
				}

				m_aPlugInNamez.Add( c_file.name );
				break;
			}

			// 次の要素を調べる
			if ( _findnext( hFile, &c_file ) != 0)
			{
				bEnd = TRUE;
			}
		}
	}
	return;
}


/****************************************************************************
[名称]
	画像ヘッダ取得
[概要]
	とにかく画像の先頭部分を得る。
[引数]
	buf				- <I>
	len				- <I>
	flag			- <I>
	pImageHeader	- <O> 画像ヘッダ内容 (-) [-]
	ImageHeaderSize	- <I> 格納可能サイズ (-) [-]
[戻り値]
	BOOL - 処理結果 [-] （TRUE：成功、FALSE：失敗）
[備考]
	Susie 32bit Plug-in 仕様 rev4 抜粋

    Parameter:
      LPSTR buf : 入力がファイルの場合 ファイル名
                        メモリーの場合 ファイルイメージへのポインタ
      long len  : 入力がファイルの場合 読込み開始オフセット(MacBin対応のため)
                        メモリーの場合 データサイズ
      unsigned int flag : 追加情報 xxxx xxxx xxxx xSSS
                  SSS : 入力形式
                        0 : ディスクファイル
                        1 : メモリ上のイメージ
****************************************************************************/
BOOL CHiddenDecoder::GetImageHeader(
	LPSTR			buf,
	long			len,
	unsigned int	flag,
	char*			pImageHeader,
	long			ImageHeaderSize
){

	// サポートしているかを検査
	memset( pImageHeader, 0, ImageHeaderSize );

	switch ( flag & 0x07 )
	{
	case 0:
	// ディスクファイル
		{
			FILE*	dw = fopen( buf, "r+b"  );
			DWORD ReadBytes;
			ReadBytes = fread( pImageHeader, 1, ImageHeaderSize, dw);
			fclose( dw );
		}
		return( TRUE );
		break;

	case 1:
	// メモリ上のイメージ
		{
			// buffにコピー
			memcpy( pImageHeader, buf, len );
		}
		return( TRUE );
		break;

	default:
		return( FALSE );
		break;
	}

}


/****************************************************************************
[名称]
	プラグイン情報取得
[概要]
	プラグイン情報を返す
[引数]
	iRequest	- <I> プラグイン情報 (列挙された順) [-]
	pDst		- <O> プラグイン情報格納先 (-) [-]
	lDstSize	- <I> 格納先サイズ (-) [-]
[戻り値]
	long コピー済みバイト数 (-)
[備考]
	なし
****************************************************************************/
long CHiddenDecoder::GetPluginInfoCore(
	int		iRequest,
	LPSTR	pDst,
	int		lDstSize
){
	// 列挙がまだなら列挙する
	if ( !m_bEnumlated )
	{
		// 使用可能なSpiの列挙
		EnumlateSpiz();
	}

	// リクエスト範囲の確認
	if ( iRequest >= m_aPluginInfoz.GetSize() )
	{
		return( 0 );
	}

	// 情報をコピーして返す
	ZeroMemory( pDst, lDstSize );
	long		nCopied;
	nCopied = min( lDstSize, m_aPluginInfoz[iRequest].GetLength() );

	memcpy(
		pDst,
		m_aPluginInfoz[iRequest].GetBuffer( nCopied ),
		nCopied
	);

	return( nCopied );
}


/****************************************************************************
[名称]
	サポート可能検査
[概要]
	任意のプラグインが、指定の画像をサポートしているか検査する。
[引数]
	strPlugInName	- <I> プラグインファイルパス名 (-) [-]
	pImageHeader	- <I> 画像ファイルヘッダ (-) [-]
[戻り値]
	BOOL - 処理結果 [-] （TRUE：成功、FALSE：失敗）
[備考]
	なし
****************************************************************************/
BOOL CHiddenDecoder::IsSupportedPlugIn(
	CString			strPlugInName,
	char*			pImageHeader
){
	HINSTANCE	hPlugIn;
	hPlugIn = AfxLoadLibrary( m_strPluginFolder+strPlugInName );
	if ( hPlugIn != NULL )
	{
	// サポートしているかを検査
		int		iResult;

		// IsSupported()のエントリポイントを得る
		ISSUPPORTED	IsSupportedFunc;
		IsSupportedFunc = (ISSUPPORTED)GetProcAddress(
			hPlugIn,
			"IsSupported"
		);
		if ( IsSupportedFunc == NULL )
		{
			// IsSupported()が存在しない
			AfxFreeLibrary( hPlugIn );
			return( FALSE );
		}

		// フォーマット確認
		iResult = IsSupportedFunc( strPlugInName.GetBuffer(256), (unsigned long)pImageHeader );
		AfxFreeLibrary( hPlugIn );
		return( iResult );
	}
	return( FALSE );
}



int CHiddenDecoder::GetSupportExt(
	CStringArray*	paExtz
)
{
	// Spiが列挙済みか
	if ( !m_bEnumlated )
	{
		// 使用可能なSpiの列挙
		EnumlateSpiz();
	}

	paExtz->RemoveAll();
	paExtz->Append( m_aPluginInfoz );
	return( paExtz->GetSize() );
}



