QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsziputils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsziputils.cpp
3  ---------------------
4  begin : Jul 2017
5  copyright : (C) 2017 by Paul Blottiere
6  email : [email protected]
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 bool QgsZipUtils::isZipFile( const QString &filename )
30 {
31  return QFileInfo( filename ).suffix().compare( QLatin1String( "qgz" ), Qt::CaseInsensitive ) == 0;
32 }
33 
34 bool QgsZipUtils::unzip( const QString &zipFilename, const QString &dir, QStringList &files )
35 {
36  files.clear();
37 
38  if ( !QFileInfo::exists( zipFilename ) )
39  {
40  QString err = QObject::tr( "Error zip file does not exist: '%1'" ).arg( zipFilename );
41  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
42  return false;
43  }
44  else if ( zipFilename.isEmpty() )
45  {
46  QString err = QObject::tr( "Error zip filename is empty" );
47  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
48  return false;
49  }
50  else if ( !QDir( dir ).exists( dir ) )
51  {
52  QString err = QObject::tr( "Error output dir does not exist: '%1'" ).arg( dir );
53  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
54  return false;
55  }
56  else if ( !QFileInfo( dir ).isDir() )
57  {
58  QString err = QObject::tr( "Error output dir is not a directory: '%1'" ).arg( dir );
59  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
60  return false;
61  }
62  else if ( !QFileInfo( dir ).isWritable() )
63  {
64  QString err = QObject::tr( "Error output dir is not writable: '%1'" ).arg( dir );
65  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
66  return false;
67  }
68 
69  int rc = 0;
70  const QByteArray fileNamePtr = zipFilename.toUtf8();
71  struct zip *z = zip_open( fileNamePtr.constData(), ZIP_CHECKCONS, &rc );
72 
73  if ( rc == ZIP_ER_OK && z )
74  {
75  int count = zip_get_num_files( z );
76  if ( count != -1 )
77  {
78  struct zip_stat stat;
79 
80  for ( int i = 0; i < count; i++ )
81  {
82  zip_stat_index( z, i, 0, &stat );
83  size_t len = stat.size;
84 
85  struct zip_file *file = zip_fopen_index( z, i, 0 );
86  char *buf = new char[len];
87  if ( zip_fread( file, buf, len ) != -1 )
88  {
89  QString fileName( stat.name );
90  QFileInfo newFile( QDir( dir ), fileName );
91 
92  // Create path for a new file if it does not exist.
93  if ( !newFile.absoluteDir().exists() )
94  {
95  if ( !QDir( dir ).mkpath( newFile.absolutePath() ) )
96  QgsMessageLog::logMessage( QStringLiteral( "Failed to create a subdirectory %1/%2" ).arg( dir ).arg( fileName ) );
97  }
98 
99  QFile outFile( newFile.absoluteFilePath() );
100  if ( !outFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
101  {
102  QgsMessageLog::logMessage( QStringLiteral( "Could not write to %1" ).arg( newFile.absoluteFilePath() ) );
103  }
104  else
105  {
106  outFile.write( buf, len );
107  }
108  zip_fclose( file );
109  files.append( newFile.absoluteFilePath() );
110  }
111  else
112  {
113  zip_fclose( file );
114  QString err = QObject::tr( "Error reading file: '%1'" ).arg( zip_strerror( z ) );
115  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
116  return false;
117  }
118  }
119  }
120  else
121  {
122  zip_close( z );
123  QString err = QObject::tr( "Error getting files: '%1'" ).arg( zip_strerror( z ) );
124  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
125  return false;
126  }
127 
128  zip_close( z );
129  }
130  else
131  {
132  QString err = QObject::tr( "Error opening zip archive: '%1'" ).arg( z ? zip_strerror( z ) : zipFilename );
133  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
134  return false;
135  }
136 
137  return true;
138 }
139 
140 bool QgsZipUtils::zip( const QString &zipFilename, const QStringList &files )
141 {
142  if ( zipFilename.isEmpty() )
143  {
144  QString err = QObject::tr( "Error zip filename is empty" );
145  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
146  return false;
147  }
148 
149  int rc = 0;
150  const QByteArray fileNamePtr = zipFilename.toUtf8();
151  struct zip *z = zip_open( fileNamePtr.constData(), ZIP_CREATE, &rc );
152 
153  if ( rc == ZIP_ER_OK && z )
154  {
155  for ( const auto &file : files )
156  {
157  QFileInfo fileInfo( file );
158  if ( !fileInfo.exists() )
159  {
160  QString err = QObject::tr( "Error input file does not exist: '%1'" ).arg( file );
161  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
162  zip_close( z );
163  return false;
164  }
165 
166  const QByteArray fileNamePtr = file.toUtf8();
167  zip_source *src = zip_source_file( z, fileNamePtr.constData(), 0, 0 );
168  if ( src )
169  {
170  const QByteArray fileInfoPtr = fileInfo.fileName().toUtf8();
171 #if LIBZIP_VERSION_MAJOR < 1
172  int rc = ( int ) zip_add( z, fileInfoPtr.constData(), src );
173 #else
174  int rc = ( int ) zip_file_add( z, fileInfoPtr.constData(), src, 0 );
175 #endif
176  if ( rc == -1 )
177  {
178  QString err = QObject::tr( "Error adding file '%1': %2" ).arg( file, zip_strerror( z ) );
179  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
180  zip_close( z );
181  return false;
182  }
183  }
184  else
185  {
186  QString err = QObject::tr( "Error creating data source '%1': %2" ).arg( file, zip_strerror( z ) );
187  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
188  zip_close( z );
189  return false;
190  }
191  }
192 
193  zip_close( z );
194  }
195  else
196  {
197  QString err = QObject::tr( "Error creating zip archive '%1': %2" ).arg( zipFilename, zip_strerror( z ) );
198  QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
199  return false;
200  }
201 
202  return true;
203 }
CORE_EXPORT bool unzip(const QString &zip, const QString &dir, QStringList &files)
Unzip a zip file in an output directory.
Definition: qgsziputils.cpp:34
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
CORE_EXPORT bool isZipFile(const QString &filename)
Returns true if the file name is a zipped file ( i.e with a &#39;.qgz&#39; extension, false otherwise...
Definition: qgsziputils.cpp:29
CORE_EXPORT bool zip(const QString &zip, const QStringList &files)
Zip the list of files in the zip file.