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;