CABITMS.CPP
//******************************************************************************************* 
// 
// Filename : CabItms.cpp 
// 
//Implementation file for CMemFile, CCabEnum and CCabExtract 
// 
// Copyright 1994 - 1998 Microsoft Corporation. All rights reserved 
// 
//******************************************************************************************* 
 
#include "pch.h" 
 
#include "thisdll.h" 
 
#include "resource.h" 
 
#include "path.h" 
#include "fdi.h" 
#include "cabitms.h" 
 
class CMemFile 
{ 
public: 
CMemFile(HGLOBAL *phMem, DWORD dwSize); 
~CMemFile() {} 
 
BOOL Create(LPCSTR pszFile, int fnAttribute); 
BOOL Open(LPCSTR pszFile, int oflag); 
LONG Seek(LONG dist, int seektype); 
UINT Read(LPVOID pv, UINT cb); 
UINT Write(LPVOID pv, UINT cb); 
HFILE Close(); 
 
private: 
HFILE m_hf; 
 
HGLOBAL *m_phMem; 
DWORD m_dwSize; 
LONG m_lLoc; 
} ; 
 
 
CMemFile::CMemFile(HGLOBAL *phMem, DWORD dwSize) : m_hf(HFILE_ERROR), m_lLoc(0) 
{ 
m_phMem = phMem; 
m_dwSize = dwSize; 
 
if (phMem) 
{ 
*phMem = NULL; 
} 
} 
 
 
BOOL CMemFile::Create(LPCSTR pszFile, int fnAttribute) 
{ 
if (m_phMem) 
{ 
if (*m_phMem) 
{ 
return(FALSE); 
} 
 
*m_phMem = GlobalAlloc(LMEM_FIXED, m_dwSize); 
return(*m_phMem != NULL); 
} 
else 
{ 
if (m_hf != HFILE_ERROR) 
{ 
return(FALSE); 
} 
 
m_hf = _lcreat(pszFile, fnAttribute); 
return(m_hf != HFILE_ERROR); 
} 
} 
 
 
BOOL CMemFile::Open(LPCSTR pszFile, int oflag) 
{ 
if (m_phMem) 
{ 
return(FALSE); 
} 
else 
{ 
if (m_hf != HFILE_ERROR) 
{ 
return(FALSE); 
} 
 
m_hf = _lopen(pszFile, oflag); 
return(m_hf != HFILE_ERROR); 
} 
} 
 
 
LONG CMemFile::Seek(LONG dist, int seektype) 
{ 
if (m_phMem) 
{ 
if (!*m_phMem) 
{ 
return(HFILE_ERROR); 
} 
 
switch (seektype) 
{ 
case FILE_BEGIN: 
break; 
 
case FILE_CURRENT: 
dist += m_lLoc; 
break; 
 
case FILE_END: 
dist = m_dwSize - dist; 
break; 
 
default: 
return(HFILE_ERROR); 
} 
 
if (dist<0 || dist>(LONG)m_dwSize) 
{ 
return(HFILE_ERROR); 
} 
 
m_lLoc = dist; 
return(dist); 
} 
else 
{ 
return(_llseek(m_hf, dist, seektype)); 
} 
} 
 
 
UINT CMemFile::Read(LPVOID pv, UINT cb) 
{ 
if (m_phMem) 
{ 
if (!*m_phMem) 
{ 
return((UINT)HFILE_ERROR); 
} 
 
if (cb > m_dwSize - m_lLoc) 
{ 
cb = m_dwSize - m_lLoc; 
} 
 
hmemcpy(pv, (LPSTR)(*m_phMem)+m_lLoc, cb); 
m_lLoc += cb; 
return(cb); 
} 
else 
{ 
return(_lread(m_hf, pv, cb)); 
} 
} 
 
 
UINT CMemFile::Write(LPVOID pv, UINT cb) 
{ 
if (m_phMem) 
{ 
if (!*m_phMem) 
{ 
return((UINT)HFILE_ERROR); 
} 
 
if (cb > m_dwSize - m_lLoc) 
{ 
cb = m_dwSize - m_lLoc; 
} 
 
hmemcpy((LPSTR)(*m_phMem)+m_lLoc, pv, cb); 
m_lLoc += cb; 
return(cb); 
} 
else 
{ 
return(_lwrite(m_hf, (LPCSTR)pv, cb)); 
} 
} 
 
 
HFILE CMemFile::Close() 
{ 
HFILE hRet; 
 
if (m_phMem) 
{ 
hRet = *m_phMem ? 0 : HFILE_ERROR; 
} 
else 
{ 
hRet = _lclose(m_hf); 
} 
 
delete this; 
 
return(hRet); 
} 
 
