Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsziputils.cpp 3 : : --------------------- 4 : : begin : Jul 2017 5 : : copyright : (C) 2017 by Paul Blottiere 6 : : email : paul.blottiere@oslandia.com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include <fstream> 17 : : 18 : : #include <QFileInfo> 19 : : #include <QDir> 20 : : 21 : : #include "zip.h" 22 : : 23 : : #include "qgsmessagelog.h" 24 : : #include "qgsziputils.h" 25 : : #include "qgslogger.h" 26 : : 27 : : #include <iostream> 28 : : 29 : 0 : bool QgsZipUtils::isZipFile( const QString &filename ) 30 : : { 31 : 0 : return QFileInfo( filename ).suffix().compare( QLatin1String( "qgz" ), Qt::CaseInsensitive ) == 0; 32 : 0 : } 33 : : 34 : 0 : bool QgsZipUtils::unzip( const QString &zipFilename, const QString &dir, QStringList &files ) 35 : : { 36 : 0 : files.clear(); 37 : : 38 : 0 : if ( !QFileInfo::exists( zipFilename ) ) 39 : : { 40 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error zip file does not exist: '%1'" ).arg( zipFilename ) ); 41 : 0 : return false; 42 : : } 43 : 0 : else if ( zipFilename.isEmpty() ) 44 : : { 45 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error zip filename is empty" ) ); 46 : 0 : return false; 47 : : } 48 : 0 : else if ( !QDir( dir ).exists( dir ) ) 49 : : { 50 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error output dir does not exist: '%1'" ).arg( dir ) ); 51 : 0 : return false; 52 : : } 53 : 0 : else if ( !QFileInfo( dir ).isDir() ) 54 : : { 55 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error output dir is not a directory: '%1'" ).arg( dir ) ); 56 : 0 : return false; 57 : : } 58 : 0 : else if ( !QFileInfo( dir ).isWritable() ) 59 : : { 60 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error output dir is not writable: '%1'" ).arg( dir ) ); 61 : 0 : return false; 62 : : } 63 : : 64 : 0 : int rc = 0; 65 : 0 : const QByteArray fileNamePtr = zipFilename.toUtf8(); 66 : 0 : struct zip *z = zip_open( fileNamePtr.constData(), ZIP_CHECKCONS, &rc ); 67 : : 68 : 0 : if ( rc == ZIP_ER_OK && z ) 69 : : { 70 : 0 : int count = zip_get_num_files( z ); 71 : 0 : if ( count != -1 ) 72 : : { 73 : : struct zip_stat stat; 74 : : 75 : 0 : for ( int i = 0; i < count; i++ ) 76 : : { 77 : 0 : zip_stat_index( z, i, 0, &stat ); 78 : 0 : size_t len = stat.size; 79 : : 80 : 0 : struct zip_file *file = zip_fopen_index( z, i, 0 ); 81 : 0 : std::unique_ptr< char[] > buf( new char[len] ); 82 : 0 : if ( zip_fread( file, buf.get(), len ) != -1 ) 83 : : { 84 : 0 : QString fileName( stat.name ); 85 : 0 : QFileInfo newFile( QDir( dir ), fileName ); 86 : : 87 : : // Create path for a new file if it does not exist. 88 : 0 : if ( !newFile.absoluteDir().exists() ) 89 : : { 90 : 0 : if ( !QDir( dir ).mkpath( newFile.absolutePath() ) ) 91 : 0 : QgsMessageLog::logMessage( QObject::tr( "Failed to create a subdirectory %1/%2" ).arg( dir ).arg( fileName ) ); 92 : 0 : } 93 : : 94 : 0 : QFile outFile( newFile.absoluteFilePath() ); 95 : 0 : if ( !outFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) 96 : : { 97 : 0 : QgsMessageLog::logMessage( QObject::tr( "Could not write to %1" ).arg( newFile.absoluteFilePath() ) ); 98 : 0 : } 99 : : else 100 : : { 101 : 0 : outFile.write( buf.get(), len ); 102 : : } 103 : 0 : zip_fclose( file ); 104 : 0 : files.append( newFile.absoluteFilePath() ); 105 : 0 : } 106 : : else 107 : : { 108 : 0 : zip_fclose( file ); 109 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error reading file: '%1'" ).arg( zip_strerror( z ) ) ); 110 : 0 : return false; 111 : : } 112 : 0 : } 113 : 0 : } 114 : : else 115 : : { 116 : 0 : zip_close( z ); 117 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error getting files: '%1'" ).arg( zip_strerror( z ) ) ); 118 : 0 : return false; 119 : : } 120 : : 121 : 0 : zip_close( z ); 122 : 0 : } 123 : : else 124 : : { 125 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error opening zip archive: '%1' (Error code: %2)" ).arg( z ? zip_strerror( z ) : zipFilename ).arg( rc ) ); 126 : 0 : return false; 127 : : } 128 : : 129 : 0 : return true; 130 : 0 : } 131 : : 132 : 0 : bool QgsZipUtils::zip( const QString &zipFilename, const QStringList &files ) 133 : : { 134 : 0 : if ( zipFilename.isEmpty() ) 135 : : { 136 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error zip filename is empty" ) ); 137 : 0 : return false; 138 : : } 139 : : 140 : 0 : int rc = 0; 141 : 0 : const QByteArray zipFileNamePtr = zipFilename.toUtf8(); 142 : 0 : struct zip *z = zip_open( zipFileNamePtr.constData(), ZIP_CREATE, &rc ); 143 : : 144 : 0 : if ( rc == ZIP_ER_OK && z ) 145 : : { 146 : 0 : for ( const auto &file : files ) 147 : : { 148 : 0 : QFileInfo fileInfo( file ); 149 : 0 : if ( !fileInfo.exists() ) 150 : : { 151 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error input file does not exist: '%1'" ).arg( file ) ); 152 : 0 : zip_close( z ); 153 : 0 : return false; 154 : : } 155 : : 156 : 0 : const QByteArray fileNamePtr = file.toUtf8(); 157 : 0 : zip_source *src = zip_source_file( z, fileNamePtr.constData(), 0, 0 ); 158 : 0 : if ( src ) 159 : : { 160 : 0 : const QByteArray fileInfoPtr = fileInfo.fileName().toUtf8(); 161 : : #if LIBZIP_VERSION_MAJOR < 1 162 : : rc = ( int ) zip_add( z, fileInfoPtr.constData(), src ); 163 : : #else 164 : 0 : rc = ( int ) zip_file_add( z, fileInfoPtr.constData(), src, 0 ); 165 : : #endif 166 : 0 : if ( rc == -1 ) 167 : : { 168 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error adding file '%1': %2" ).arg( file, zip_strerror( z ) ) ); 169 : 0 : zip_close( z ); 170 : 0 : return false; 171 : : } 172 : 0 : } 173 : : else 174 : : { 175 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error creating data source '%1': %2" ).arg( file, zip_strerror( z ) ) ); 176 : 0 : zip_close( z ); 177 : 0 : return false; 178 : : } 179 : 0 : } 180 : : 181 : 0 : zip_close( z ); 182 : 0 : } 183 : : else 184 : : { 185 : 0 : QgsMessageLog::logMessage( QObject::tr( "Error creating zip archive '%1': %2" ).arg( zipFilename, zip_strerror( z ) ) ); 186 : 0 : return false; 187 : : } 188 : : 189 : 0 : return true; 190 : 0 : }