home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 1996 March / PCPRO0396.ISO / code / visualc / zipfin~1.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-12  |  12.0 KB  |  462 lines

  1. // ZIPFindDlg.cpp : implementation file
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include <io.h>
  6. #include "ZIPFind.h"
  7. #include "ZIPFindDlg.h"
  8.  
  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #undef THIS_FILE
  12. static char THIS_FILE[] = __FILE__;
  13. #endif
  14.  
  15. #define        CENTRALDIRSIG                    0x02014B50
  16. #define        DIRTAILSIG                        0x06054B50
  17.  
  18. #pragma pack(1)                                // Give me it like it is !!
  19.  
  20. typedef struct DIRTAIL
  21. {
  22.     long            Signature;                // should be DIRTAILSIG
  23.     unsigned short  ThisDisk;                // number of this disk
  24.     unsigned short    DirDisk;                // disk # holding dir
  25.     unsigned short  NumEntries;                // number of entries (this disk)
  26.     unsigned short  TotEntries;                // total # files in ZIP
  27.     long            DirSize;                // size of central dir
  28.     long            DirOffset;                // offset of central dir
  29.     unsigned short    BannerLength;            // length of ZIP file banner
  30. }   DIRTAIL;
  31.  
  32. typedef struct DIRENTRY
  33. {
  34.     long            Signature;                // should be $02014B50
  35.     unsigned short    CreatorVersion;            // version of PKZIP used for create
  36.     unsigned short    ExtractorVersion;        // version needed for extract
  37.     unsigned short    GenBits;                // general purpose bit flags
  38.     unsigned short    CompressMethod;            // compression method used
  39.     unsigned short    Modtime;                // last modification time
  40.     unsigned short    ModDate;                // last modification date
  41.     long            Crc32;                    // 32-bit CRC 
  42.     long            CompressedSize;            // compressed size of file
  43.     long            OriginalSize;            // original size of file
  44.     unsigned short    FileNameLen;            // length of file name
  45.     unsigned short    ExtraLen;                // extra info length
  46.     unsigned short    CommentLen;                // length of file comment
  47.     unsigned short    DiskNumStart;            // starting disk number
  48.     unsigned short    FileAttribs;            // file attributes
  49.     long            FileFlags;                // file flag bits
  50.     long            HeaderPos;                // pointer to local header
  51. }    DIRENTRY;
  52.  
  53. /////////////////////////////////////////////////////////////////////////////
  54. // CAboutDlg dialog used for App About
  55.  
  56. class CAboutDlg : public CDialog
  57. {
  58. public:
  59.     CAboutDlg();
  60.  
  61. // Dialog Data
  62.     //{{AFX_DATA(CAboutDlg)
  63.     enum { IDD = IDD_ABOUTBOX };
  64.     //}}AFX_DATA
  65.  
  66.     // ClassWizard generated virtual function overrides
  67.     //{{AFX_VIRTUAL(CAboutDlg)
  68.     protected:
  69.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  70.     //}}AFX_VIRTUAL
  71.  
  72. // Implementation
  73. protected:
  74.     //{{AFX_MSG(CAboutDlg)
  75.     //}}AFX_MSG
  76.     DECLARE_MESSAGE_MAP()
  77. };
  78.  
  79. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  80. {
  81.     //{{AFX_DATA_INIT(CAboutDlg)
  82.     //}}AFX_DATA_INIT
  83. }
  84.  
  85. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  86. {
  87.     CDialog::DoDataExchange(pDX);
  88.     //{{AFX_DATA_MAP(CAboutDlg)
  89.     //}}AFX_DATA_MAP
  90. }
  91.  
  92. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  93.     //{{AFX_MSG_MAP(CAboutDlg)
  94.         // No message handlers
  95.     //}}AFX_MSG_MAP
  96. END_MESSAGE_MAP()
  97.  
  98. /////////////////////////////////////////////////////////////////////////////
  99. // CZIPFindDlg dialog
  100.  
  101. CZIPFindDlg::CZIPFindDlg(CWnd* pParent /*=NULL*/)
  102.     : CDialog(CZIPFindDlg::IDD, pParent)
  103. {
  104.     //{{AFX_DATA_INIT(CZIPFindDlg)
  105.         // NOTE: the ClassWizard will add member initialization here
  106.     //}}AFX_DATA_INIT
  107.     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  108.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  109. }
  110.  
  111. void CZIPFindDlg::DoDataExchange(CDataExchange* pDX)
  112. {
  113.     CDialog::DoDataExchange(pDX);
  114.     //{{AFX_DATA_MAP(CZIPFindDlg)
  115.         // NOTE: the ClassWizard will add DDX and DDV calls here
  116.     //}}AFX_DATA_MAP
  117. }
  118.  
  119. BEGIN_MESSAGE_MAP(CZIPFindDlg, CDialog)
  120.     //{{AFX_MSG_MAP(CZIPFindDlg)
  121.     ON_WM_SYSCOMMAND()
  122.     ON_WM_PAINT()
  123.     ON_WM_QUERYDRAGICON()
  124.     ON_BN_CLICKED(IDC_SEARCH, OnSearch)
  125.     //}}AFX_MSG_MAP
  126. END_MESSAGE_MAP()
  127.  
  128. /////////////////////////////////////////////////////////////////////////////
  129. // CZIPFindDlg message handlers
  130.  
  131. BOOL CZIPFindDlg::OnInitDialog()
  132. {
  133.     CDialog::OnInitDialog();
  134.  
  135.     // Add "About..." menu item to system menu.
  136.  
  137.     // IDM_ABOUTBOX must be in the system command range.
  138.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  139.     ASSERT(IDM_ABOUTBOX < 0xF000);
  140.  
  141.     CMenu* pSysMenu = GetSystemMenu(FALSE);
  142.     CString strAboutMenu;
  143.     strAboutMenu.LoadString(IDS_ABOUTBOX);
  144.     if (!strAboutMenu.IsEmpty())
  145.     {
  146.         pSysMenu->AppendMenu(MF_SEPARATOR);
  147.         pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  148.     }
  149.  
  150.     // Set the icon for this dialog.  The framework does this automatically
  151.     //  when the application's main window is not a dialog
  152.     SetIcon(m_hIcon, TRUE);            // Set big icon
  153.     SetIcon(m_hIcon, FALSE);        // Set small icon
  154.     
  155.     // Set up drive list combo box
  156.     
  157.     char drvName [5];
  158.     CComboBox * p = (CComboBox *)GetDlgItem(IDC_DRIVELIST);
  159.  
  160.     for (int drv = 2; drv < 26; drv++)
  161.     {
  162.         lstrcpy (drvName, "X:\\");    
  163.         drvName [0] = drv + 'A';
  164.         if (GetDriveType (drvName) == DRIVE_FIXED) 
  165.         {
  166.             char volName [128], sz [128];
  167.             GetVolumeInformation (drvName, volName, sizeof (volName), 0, 0, 0, 0, 0);
  168.             sprintf (sz, "%c:  [%s]", drv + 'A', volName);
  169.             p->AddString (sz);
  170.         }
  171.     }
  172.     
  173.     p->SetCurSel (p->AddString("[All Drives]"));
  174.  
  175.     GetDlgItem(IDC_FILENAME)->SetFocus();        // Filename edit box has focus
  176.  
  177.     return TRUE;  // return TRUE  unless you set the focus to a control
  178. }
  179.  
  180. void CZIPFindDlg::OnSysCommand(UINT nID, LPARAM lParam)
  181. {
  182.     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  183.     {
  184.         CAboutDlg dlgAbout;
  185.         dlgAbout.DoModal();
  186.     }
  187.     else
  188.     {
  189.         CDialog::OnSysCommand(nID, lParam);
  190.     }
  191. }
  192.  
  193. // If you add a minimize button to your dialog, you will need the code below
  194. //  to draw the icon.  For MFC applications using the document/view model,
  195. //  this is automatically done for you by the framework.
  196.  
  197. void CZIPFindDlg::OnPaint() 
  198. {
  199.     if (IsIconic())
  200.     {
  201.         CPaintDC dc(this); // device context for painting
  202.  
  203.         SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  204.  
  205.         // Center icon in client rectangle
  206.         int cxIcon = GetSystemMetrics(SM_CXICON);
  207.         int cyIcon = GetSystemMetrics(SM_CYICON);
  208.         CRect rect;
  209.         GetClientRect(&rect);
  210.         int x = (rect.Width() - cxIcon + 1) / 2;
  211.         int y = (rect.Height() - cyIcon + 1) / 2;
  212.  
  213.         // Draw the icon
  214.         dc.DrawIcon(x, y, m_hIcon);
  215.     }
  216.     else
  217.     {
  218.         CDialog::OnPaint();
  219.     }
  220. }
  221.  
  222. // The system calls this to obtain the cursor to display while the user drags
  223. //  the minimized window.
  224.  
  225. HCURSOR CZIPFindDlg::OnQueryDragIcon()
  226. {
  227.     return (HCURSOR) m_hIcon;
  228. }
  229.  
  230. // Fast scanner for Signature
  231.  
  232. int FindSig (char * buff, int len, long Signature)
  233. {
  234.     for (char * p = buff; p <= &buff [len - 4]; p++)
  235.     {
  236.         p = (char *) memchr (p, Signature & 255, &buff [len] - p);
  237.         if (p == NULL || buff + len - p < 4) break;
  238.         if (*(long *)p == Signature) return p - buff;
  239.     }
  240.  
  241.     return (-1);
  242. }
  243.  
  244. // Scan the ZIP file for the wanted signature
  245.  
  246. long GetSigOffset (HFILE fd, long Signature)
  247. {
  248.     int bp;                        // found position of sig
  249.     int bytesRead;                // bytes read from the file
  250.     long fs;                    // size of the ZIP file
  251.     long pos;                    // current seek position
  252.     static char sigbuff [4096];    // buffer for sig searches
  253.  
  254.     fs = _llseek (fd, 0, FILE_END);
  255.     pos = (fs <= sizeof (sigbuff)) ? 0 : fs - sizeof (sigbuff);
  256.     _llseek (fd, pos, 0);
  257.  
  258.     // Get initial buffer content
  259.  
  260.     _lread (fd, sigbuff, sizeof (sigbuff));
  261.     bp = FindSig (sigbuff, sizeof (sigbuff), Signature);
  262.  
  263.     // This is the main search loop...
  264.     
  265.     while (bp < 0 && pos > 0)
  266.     {
  267.         memcpy (&sigbuff [sizeof (sigbuff) - 4], sigbuff, 4);
  268.         pos -= sizeof (sigbuff) - 4;
  269.         if (pos < 0) pos = 0;
  270.         _llseek (fd, pos, 0);
  271.         bytesRead = _lread (fd, sigbuff, sizeof (sigbuff) - 4);
  272.  
  273.         if (bytesRead < sizeof (sigbuff) - 4)
  274.             memcpy (&sigbuff [bytesRead], &sigbuff [sizeof (sigbuff) - 4], 4);
  275.  
  276.         if (bytesRead > 0)
  277.         {
  278.             bytesRead += 4;
  279.             bp = FindSig (sigbuff, bytesRead, Signature);
  280.         }
  281.     }
  282.  
  283.     return (bp < 0) ? -1 : (pos + bp);
  284. }
  285.  
  286.  
  287. // Read a ZIP file directory into memory
  288.  
  289. char * ReadDirectory (HFILE fd, int * numFiles)
  290. {
  291.     long tailpos;
  292.     DIRTAIL tail;
  293.     char * dir = NULL;
  294.  
  295.     if ((tailpos = GetSigOffset (fd, DIRTAILSIG)) >= 0)
  296.     {
  297.         _llseek (fd, tailpos, 0);
  298.         _lread (fd, &tail, sizeof (tail));
  299.         *numFiles = tail.TotEntries;
  300.         _llseek (fd, tail.DirOffset, 0);
  301.         _lread (fd, dir = (char *) malloc (tail.DirSize), tail.DirSize);
  302.  
  303.     }
  304.  
  305.     return (dir);
  306. }
  307.  
  308. // Try to find a match on ZIP file contents 
  309.  
  310. int MatchFile (DIRENTRY * p, int numFiles, char * FileSpec)
  311. {
  312.     int next;
  313.     char * p1, * p2;
  314.     char buff [128];
  315.     char spec [128];
  316.  
  317.     while (numFiles--)
  318.     {
  319.         // We need this sanity check to guard against nested ZIP's
  320.  
  321.         if (p->Signature != CENTRALDIRSIG) break;
  322.  
  323.         memcpy (buff, p + 1, p->FileNameLen);
  324.         buff [p->FileNameLen] = '\0';
  325.  
  326.         // Now do a rather simplistic pattern match
  327.  
  328.         _strupr (buff);
  329.         strcpy (spec, FileSpec);
  330.         if (strcmp (buff, spec) == 0) return (1);
  331.         
  332.         if ((p1 = strchr (buff, '.')) != NULL && (p2 = strchr (spec, '.')) != NULL)
  333.         {
  334.             *p1++ = '\0';
  335.             *p2++ = '\0';
  336.  
  337.             if (strcmp (buff, spec) == 0 || *buff == '*' || *spec == '*')
  338.                   if (strcmp (p1, p2) == 0 || *p1 == '*' || *p2 == '*')
  339.                     return (1);
  340.         }
  341.         
  342.         next = p->FileNameLen + p->ExtraLen + p->CommentLen + sizeof (DIRENTRY);
  343.         p = (DIRENTRY *)(next + (char *) p);
  344.     }
  345.  
  346.     return (0);
  347. }
  348.  
  349. // See if the ZIP file contains the wanted file spec
  350.  
  351. void ValidateZIP (char * ZipFileName, CListBox * FileList, char * FileSpec)
  352. {
  353.     HFILE fd;                // file descriptor for this ZIP file
  354.     char * p;                // pointer to ZIP file directory
  355.     int numFiles;            // number of files in this ZIP file
  356.  
  357.     if ((fd = _lopen (ZipFileName, OF_READ)) != -1)
  358.     {
  359.         if ((p = ReadDirectory (fd, &numFiles)) != NULL)
  360.         {
  361.             if (MatchFile ((DIRENTRY *) p, numFiles, FileSpec)) FileList->AddString (ZipFileName);
  362.             free (p);
  363.         }
  364.         
  365.         _lclose (fd);
  366.     }
  367. }
  368.  
  369. void ScanZipFiles (char * PathSpec, CListBox * FileList, char * FileSpec, CStatic * progress)
  370. {
  371.     long findHandle;
  372.     char Path [256], temp [256];        // Recursive ? Don't do this at home...
  373.     _finddata_t findBuffer;
  374.  
  375.     strcat (strcpy (Path, PathSpec), "*.*");
  376.     findHandle = _findfirst (Path, &findBuffer);
  377.     while (findHandle != -1)
  378.     {
  379.         // Is it a ZIP file ?
  380.  
  381.         if ((findBuffer.attrib & _A_SUBDIR) == 0)
  382.         {
  383.             if (strcmpi (&findBuffer.name [strlen (findBuffer.name) - 4], ".ZIP") == 0)         
  384.             {
  385.                 strcat (strcpy (temp, PathSpec), findBuffer.name);
  386.                 progress->SetWindowText (temp);
  387.                 ValidateZIP (temp, FileList, FileSpec);
  388.             }
  389.         }
  390.         else if (findBuffer.name [0] != '.')    
  391.         {
  392.             // It's recursion time !
  393.             strcat (strcat (strcpy (temp, PathSpec), findBuffer.name), "\\");
  394.             ScanZipFiles (temp, FileList, FileSpec, progress);
  395.         }
  396.  
  397.         // Set up for the next directory entry...*/
  398.             
  399.         if (_findnext (findHandle, &findBuffer) != 0) break;
  400.     }
  401.  
  402.     if (findHandle != -1) _findclose (findHandle);
  403. }
  404.  
  405. void CZIPFindDlg::OnSearch() 
  406. {
  407.     CEdit * fName = (CEdit *)GetDlgItem(IDC_FILENAME);
  408.     CListBox * fList = (CListBox *)GetDlgItem(IDC_FOUNDLIST);
  409.     CComboBox * dList = (CComboBox *)GetDlgItem(IDC_DRIVELIST);
  410.     CStatic * progress = (CStatic *)GetDlgItem(IDC_PROGRESS);
  411.  
  412.     char szBuff [128];
  413.     fName->GetWindowText (szBuff, sizeof (szBuff));
  414.     if (szBuff [0] == '\0') MessageBox ("No file name was specified.");
  415.     else
  416.     {
  417.         // automatic wait cursor handling
  418.         CWaitCursor cWait;            
  419.         
  420.         // disable the OnSearch button
  421.         (CButton *)GetDlgItem(IDC_SEARCH)->EnableWindow (FALSE);
  422.         
  423.         // clear the list box
  424.         fList->ShowWindow (SW_HIDE);
  425.         fList->ResetContent();
  426.  
  427.         // Show progress item
  428.         progress->ShowWindow (SW_SHOW);
  429.     
  430.         // get current drive selection
  431.         char driveSel [20];
  432.         dList->GetLBText (dList->GetCurSel(), driveSel);
  433.  
  434.         for (int drv = 2; drv < 26; drv++)
  435.             if (driveSel[0] == '[' || driveSel[0] == drv + 'A')
  436.             {
  437.                 char searchPath [4];
  438.                 strcpy (searchPath, "X:\\");
  439.                 searchPath [0] = drv + 'A';
  440.                 ScanZipFiles (searchPath, fList, _strupr (szBuff), progress);
  441.             }
  442.  
  443.         // enable the OnSearch button
  444.         (CButton *)GetDlgItem(IDC_SEARCH)->EnableWindow (TRUE);
  445.         progress->ShowWindow (SW_HIDE);
  446.         fList->ShowWindow (SW_SHOW);
  447.     }
  448. }
  449.  
  450.  
  451. BOOL CZIPFindDlg::OnCommand(WPARAM wParam, LPARAM lParam) 
  452. {
  453.     if (wParam == IDOK)        // Interpret ENTER as a click on "Search" button
  454.     {
  455.         OnSearch ();
  456.         return FALSE;
  457.     }
  458.  
  459.     return CDialog::OnCommand(wParam, lParam);
  460. }
  461.  
  462.