//***************************************************************************** 
// 
// CCabEnum 
// 
// Purpose: 
// 
//        Class encapsulating all the FDI operations 
// 
// Comments: 
// 
//***************************************************************************** 
 
class CCabEnum 
{ 
public: 
CCabEnum() : m_hfdi(0) {} 
~CCabEnum() {} 
 
protected: 
static void HUGE * FAR DIAMONDAPI CabAlloc(ULONG cb); 
static void FAR DIAMONDAPI CabFree(void HUGE *pv); 
static int  FAR DIAMONDAPI CabOpen(char FAR *pszFile, int oflag, int pmode); 
static UINT FAR DIAMONDAPI CabRead(int hf, void FAR *pv, UINT cb); 
static UINT FAR DIAMONDAPI CabWrite(int hf, void FAR *pv, UINT cb); 
static int  FAR DIAMONDAPI CabClose(int hf); 
static long FAR DIAMONDAPI CabSeek(int hf, long dist, int seektype); 
 
BOOL StartEnum(); 
BOOL SimpleEnum(LPCSTR szCabFile, PFNFDINOTIFY pfnCallBack, LPVOID pv); 
void EndEnum(); 
 
HFDI m_hfdi; 
 
private: 
static CMemFile * s_hSpill; 
} ; 
 
 
CMemFile * CCabEnum::s_hSpill = NULL; 
 
void HUGE * FAR DIAMONDAPI CCabEnum::CabAlloc(ULONG cb) 
{ 
    return(GlobalAllocPtr(GHND, cb)); 
} 
 
void FAR DIAMONDAPI CCabEnum::CabFree(void HUGE *pv) 
{ 
    GlobalFreePtr(pv); 
} 
 
