\section{Archive formats such as zip}\label{wxarc}
The archive classes handle archive formats such as zip, tar, rar and cab.
-Currently only the wxZip classes are included.
+Currently \helpref{wxZip}{wxzipinputstream}
+and \helpref{wxTar}{wxtarinputstream} classes are included.
For each archive type, there are the following classes (using zip here
as an example):
wxFFileOutputStream out(_T("test.zip"));
wxZipOutputStream zip(out);
wxTextOutputStream txt(zip);
+ wxString sep(wxFileName::GetPathSeparator());
zip.PutNextEntry(_T("entry1.txt"));
- txt << _T("Some text for entry1\n");
+ txt << _T("Some text for entry1.txt\n");
- zip.PutNextEntry(_T("entry2.txt"));
- txt << _T("Some text for entry2\n");
+ zip.PutNextEntry(_T("subdir") + sep + _T("entry2.txt"));
+ txt << _T("Some text for subdir/entry2.txt\n");
\end{verbatim}
+The name of each entry can be a full path, which makes it possible to
+store entries in subdirectories.
+
\subsection{Extracting an archive}\label{wxarcextract}
\helpref{Archive formats such as zip}{wxarc}
-\helpref{GetNextEntry()}{wxarchiveinputstreamgetnextentry} returns an
-entry object containing the meta-data for the next entry in the archive
-(and gives away ownership). Reading from the input stream then returns
-the entry's data. Eof() becomes true after an attempt has been made to
-read past the end of the entry's data.
+\helpref{GetNextEntry()}{wxarchiveinputstreamgetnextentry} returns a pointer
+to entry object containing the meta-data for the next entry in the archive
+(and gives away ownership). Reading from the input stream then returns the
+entry's data. Eof() becomes true after an attempt has been made to read past
+the end of the entry's data.
When there are no more entries, GetNextEntry() returns NULL and sets Eof().
\begin{verbatim}
- wxDEFINE_SCOPED_PTR_TYPE(wxZipEntry);
- wxZipEntryPtr entry;
+ auto_ptr<wxZipEntry> entry;
wxFFileInputStream in(_T("test.zip"));
wxZipInputStream zip(in);
- wxTextInputStream txt(zip);
- wxString data;
while (entry.reset(zip.GetNextEntry()), entry.get() != NULL)
{
- wxString name = entry->GetName(); // access meta-data
- txt >> data; // access data
+ // access meta-data
+ wxString name = entry->GetName();
+ // read 'zip' to access the entry's data
}
\end{verbatim}
since it will copy them without decompressing and recompressing them.
In general modifications are not possible without rewriting the archive,
-though it may be possible in some limited cases. Even then, rewriting
-the archive is usually a better choice since a failure can be handled
-without losing the whole archive.
+though it may be possible in some limited cases. Even then, rewriting the
+archive is usually a better choice since a failure can be handled without
+losing the whole
+archive. \helpref{wxTempFileOutputStream}{wxtempfileoutputstream} can
+be helpful to do this.
For example to delete all entries matching the pattern "*.txt":
\begin{verbatim}
- wxFFileInputStream in(_T("in.zip"));
- wxFFileOutputStream out(_T("out.zip"));
+ auto_ptr<wxFFileInputStream> in(new wxFFileInputStream(_T("test.zip")));
+ wxTempFileOutputStream out(_T("test.zip"));
- wxZipInputStream inzip(in);
+ wxZipInputStream inzip(*in);
wxZipOutputStream outzip(out);
- wxZipEntryPtr entry;
+
+ auto_ptr<wxZipEntry> entry;
// transfer any meta-data for the archive as a whole (the zip comment
// in the case of zip)
if (!outzip.CopyEntry(entry.release(), inzip))
break;
- bool success = inzip.Eof() && outzip.Close();
+ // close the input stream by releasing the pointer to it, do this
+ // before closing the output stream so that the file can be replaced
+ in.reset();
+
+ // you can check for success as follows
+ bool success = inzip.Eof() && outzip.Close() && out.Commit();
\end{verbatim}
and search for that:
\begin{verbatim}
- wxDEFINE_SCOPED_PTR_TYPE(wxZipEntry);
- wxZipEntryPtr entry;
+ auto_ptr<wxZipEntry> entry;
// convert the local name we are looking for into the internal format
wxString name = wxZipEntry::GetInternalName(localname);
In order to able to write generic code it's necessary to be able to create
instances of the classes without knowing which archive type is being used.
-So there is a class factory for each archive type, derived from
- \helpref{wxArchiveClassFactory}{wxarchiveclassfactory}, which can create
+To allow this there is a class factory for each archive type, derived from
+ \helpref{wxArchiveClassFactory}{wxarchiveclassfactory}, that can create
the other classes.
-For example, given {\it wxArchiveClassFactory* factory}:
+For example, given {\it wxArchiveClassFactory* factory}, streams and
+entries can be created like this:
\begin{verbatim}
// create streams without knowing their type
- wxArchiveInputStreamPtr inarc(factory->NewStream(in));
- wxArchiveOutputStreamPtr outarc(factory->NewStream(out));
+ auto_ptr<wxArchiveInputStream> inarc(factory->NewStream(in));
+ auto_ptr<wxArchiveOutputStream> outarc(factory->NewStream(out));
// create an empty entry object
- wxArchiveEntryPtr entry(factory->NewEntry());
+ auto_ptr<wxArchiveEntry> entry(factory->NewEntry());
\end{verbatim}
-The class factory itself can either be created explicitly:
+For the factory itself, the static member
+ \helpref{wxArchiveClassFactory::Find()}{wxarchiveclassfactoryfind}.
+can be used to find a class factory that can handle a given file
+extension or mime type. For example, given {\it filename}:
\begin{verbatim}
- wxArchiveClassFactory *factory = new wxZipClassFactory;
+ const wxArchiveClassFactory *factory;
+ factory = wxArchiveClassFactory::Find(filename, wxSTREAM_FILEEXT);
+
+ if (factory)
+ stream = factory->NewStream(new wxFFileInputStream(filename));
\end{verbatim}
-or using wxWidgets' \helpref{RTTI}{runtimeclassoverview}:
+{\it Find} does not give away ownership of the returned pointer, so it
+does not need to be deleted.
-\begin{verbatim}
-wxArchiveClassFactory *MakeFactory(const wxString& type)
-{
- wxString name = _T("wx") + type.Left(1).Upper() +
- type.Mid(1).Lower() + _T("ClassFactory");
+There are similar class factories for the filter streams that handle the
+compression and decompression of a single stream, such as wxGzipInputStream.
+These can be found using
+ \helpref{wxFilterClassFactory::Find()}{wxfilterclassfactoryfind}.
- wxObject *pObj = wxCreateDynamicObject(name);
- wxArchiveClassFactory *pcf = wxDynamicCast(pObj, wxArchiveClassFactory);
+For example, to list the contents of archive {\it filename}:
- if (!pcf) {
- wxLogError(_T("can't handle '%s' archives"), type.c_str());
- delete pObj;
- }
+\begin{verbatim}
+ auto_ptr<wxInputStream> in(new wxFFileInputStream(filename));
- return pcf;
-}
+ if (in->IsOk())
+ {
+ // look for a filter handler, e.g. for '.gz'
+ const wxFilterClassFactory *fcf;
+ fcf = wxFilterClassFactory::Find(filename, wxSTREAM_FILEEXT);
+ if (fcf) {
+ in.reset(fcf->NewStream(in.release()));
+ // pop the extension, so if it was '.tar.gz' it is now just '.tar'
+ filename = fcf->PopExtension(filename);
+ }
+
+ // look for a archive handler, e.g. for '.zip' or '.tar'
+ const wxArchiveClassFactory *acf;
+ acf = wxArchiveClassFactory::Find(filename, wxSTREAM_FILEEXT);
+ if (acf) {
+ auto_ptr<wxArchiveInputStream> arc(acf->NewStream(in.release()));
+ auto_ptr<wxArchiveEntry> entry;
+
+ // list the contents of the archive
+ while ((entry.reset(arc->GetNextEntry())), entry.get() != NULL)
+ std::wcout << entry->GetName().c_str() << "\n";
+ }
+ else {
+ wxLogError(_T("can't handle '%s'"), filename.c_str());
+ }
+ }
\end{verbatim}
\helpref{CopyEntry()}{wxarchiveoutputstreamcopyentry}:
\begin{verbatim}
- wxArchiveInputStreamPtr arc(factory->NewStream(in));
- wxArchiveOutputStreamPtr outarc(factory->NewStream(out));
- wxArchiveEntryPtr entry;
+ auto_ptr<wxArchiveInputStream> arc(factory->NewStream(in));
+ auto_ptr<wxArchiveOutputStream> outarc(factory->NewStream(out));
+ auto_ptr<wxArchiveEntry> entry;
outarc->CopyArchiveMetaData(*arc);
CopyEntry():
\begin{verbatim}
- wxArchiveInputStreamPtr arc(factory->NewStream(in));
- wxArchiveOutputStreamPtr outarc(factory->NewStream(out));
- wxArchiveEntryPtr entry;
- MyNotifier notifier;
+ auto_ptr<wxArchiveInputStream> arc(factory->NewStream(in));
+ auto_ptr<wxArchiveOutputStream> outarc(factory->NewStream(out));
+ auto_ptr<wxArchiveEntry> entry;
+ MyNotifier notifier;
outarc->CopyArchiveMetaData(*arc);