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"
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()
{
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()
{
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) {
};
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()
{
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) {
};
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
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.