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:
@@ -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,34 +196,53 @@ int ArchiveApp::DoCreate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
wxTempFileOutputStream fileOutputStream(m_archiveFileName);
|
wxTempFileOutputStream fileOutputStream(m_archiveFileName);
|
||||||
wxScopedPtr<wxArchiveOutputStream> archiveOutputStream(m_archiveClassFactory->NewStream(fileOutputStream));
|
if (m_archiveClassFactory)
|
||||||
if (m_archiveClassFactory->GetProtocol().IsSameAs("zip", false) && m_forceZip64)
|
|
||||||
reinterpret_cast<wxZipOutputStream*>(archiveOutputStream.get())->SetFormat(wxZIP_FORMAT_ZIP64);
|
|
||||||
|
|
||||||
for(wxVector<wxString>::iterator fileName = m_fileNames.begin(); fileName != m_fileNames.end(); fileName++)
|
|
||||||
{
|
{
|
||||||
wxFileName inputFileName(*fileName);
|
wxScopedPtr<wxArchiveOutputStream> archiveOutputStream(m_archiveClassFactory->NewStream(fileOutputStream));
|
||||||
wxPrintf("Adding %s...\n", inputFileName.GetFullName());
|
if (m_archiveClassFactory->GetProtocol().IsSameAs("zip", false) && m_forceZip64)
|
||||||
wxFileInputStream inputFileStream(*fileName);
|
reinterpret_cast<wxZipOutputStream*>(archiveOutputStream.get())->SetFormat(wxZIP_FORMAT_ZIP64);
|
||||||
|
|
||||||
|
for(wxVector<wxString>::iterator fileName = m_fileNames.begin(); fileName != m_fileNames.end(); fileName++)
|
||||||
|
{
|
||||||
|
wxFileName inputFileName(*fileName);
|
||||||
|
wxPrintf("Adding %s...\n", inputFileName.GetFullName());
|
||||||
|
wxFileInputStream inputFileStream(*fileName);
|
||||||
|
if (!inputFileStream.IsOk())
|
||||||
|
{
|
||||||
|
wxLogError("Could not open file");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!archiveOutputStream->PutNextEntry(inputFileName.GetFullName(), wxDateTime::Now(), inputFileStream.GetLength()))
|
||||||
|
break;
|
||||||
|
if (!CopyStreamData(inputFileStream, *archiveOutputStream, inputFileStream.GetLength()))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
if (!inputFileStream.IsOk())
|
||||||
{
|
{
|
||||||
wxLogError("Could not open file");
|
wxLogError("Could not open file");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!archiveOutputStream->PutNextEntry(inputFileName.GetFullName(), wxDateTime::Now(), inputFileStream.GetLength()))
|
if (!CopyStreamData(inputFileStream, *filterOutputStream, inputFileStream.GetLength()))
|
||||||
break;
|
|
||||||
if (!CopyStreamData(inputFileStream, *archiveOutputStream, inputFileStream.GetLength()))
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (archiveOutputStream->Close())
|
fileOutputStream.Commit();
|
||||||
{
|
wxPrintf("Created archive\n");
|
||||||
fileOutputStream.Commit();
|
return 0;
|
||||||
wxPrintf("Created archive\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ArchiveApp::DoList()
|
int ArchiveApp::DoList()
|
||||||
@@ -197,26 +251,35 @@ int ArchiveApp::DoList()
|
|||||||
if (!fileInputStream.IsOk())
|
if (!fileInputStream.IsOk())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
wxScopedPtr<wxArchiveInputStream> archiveStream(m_archiveClassFactory->NewStream(fileInputStream));
|
if (m_archiveClassFactory)
|
||||||
wxPrintf("Archive: %s\n", m_archiveFileName);
|
|
||||||
wxPrintf("Length Date Time Name\n");
|
|
||||||
wxPrintf("---------- ---------- -------- ----\n");
|
|
||||||
|
|
||||||
wxFileOffset combinedSize = 0;
|
|
||||||
int entryCount = 0;
|
|
||||||
for (wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry;
|
|
||||||
entry = archiveStream->GetNextEntry())
|
|
||||||
{
|
{
|
||||||
combinedSize += entry->GetSize();
|
wxScopedPtr<wxArchiveInputStream> archiveStream(m_archiveClassFactory->NewStream(fileInputStream));
|
||||||
entryCount++;
|
wxPrintf("Archive: %s\n", m_archiveFileName);
|
||||||
wxPrintf("%10lld %s %s %s\n",
|
wxPrintf("Length Date Time Name\n");
|
||||||
entry->GetSize(),
|
wxPrintf("---------- ---------- -------- ----\n");
|
||||||
entry->GetDateTime().FormatISODate(),
|
|
||||||
entry->GetDateTime().FormatISOTime(),
|
wxFileOffset combinedSize = 0;
|
||||||
entry->GetName());
|
int entryCount = 0;
|
||||||
|
for (wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry;
|
||||||
|
entry = archiveStream->GetNextEntry())
|
||||||
|
{
|
||||||
|
combinedSize += entry->GetSize();
|
||||||
|
entryCount++;
|
||||||
|
wxPrintf("%10lld %s %s %s\n",
|
||||||
|
entry->GetSize(),
|
||||||
|
entry->GetDateTime().FormatISODate(),
|
||||||
|
entry->GetDateTime().FormatISOTime(),
|
||||||
|
entry->GetName());
|
||||||
|
}
|
||||||
|
wxPrintf("---------- -------\n");
|
||||||
|
wxPrintf("%10lld %d files\n", combinedSize, entryCount);
|
||||||
}
|
}
|
||||||
wxPrintf("---------- -------\n");
|
else
|
||||||
wxPrintf("%10lld %d files\n", combinedSize, entryCount);
|
{
|
||||||
|
wxPrintf("Archive \"%s\" contains a single file named \"%s\"\n",
|
||||||
|
m_archiveFileName, wxFileName(m_archiveFileName).GetName());
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,18 +289,32 @@ int ArchiveApp::DoExtract()
|
|||||||
if (!fileInputStream.IsOk())
|
if (!fileInputStream.IsOk())
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
wxScopedPtr<wxArchiveInputStream> archiveStream(m_archiveClassFactory->NewStream(fileInputStream));
|
if (m_archiveClassFactory)
|
||||||
wxPrintf("Extracting from: %s\n", m_archiveFileName);
|
|
||||||
for (wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry;
|
|
||||||
entry = archiveStream->GetNextEntry())
|
|
||||||
{
|
{
|
||||||
wxPrintf("Extracting: %s...\n", entry->GetName());
|
wxScopedPtr<wxArchiveInputStream> archiveStream(m_archiveClassFactory->NewStream(fileInputStream));
|
||||||
wxTempFileOutputStream outputFileStream(entry->GetName());
|
wxPrintf("Extracting from: %s\n", m_archiveFileName);
|
||||||
if (!CopyStreamData(*archiveStream, outputFileStream, entry->GetSize()))
|
for (wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry;
|
||||||
|
entry = archiveStream->GetNextEntry())
|
||||||
|
{
|
||||||
|
wxPrintf("Extracting: %s...\n", entry->GetName());
|
||||||
|
wxTempFileOutputStream outputFileStream(entry->GetName());
|
||||||
|
if (!CopyStreamData(*archiveStream, outputFileStream, entry->GetSize()))
|
||||||
|
return 1;
|
||||||
|
outputFileStream.Commit();
|
||||||
|
}
|
||||||
|
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;
|
return 1;
|
||||||
outputFileStream.Commit();
|
outputFileStream.Commit();
|
||||||
|
wxPrintf("Extracted successfully\n");
|
||||||
}
|
}
|
||||||
wxPrintf("Extracted all files\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,8 +323,13 @@ 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);
|
||||||
return -1;
|
if (!m_filterClassFactory)
|
||||||
|
{
|
||||||
|
wxLogError("File \"%s\" has unsupported extension, supported ones are: %s",
|
||||||
|
m_archiveFileName, GetAllSupported(wxSTREAM_FILEEXT));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = -1;
|
int result = -1;
|
||||||
|
Reference in New Issue
Block a user