int  FAR DIAMONDAPI CCabEnum::CabOpen(char FAR *pszFile, int oflag, int pmode) 
{ 
    if(!pszFile) 
    { 
      return -1; 
    } 
 
    // See if we are opening the spill file. 
    if( *pszFile=='*' ) 
    { 
char szSpillFile[MAX_PATH]; 
char szTempPath[MAX_PATH]; 
 
        if(s_hSpill != NULL) 
            return -1; 
 
GetTempPath(sizeof(szTempPath), szTempPath); 
GetTempFileName(szTempPath, "fdi", 0, szSpillFile); 
 
        s_hSpill = new CMemFile(NULL, 0); 
if (!s_hSpill) 
{ 
return(-1); 
} 
        if (!s_hSpill->Create(szSpillFile, 0)) 
{ 
delete s_hSpill; 
s_hSpill = NULL; 
return(-1); 
} 
            
        // Set its extent. 
        if( s_hSpill->Seek( ((FDISPILLFILE FAR *)pszFile)->cbFile-1, 0) == HFILE_ERROR) 
        { 
s_hSpill->Close(); 
s_hSpill = NULL; 
return -1; 
        } 
        s_hSpill->Write(szSpillFile, 1); 
 
        return (int)s_hSpill; 
    } 
 
    CMemFile *hFile = new CMemFile(NULL, 0); 
if (!hFile) 
{ 
return(-1); 
} 
 
    while (!hFile->Open(pszFile, oflag)) 
    { 
#if 1// TODO: No UI for inserting a disk at this point 
delete hFile; 
return(-1); 
#else 
       // Failed to open the source. 
       if (!LoadString (g_hInst, IDS_DISKPROMPT, szText, MAX_STRTABLE_LEN)) 
           return -1; 
            
   char szText[MAX_PATH]; 
 
       wsprintf (g_pErrorBuffer, (LPSTR)szText, (LPSTR)g_pCabName); 
 
       // Use hwndIniting to have a parent window  
       if ( MyMessageBox(g_hwndIniting, g_pErrorBuffer, 
                    MAKEINTRESOURCE(IDS_DISKPROMPT_TIT), 
                    MB_OKCANCEL|MB_ICONSTOP, 0) == IDOK ) 
          continue; 
       else 
          return -1; 
#endif 
    } 
    
    return((int)hFile); 
} 
 
 
UINT FAR DIAMONDAPI CCabEnum::CabRead(int hf, void FAR *pv, UINT cb) 
{ 
CMemFile *hFile = (CMemFile *)hf; 
 
    if (hFile->Read(pv, cb) != cb) 
    {     
        cb = (UINT)-1; 
} 
 
    return(cb);     
} 
 
 
UINT FAR DIAMONDAPI CCabEnum::CabWrite(int hf, void FAR *pv, UINT cb) 
{ 
CMemFile *hFile = (CMemFile *)hf; 
 
    if (hFile->Write(pv, cb) != cb) 
{ 
cb = (UINT)-1; 
} 
   
return(cb); 
} 
 
 
int  FAR DIAMONDAPI CCabEnum::CabClose(int hf) 
{ 
CMemFile *hFile = (CMemFile *)hf; 
 
    // Special case for the deletion of the spill file. 
    if(hFile == s_hSpill) 
{ 
        s_hSpill = NULL; 
} 
 
    return (hFile->Close()); 
} 
 
 
long FAR DIAMONDAPI CCabEnum::CabSeek(int hf, long dist, int seektype) 
{ 
CMemFile *hFile = (CMemFile *)hf; 
 
    return(hFile->Seek(dist, seektype)); 
} 
 
 
BOOL CCabEnum::StartEnum() 
{ 
if (m_hfdi) 
{ 
// We seem to already be enumerating 
return(FALSE); 
} 
 
ERF erf; 
 
m_hfdi = FDICreate( 
CabAlloc, 
        CabFree, 
        CabOpen, 
        CabRead, 
        CabWrite, 
        CabClose, 
        CabSeek, 
        cpu80386, 
        &erf); 
 
return(m_hfdi != NULL); 
} 
 
 
BOOL CCabEnum::SimpleEnum(LPCSTR szCabFile, PFNFDINOTIFY pfnCallBack, LPVOID pv) 
{ 
char szCabPath[MAX_PATH]; 
char szCabName[MAX_PATH]; 
 
// Path should be fully qualified 
lstrcpyn(szCabPath, szCabFile, sizeof(szCabPath)); 
LPSTR pszName = PathFindFileName(szCabPath); 
if (!pszName) 
{ 
return(FALSE); 
} 
 
lstrcpy(szCabName, pszName); 
*pszName = '\0'; 
 
if (!StartEnum()) 
{ 
return(FALSE); 
} 
 
BOOL bRet = FDICopy( 
m_hfdi, 
szCabName, 
szCabPath,// path to cabinet files 
0,// flags 
pfnCallBack, 
NULL, 
pv); 
 
EndEnum(); 
 
return(bRet); 
} 
 
 
void CCabEnum::EndEnum() 
{ 
if (!m_hfdi) 
{ 
return; 
} 
 
FDIDestroy(m_hfdi); 
m_hfdi = NULL; 
} 
 
 
class CCabItemsCB : private CCabEnum 
{ 
public: 
CCabItemsCB(CCabItems::PFNCABITEM pfnCallBack, LPARAM lParam) 
{ 
m_pfnCallBack = pfnCallBack; 
m_lParam = lParam; 
} 
~CCabItemsCB() {} 
 
BOOL DoEnum(LPCSTR szCabFile) 
{ 
return(SimpleEnum(szCabFile, CabItemsNotify, this)); 
} 
 
private: 
static int  FAR DIAMONDAPI CabItemsNotify(FDINOTIFICATIONTYPE fdint, 
PFDINOTIFICATION pfdin); 
 
CCabItems::PFNCABITEM m_pfnCallBack; 
LPARAM m_lParam; 
} ; 
 
 
int FAR DIAMONDAPI CCabItemsCB::CabItemsNotify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) 
{ 
CCabItemsCB *pThis = (CCabItemsCB *)pfdin->pv; 
 
    // uiYield( g_hwndSetup ); 
     
    switch (fdint) 
    { 
    case fdintCOPY_FILE: 
pThis->m_pfnCallBack(pfdin->psz1, pfdin->cb, pfdin->date, pfdin->time, pfdin->attribs, 
pThis->m_lParam); 
break; 
 
default: 
break; 
    } // end switch 
 
    return 0; 
} 
 
