Click here to Skip to main content
15,894,740 members
Articles / Desktop Programming / MFC
Article

Store and Extract multiple compressed files in an archive & Extract from Resource

Rate me:
Please Sign up or sign in to vote.
3.50/5 (6 votes)
26 Apr 20036 min read 54.1K   1.1K   21   2
This class archives files together. It can compress them, decompress them & decompress them from a resource. It uses it's own format and not the normal zip format

Image 1

Introduction

What it does:

  • Put loads of files into one file (archive)
  • Extract files from single file (archive)
  • Extract from archive even if it's a resource!
  • Works with sub directories

What it does not do:

  • Support standard zip format (although a utility to create archives it does support is included. It's the demo app, zip_test)
  • Make cups of tea

Background

After ages of searching for some code to do this, I came up with nothing. The closest I had was CGZip by Jonathan de Halleux. (CGZip, a C++ wrapper for gzip methods) The problem was that this only did one file at a time. I wanted to write an installer program to do loads. It can't be too hard to write some code to lump them all together I thought, and I was right.

Using the Demo

Ok, now embarking on rArchiving for dummies. First get all the files you need. Go to (CGZip, a C++ wrapper for gzip methods) and get the demo project. Now go to the top of this article and get rArchive.zip. On my computer I have a folder where I keep all my programs. I have a subfolder in it called _common. This is where I put all the common stuff. Unzip CGZip into a temp folder then move the zlib folder into whatever is your equivalent of _common. You do not need any more files from CGZip. Next unzip rArchive.zip into a tmp folder. Move rArchive.h and rArchive.cpp into the _common folder. Now your _common folder should have at least these entries:

  • zlib (directory)
  • rArchive.h
  • rarchive.cpp

Now move the zip_test directory from the rArchive zip into the folder where you keep your Visual Studio projects. (It should now be along side the _common folder) Now go into the zip_test folder and load zip_test.dsw. It will probably lose the zlib project. Now browse to common \zlib\zlib.dsp. Once you have re-setup the link to the project, select the ziptest project and compile. You might get the following two errors:

fatal error C1083: Cannot open source file: 'D:\My Documents\Programming Projects\Visual Studio\_common\rArchive.cpp': No such file or directory

You might also get lots of link errors. To fix the above error go to file view, and in the zip_test project, remove the entries rArchive.h and rArchive.cpp, then right click on zip_test files and then use Add files to project option, browse to the _common folder, where you put the rArchive files and add rArchive.h and rArchive.cpp to the project.

D:\My Documents\Programming Projects\Visual Studio\zip_test\zip_testDlg.cpp(9) : fatal error C1083: Cannot open include file: '../_common/rArchive.h': No such file or directory

To solve this one, double click on it and alter the line to point to the correct file.

#include "../_common/rArchive.h"

Now the program should compile. It doesn't have much checking, so make sure values in the text boxes are ok before using it. You can test each of the three main features of the archive.

Note: It will always overwrite files, so be careful.

Using the code

Once you have done the last bit, you can now use the code. I'll go through the process of creating an app similar to the demo one. Create an MFC dialog based app in the usual way. Add 3 controls onto it, named compress, extract and extract from resource. Now select Project -> Insert into workspace. Add the zlib project (_common\zlib\zlib.dsp). Click on Project -> Dependencies, select the new project in the top box and check the checkbox below. (It should say zlib)

Go to Project -> Set Active Project and select your new dialog app. Now go to File view and add _common\rArchive.h and rArchive.cpp to the project. Go back to the dialog and double click on the compress button. Create it's handler and don't put anything in it. Instead scroll to the top of the file and near the top, add the include line below:

static char THIS_FILE[] = __FILE__;
#endif

#include "../_common/rArchive.h"   //ADD THIS LINE

////////////////////////////////////////////////////
// CZip_test_twoDlg dialog

Now, go back to your compress handler. I am not showing the code to scan a directory for files here, but if you want it, nick it from the zip_test app. Instead, here's a handler that will create an archive, then add some common files to it:

void CZip_test_twoDlg::OnComp() 
{
// TODO: Add your control notification handler code here
    rArchive arc;
    if (arc.Open(_T("c:\\windows\\desktop\\new_arch.r"),true)==FALSE) 
        FatalAppExit(0,_T("couldn't create archive"));;
    arc.SetRoot(_T("c:\\"));
    if (arc.AddToArchive(_T("autoexec.bat"))==FALSE) 
        FatalAppExit(0,_T("Couldn't add file"));
    if (arc.AddToArchive(_T("config.sys"))==FALSE) 
        FatalAppExit(0,_T("Couldn't add file"));
    arc.Close();
    MessageBox(_T("Done"));
}

Some notes on the code above:

The second parameter of Open tells it whether or not to create a new blank archive. You can do two things, to create an archive or have an existing one written over, set it to true. If you are reading from an archive, or simply want to append some files to the archive, set it to false. You must always call SetRoot. You need a relative location to extract the files to. Also it's nice to have a message box at the end, as otherwise I always have to wait 5 minutes and then realize it's already done! (Needless to say, this won't work if you don't have autoexec.bat or config.sys, if not change to some files you have got!)

Next is the code for the Extract button:

void CZip_test_twoDlg::OnExtract() 
{
    // TODO: Add your control notification handler code here
    rArchive arc;
    if (arc.Open(_T("c:\\windows\\desktop\\new_arch.r"),false)==FALSE) 
        FatalAppExit(0,_T("couldn't create archive"));;
    arc.SetRoot(_T("c:\\windows\\desktop\\test_dir"));
    while (arc.WriteNextFile() == TRUE) {
        //Good place to put code to incrment progress bar!
    };
    arc.Close;
    MessageBox(_T("Done"));
}

Note the parameter is now false in the Open statement. Otherwise the archive would be deleted before we got anything out of it.

Now the fun bit. Use either your or my program to create an archive of what ever you want (Mine will search folders automatically and save you work). Now, lets say the file you use is new_arch.r. Click Insert -> Resource, then click the Import button. Select the new_arch.r file you just created. Change the filter to *.* to see it. Now click Import. Enter RFILE as the resource type, then click ok. Note down the ID the resource has been given. (IDR_RFILE1 in my case) Now add the handler for the "Extract from" resource button.

void CZip_test_twoDlg::OnExtres() 
{
    // TODO: Add your control notification handler code here
    rArchive arc;
    if (arc.Open(IDR_RFILE1)==FALSE) FatalAppExit(0,_T("couldn't create archive"));
    arc.SetRoot(_T("c:\\windows\\desktop\\test_dir_from_res"));
    while (arc.WriteNextFile() == TRUE) {
        //Good place to put code to increment progress bar!
    };
    arc.Close;
    MessageBox(_T("Done"));
}

Now it should work, ain't that good? Note, the only difference is we have used the second version of the Open member function, passing it only one parameter, that is the resource id. I won't explain how I did it, but if you look at rArchive.h and rArchive.cpp you should see.

Points of Interest

Ok, now that I have shown you how to use the code, I am going to explain it's limitations. It's a best fix and there are some things I don't know how to do, maybe someone can help.

  • It messes around with tmp files. It compresses by using CGZip to compress the original file to a tmp file, then it adds the tmp file to the archive. It decompresses by extracting the zipped file to a tmp file and decompressing the tmp file to whatever we want the new file to be. I would love to learn how to use CGZip on memory files.
  • It adds it's own info in an uncompressed format. You could save a few bytes by making it compress it. I'm not really worried about this.
  • It makes heavy use of MFC. What I wanted was to put rArchive.h and .cpp into the zlib project but couldn't because I got hundreds of errors. I didn't know how to fix this.
  • It doesn't support those standard zip archives. Which sucks! But at least I supplied a program for making the kinda archives it does use, so it's not hard to use it to write installer apps. It's not going to help other common zipping and unzipping requirements though :-(.
  • As you can see I am not so good at this. If someone knows of a tutorial that covers the same material but doesn't have the flaws identified, let me know and I'll just replace this with a link to that one.

History

  • 8 April 2003 - created tutorial

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalmy article is here twice. Pin
metcarob28-Apr-03 7:00
metcarob28-Apr-03 7:00 
GeneralPoints of Interest Pin
Andreas Saurwein28-Apr-03 0:58
Andreas Saurwein28-Apr-03 0:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.