Add support for using filter streams in the archive sample

Allow using wxZlib{Input,Output}Stream too, meaning that the sample can
now also work with .gz files, handling them as a degenerate (because
containing only a single file) special case of archives.

The changes here -- which should be viewed ignoring whitespace to be
actually readable -- don't modify the existing code and just add the
possibility to use a wxFilterClassFactory if there is no
wxArchiveClassFactory corresponding to the specified file extension.
This commit is contained in:
Vadim Zeitlin
2018-03-31 01:35:55 +02:00
parent 8de66bc753
commit 6da3c3c34d

View File

@@ -30,6 +30,7 @@ public:
{ {
m_forceZip64 = false; m_forceZip64 = false;
m_archiveClassFactory = NULL; m_archiveClassFactory = NULL;
m_filterClassFactory = NULL;
} }
virtual void OnInitCmdLine(wxCmdLineParser& parser) wxOVERRIDE; virtual void OnInitCmdLine(wxCmdLineParser& parser) wxOVERRIDE;
@@ -61,7 +62,9 @@ private:
wxVector<wxString> m_fileNames; wxVector<wxString> m_fileNames;
bool m_forceZip64; bool m_forceZip64;
// At most one of these pointers is non-NULL.
const wxArchiveClassFactory* m_archiveClassFactory; const wxArchiveClassFactory* m_archiveClassFactory;
const wxFilterClassFactory* m_filterClassFactory;
int DoCreate(); int DoCreate();
@@ -81,6 +84,35 @@ const ArchiveApp::ArchiveCommandDesc ArchiveApp::s_cmdDesc[] =
{CMD_NONE, 0, 0} {CMD_NONE, 0, 0}
}; };
// Helper function iterating over all factories of the given type (assumed to
// derive from wxFilterClassFactoryBase) and returning a string containing all
// comma-separated values returned from their GetProtocols() called with the
// given protocol type.
template <typename T>
void AppendAllSupportedOfType(wxString& all, wxStreamProtocolType type)
{
for (const T* factory = T::GetFirst(); factory; factory = factory->GetNext())
{
const wxChar* const* exts = factory->GetProtocols(type);
while (*exts)
{
if (!all.empty())
all+= ", ";
all += *exts++;
}
}
}
// Returns all supported protocols or extensions (depending on the type
// parameter value) for both archive and filter factories.
wxString GetAllSupported(wxStreamProtocolType type)
{
wxString all;
AppendAllSupportedOfType<wxArchiveClassFactory>(all, type);
AppendAllSupportedOfType<wxFilterClassFactory>(all, type);
return all;
}
void ArchiveApp::OnInitCmdLine(wxCmdLineParser& parser) void ArchiveApp::OnInitCmdLine(wxCmdLineParser& parser)
{ {
wxAppConsole::OnInitCmdLine(parser); wxAppConsole::OnInitCmdLine(parser);
@@ -95,15 +127,7 @@ void ArchiveApp::OnInitCmdLine(wxCmdLineParser& parser)
for (const ArchiveCommandDesc* cmdDesc = s_cmdDesc; cmdDesc->type != CMD_NONE; cmdDesc++) for (const ArchiveCommandDesc* cmdDesc = s_cmdDesc; cmdDesc->type != CMD_NONE; cmdDesc++)
parser.AddUsageText(wxString::Format(" %s: %s", cmdDesc->id, cmdDesc->desc)); parser.AddUsageText(wxString::Format(" %s: %s", cmdDesc->id, cmdDesc->desc));
wxString formats; parser.AddUsageText("\nsupported formats: " + GetAllSupported(wxSTREAM_PROTOCOL));
for(const wxArchiveClassFactory* factory = wxArchiveClassFactory::GetFirst(); factory;
factory = factory->GetNext())
{
if(!formats.empty())
formats += ", ";
formats += factory->GetProtocol();
}
parser.AddUsageText("\nsupported formats: " + formats);
} }
bool ArchiveApp::OnCmdLineParsed(wxCmdLineParser& parser) bool ArchiveApp::OnCmdLineParsed(wxCmdLineParser& parser)
@@ -133,11 +157,12 @@ bool ArchiveApp::CopyStreamData(wxInputStream& inputStream, wxOutputStream& outp
wxChar buf[128 * 1024]; wxChar buf[128 * 1024];
int readSize = 128 * 1024; int readSize = 128 * 1024;
wxFileOffset copiedData = 0; wxFileOffset copiedData = 0;
while (copiedData < size) for (;;)
{ {
if (copiedData + readSize > size) if (size != -1 && copiedData + readSize > size)
readSize = size - copiedData; readSize = size - copiedData;
inputStream.Read(buf, readSize); inputStream.Read(buf, readSize);
size_t actuallyRead = inputStream.LastRead(); size_t actuallyRead = inputStream.LastRead();
outputStream.Write(buf, actuallyRead); outputStream.Write(buf, actuallyRead);
if (outputStream.LastWrite() != actuallyRead) if (outputStream.LastWrite() != actuallyRead)
@@ -146,7 +171,17 @@ bool ArchiveApp::CopyStreamData(wxInputStream& inputStream, wxOutputStream& outp
return false; return false;
} }
copiedData += readSize; if (size == -1)
{
if (inputStream.Eof())
break;
}
else
{
copiedData += actuallyRead;
if (copiedData >= size)
break;
}
} }
return true; return true;
@@ -161,6 +196,8 @@ int ArchiveApp::DoCreate()
} }
wxTempFileOutputStream fileOutputStream(m_archiveFileName); wxTempFileOutputStream fileOutputStream(m_archiveFileName);
if (m_archiveClassFactory)
{
wxScopedPtr<wxArchiveOutputStream> archiveOutputStream(m_archiveClassFactory->NewStream(fileOutputStream)); wxScopedPtr<wxArchiveOutputStream> archiveOutputStream(m_archiveClassFactory->NewStream(fileOutputStream));
if (m_archiveClassFactory->GetProtocol().IsSameAs("zip", false) && m_forceZip64) if (m_archiveClassFactory->GetProtocol().IsSameAs("zip", false) && m_forceZip64)
reinterpret_cast<wxZipOutputStream*>(archiveOutputStream.get())->SetFormat(wxZIP_FORMAT_ZIP64); reinterpret_cast<wxZipOutputStream*>(archiveOutputStream.get())->SetFormat(wxZIP_FORMAT_ZIP64);
@@ -181,14 +218,31 @@ int ArchiveApp::DoCreate()
return 1; return 1;
} }
if (archiveOutputStream->Close()) if (!archiveOutputStream->Close())
return 1;
}
else // use m_filterClassFactory
{ {
if (m_fileNames.size() != 1)
{
wxLogError("Filter-based formats only support archives consisting of a single file");
return -1;
}
wxScopedPtr<wxFilterOutputStream> filterOutputStream(m_filterClassFactory->NewStream(fileOutputStream));
wxFileInputStream inputFileStream(*m_fileNames.begin());
if (!inputFileStream.IsOk())
{
wxLogError("Could not open file");
return 1;
}
if (!CopyStreamData(inputFileStream, *filterOutputStream, inputFileStream.GetLength()))
return 1;
}
fileOutputStream.Commit(); fileOutputStream.Commit();
wxPrintf("Created archive\n"); wxPrintf("Created archive\n");
return 0; return 0;
}
else
return 1;
} }
int ArchiveApp::DoList() int ArchiveApp::DoList()
@@ -197,6 +251,8 @@ int ArchiveApp::DoList()
if (!fileInputStream.IsOk()) if (!fileInputStream.IsOk())
return 1; return 1;
if (m_archiveClassFactory)
{
wxScopedPtr<wxArchiveInputStream> archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); wxScopedPtr<wxArchiveInputStream> archiveStream(m_archiveClassFactory->NewStream(fileInputStream));
wxPrintf("Archive: %s\n", m_archiveFileName); wxPrintf("Archive: %s\n", m_archiveFileName);
wxPrintf("Length Date Time Name\n"); wxPrintf("Length Date Time Name\n");
@@ -217,6 +273,13 @@ int ArchiveApp::DoList()
} }
wxPrintf("---------- -------\n"); wxPrintf("---------- -------\n");
wxPrintf("%10lld %d files\n", combinedSize, entryCount); wxPrintf("%10lld %d files\n", combinedSize, entryCount);
}
else
{
wxPrintf("Archive \"%s\" contains a single file named \"%s\"\n",
m_archiveFileName, wxFileName(m_archiveFileName).GetName());
}
return 0; return 0;
} }
@@ -226,6 +289,8 @@ int ArchiveApp::DoExtract()
if (!fileInputStream.IsOk()) if (!fileInputStream.IsOk())
return 1; return 1;
if (m_archiveClassFactory)
{
wxScopedPtr<wxArchiveInputStream> archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); wxScopedPtr<wxArchiveInputStream> archiveStream(m_archiveClassFactory->NewStream(fileInputStream));
wxPrintf("Extracting from: %s\n", m_archiveFileName); wxPrintf("Extracting from: %s\n", m_archiveFileName);
for (wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry; for (wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry;
@@ -238,6 +303,18 @@ int ArchiveApp::DoExtract()
outputFileStream.Commit(); outputFileStream.Commit();
} }
wxPrintf("Extracted all files\n"); wxPrintf("Extracted all files\n");
}
else
{
wxScopedPtr<wxFilterInputStream> filterStream(m_filterClassFactory->NewStream(fileInputStream));
wxPrintf("Extracting single file from: %s\n", m_archiveFileName);
wxTempFileOutputStream outputFileStream(wxFileName(m_archiveFileName).GetName());
if (!CopyStreamData(*filterStream, outputFileStream, -1))
return 1;
outputFileStream.Commit();
wxPrintf("Extracted successfully\n");
}
return 0; return 0;
} }
@@ -246,9 +323,14 @@ int ArchiveApp::OnRun()
m_archiveClassFactory = wxArchiveClassFactory::Find(m_archiveFileName, wxSTREAM_FILEEXT); m_archiveClassFactory = wxArchiveClassFactory::Find(m_archiveFileName, wxSTREAM_FILEEXT);
if (!m_archiveClassFactory) if (!m_archiveClassFactory)
{ {
wxLogError("Unsupported file format"); m_filterClassFactory = wxFilterClassFactory::Find(m_archiveFileName, wxSTREAM_FILEEXT);
if (!m_filterClassFactory)
{
wxLogError("File \"%s\" has unsupported extension, supported ones are: %s",
m_archiveFileName, GetAllSupported(wxSTREAM_FILEEXT));
return -1; return -1;
} }
}
int result = -1; int result = -1;
switch (m_command) { switch (m_command) {