July 28, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Zip and Unzip the MFC Way

  • October 11, 2000
  • By Tadeusz Dracz
  • Send Email »
  • More Articles »

Gilles Vollant did a great job writing zip.c and unzip.c (IO on .zip files using zlib), which are distributed with the zlib library. However using them in a program is quite risky. There is no way to recover from an error occurred during zipping, without memory leaks. Let's say we are out of disk space during packing files. There are two things we can do then; we can close our zipFile and get unexpected results, because the function which performs this action tries to write some buffers left back to the disk (and the stream it operates is already in the error state), or we may leave the zipFile opened and have the buffers not freed. None of these possibilities was a good solution so I rewrote the code to better handle the errors. I left type names as in the original.

The main improvements are:

- smart buffers (they free automatically at the destruction eliminating memory leaks when an error occurs)

- CFile class used instead of stream to manipulate files (throws CFileException)

- operator "new" used to allocate memory (it throws CMemoryException so errors can be easily handled).

The ZipFunc is a static library (you can change it if you want) and statically links with compiled zlib.lib (version 1.13 nowadays). The zlib library can be replaced with a newer version providing you also replace the files: "zlib.h" and "zconf.h". To add ZipFunc library functionality to your project you need to link the library to the project (e.g. add "..\ZipFunc\debug(release)\ZipFunc.lib" to Project Settings->Link->Input->Object/library modules) and add ZipFunc directory to the preprocessor searches (Project Settings -> C++ -> Preprocessor -> Additional include directories). You may also need to ignore libc.lib library. The ZipFunc library uses MFC in a static library as a Release Configuration and in a shared library as a Debug Configuration. You may need to adapt this to your needs. The details about the functions use are in the sources.

Here goes the example of use CZipFile:

#define BUF_SIZE 16384

#include "ZipFile.h"

void CCompresorDlg::OnButton1() 
{
 <font color=#008000>// getting the file to zip</font>

 CFileDialog fd(TRUE);

 if (fd.DoModal() != IDOK)
  return;

 <font color=#008000>// adding extension</font>
 CZipFile zf(fd.GetPathName() + ".zip", 0);

 char buf[BUF_SIZE];

 CFile f(fd.GetPathName(), CFile::modeRead);

 zip_fileinfo zi;

 <font color=#008000>// getting information about the </font>
 <font color=#008000>// date and the attributes (this is new </font>
 <font color=#008000>// in ZipFunc)</font>
 zf.UpdateZipInfo(zi, f);

 zf.OpenNewFileInZip(fd.GetFileName(), zi, Z_BEST_COMPRESSION);

 int size_read;

 do
 {
  size_read = f.Read(buf, BUF_SIZE);
  if (size_read)

  zf.WriteInFileInZip(buf, size_read);
 } while (size_read == BUF_SIZE);

 <font color=#008000>// cannot be called by the destructor because it may throw</font>
 <font color=#008000>// an exception (it is not good to throw an exception</font>
 <font color=#008000>// when another one may be progress)</font>
 zf.Close();
}

And below is an example of using the CUnzipFile:

#include "unzipFile.h"

void CCompresorDlg::OnButton2() 
{
 <font color=#008000>// getting the file to unzip </font>
 CFileDialog fd(TRUE);

 if (fd.DoModal() != IDOK)
  return;

 CUnzipFile uf(fd.GetPathName());
 uf.GoToFirstFile();
 unz_file_info ui;

 <font color=#008000>// getting the information about the file </font>
 <font color=#008000>// (date, attributes, the size of the filename)</font>
 uf.GetCurrentFileInfo(&ui);

 int iNameSize = ui.size_filename + 1;
 char* pName = new char [iNameSize];

 <font color=#008000>// get the name of the file</font>
 uf.GetCurrentFileInfo(NULL, pName, iNameSize);

 TCHAR szDir[_MAX_DIR];
 TCHAR szDrive[_MAX_DRIVE];

 _tsplitpath(fd.GetPathName(), szDrive, szDir,NULL, NULL);

 CString szPath = CString(szDrive) + szDir;

 CFile f( szPath + pName, CFile::modeWrite | CFile::modeCreate);

 delete[] pName;

 uf.OpenCurrentFile();

 char buf[BUF_SIZE];
 int size_read;

 do
 {
  size_read = uf.ReadCurrentFile(buf, BUF_SIZE);
  if (size_read > 0)
  f.Write(buf, size_read);
 } while (size_read == BUF_SIZE);

 <font color=#008000>// set the original date stamp and attributes to the unpacked file</font>
 <font color=#008000>// (this function closes the file "f" which is needed to apply</font>
 <font color=#008000>// the attributes)</font>
 uf.UpdateFileStatus(f, ui);

 <font color=#008000>// cannot be called by the destructor </font>

 uf.Close(); 
}

The library throws the following exceptions: CMemoryException, CFileExeption and CZipException. The first two don't need an explanation. The last is thrown when some internal zip or unzip error occurs. (The details, once again, are in the sources). Handling them may be done in a following way:

try
{
 <font color=#008000>// ...</font>
 <font color=#008000>// some zipping or unzipping here(it may be the one of </font>
 <font color=#008000>// the previous examples)</font>
}
catch (CException* e)
{
 if (e->IsKindOf( RUNTIME_CLASS( CZipException )))
 {
  CZipException* p = (CZipException*) e;
  <font color=#008000>//... and so on </font>
 }
 else if (e->IsKindOf( RUNTIME_CLASS( CFileException )))
 {
  CFileException* p = (CFileException*) e;
  <font color=#008000>//... and so on </font>
 }
 else <font color=#008000>// the only possibility is a memory exception I suppose</font>
 {
  <font color=#008000>//... and so on </font>
 }
e->Delete();
}

Downloads

ZipFunc.zip
ZipFunc_demo.zip
ZipFunc_src.zip






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel