28#include <QDomDocument>
29#include <QTextDocumentFragment>
35 : mFilename( filename )
53 const QByteArray fileNamePtr = mFilename.toUtf8();
55 mZip = zip_open( fileNamePtr.constData(), ZIP_CHECKCONS, &rc );
56 if ( rc == ZIP_ER_OK && mZip )
58 const int count = zip_get_num_entries( mZip, ZIP_FL_UNCHANGED );
73 QgsMessageLog::logMessage( QObject::tr(
"Error opening zip archive: '%1' (Error code: %2)" ).arg( mZip ? zip_strerror( mZip ) : mFilename ).arg( rc ) );
85 return static_cast< bool >( mZip );
90 if ( !mMetadata.isEmpty() )
96 const char *name =
"p12/root.json";
98 zip_stat_init( &stat );
99 zip_stat( mZip, name, 0, &stat );
101 const size_t len = stat.size;
102 const std::unique_ptr< char[] > buf(
new char[len + 1] );
105 zip_file *file = zip_fopen( mZip, name, 0 );
106 if ( zip_fread( file, buf.get(), len ) != -1 )
109 std::string jsonString( buf.get( ) );
122 mTileMapPath = mMetadata.value( QStringLiteral(
"tileMap" ) ).toString();
130 return QVariantMap();
132 const char *name =
"p12/resources/styles/root.json";
133 struct zip_stat stat;
134 zip_stat_init( &stat );
135 zip_stat( mZip, name, 0, &stat );
137 const size_t len = stat.size;
138 const std::unique_ptr< char[] > buf(
new char[len + 1] );
142 zip_file *file = zip_fopen( mZip, name, 0 );
143 if ( zip_fread( file, buf.get(), len ) != -1 )
146 std::string jsonString( buf.get( ) );
164 return QVariantMap();
166 for (
int resolution = 2; resolution > 0; resolution-- )
168 const QString spriteFileCandidate = QStringLiteral(
"p12/resources/sprites/sprite%1.json" ).arg( resolution > 1 ? QStringLiteral(
"@%1x" ).arg( resolution ) : QString() );
169 const QByteArray spriteFileCandidateBa = spriteFileCandidate.toLocal8Bit();
170 const char *name = spriteFileCandidateBa.constData();
171 struct zip_stat stat;
172 zip_stat_init( &stat );
173 zip_stat( mZip, name, 0, &stat );
178 const size_t len = stat.size;
179 const std::unique_ptr< char[] > buf(
new char[len + 1] );
181 QVariantMap definition;
183 zip_file *file = zip_fopen( mZip, name, 0 );
184 if ( zip_fread( file, buf.get(), len ) != -1 )
187 std::string jsonString( buf.get( ) );
202 return QVariantMap();
210 for (
int resolution = 2; resolution > 0; resolution-- )
212 const QString spriteFileCandidate = QStringLiteral(
"p12/resources/sprites/sprite%1.png" ).arg( resolution > 1 ? QStringLiteral(
"@%1x" ).arg( resolution ) : QString() );
213 const QByteArray spriteFileCandidateBa = spriteFileCandidate.toLocal8Bit();
214 const char *name = spriteFileCandidateBa.constData();
215 struct zip_stat stat;
216 zip_stat_init( &stat );
217 zip_stat( mZip, name, 0, &stat );
222 const size_t len = stat.size;
223 const std::unique_ptr< char[] > buf(
new char[len + 1] );
227 zip_file *file = zip_fopen( mZip, name, 0 );
228 if ( zip_fread( file, buf.get(), len ) != -1 )
232 result = QImage::fromData(
reinterpret_cast<const uchar *
>( buf.get() ), len );
255 const char *name =
"esriinfo/iteminfo.xml";
256 struct zip_stat stat;
257 zip_stat_init( &stat );
258 zip_stat( mZip, name, 0, &stat );
260 const size_t len = stat.size;
261 QByteArray buf( len, Qt::Uninitialized );
265 zip_file *file = zip_fopen( mZip, name, 0 );
266 if ( zip_fread( file, buf.data(), len ) != -1 )
272 QString errorMessage;
275 if ( !doc.setContent( buf,
false, &errorMessage, &errorLine, &errorColumn ) )
277 QgsMessageLog::logMessage( QObject::tr(
"Error reading layer metadata (line %1, col %2): %3" ).arg( errorLine ).arg( errorColumn ).arg( errorMessage ) );
281 metadata.setType( QStringLiteral(
"dataset" ) );
283 const QDomElement infoElement = doc.firstChildElement( QStringLiteral(
"ESRI_ItemInformation" ) );
285 metadata.setLanguage( infoElement.attribute( QStringLiteral(
"Culture" ) ) );
287 const QDomElement guidElement = infoElement.firstChildElement( QStringLiteral(
"guid" ) );
288 metadata.setIdentifier( guidElement.text() );
290 const QDomElement nameElement = infoElement.firstChildElement( QStringLiteral(
"name" ) );
291 metadata.setTitle( nameElement.text() );
293 const QDomElement descriptionElement = infoElement.firstChildElement( QStringLiteral(
"description" ) );
294 metadata.setAbstract( QTextDocumentFragment::fromHtml( descriptionElement.text() ).toPlainText() );
296 const QDomElement tagsElement = infoElement.firstChildElement( QStringLiteral(
"tags" ) );
298 const QStringList rawTags = tagsElement.text().split(
',' );
300 tags.reserve( rawTags.size() );
301 for (
const QString &tag : rawTags )
302 tags.append( tag.trimmed() );
303 metadata.addKeywords( QStringLiteral(
"keywords" ), tags );
305 const QDomElement accessInformationElement = infoElement.firstChildElement( QStringLiteral(
"accessinformation" ) );
306 metadata.setRights( { accessInformationElement.text() } );
308 const QDomElement licenseInfoElement = infoElement.firstChildElement( QStringLiteral(
"licenseinfo" ) );
309 metadata.setLicenses( { QTextDocumentFragment::fromHtml( licenseInfoElement.text() ).toPlainText() } );
311 const QDomElement extentElement = infoElement.firstChildElement( QStringLiteral(
"extent" ) );
312 const double xMin = extentElement.firstChildElement( QStringLiteral(
"xmin" ) ).text().toDouble();
313 const double xMax = extentElement.firstChildElement( QStringLiteral(
"xmax" ) ).text().toDouble();
314 const double yMin = extentElement.firstChildElement( QStringLiteral(
"ymin" ) ).text().toDouble();
315 const double yMax = extentElement.firstChildElement( QStringLiteral(
"ymax" ) ).text().toDouble();
323 extent.setSpatialExtents( { spatialExtent } );
345 if ( mHasReadTileMap || mTileMapPath.isEmpty() )
349 return QVariantMap();
351 const QString tileMapPath = QStringLiteral(
"p12/%1/root.json" ).arg( mTileMapPath );
352 struct zip_stat stat;
353 zip_stat_init( &stat );
354 zip_stat( mZip, tileMapPath.toLocal8Bit().constData(), 0, &stat );
356 const size_t len = stat.size;
357 const std::unique_ptr< char[] > buf(
new char[len + 1] );
360 zip_file *file = zip_fopen( mZip, tileMapPath.toLocal8Bit().constData(), 0 );
363 QgsDebugError( QStringLiteral(
"Tilemap %1 was not found in vtpk archive" ).arg( tileMapPath ) );
364 mTileMapPath.clear();
368 if ( zip_fread( file, buf.get(), len ) != -1 )
371 std::string jsonString( buf.get( ) );
381 QgsDebugError( QStringLiteral(
"Tilemap %1 could not be read from vtpk archive" ).arg( tileMapPath ) );
382 mTileMapPath.clear();
384 mHasReadTileMap =
true;
406 const QVariantMap fullExtent = md.value( QStringLiteral(
"fullExtent" ) ).toMap();
407 if ( !fullExtent.isEmpty() )
410 fullExtent.value( QStringLiteral(
"xmin" ) ).toDouble(),
411 fullExtent.value( QStringLiteral(
"ymin" ) ).toDouble(),
412 fullExtent.value( QStringLiteral(
"xmax" ) ).toDouble(),
413 fullExtent.value( QStringLiteral(
"ymax" ) ).toDouble()
424 QgsDebugError( QStringLiteral(
"Could not transform layer fullExtent to layer CRS" ) );
435 QgsDebugError( QStringLiteral(
"VTPK tile package not open: " ) + mFilename );
438 if ( mPacketSize < 0 )
439 mPacketSize =
metadata().value( QStringLiteral(
"resourceInfo" ) ).toMap().value( QStringLiteral(
"cacheInfo" ) ).toMap().value( QStringLiteral(
"storageInfo" ) ).toMap().value( QStringLiteral(
"packetSize" ) ).toInt();
441 const int fileRow = mPacketSize *
static_cast< int >( std::floor( y /
static_cast< double>( mPacketSize ) ) );
442 const int fileCol = mPacketSize *
static_cast< int >( std::floor( x /
static_cast< double>( mPacketSize ) ) );
444 const QString tileName = QStringLiteral(
"R%1C%2" )
445 .arg( fileRow, 4, 16, QLatin1Char(
'0' ) )
446 .arg( fileCol, 4, 16, QLatin1Char(
'0' ) );
448 const QString fileName = QStringLiteral(
"p12/tile/L%1/%2.bundle" )
449 .arg( z, 2, 10, QLatin1Char(
'0' ) ).arg( tileName );
450 struct zip_stat stat;
451 zip_stat_init( &stat );
452 zip_stat( mZip, fileName.toLocal8Bit().constData(), 0, &stat );
454 const size_t tileIndexOffset = 64 + 8 * ( mPacketSize * ( y % mPacketSize ) + ( x % mPacketSize ) );
457 const size_t len = stat.size;
458 if ( len <= tileIndexOffset )
461 res = QByteArray(
"" );
465 const std::unique_ptr< char[] > buf(
new char[len] );
468 zip_file *file = zip_fopen( mZip, fileName.toLocal8Bit().constData(), 0 );
469 if ( zip_fread( file, buf.get(), len ) != -1 )
471 unsigned long long indexValue;
472 memcpy( &indexValue, buf.get() + tileIndexOffset, 8 );
474 const std::size_t tileOffset = indexValue % ( 2ULL << 39 );
475 const std::size_t tileSize =
static_cast< std::size_t
>( std::floor( indexValue / ( 2ULL << 39 ) ) );
480 res = QByteArray(
"" );
static QgsCoordinateReferenceSystem convertSpatialReference(const QVariantMap &spatialReferenceMap)
Converts a spatial reference JSON definition to a QgsCoordinateReferenceSystem value.
A 3-dimensional box composed of x, y, z coordinates.
This class represents a coordinate reference system (CRS).
Contains information about the context in which a coordinate transform is executed.
Custom exception class for Coordinate Reference System related exceptions.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
A rectangle specified with double values.
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system associated with the tiles.
bool isEmpty() const
Returns true if the matrix set is empty.
Encapsulates properties of a vector tile matrix set, including tile origins and scaling information.
bool fromEsriJson(const QVariantMap &json, const QVariantMap &rootTileMap=QVariantMap())
Initializes the tile structure settings from an ESRI REST VectorTileService json map.
QByteArray tileData(int z, int x, int y)
Returns the raw tile data for the matching tile.
QgsRectangle extent(const QgsCoordinateTransformContext &context) const
Returns bounding box from metadata, given in the tiles crs().
bool isOpen() const
Returns whether the VTPK file is currently opened.
QVariantMap rootTileMap() const
Returns the root tilemap content, if it exists.
QVariantMap spriteDefinition() const
Returns the VTPK sprites definitions.
QgsCoordinateReferenceSystem crs() const
Returns the coordinate reference system of the tiles.
QgsLayerMetadata layerMetadata() const
Reads layer metadata from the VTPK file.
bool open()
Tries to open the file, returns true on success.
QgsVtpkTiles(const QString &filename)
Constructs VTPK reader (but it does not open the file yet)
QgsVectorTileMatrixSet matrixSet() const
Returns the vector tile matrix set representing the tiles.
QVariantMap styleDefinition() const
Returns the VTPK style definition.
QVariantMap metadata() const
Returns the VTPK metadata.
QImage spriteImage() const
Returns the VTPK sprite image, if it exists.
CORE_EXPORT bool decodeGzip(const QByteArray &bytesIn, QByteArray &bytesOut)
Decodes gzip byte stream, returns true on success.
#define QgsDebugError(str)