|
|
/*
* This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <wx/dir.h>
#include <wx/filedlg.h>
#include <wx/fs_zip.h>
#include <wx/uri.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include <core/arraydim.h>
#include <macros.h>
#include <project/project_archiver.h>
#include <reporter.h>
#include <wildcards_and_files_ext.h>
#include <wxstream_helper.h>
#include <wx/log.h>
#define ZipFileExtension wxT( "zip" )
PROJECT_ARCHIVER::PROJECT_ARCHIVER(){}
// Unarchive Files code comes from wxWidgets sample/archive/archive.cpp
bool PROJECT_ARCHIVER::Unarchive( const wxString& aSrcFile, const wxString& aDestDir, REPORTER& aReporter ){ wxFFileInputStream stream( aSrcFile );
if( !stream.IsOk() ) { aReporter.Report( _( "Could not open archive file." ), RPT_SEVERITY_ERROR ); return false; }
const wxArchiveClassFactory* archiveClassFactory = wxArchiveClassFactory::Find( aSrcFile, wxSTREAM_FILEEXT );
if( !archiveClassFactory ) { aReporter.Report( _( "Invalid archive file format." ), RPT_SEVERITY_ERROR ); return false; }
wxScopedPtr<wxArchiveInputStream> archiveStream( archiveClassFactory->NewStream( stream ) );
wxString fileStatus;
for( wxArchiveEntry* entry = archiveStream->GetNextEntry(); entry; entry = archiveStream->GetNextEntry() ) { fileStatus.Printf( _( "Extracting file '%s'." ), entry->GetName() ); aReporter.Report( fileStatus, RPT_SEVERITY_INFO );
wxString fullname = aDestDir + entry->GetName();
// Ensure the target directory exists and create it if not
wxString t_path = wxPathOnly( fullname );
if( !wxDirExists( t_path ) ) { wxFileName::Mkdir( t_path, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ); }
// Directory entries need only be created, not extracted (0 size)
if( entry->IsDir() ) continue;
wxTempFileOutputStream outputFileStream( fullname );
if( CopyStreamData( *archiveStream, outputFileStream, entry->GetSize() ) ) outputFileStream.Commit(); else aReporter.Report( _( "Error extracting file!" ), RPT_SEVERITY_ERROR );
// Now let's set the filetimes based on what's in the zip
wxFileName outputFileName( fullname ); wxDateTime fileTime = entry->GetDateTime(); // For now we set access, mod, create to the same datetime
// create (third arg) is only used on Windows
outputFileName.SetTimes( &fileTime, &fileTime, &fileTime ); }
aReporter.Report( wxT( "Extracted project." ), RPT_SEVERITY_INFO ); return true;}
bool PROJECT_ARCHIVER::Archive( const wxString& aSrcDir, const wxString& aDestFile, REPORTER& aReporter, bool aVerbose, bool aIncludeExtraFiles ){ // List of file extensions that are always archived
static const wxChar* extensionList[] = { wxT( "*.kicad_pro" ), wxT( "*.kicad_prl" ), wxT( "*.kicad_sch" ), wxT( "*.kicad_sym" ), wxT( "*.kicad_pcb" ), wxT( "*.kicad_mod" ), wxT( "*.kicad_dru" ), wxT( "*.kicad_wks" ), wxT( "fp-lib-table" ), wxT( "sym-lib-table" ) };
// List of additional file extensions that are only archived when aIncludeExtraFiles is true
static const wxChar* extraExtensionList[] = { wxT( "*.pro" ), wxT( "*.sch" ), // Legacy schematic files
wxT( "*.lib" ), wxT( "*.dcm" ), // Legacy schematic library files
wxT( "*.cmp" ), wxT( "*.brd" ), wxT( "*.mod" ), wxT( "*.stp" ), wxT( "*.step" ), // 3d files
wxT( "*.wrl" ), wxT( "*.gb?" ), wxT( "*.gbrjob" ), // Gerber files
wxT( "*.gko" ), wxT( "*.gm1" ), wxT( "*.gm2" ), wxT( "*.g?" ), wxT( "*.gp1" ), wxT( "*.gp2" ), wxT( "*.gpb" ), wxT( "*.gpt" ), wxT( "*.gt?" ), wxT( "*.pos" ), wxT( "*.drl" ), wxT( "*.nc" ), wxT( "*.xnc" ), // Fab files
wxT( "*.d356" ), wxT( "*.rpt" ), wxT( "*.net" ), wxT( "*.py" ), wxT( "*.pdf" ), wxT( "*.txt" ) };
bool success = true; wxString msg; wxString oldCwd = wxGetCwd();
wxSetWorkingDirectory( aSrcDir );
wxFFileOutputStream ostream( aDestFile );
if( !ostream.IsOk() ) // issue to create the file. Perhaps not writable dir
{ msg.Printf( _( "Failed to create file '%s'." ), aDestFile ); aReporter.Report( msg, RPT_SEVERITY_ERROR ); return false; }
wxZipOutputStream zipstream( ostream, -1, wxConvUTF8 );
// Build list of filenames to put in zip archive
wxString currFilename;
wxArrayString files;
for( unsigned ii = 0; ii < arrayDim( extensionList ); ii++ ) wxDir::GetAllFiles( aSrcDir, &files, extensionList[ii] );
if( aIncludeExtraFiles ) { for( unsigned ii = 0; ii < arrayDim( extraExtensionList ); ii++ ) wxDir::GetAllFiles( aSrcDir, &files, extraExtensionList[ii] ); }
files.Sort();
unsigned long uncompressedBytes = 0;
for( unsigned ii = 0; ii < files.GetCount(); ii++ ) { wxFileSystem fsfile;
wxFileName curr_fn( files[ii] ); curr_fn.MakeRelativeTo( aSrcDir ); currFilename = curr_fn.GetFullPath();
// Read input file and add it to the zip file:
wxFSFile* infile = fsfile.OpenFile( wxFileSystem::FileNameToURL( curr_fn ) );
if( infile ) { zipstream.PutNextEntry( currFilename, infile->GetModificationTime() ); infile->GetStream()->Read( zipstream ); zipstream.CloseEntry();
uncompressedBytes += infile->GetStream()->GetSize();
if( aVerbose ) { msg.Printf( _( "Archived file '%s'." ), currFilename ); aReporter.Report( msg, RPT_SEVERITY_INFO ); }
delete infile; } else { if( aVerbose ) { msg.Printf( _( "Failed to archive file '%s'." ), currFilename ); aReporter.Report( msg, RPT_SEVERITY_ERROR ); }
success = false; } }
auto reportSize = []( unsigned long aSize ) -> wxString { constexpr float KB = 1024.0; constexpr float MB = KB * 1024.0;
if( aSize >= MB ) return wxString::Format( wxT( "%0.2f MB" ), aSize / MB ); else if( aSize >= KB ) return wxString::Format( wxT( "%0.2f KB" ), aSize / KB ); else return wxString::Format( wxT( "%lu bytes" ), aSize ); };
size_t zipBytesCnt = ostream.GetSize();
if( zipstream.Close() ) { msg.Printf( _( "Zip archive '%s' created (%s uncompressed, %s compressed)." ), aDestFile, reportSize( uncompressedBytes ), reportSize( zipBytesCnt ) ); aReporter.Report( msg, RPT_SEVERITY_INFO ); } else { msg.Printf( wxT( "Failed to create file '%s'." ), aDestFile ); aReporter.Report( msg, RPT_SEVERITY_ERROR ); success = false; }
wxSetWorkingDirectory( oldCwd ); return success;}
|