QgsZipUtils unzips also subdirectories of a zip file (#8672)

QgsZipUtils unzips also subdirectories of a zip file
This commit is contained in:
sklencar 2018-12-20 14:42:22 +01:00 committed by Peter Petrik
parent 3dd360922f
commit be34a0ed27
4 changed files with 154 additions and 1 deletions

View File

@ -22,6 +22,7 @@
#include "qgsmessagelog.h"
#include "qgsziputils.h"
#include "qgslogger.h"
#include <iostream>
@ -84,8 +85,17 @@ bool QgsZipUtils::unzip( const QString &zipFilename, const QString &dir, QString
char *buf = new char[len];
if ( zip_fread( file, buf, len ) != -1 )
{
QFileInfo newFile( QDir( dir ), QString( stat.name ) );
QString fileName( stat.name );
QFileInfo newFile( QDir( dir ), fileName );
// Create path for a new file if it does not exist.
if ( !newFile.absoluteDir().exists() )
{
if ( !QDir( dir ).mkpath( newFile.absolutePath() ) )
QgsMessageLog::logMessage( QString( "Failed to create a subdirectory %1/%2" ).arg( dir ).arg( fileName ) );
}
std::ofstream( newFile.absoluteFilePath().toStdString() ).write( buf, len );
zip_fclose( file );
files.append( newFile.absoluteFilePath() );
}

View File

@ -204,6 +204,7 @@ SET(TESTS
testqgsvectorlayerjoinbuffer.cpp
testqgsvectorlayer.cpp
testqgsvectorlayerutils.cpp
testqgsziputils.cpp
testziplayer.cpp
testqgsmeshlayer.cpp
testqgsmeshlayerrenderer.cpp

View File

@ -0,0 +1,142 @@
/***************************************************************************
testqgsziputils.cpp
--------------------
begin : December 2018
copyright : (C) 2018 Viktor Sklencar
email : vsklencar at gmail dot com
***************************************************************************
* *
* 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 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgstest.h"
#include <QObject>
#include <QString>
#include <QStringList>
#include <QDirIterator>
#include "qgsziputils.h"
#include "qgsapplication.h"
class TestQgsZipUtils: public QObject
{
Q_OBJECT
private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.
void init();// will be called before each testfunction is executed.
void cleanup();// will be called after every testfunction.
void unzipWithSubdirs();
void unzipWithSubdirs2();
private:
void genericTest( QString zipName, int expectedEntries, bool includeFolders, const QStringList &testFileNames );
};
void TestQgsZipUtils::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();
}
void TestQgsZipUtils::cleanupTestCase()
{
QgsApplication::exitQgis();
}
void TestQgsZipUtils::init()
{
}
void TestQgsZipUtils::cleanup()
{
}
void TestQgsZipUtils::unzipWithSubdirs()
{
QStringList testFileNames;
testFileNames << "/folder/folder2/landsat_b2.tif" << "/folder/points.geojson" << "/points.qml";
genericTest( QString( "testzip" ), 11, true, testFileNames );
}
/**
* Test unzips zip file with a following structure. Note that subfolder is not included in the structure as
* usually expected. Zip file has been made with the python zipstream lib (https://github.com/allanlei/python-zipstream).
*
* output of zipinfo diff_structured.zip:
* Archive: diff_structured.zip
* Zip file size: 452 bytes, number of entries: 3
* ?rw------- 2.0 unx 16 bl defN 18-Dec-18 13:27 subfolder/second_level.txt
* ?rw------- 2.0 unx 5 bl defN 18-Dec-18 13:27 subfolder/3.txt
* ?rw------- 2.0 unx 15 bl defN 18-Dec-18 13:27 first_level.txt
*
*/
void TestQgsZipUtils::unzipWithSubdirs2()
{
genericTest( QString( "diff_structured" ), 3, false, QStringList() << "/subfolder/3.txt" );
}
/**
* \brief TestQgsZipUtils::genericTest
* \param zipName File to unzip
* \param expectedEntries number of expected entries in given file
* \param includeFolders Tag if a folder should be count as an entry
* \param testFileNames List of file names to check if files were unzipped successfully
*/
void TestQgsZipUtils::genericTest( QString zipName, int expectedEntries, bool includeFolders, const QStringList &testFileNames )
{
QFile zipFile( QString( TEST_DATA_DIR ) + QString( "/zip/%1.zip" ).arg( zipName ) );
QVERIFY( zipFile.exists() );
QFileInfo fileInfo( zipFile );
QString unzipDirPath = QDir::tempPath() + zipName;
QStringList files;
// Create a root folder otherwise nothing is unzipped
QDir dir( unzipDirPath );
if ( !dir.exists( unzipDirPath ) )
{
dir.mkdir( unzipDirPath );
}
QgsZipUtils::unzip( fileInfo.absoluteFilePath(), unzipDirPath, files );
// Test number of unzipped files
QCOMPARE( files.count(), expectedEntries );
if ( includeFolders )
{
dir.setFilter( QDir::Files | QDir::NoDotAndDotDot | QDir::Dirs );
}
else
{
dir.setFilter( QDir::Files | QDir::NoDotAndDotDot );
}
// Get list of entries from the root folder
QDirIterator it( dir, QDirIterator::Subdirectories );
QStringList filesFromResultDir;
while ( it.hasNext() )
filesFromResultDir << it.next();
// Test if ziplib matches number of files in the root folder
QCOMPARE( files.count(), filesFromResultDir.count() );
// Test if specific files are included in the root folder
for ( QString fileName : testFileNames )
{
QVERIFY( filesFromResultDir.contains( unzipDirPath + fileName ) );
}
// Delete unzipped data
bool testDataRemoved = dir.removeRecursively();
QVERIFY( testDataRemoved );
}
QGSTEST_MAIN( TestQgsZipUtils )
#include "testqgsziputils.moc"

BIN
tests/testdata/zip/diff_structured.zip vendored Normal file

Binary file not shown.