From a0cc2366783083814ad78e8da4bfce936009edb2 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 30 Mar 2018 22:37:23 +0200 Subject: [PATCH 1/5] Fix typo in a message in the archive sample No real changes. --- samples/archive/archive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/archive/archive.cpp b/samples/archive/archive.cpp index 1707993d8d..f7cbfda4b2 100644 --- a/samples/archive/archive.cpp +++ b/samples/archive/archive.cpp @@ -214,7 +214,7 @@ int ArchiveApp::DoExtract() return 1; wxSharedPtr archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); - wxPrintf("Extrating from: %s\n", m_archiveFileName); + wxPrintf("Extracting from: %s\n", m_archiveFileName); for (wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry; entry = archiveStream->GetNextEntry()) { From b9c10f215dc9024ceb2215cd8dbe9791cdc60d0d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 30 Mar 2018 22:38:03 +0200 Subject: [PATCH 2/5] Use wxScopedPtr<> instead of wxSharedPtr<> in archive sample There is no need to use wxSharedPtr<> when ownership is not shared, use simpler and overhead-free wxScopedPtr<> instead. --- samples/archive/archive.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/archive/archive.cpp b/samples/archive/archive.cpp index f7cbfda4b2..74f23102c6 100644 --- a/samples/archive/archive.cpp +++ b/samples/archive/archive.cpp @@ -18,7 +18,7 @@ #include "wx/app.h" #include "wx/cmdline.h" #include "wx/filename.h" -#include "wx/sharedptr.h" +#include "wx/scopedptr.h" #include "wx/vector.h" #include "wx/wfstream.h" #include "wx/zipstrm.h" @@ -149,7 +149,7 @@ int ArchiveApp::DoCreate() } wxTempFileOutputStream fileOutputStream(m_archiveFileName); - wxSharedPtr archiveOutputStream(m_archiveClassFactory->NewStream(fileOutputStream)); + wxScopedPtr archiveOutputStream(m_archiveClassFactory->NewStream(fileOutputStream)); if (m_archiveClassFactory->GetProtocol().IsSameAs("zip", false) && m_forceZip64) reinterpret_cast(archiveOutputStream.get())->SetFormat(wxZIP_FORMAT_ZIP64); @@ -184,7 +184,7 @@ int ArchiveApp::DoList() if (!fileInputStream.IsOk()) return 1; - wxSharedPtr archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); + wxScopedPtr archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); wxPrintf("Archive: %s\n", m_archiveFileName); wxPrintf("Length Date Time Name\n"); wxPrintf("---------- ---------- -------- ----\n"); @@ -213,7 +213,7 @@ int ArchiveApp::DoExtract() if (!fileInputStream.IsOk()) return 1; - wxSharedPtr archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); + wxScopedPtr archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); wxPrintf("Extracting from: %s\n", m_archiveFileName); for (wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry; entry = archiveStream->GetNextEntry()) From 36fe1e0f663016fb4c27759b9deecc04b5e4bea5 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 30 Mar 2018 22:53:07 +0200 Subject: [PATCH 3/5] Initialize ArchiveApp members in ctor in the sample No real changes, but initialize members of ArchiveApp class in its ctor to avoid leaving them uninitialized. --- samples/archive/archive.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/archive/archive.cpp b/samples/archive/archive.cpp index 74f23102c6..f622ca1d99 100644 --- a/samples/archive/archive.cpp +++ b/samples/archive/archive.cpp @@ -26,6 +26,11 @@ class ArchiveApp: public wxAppConsole { public: + ArchiveApp() + { + m_forceZip64 = false; + m_archiveClassFactory = NULL; + } virtual void OnInitCmdLine(wxCmdLineParser& parser) wxOVERRIDE; From 8de66bc753d1c894682a3fac870575eb70cee7d0 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 31 Mar 2018 01:34:35 +0200 Subject: [PATCH 4/5] Add error checks when copying data in the archive sample Errors when writing the output data in CopyStreamData() were not detected. --- samples/archive/archive.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/samples/archive/archive.cpp b/samples/archive/archive.cpp index f622ca1d99..0292be4d18 100644 --- a/samples/archive/archive.cpp +++ b/samples/archive/archive.cpp @@ -138,7 +138,14 @@ bool ArchiveApp::CopyStreamData(wxInputStream& inputStream, wxOutputStream& outp if (copiedData + readSize > size) readSize = size - copiedData; inputStream.Read(buf, readSize); - outputStream.Write(buf, readSize); + size_t actuallyRead = inputStream.LastRead(); + outputStream.Write(buf, actuallyRead); + if (outputStream.LastWrite() != actuallyRead) + { + wxLogError("Failed to output data"); + return false; + } + copiedData += readSize; } @@ -170,7 +177,8 @@ int ArchiveApp::DoCreate() } if (!archiveOutputStream->PutNextEntry(inputFileName.GetFullName(), wxDateTime::Now(), inputFileStream.GetLength())) break; - CopyStreamData(inputFileStream, *archiveOutputStream, inputFileStream.GetLength()); + if (!CopyStreamData(inputFileStream, *archiveOutputStream, inputFileStream.GetLength())) + return 1; } if (archiveOutputStream->Close()) @@ -225,7 +233,8 @@ int ArchiveApp::DoExtract() { wxPrintf("Extracting: %s...\n", entry->GetName()); wxTempFileOutputStream outputFileStream(entry->GetName()); - CopyStreamData(*archiveStream, outputFileStream, entry->GetSize()); + if (!CopyStreamData(*archiveStream, outputFileStream, entry->GetSize())) + return 1; outputFileStream.Commit(); } wxPrintf("Extracted all files\n"); From 6da3c3c34d864a897d613a0099430899b96c9527 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 31 Mar 2018 01:35:55 +0200 Subject: [PATCH 5/5] 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. --- samples/archive/archive.cpp | 200 +++++++++++++++++++++++++----------- 1 file changed, 141 insertions(+), 59 deletions(-) diff --git a/samples/archive/archive.cpp b/samples/archive/archive.cpp index 0292be4d18..afc26b1c39 100644 --- a/samples/archive/archive.cpp +++ b/samples/archive/archive.cpp @@ -30,6 +30,7 @@ public: { m_forceZip64 = false; m_archiveClassFactory = NULL; + m_filterClassFactory = NULL; } virtual void OnInitCmdLine(wxCmdLineParser& parser) wxOVERRIDE; @@ -61,7 +62,9 @@ private: wxVector m_fileNames; bool m_forceZip64; + // At most one of these pointers is non-NULL. const wxArchiveClassFactory* m_archiveClassFactory; + const wxFilterClassFactory* m_filterClassFactory; int DoCreate(); @@ -81,6 +84,35 @@ const ArchiveApp::ArchiveCommandDesc ArchiveApp::s_cmdDesc[] = {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 +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(all, type); + AppendAllSupportedOfType(all, type); + return all; +} + void ArchiveApp::OnInitCmdLine(wxCmdLineParser& parser) { wxAppConsole::OnInitCmdLine(parser); @@ -95,15 +127,7 @@ void ArchiveApp::OnInitCmdLine(wxCmdLineParser& parser) for (const ArchiveCommandDesc* cmdDesc = s_cmdDesc; cmdDesc->type != CMD_NONE; cmdDesc++) parser.AddUsageText(wxString::Format(" %s: %s", cmdDesc->id, cmdDesc->desc)); - wxString formats; - for(const wxArchiveClassFactory* factory = wxArchiveClassFactory::GetFirst(); factory; - factory = factory->GetNext()) - { - if(!formats.empty()) - formats += ", "; - formats += factory->GetProtocol(); - } - parser.AddUsageText("\nsupported formats: " + formats); + parser.AddUsageText("\nsupported formats: " + GetAllSupported(wxSTREAM_PROTOCOL)); } bool ArchiveApp::OnCmdLineParsed(wxCmdLineParser& parser) @@ -133,11 +157,12 @@ bool ArchiveApp::CopyStreamData(wxInputStream& inputStream, wxOutputStream& outp wxChar buf[128 * 1024]; int readSize = 128 * 1024; wxFileOffset copiedData = 0; - while (copiedData < size) + for (;;) { - if (copiedData + readSize > size) + if (size != -1 && copiedData + readSize > size) readSize = size - copiedData; inputStream.Read(buf, readSize); + size_t actuallyRead = inputStream.LastRead(); outputStream.Write(buf, actuallyRead); if (outputStream.LastWrite() != actuallyRead) @@ -146,7 +171,17 @@ bool ArchiveApp::CopyStreamData(wxInputStream& inputStream, wxOutputStream& outp return false; } - copiedData += readSize; + if (size == -1) + { + if (inputStream.Eof()) + break; + } + else + { + copiedData += actuallyRead; + if (copiedData >= size) + break; + } } return true; @@ -161,34 +196,53 @@ int ArchiveApp::DoCreate() } wxTempFileOutputStream fileOutputStream(m_archiveFileName); - wxScopedPtr archiveOutputStream(m_archiveClassFactory->NewStream(fileOutputStream)); - if (m_archiveClassFactory->GetProtocol().IsSameAs("zip", false) && m_forceZip64) - reinterpret_cast(archiveOutputStream.get())->SetFormat(wxZIP_FORMAT_ZIP64); - - for(wxVector::iterator fileName = m_fileNames.begin(); fileName != m_fileNames.end(); fileName++) + if (m_archiveClassFactory) { - wxFileName inputFileName(*fileName); - wxPrintf("Adding %s...\n", inputFileName.GetFullName()); - wxFileInputStream inputFileStream(*fileName); + wxScopedPtr archiveOutputStream(m_archiveClassFactory->NewStream(fileOutputStream)); + if (m_archiveClassFactory->GetProtocol().IsSameAs("zip", false) && m_forceZip64) + reinterpret_cast(archiveOutputStream.get())->SetFormat(wxZIP_FORMAT_ZIP64); + + for(wxVector::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 filterOutputStream(m_filterClassFactory->NewStream(fileOutputStream)); + wxFileInputStream inputFileStream(*m_fileNames.begin()); 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())) + if (!CopyStreamData(inputFileStream, *filterOutputStream, inputFileStream.GetLength())) return 1; } - if (archiveOutputStream->Close()) - { - fileOutputStream.Commit(); - wxPrintf("Created archive\n"); - return 0; - } - else - return 1; + fileOutputStream.Commit(); + wxPrintf("Created archive\n"); + return 0; } int ArchiveApp::DoList() @@ -197,26 +251,35 @@ int ArchiveApp::DoList() if (!fileInputStream.IsOk()) return 1; - wxScopedPtr archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); - 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()) + if (m_archiveClassFactory) { - combinedSize += entry->GetSize(); - entryCount++; - wxPrintf("%10lld %s %s %s\n", - entry->GetSize(), - entry->GetDateTime().FormatISODate(), - entry->GetDateTime().FormatISOTime(), - entry->GetName()); + wxScopedPtr archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); + 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(); + 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"); - 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; } @@ -226,18 +289,32 @@ int ArchiveApp::DoExtract() if (!fileInputStream.IsOk()) return 1; - wxScopedPtr archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); - wxPrintf("Extracting from: %s\n", m_archiveFileName); - for (wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry; - entry = archiveStream->GetNextEntry()) + if (m_archiveClassFactory) { - wxPrintf("Extracting: %s...\n", entry->GetName()); - wxTempFileOutputStream outputFileStream(entry->GetName()); - if (!CopyStreamData(*archiveStream, outputFileStream, entry->GetSize())) + wxScopedPtr archiveStream(m_archiveClassFactory->NewStream(fileInputStream)); + wxPrintf("Extracting from: %s\n", m_archiveFileName); + 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 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"); } - wxPrintf("Extracted all files\n"); + return 0; } @@ -246,8 +323,13 @@ int ArchiveApp::OnRun() m_archiveClassFactory = wxArchiveClassFactory::Find(m_archiveFileName, wxSTREAM_FILEEXT); if (!m_archiveClassFactory) { - wxLogError("Unsupported file format"); - return -1; + 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; + } } int result = -1;