#pragma once
//---------------------------------------------------------------------------
#include "../KbUnArc.h"
#include "fdi.h"

class KbUnCab : public KbUnArc
{
private:
    struct CabInfo
    {
        KPI_FILEINFO  fi;
        BYTE         *pData;      //解凍後のデータ
        UINT64        qwPointer;  //現在のファイルポインタ
        volatile BOOL bWriteDone; //書き込みが完了した（volatile は非常に重要！）
        wchar_t       szMethod[20];
        wchar_t       szFileName[1];
    };
    struct CabFileHandle
    {
        IKpiFile *pFile;
        CabInfo  *pInfo;
    };
    HANDLE       m_hHeap;
    IKpiFile    *m_pFile;
    IKpiFile   **m_ppFiles;
    IKpiFolder  *m_pFolder;
    CabInfo    **m_ppCabInfo;
    DWORD        m_dwCount;
    HANDLE       m_hThread;   //解凍スレッドのハンドル
    BOOL         m_bIsUtf8;
    UINT64       m_qwTotalSize;
    struct ThreadData
    { //解凍スレッド内で更新・参照されるデータ
        HANDLE        hSemaphore; //ファイルを１つ解凍する毎にカウンタを１つ増やす
        HANDLE        hEvent;     //解凍する場合はシグナル状態
        DWORD         dwTarget;   //解凍中のファイルのインデックス
        volatile BOOL bTerminated;//スレッドを終了する場合に TRUE
    }m_ThreadData;
    //thread
    static unsigned int __stdcall CabThreadProc(void *pThis);
    void __fastcall CabThreadProcInternal(void);
    BOOL __fastcall CreateCabThread(void);
    void __fastcall TerminateCabThread(void);
    //
    static CabFileHandle* __fastcall GetFileHandleFromCabPath(const char *cszCabPath);//wchar にする必要なし
    static void __fastcall GetCabPathFromUnCab(char *pszCabPath, KbUnCab *pUnCab);//wchar にする必要なし
    //FDI
    static PVOID   DIAMONDAPI FDIAlloc(ULONG cb);
    static void    DIAMONDAPI FDIFree(PVOID pv);
    static INT_PTR DIAMONDAPI FDIOpen(PSTR pszFile, int  oflag, int  pmode);
    static UINT    DIAMONDAPI FDIRead(INT_PTR hf, PVOID pv, UINT cb);
    static UINT    DIAMONDAPI FDIWrite(INT_PTR hf, PVOID pv, UINT  cb);
    static long    DIAMONDAPI FDISeek(INT_PTR  hf, long dist, int seektype);
    static int     DIAMONDAPI FDIClose(INT_PTR hf);
    static INT_PTR DIAMONDAPI FDIExtract(FDINOTIFICATIONTYPE fdint,
                                         PFDINOTIFICATION    pfdin);
    INT_PTR __fastcall FDIExtractInternal(FDINOTIFICATIONTYPE fdint,
                                      PFDINOTIFICATION    pfdin);
    //
    void*    __fastcall OpenCabinet(IKpiFile *pFile);
    void     __fastcall CloseCabinet(void *hc);
    BOOL     __fastcall ScanCabinet(void *hc, CabInfo **ppCabInfo);
    virtual ~KbUnCab(void);
public:
    BOOL WINAPI GetArchiveInfo(const KPI_ARCHIVEINFO **ppArchiveInfo);
    BOOL WINAPI EnumFileInfo(DWORD dwIndex, const KPI_FILEINFO **ppFileInfo);
    BOOL WINAPI Extract(DWORD dwIndex, IKpiFile **ppFile, UINT64 qwSize);

    BOOL __fastcall Open(IKpiFile *pFile, IKpiFolder *pFolder, const wchar_t *cszOutputPath);
    KbUnCab(UnArcConfig *pConfig);
};

