- Also see wxFileSystem for a higher level interface that
- can handle archive files in a generic way.
-
- The specific archive classes, such as the wxZip classes, inherit from
- the following abstract classes which can be used to write code that can
- handle any of the archive types:
-
- @li wxArchiveInputStream: input stream
- @li wxArchiveOutputStream: output stream
- @li wxArchiveEntry: holds the meta-data for an entry (e.g. filename)
-
- 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.
-
- To allow this there is a class factory for each archive type, derived from
- wxArchiveClassFactory, that can create the other classes.
-
- For example, given @e wxArchiveClassFactory* factory, streams and
- entries can be created like this:
-
- @code
- // create streams without knowing their type
- auto_ptr<wxArchiveInputStream> inarc(factory->NewStream(in));
- auto_ptr<wxArchiveOutputStream> outarc(factory->NewStream(out));
-
- // create an empty entry object
- auto_ptr<wxArchiveEntry> entry(factory->NewEntry());
- @endcode
-
- For the factory itself, the static member wxArchiveClassFactory::Find().
- can be used to find a class factory that can handle a given file
- extension or mime type. For example, given @e filename:
-
- @code
- const wxArchiveClassFactory *factory;
- factory = wxArchiveClassFactory::Find(filename, wxSTREAM_FILEEXT);
-
- if (factory)
- stream = factory->NewStream(new wxFFileInputStream(filename));
- @endcode
-
- @e Find does not give away ownership of the returned pointer, so it
- does not need to be deleted.
-
- 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 wxFilterClassFactory::Find().
-
- For example, to list the contents of archive @e filename:
-
- @code
- auto_ptr<wxInputStream> in(new wxFFileInputStream(filename));
-
- 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());
- }
- }
- @endcode
-
-
-
- @section overview_arc_noseek Archives on non-seekable streams
-
- In general, handling archives on non-seekable streams is done in the same
- way as for seekable streams, with a few caveats.
-
- The main limitation is that accessing entries randomly using
- wxArchiveInputStream::OpenEntry() is not possible, the entries can only be
- accessed sequentially in the order they are stored within the archive.
-
- For each archive type, there will also be other limitations which will
- depend on the order the entries' meta-data is stored within the archive.
- These are not too difficult to deal with, and are outlined below.
-
- @subsection overview_arc_noseek_entrysize PutNextEntry and the entry size
-
- When writing archives, some archive formats store the entry size before
- the entry's data (tar has this limitation, zip doesn't). In this case
- the entry's size must be passed to wxArchiveOutputStream::PutNextEntry()
- or an error occurs.
-
- This is only an issue on non-seekable streams, since otherwise the archive
- output stream can seek back and fix up the header once the size of the
- entry is known.
-
- For generic programming, one way to handle this is to supply the size
- whenever it is known, and rely on the error message from the output
- stream when the operation is not supported.
-
- @subsection overview_arc_noseek_weak GetNextEntry and the weak reference mechanism
-
- Some archive formats do not store all an entry's meta-data before the
- entry's data (zip is an example). In this case, when reading from a
- non-seekable stream, wxArchiveInputStream::GetNextEntry() can only return
- a partially populated wxArchiveEntry object - not all the fields are set.
-
- The input stream then keeps a weak reference to the entry object and
- updates it when more meta-data becomes available. A weak reference being
- one that does not prevent you from deleting the wxArchiveEntry object - the
- input stream only attempts to update it if it is still around.
-
- The documentation for each archive entry type gives the details
- of what meta-data becomes available and when. For generic programming,
- when the worst case must be assumed, you can rely on all the fields
- of wxArchiveEntry being fully populated when GetNextEntry() returns,
- with the the following exceptions:
-
- @li wxArchiveEntry::GetSize(): guaranteed to be available after the
- entry has been read to wxInputStream::Eof(), or wxArchiveInputStream::CloseEntry()
- has been called
-
- @li wxArchiveEntry::IsReadOnly(): guaranteed to be available after the end of
- the archive has been reached, i.e. after GetNextEntry() returns @NULL and
- Eof() is @true
-
- This mechanism allows wxArchiveOutputStream::CopyEntry() to always fully
- preserve entries' meta-data. No matter what order order the meta-data occurs
- within the archive, the input stream will always have read it before the output
- stream must write it.
-
- @subsection overview_arc_noseek_notifier wxArchiveNotifier
-
- Notifier objects can be used to get a notification whenever an input
- stream updates a wxArchiveEntry object's data via the weak reference mechanism.
-
- Consider the following code which renames an entry in an archive.
- This is the usual way to modify an entry's meta-data, simply set the
- required field before writing it with wxArchiveOutputStream::CopyEntry():
-
- @code
- auto_ptr<wxArchiveInputStream> arc(factory->NewStream(in));
- auto_ptr<wxArchiveOutputStream> outarc(factory->NewStream(out));
- auto_ptr<wxArchiveEntry> entry;
-
- outarc->CopyArchiveMetaData(*arc);
-
- while (entry.reset(arc->GetNextEntry()), entry.get() != NULL) {
- if (entry->GetName() == from)
- entry->SetName(to);
- if (!outarc->CopyEntry(entry.release(), *arc))
- break;
- }
-
- bool success = arc->Eof() && outarc->Close();
- @endcode
-
- However, for non-seekable streams, this technique cannot be used for
- fields such as wxArchiveEntry::IsReadOnly(), which are not necessarily set when
- wxArchiveInputStream::GetNextEntry() returns.
-
- In this case a wxArchiveNotifier can be used:
-
- @code
- class MyNotifier : public wxArchiveNotifier
- {
- public:
- void OnEntryUpdated(wxArchiveEntry& entry) { entry.SetIsReadOnly(false); }
- };
- @endcode
-
- The meta-data changes are done in your notifier's wxArchiveNotifier::OnEntryUpdated()
- method, then wxArchiveEntry::SetNotifier() is called before CopyEntry():
-
- @code
- auto_ptr<wxArchiveInputStream> arc(factory->NewStream(in));
- auto_ptr<wxArchiveOutputStream> outarc(factory->NewStream(out));
- auto_ptr<wxArchiveEntry> entry;
- MyNotifier notifier;
-
- outarc->CopyArchiveMetaData(*arc);
-
- while (entry.reset(arc->GetNextEntry()), entry.get() != NULL) {
- entry->SetNotifier(notifier);
- if (!outarc->CopyEntry(entry.release(), *arc))
- break;
- }
-
- bool success = arc->Eof() && outarc->Close();
- @endcode
-
- SetNotifier() calls OnEntryUpdated() immediately, then the input
- stream calls it again whenever it sets more fields in the entry. Since
- OnEntryUpdated() will be called at least once, this technique always
- works even when it is not strictly necessary to use it. For example,
- changing the entry name can be done this way too and it works on seekable
- streams as well as non-seekable.
+@section overview_archive_noseek Archives on Non-Seekable Streams
+
+In general, handling archives on non-seekable streams is done in the same way
+as for seekable streams, with a few caveats.
+
+The main limitation is that accessing entries randomly using
+wxArchiveInputStream::OpenEntry() is not possible, the entries can only be
+accessed sequentially in the order they are stored within the archive.
+
+For each archive type, there will also be other limitations which will depend
+on the order the entries' meta-data is stored within the archive. These are not
+too difficult to deal with, and are outlined below.
+
+@subsection overview_archive_noseek_entrysize PutNextEntry and the Entry Size
+
+When writing archives, some archive formats store the entry size before the
+entry's data (tar has this limitation, zip doesn't). In this case the entry's
+size must be passed to wxArchiveOutputStream::PutNextEntry() or an error
+occurs.
+
+This is only an issue on non-seekable streams, since otherwise the archive
+output stream can seek back and fix up the header once the size of the entry is
+known.
+
+For generic programming, one way to handle this is to supply the size whenever
+it is known, and rely on the error message from the output stream when the
+operation is not supported.
+
+@subsection overview_archive_noseek_weak GetNextEntry and the Weak Reference Mechanism
+
+Some archive formats do not store all an entry's meta-data before the entry's
+data (zip is an example). In this case, when reading from a non-seekable
+stream, wxArchiveInputStream::GetNextEntry() can only return a partially
+populated wxArchiveEntry object - not all the fields are set.
+
+The input stream then keeps a weak reference to the entry object and updates it
+when more meta-data becomes available. A weak reference being one that does not
+prevent you from deleting the wxArchiveEntry object - the input stream only
+attempts to update it if it is still around.
+
+The documentation for each archive entry type gives the details of what
+meta-data becomes available and when. For generic programming, when the worst
+case must be assumed, you can rely on all the fields of wxArchiveEntry being
+fully populated when GetNextEntry() returns, with the following exceptions:
+
+@li wxArchiveEntry::GetSize(): Guaranteed to be available after the entry has
+ been read to wxInputStream::Eof(), or wxArchiveInputStream::CloseEntry()
+ has been called.
+@li wxArchiveEntry::IsReadOnly(): Guaranteed to be available after the end of
+ the archive has been reached, i.e. after GetNextEntry() returns @NULL and
+ Eof() is @true.
+
+This mechanism allows wxArchiveOutputStream::CopyEntry() to always fully
+preserve entries' meta-data. No matter what order order the meta-data occurs
+within the archive, the input stream will always have read it before the output
+stream must write it.
+
+@subsection overview_archive_noseek_notifier wxArchiveNotifier
+
+Notifier objects can be used to get a notification whenever an input stream
+updates a wxArchiveEntry object's data via the weak reference mechanism.
+
+Consider the following code which renames an entry in an archive. This is the
+usual way to modify an entry's meta-data, simply set the required field before
+writing it with wxArchiveOutputStream::CopyEntry():
+
+@code
+auto_ptr<wxArchiveInputStream> arc(factory->NewStream(in));
+auto_ptr<wxArchiveOutputStream> outarc(factory->NewStream(out));
+auto_ptr<wxArchiveEntry> entry;
+
+outarc->CopyArchiveMetaData(*arc);
+
+while (entry.reset(arc->GetNextEntry()), entry.get() != NULL)
+{
+ if (entry->GetName() == from)
+ entry->SetName(to);
+ if (!outarc->CopyEntry(entry.release(), *arc))
+ break;
+}
+
+bool success = arc->Eof() && outarc->Close();
+@endcode
+
+However, for non-seekable streams, this technique cannot be used for fields
+such as wxArchiveEntry::IsReadOnly(), which are not necessarily set when
+wxArchiveInputStream::GetNextEntry() returns.
+
+In this case a wxArchiveNotifier can be used:
+
+@code
+class MyNotifier : public wxArchiveNotifier
+{
+public:
+ void OnEntryUpdated(wxArchiveEntry& entry) { entry.SetIsReadOnly(false); }
+};
+@endcode
+
+The meta-data changes are done in your notifier's
+wxArchiveNotifier::OnEntryUpdated() method, then wxArchiveEntry::SetNotifier()
+is called before CopyEntry():
+
+@code
+auto_ptr<wxArchiveInputStream> arc(factory->NewStream(in));
+auto_ptr<wxArchiveOutputStream> outarc(factory->NewStream(out));
+auto_ptr<wxArchiveEntry> entry;
+MyNotifier notifier;
+
+outarc->CopyArchiveMetaData(*arc);
+
+while (entry.reset(arc->GetNextEntry()), entry.get() != NULL)
+{
+ entry->SetNotifier(notifier);
+ if (!outarc->CopyEntry(entry.release(), *arc))
+ break;
+}
+
+bool success = arc->Eof() && outarc->Close();
+@endcode
+
+SetNotifier() calls OnEntryUpdated() immediately, then the input stream calls
+it again whenever it sets more fields in the entry. Since OnEntryUpdated() will
+be called at least once, this technique always works even when it is not
+strictly necessary to use it. For example, changing the entry name can be done
+this way too and it works on seekable streams as well as non-seekable.