//***************************************************************************** 
// 
// CCabItems::EnumItems 
// 
// Purpose: 
// 
//        Enumerate the items in the cab file 
// 
// 
// Comments: 
// 
//         lParam contains pointer to CCabFolder 
// 
//***************************************************************************** 
 
BOOL CCabItems::EnumItems(PFNCABITEM pfnCallBack, LPARAM lParam) 
{ 
CCabItemsCB cItems(pfnCallBack, lParam); 
 
return(cItems.DoEnum(m_szCabFile)); 
} 
 
//***************************************************************************** 
// 
// CCabExtractCB 
// 
// Purpose: 
// 
//        handles the call back while extracting Cab files 
// 
// 
//***************************************************************************** 
 
class CCabExtractCB : private CCabEnum 
{ 
public: 
CCabExtractCB(LPCSTR szDir, HWND hwndOwner, CCabExtract::PFNCABEXTRACT pfnCallBack, 
LPARAM lParam) 
{ 
m_szDir = szDir; 
m_hwndOwner = hwndOwner; 
m_pfnCallBack = pfnCallBack; 
m_lParam = lParam; 
m_bTryNextCab = FALSE; 
} 
~CCabExtractCB() {} 
 
BOOL DoEnum(LPCSTR szCabFile) 
{ 
return(SimpleEnum(szCabFile, CabExtractNotify, this)); 
} 
 
private: 
static int  FAR DIAMONDAPI CabExtractNotify(FDINOTIFICATIONTYPE fdint, 
PFDINOTIFICATION pfdin); 
static int CALLBACK CCabExtractCB::BrowseNotify(HWND hwnd, UINT uMsg, LPARAM lParam, 
LPARAM lpData); 
 
LPCSTR m_szDir; 
HWND m_hwndOwner; 
CCabExtract::PFNCABEXTRACT m_pfnCallBack; 
LPARAM m_lParam; 
BOOL m_bTryNextCab; 
PFDINOTIFICATION m_pfdin; 
} ; 
 
 
int CALLBACK CCabExtractCB::BrowseNotify(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) 
{ 
CCabExtractCB *pThis = (CCabExtractCB *)lpData; 
 
switch (uMsg) 
{ 
case BFFM_INITIALIZED: 
{ 
// Set initial folder 
LPSTR pszEnd = PathAddBackslash(pThis->m_pfdin->psz3); 
if (pszEnd - pThis->m_pfdin->psz3 > 3) 
{ 
// No problems if not drive root 
*(pszEnd - 1) = '\0'; 
} 
SendMessage(hwnd, BFFM_SETSELECTION, 1, (LPARAM)pThis->m_pfdin->psz3); 
break; 
} 
 
default: 
return(0); 
} 
 
return(1); 
} 
 
 
int FAR DIAMONDAPI CCabExtractCB::CabExtractNotify(FDINOTIFICATIONTYPE fdint, 
PFDINOTIFICATION pfdin) 
{ 
CCabExtractCB *pThis = (CCabExtractCB *)pfdin->pv; 
 
    // uiYield( g_hwndSetup ); 
     
    switch (fdint) 
    { 
case fdintCABINET_INFO: 
pThis->m_bTryNextCab = TRUE; 
break; 
 
case fdintNEXT_CABINET: 
{ 
if (pThis->m_bTryNextCab) 
{ 
// Automatically open next cab if already in default dir 
pThis->m_bTryNextCab = FALSE; 
return(1); 
} 
 
pThis->m_pfdin = pfdin; 
 
char szTitle[80]; 
LoadString(g_ThisDll.GetInstance(), IDS_NEXTCABBROWSE, szTitle, sizeof(szTitle)); 
 
BROWSEINFO bi; 
bi.hwndOwner = pThis->m_hwndOwner; 
bi.pidlRoot = NULL; 
bi.pszDisplayName = NULL; 
bi.lpszTitle = szTitle; 
bi.ulFlags = BIF_RETURNONLYFSDIRS; 
bi.lpfn = BrowseNotify; 
bi.lParam = (LPARAM)pThis; 
 
LPITEMIDLIST pidl = SHBrowseForFolder(&bi); 
 
if (bi.pidlRoot) 
{ 
ILFree((LPITEMIDLIST)bi.pidlRoot); 
} 
 
if (!pidl) 
{ 
return(-1); 
} 
 
BOOL bSuccess = SHGetPathFromIDList(pidl, pfdin->psz3); 
ILFree(pidl); 
 
if (bSuccess) 
{ 
PathAddBackslash(pfdin->psz3); 
return(1); 
} 
 
return(-1); 
} 
 
    case fdintCOPY_FILE: 
{ 
HGLOBAL *phMem = pThis->m_pfnCallBack(pfdin->psz1, pfdin->cb, pfdin->date, 
pfdin->time, pfdin->attribs, pThis->m_lParam); 
if (!phMem) 
{ 
break; 
} 
 
char szTemp[MAX_PATH]; 
 
CMemFile *hFile; 
 
if (pThis->m_szDir == DIR_MEM) 
{ 
*szTemp = '\0'; 
hFile = new CMemFile(phMem, pfdin->cb); 
} 
else 
{ 
PathCombine(szTemp, pThis->m_szDir, pfdin->psz1); 
hFile = new CMemFile(NULL, 0); 
} 
 
if (!hFile) 
{ 
return(-1); 
} 
 
if (hFile->Create(szTemp, OF_WRITE)) 
{ 
return((int)hFile); 
} 
 
delete hFile; 
return(-1); 
} 
 
    case fdintCLOSE_FILE_INFO: 
{ 
CMemFile *hFile = (CMemFile *)pfdin->hf; 
 
return(hFile->Close() == 0); 
} 
 
default: 
break; 
    } // end switch 
 
    return 0; 
} 
 
 
BOOL CCabExtract::ExtractItems(HWND hwndOwner, LPCSTR szDir, PFNCABEXTRACT pfnCallBack, LPARAM lParam) 
{ 
char szTempDir[MAX_PATH]; 
 
if (!szDir) 
{ 
szDir = szTempDir; 
 
char szTitle[80]; 
LoadString(g_ThisDll.GetInstance(), IDS_EXTRACTBROWSE, szTitle, sizeof(szTitle)); 
 
BROWSEINFO bi; 
bi.hwndOwner = hwndOwner; 
bi.pidlRoot = NULL; 
bi.pszDisplayName = NULL; 
bi.lpszTitle = szTitle; 
bi.ulFlags = BIF_RETURNONLYFSDIRS; 
bi.lpfn = NULL; 
 
LPITEMIDLIST pidl = SHBrowseForFolder(&bi); 
if (!pidl) 
{ 
return(FALSE); 
} 
 
BOOL bSuccess = SHGetPathFromIDList(pidl, szTempDir); 
 
ILFree(pidl); 
if (!bSuccess) 
{ 
return(FALSE); 
} 
} 
 
CCabExtractCB cExtract(szDir, hwndOwner, pfnCallBack, lParam); 
 
// Display Wait cursor until done copying 
CWaitCursor cWait; 
 
return(cExtract.DoEnum(m_szCabFile)); 
}