29 #include <QDomDocument>
30 #include <QTextDocumentFragment>
36 : mFilename( filename )
54 const QByteArray fileNamePtr = mFilename.toUtf8();
56 mZip = zip_open( fileNamePtr.constData(), ZIP_CHECKCONS, &rc );
57 if ( rc == ZIP_ER_OK && mZip )
59 const int count = zip_get_num_files( mZip );
74 QgsMessageLog::logMessage( QObject::tr(
"Error opening zip archive: '%1' (Error code: %2)" ).arg( mZip ? zip_strerror( mZip ) : mFilename ).arg( rc ) );
86 return static_cast< bool >( mZip );
91 if ( !mMetadata.isEmpty() )
97 const char *name =
"p12/root.json";
99 zip_stat_init( &stat );
100 zip_stat( mZip, name, 0, &stat );
102 const size_t len = stat.size;
103 const std::unique_ptr< char[] > buf(
new char[len + 1] );
106 zip_file *file = zip_fopen( mZip, name, 0 );
107 if ( zip_fread( file, buf.get(), len ) != -1 )
110 std::string jsonString( buf.get( ) );
127 return QVariantMap();
129 const char *name =
"p12/resources/styles/root.json";
130 struct zip_stat stat;
131 zip_stat_init( &stat );
132 zip_stat( mZip, name, 0, &stat );
134 const size_t len = stat.size;
135 const std::unique_ptr< char[] > buf(
new char[len + 1] );
139 zip_file *file = zip_fopen( mZip, name, 0 );
140 if ( zip_fread( file, buf.get(), len ) != -1 )
143 std::string jsonString( buf.get( ) );
160 return QVariantMap();
162 for (
int resolution = 2; resolution > 0; resolution-- )
164 const QString spriteFileCandidate = QStringLiteral(
"p12/resources/sprites/sprite%1.json" ).arg( resolution > 1 ? QStringLiteral(
"@%1x" ).arg( resolution ) : QString() );
165 const QByteArray spriteFileCandidateBa = spriteFileCandidate.toLocal8Bit();
166 const char *name = spriteFileCandidateBa.constData();
167 struct zip_stat stat;
168 zip_stat_init( &stat );
169 zip_stat( mZip, name, 0, &stat );
174 const size_t len = stat.size;
175 const std::unique_ptr< char[] > buf(
new char[len + 1] );
177 QVariantMap definition;
179 zip_file *file = zip_fopen( mZip, name, 0 );
180 if ( zip_fread( file, buf.get(), len ) != -1 )
183 std::string jsonString( buf.get( ) );
197 return QVariantMap();
205 for (
int resolution = 2; resolution > 0; resolution-- )
207 const QString spriteFileCandidate = QStringLiteral(
"p12/resources/sprites/sprite%1.png" ).arg( resolution > 1 ? QStringLiteral(
"@%1x" ).arg( resolution ) : QString() );
208 const QByteArray spriteFileCandidateBa = spriteFileCandidate.toLocal8Bit();
209 const char *name = spriteFileCandidateBa.constData();
210 struct zip_stat stat;
211 zip_stat_init( &stat );
212 zip_stat( mZip, name, 0, &stat );
217 const size_t len = stat.size;
218 const std::unique_ptr< char[] > buf(
new char[len + 1] );
222 zip_file *file = zip_fopen( mZip, name, 0 );
223 if ( zip_fread( file, buf.get(), len ) != -1 )
227 result = QImage::fromData(
reinterpret_cast<const uchar *
>( buf.get() ), len );
249 const char *name =
"esriinfo/iteminfo.xml";
250 struct zip_stat stat;
251 zip_stat_init( &stat );
252 zip_stat( mZip, name, 0, &stat );
254 const size_t len = stat.size;
255 QByteArray buf( len, Qt::Uninitialized );
259 zip_file *file = zip_fopen( mZip, name, 0 );
260 if ( zip_fread( file, buf.data(), len ) != -1 )
266 QString errorMessage;
269 if ( !doc.setContent( buf,
false, &errorMessage, &errorLine, &errorColumn ) )
271 QgsMessageLog::logMessage( QObject::tr(
"Error reading layer metadata (line %1, col %2): %3" ).arg( errorLine ).arg( errorColumn ).arg( errorMessage ) );
275 metadata.setType( QStringLiteral(
"dataset" ) );
277 const QDomElement infoElement = doc.firstChildElement( QStringLiteral(
"ESRI_ItemInformation" ) );
279 metadata.setLanguage( infoElement.attribute( QStringLiteral(
"Culture" ) ) );
281 const QDomElement guidElement = infoElement.firstChildElement( QStringLiteral(
"guid" ) );
282 metadata.setIdentifier( guidElement.text() );
284 const QDomElement nameElement = infoElement.firstChildElement( QStringLiteral(
"name" ) );
285 metadata.setTitle( nameElement.text() );
287 const QDomElement descriptionElement = infoElement.firstChildElement( QStringLiteral(
"description" ) );
288 metadata.setAbstract( QTextDocumentFragment::fromHtml( descriptionElement.text() ).toPlainText() );
290 const QDomElement tagsElement = infoElement.firstChildElement( QStringLiteral(
"tags" ) );
292 const QStringList rawTags = tagsElement.text().split(
',' );
294 tags.reserve( rawTags.size() );
295 for (
const QString &tag : rawTags )
296 tags.append( tag.trimmed() );
297 metadata.addKeywords( QStringLiteral(
"keywords" ), tags );
299 const QDomElement accessInformationElement = infoElement.firstChildElement( QStringLiteral(
"accessinformation" ) );
300 metadata.setRights( { accessInformationElement.text() } );
302 const QDomElement licenseInfoElement = infoElement.firstChildElement( QStringLiteral(
"licenseinfo" ) );
303 metadata.setLicenses( { QTextDocumentFragment::fromHtml( licenseInfoElement.text() ).toPlainText() } );
305 const QDomElement extentElement = infoElement.firstChildElement( QStringLiteral(
"extent" ) );
306 const double xMin = extentElement.firstChildElement( QStringLiteral(
"xmin" ) ).text().toDouble();
307 const double xMax = extentElement.firstChildElement( QStringLiteral(
"xmax" ) ).text().toDouble();
308 const double yMin = extentElement.firstChildElement( QStringLiteral(
"ymin" ) ).text().toDouble();
309 const double yMax = extentElement.firstChildElement( QStringLiteral(
"ymax" ) ).text().toDouble();
317 extent.setSpatialExtents( { spatialExtent } );
351 const QVariantMap fullExtent = md.value( QStringLiteral(
"fullExtent" ) ).toMap();
352 if ( !fullExtent.isEmpty() )
355 fullExtent.value( QStringLiteral(
"xmin" ) ).toDouble(),
356 fullExtent.value( QStringLiteral(
"ymin" ) ).toDouble(),
357 fullExtent.value( QStringLiteral(
"xmax" ) ).toDouble(),
358 fullExtent.value( QStringLiteral(
"ymax" ) ).toDouble()
369 QgsDebugMsg( QStringLiteral(
"Could not transform layer fullExtent to layer CRS" ) );
380 QgsDebugMsg( QStringLiteral(
"VTPK tile package not open: " ) + mFilename );
383 if ( mPacketSize < 0 )
384 mPacketSize =
metadata().value( QStringLiteral(
"resourceInfo" ) ).toMap().value( QStringLiteral(
"cacheInfo" ) ).toMap().value( QStringLiteral(
"storageInfo" ) ).toMap().value( QStringLiteral(
"packetSize" ) ).toInt();
386 const int fileRow = mPacketSize *
static_cast< int >( std::floor( y /
static_cast< double>( mPacketSize ) ) );
387 const int fileCol = mPacketSize *
static_cast< int >( std::floor( x /
static_cast< double>( mPacketSize ) ) );
389 const QString tileName = QStringLiteral(
"R%1C%2" )
390 .arg( fileRow, 4, 16, QLatin1Char(
'0' ) )
391 .arg( fileCol, 4, 16, QLatin1Char(
'0' ) );
393 const QString fileName = QStringLiteral(
"p12/tile/L%1/%2.bundle" )
394 .arg( z, 2, 10, QLatin1Char(
'0' ) ).arg( tileName );
395 struct zip_stat stat;
396 zip_stat_init( &stat );
397 zip_stat( mZip, fileName.toLocal8Bit().constData(), 0, &stat );
399 const size_t tileIndexOffset = 64 + 8 * ( mPacketSize * ( y % mPacketSize ) + ( x % mPacketSize ) );
402 const size_t len = stat.size;
403 if ( len <= tileIndexOffset )
405 QgsMessageLog::logMessage( QObject::tr(
"Cannot read gzip contents at offset %1: %2" ).arg( tileIndexOffset ).arg( fileName ) );
409 const std::unique_ptr< char[] > buf(
new char[len] );
412 zip_file *file = zip_fopen( mZip, fileName.toLocal8Bit().constData(), 0 );
413 if ( zip_fread( file, buf.get(), len ) != -1 )
415 unsigned long long indexValue;
416 memcpy( &indexValue, buf.get() + tileIndexOffset, 8 );
418 const std::size_t tileOffset = indexValue % ( 2ULL << 39 );
419 const std::size_t tileSize =
static_cast< std::size_t
>( std::floor( indexValue / ( 2ULL << 39 ) ) );