38 if ( !QFileInfo::exists( zipFilename ) )
43 else if ( zipFilename.isEmpty() )
48 else if ( !QDir( dir ).exists( dir ) )
53 else if ( !QFileInfo( dir ).isDir() )
58 else if ( !QFileInfo( dir ).isWritable() )
65 const QByteArray fileNamePtr = zipFilename.toUtf8();
66 struct zip *z = zip_open( fileNamePtr.constData(), checkConsistency ? ZIP_CHECKCONS : 0, &rc );
68 if ( rc == ZIP_ER_OK && z )
70 const int count = zip_get_num_entries( z, ZIP_FL_UNCHANGED );
75 for (
int i = 0; i < count; i++ )
77 zip_stat_index( z, i, 0, &stat );
78 const size_t len = stat.size;
80 struct zip_file *file = zip_fopen_index( z, i, 0 );
81 const std::unique_ptr< char[] > buf(
new char[len] );
82 if ( zip_fread( file, buf.get(), len ) != -1 )
84 const QString fileName( stat.name );
85 if ( fileName.endsWith(
"/" ) )
90 const QFileInfo newFile( QDir( dir ), fileName );
92 if ( !QString( QDir::cleanPath( newFile.absolutePath() ) + QStringLiteral(
"/" ) ).startsWith( QDir( dir ).absolutePath() + QStringLiteral(
"/" ) ) )
95 newFile.absoluteFilePath(),
96 QDir( dir ).absolutePath()
102 if ( !newFile.absoluteDir().exists() )
104 if ( !QDir( dir ).mkpath( newFile.absolutePath() ) )
108 QFile outFile( newFile.absoluteFilePath() );
109 if ( !outFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
115 outFile.write( buf.get(), len );
118 files.append( newFile.absoluteFilePath() );
139 QgsMessageLog::logMessage( QObject::tr(
"Error opening zip archive: '%1' (Error code: %2)" ).arg( z ? zip_strerror( z ) : zipFilename ).arg( rc ) );
148 if ( zipFilename.isEmpty() )
155 const QByteArray zipFileNamePtr = zipFilename.toUtf8();
156 struct zip *z = zip_open( zipFileNamePtr.constData(), overwrite ? ( ZIP_CREATE | ZIP_TRUNCATE ) : ZIP_CREATE, &rc );
158 if ( rc == ZIP_ER_OK && z )
160 for (
const auto &file :
files )
162 const QFileInfo fileInfo( file );
163 if ( !fileInfo.exists() )
170 const QByteArray fileNamePtr = file.toUtf8();
171 zip_source *src = zip_source_file( z, fileNamePtr.constData(), 0, 0 );
174 const QByteArray fileInfoPtr = fileInfo.fileName().toUtf8();
175#if LIBZIP_VERSION_MAJOR < 1
176 rc = ( int ) zip_add( z, fileInfoPtr.constData(), src );
178 rc = ( int ) zip_file_add( z, fileInfoPtr.constData(), src, 0 );
199 QgsMessageLog::logMessage( QObject::tr(
"Error creating zip archive '%1': %2" ).arg( zipFilename, z ? zip_strerror( z ) : zipFilename ) );
213 unsigned char *bytesInPtr =
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( bytesIn ) );
214 uint bytesInLeft =
static_cast<uint
>( size );
216 const uint CHUNK = 16384;
217 unsigned char out[CHUNK];
218 const int DEC_MAGIC_NUM_FOR_GZIP = 16;
222 strm.zalloc = Z_NULL;
224 strm.opaque = Z_NULL;
226 strm.next_in = Z_NULL;
228 int ret = inflateInit2( &strm, MAX_WBITS + DEC_MAGIC_NUM_FOR_GZIP );
235 while ( ret != Z_STREAM_END )
238 const uint bytesToProcess = std::min( CHUNK, bytesInLeft );
239 strm.next_in = bytesInPtr;
240 strm.avail_in = bytesToProcess;
241 bytesInPtr += bytesToProcess;
242 bytesInLeft -= bytesToProcess;
244 if ( bytesToProcess == 0 )
250 strm.avail_out = CHUNK;
252 ret = inflate( &strm, Z_NO_FLUSH );
253 Q_ASSERT( ret != Z_STREAM_ERROR );
254 if ( ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR )
259 const unsigned have = CHUNK - strm.avail_out;
260 bytesOut.append( QByteArray::fromRawData(
reinterpret_cast<const char *
>( out ),
static_cast<int>( have ) ) );
262 while ( strm.avail_out == 0 );
266 return ret == Z_STREAM_END;
271 unsigned char *bytesInPtr =
reinterpret_cast<unsigned char *
>(
const_cast<char *
>( bytesIn.constData() ) );
272 const uint bytesInLeft =
static_cast<uint
>( bytesIn.count() );
274 const uint CHUNK = 16384;
275 unsigned char out[CHUNK];
276 const int DEC_MAGIC_NUM_FOR_GZIP = 16;
280 strm.zalloc = Z_NULL;
282 strm.opaque = Z_NULL;
284 int ret = deflateInit2( &strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + DEC_MAGIC_NUM_FOR_GZIP, 8, Z_DEFAULT_STRATEGY );
288 strm.avail_in = bytesInLeft;
289 strm.next_in = bytesInPtr;
295 strm.avail_out = CHUNK;
297 ret = deflate( &strm, Z_FINISH );
298 Q_ASSERT( ret != Z_STREAM_ERROR );
300 const unsigned have = CHUNK - strm.avail_out;
301 bytesOut.append( QByteArray::fromRawData(
reinterpret_cast<const char *
>( out ),
static_cast<int>( have ) ) );
303 while ( strm.avail_out == 0 );
304 Q_ASSERT( ret == Z_STREAM_END );
313 if (
zip.isEmpty() && !QFileInfo::exists(
zip ) )
315 return QStringList();
320 const QByteArray fileNamePtr =
zip.toUtf8();
321 struct zip *z = zip_open( fileNamePtr.constData(), 0, &rc );
323 if ( rc == ZIP_ER_OK && z )
325 const int count = zip_get_num_entries( z, ZIP_FL_UNCHANGED );
328 struct zip_stat stat;
330 for (
int i = 0; i < count; i++ )
332 zip_stat_index( z, i, 0, &stat );
333 files << QString( stat.name );
345 if ( !QFileInfo::exists( zipFilename ) )
351 if ( filenameInZip.isEmpty() )
358 const QByteArray zipFilenamePtr = zipFilename.toUtf8();
359 struct zip *z = zip_open( zipFilenamePtr.constData(), 0, &err );
363 zip_error_init_with_code( &error, err );
364 QgsMessageLog::logMessage( QObject::tr(
"Error opening zip archive '%1': %2" ).arg( zipFilename, zip_error_strerror( &error ) ) );
365 zip_error_fini( &error );
369 const QByteArray filenameInZipPtr = filenameInZip.toUtf8();
371 zip_stat_init( &st );
372 if ( zip_stat( z, filenameInZipPtr.constData(), 0, &st ) != 0 )
374 QgsMessageLog::logMessage( QObject::tr(
"File '%1' not found in zip archive '%2': %3" ).arg( filenameInZip, zipFilename, zip_strerror( z ) ) );
379 zip_file *zf = zip_fopen( z, filenameInZipPtr.constData(), 0 );
382 QgsMessageLog::logMessage( QObject::tr(
"Could not open file '%1' in zip archive '%2': %3" ).arg( filenameInZip, zipFilename, zip_strerror( z ) ) );
387 bytesOut.resize(
static_cast<int>( st.size ) );
388 zip_int64_t readBytes = zip_fread( zf, bytesOut.data(), st.size );
394 if (
static_cast<zip_uint64_t
>( readBytes ) != st.size )
396 QgsMessageLog::logMessage( QObject::tr(
"Error reading file '%1' from zip archive '%2'." ).arg( filenameInZip, zipFilename ) );
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static bool extractFileFromZip(const QString &zipFilename, const QString &filenameInZip, QByteArray &bytesOut)
Extracts a file from a zip archive, returns true on success.
static bool unzip(const QString &zip, const QString &dir, QStringList &files, bool checkConsistency=true)
Unzip a zip file in an output directory.