28 #include <QNetworkRequest> 
   29 #include <QNetworkReply> 
   30 #include <QProgressDialog> 
   35 #include <QRegularExpression> 
   42 static const char *
GML_NAMESPACE = 
"http://www.opengis.net/gml";
 
   47   const QString &geometryAttribute,
 
   49   : mParser( 
typeName, geometryAttribute, fields )
 
   53   const int index = mTypeName.indexOf( 
':' );
 
   54   if ( index != -1 && index < mTypeName.length() )
 
   56     mTypeName = mTypeName.mid( index + 1 );
 
   65   QNetworkRequest request( uri );
 
   68   if ( !authcfg.isEmpty() )
 
   73         tr( 
"GML Getfeature network request update failed for authcfg %1" ).arg( authcfg ),
 
   75         Qgis::MessageLevel::Critical
 
   80   else if ( !userName.isNull() || !password.isNull() )
 
   82     request.setRawHeader( 
"Authorization", 
"Basic " + QStringLiteral( 
"%1:%2" ).arg( userName, password ).toLatin1().toBase64() );
 
   86   if ( !authcfg.isEmpty() )
 
   92         tr( 
"GML Getfeature network reply update failed for authcfg %1" ).arg( authcfg ),
 
   94         Qgis::MessageLevel::Critical
 
  100   connect( reply, &QNetworkReply::finished, 
this, &QgsGml::setFinished );
 
  101   connect( reply, &QNetworkReply::downloadProgress, 
this, &QgsGml::handleProgressEvent );
 
  104   QProgressDialog *progressDialog = 
nullptr;
 
  105   QWidget *mainWindow = 
nullptr;
 
  106   const QWidgetList topLevelWidgets = qApp->topLevelWidgets();
 
  107   for ( QWidgetList::const_iterator it = topLevelWidgets.constBegin(); it != topLevelWidgets.constEnd(); ++it )
 
  109     if ( ( *it )->objectName() == QLatin1String( 
"QgisApp" ) )
 
  117     progressDialog = 
new QProgressDialog( tr( 
"Loading GML data\n%1" ).arg( mTypeName ), tr( 
"Abort" ), 0, 0, mainWindow );
 
  118     progressDialog->setWindowModality( Qt::ApplicationModal );
 
  121     connect( progressDialog, &QProgressDialog::canceled, 
this, &QgsGml::setFinished );
 
  122     progressDialog->show();
 
  132     const QByteArray readData = reply->readAll();
 
  133     if ( !readData.isEmpty() )
 
  136       if ( !mParser.
processData( readData, atEnd, errorMsg ) )
 
  140     QCoreApplication::processEvents();
 
  143   fillMapsFromParser();
 
  145   const QNetworkReply::NetworkError replyError = reply->error();
 
  146   const QString replyErrorString = reply->errorString();
 
  149   delete progressDialog;
 
  154       tr( 
"GML Getfeature network request failed with error: %1" ).arg( replyErrorString ),
 
  156       Qgis::MessageLevel::Critical
 
  168       calculateExtentFromFeatures();
 
  183   if ( !mParser.
processData( data, 
true , errorMsg ) )
 
  186   fillMapsFromParser();
 
  196 void QgsGml::fillMapsFromParser()
 
  199   const auto constFeatures = features;
 
  203     const QString &gmlId = featPair.second;
 
  204     mFeatures.insert( feat->
id(), feat );
 
  205     if ( !gmlId.isEmpty() )
 
  207       mIdMap.insert( feat->
id(), gmlId );
 
  212 void QgsGml::setFinished()
 
  217 void QgsGml::handleProgressEvent( qint64 progress, qint64 totalSteps )
 
  219   if ( totalSteps < 0 )
 
  229 void QgsGml::calculateExtentFromFeatures()
 
  231   if ( mFeatures.empty() )
 
  238   bool bboxInitialized = 
false; 
 
  240   for ( 
int i = 0; i < mFeatures.size(); ++i )
 
  242     currentFeature = mFeatures[i];
 
  243     if ( !currentFeature )
 
  247     currentGeometry = currentFeature->
geometry();
 
  248     if ( !currentGeometry.
isNull() )
 
  250       if ( !bboxInitialized )
 
  253         bboxInitialized = 
true;
 
  278     const QString &geometryAttribute,
 
  281     bool invertAxisOrientation )
 
  283   , mTypeNameBA( mTypeName.toUtf8() )
 
  284   , mTypeNamePtr( mTypeNameBA.constData() )
 
  285   , mTypeNameUTF8Len( strlen( mTypeNamePtr ) )
 
  287   , mGeometryAttribute( geometryAttribute )
 
  288   , mGeometryAttributeBA( geometryAttribute.toUtf8() )
 
  289   , mGeometryAttributePtr( mGeometryAttributeBA.constData() )
 
  290   , mGeometryAttributeUTF8Len( strlen( mGeometryAttributePtr ) )
 
  292   , mIsException( false )
 
  293   , mTruncatedResponse( false )
 
  295   , mFeatureTupleDepth( 0 )
 
  297   , mCurrentWKB( nullptr, 0 )
 
  298   , mBoundedByNullFound( false )
 
  300   , mCoorMode( Coordinate )
 
  302   , mAxisOrientationLogic( axisOrientationLogic )
 
  303   , mInvertAxisOrientationRequest( invertAxisOrientation )
 
  304   , mInvertAxisOrientation( invertAxisOrientation )
 
  305   , mNumberReturned( -1 )
 
  306   , mNumberMatched( -1 )
 
  307   , mFoundUnhandledGeometryElement( false )
 
  309   mThematicAttributes.clear();
 
  310   for ( 
int i = 0; i < fields.
size(); i++ )
 
  312     mThematicAttributes.insert( fields.
at( i ).
name(), qMakePair( i, fields.
at( i ) ) );
 
  317   const int index = mTypeName.indexOf( 
':' );
 
  318   if ( index != -1 && index < mTypeName.length() )
 
  320     mTypeName = mTypeName.mid( index + 1 );
 
  321     mTypeNameBA = mTypeName.toUtf8();
 
  322     mTypeNamePtr = mTypeNameBA.constData();
 
  323     mTypeNameUTF8Len = strlen( mTypeNamePtr );
 
  329 static QString stripNS( 
const QString &
string )
 
  331   const int index = 
string.indexOf( 
':' );
 
  332   if ( index != -1 && index < 
string.length() )
 
  334     return string.mid( index + 1 );
 
  341     const QMap< QString, QPair<QString, QString> > &mapFieldNameToSrcLayerNameFieldName,
 
  343     bool invertAxisOrientation )
 
  344   : mLayerProperties( layerProperties )
 
  345   , mTypeNameUTF8Len( 0 )
 
  347   , mGeometryAttributeUTF8Len( 0 )
 
  349   , mIsException( false )
 
  350   , mTruncatedResponse( false )
 
  352   , mFeatureTupleDepth( 0 )
 
  354   , mCurrentWKB( nullptr, 0 )
 
  355   , mBoundedByNullFound( false )
 
  357   , mCoorMode( Coordinate )
 
  359   , mAxisOrientationLogic( axisOrientationLogic )
 
  360   , mInvertAxisOrientationRequest( invertAxisOrientation )
 
  361   , mInvertAxisOrientation( invertAxisOrientation )
 
  362   , mNumberReturned( -1 )
 
  363   , mNumberMatched( -1 )
 
  364   , mFoundUnhandledGeometryElement( false )
 
  366   mThematicAttributes.clear();
 
  367   for ( 
int i = 0; i < fields.
size(); i++ )
 
  369     const QMap< QString, QPair<QString, QString> >::const_iterator att_it = mapFieldNameToSrcLayerNameFieldName.constFind( fields.
at( i ).
name() );
 
  370     if ( att_it != mapFieldNameToSrcLayerNameFieldName.constEnd() )
 
  372       if ( mLayerProperties.size() == 1 )
 
  373         mThematicAttributes.insert( att_it.value().second, qMakePair( i, fields.
at( i ) ) );
 
  375         mThematicAttributes.insert( stripNS( att_it.value().first ) + 
"|" + att_it.value().second, qMakePair( i, fields.
at( i ) ) );
 
  378   bool alreadyFoundGeometry = 
false;
 
  379   for ( 
int i = 0; i < mLayerProperties.size(); i++ )
 
  382     if ( !mLayerProperties[i].mGeometryAttribute.isEmpty() )
 
  384       if ( alreadyFoundGeometry )
 
  386         QgsDebugMsgLevel( QStringLiteral( 
"Will ignore geometry field %1 from typename %2" ).
 
  387                           arg( mLayerProperties[i].mGeometryAttribute, mLayerProperties[i].mName ), 2 );
 
  388         mLayerProperties[i].mGeometryAttribute.clear();
 
  390       alreadyFoundGeometry = 
true;
 
  392     mMapTypeNameToProperties.insert( stripNS( mLayerProperties[i].mName ), mLayerProperties[i] );
 
  395   if ( mLayerProperties.size() == 1 )
 
  397     mTypeName = mLayerProperties[0].mName;
 
  398     mGeometryAttribute = mLayerProperties[0].mGeometryAttribute;
 
  399     mGeometryAttributeBA = mGeometryAttribute.toUtf8();
 
  400     mGeometryAttributePtr = mGeometryAttributeBA.constData();
 
  401     mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
 
  402     const int index = mTypeName.indexOf( 
':' );
 
  403     if ( index != -1 && index < mTypeName.length() )
 
  405       mTypeName = mTypeName.mid( index + 1 );
 
  407     mTypeNameBA = mTypeName.toUtf8();
 
  408     mTypeNamePtr = mTypeNameBA.constData();
 
  409     mTypeNameUTF8Len = strlen( mTypeNamePtr );
 
  420   XML_ParserFree( mParser );
 
  423   const auto constMFeatureList = mFeatureList;
 
  426     delete featPair.first;
 
  429   delete mCurrentFeature;
 
  445   QByteArray data = pdata;
 
  450     QString strData = mCodec->toUnicode( pdata );
 
  451     data = strData.toUtf8();
 
  454   if ( XML_Parse( mParser, data, data.size(), atEnd ) == XML_STATUS_ERROR )
 
  456     const XML_Error errorCode = XML_GetErrorCode( mParser );
 
  457     if ( !mCodec && errorCode == XML_ERROR_UNKNOWN_ENCODING )
 
  461       QRegularExpression reEncoding( QStringLiteral( 
"<?xml.*encoding=['\"]([^'\"]*)['\"].*?>" ),
 
  462                                      QRegularExpression::CaseInsensitiveOption );
 
  463       QRegularExpressionMatch match = reEncoding.match( pdata );
 
  464       const QString encoding = match.hasMatch() ? match.captured( 1 ) : QString();
 
  465       mCodec = !encoding.isEmpty() ? QTextCodec::codecForName( encoding.toLatin1() ) : 
nullptr;
 
  469         XML_ParserFree( mParser );
 
  471         createParser( QByteArrayLiteral( 
"UTF-8" ) );
 
  477     errorMsg = QObject::tr( 
"Error: %1 on line %2, column %3" )
 
  478                .arg( XML_ErrorString( errorCode ) )
 
  479                .arg( XML_GetCurrentLineNumber( mParser ) )
 
  480                .arg( XML_GetCurrentColumnNumber( mParser ) );
 
  490   QVector<QgsGmlFeaturePtrGmlIdPair> ret = mFeatureList;
 
  491   mFeatureList.clear();
 
  495 #define LOCALNAME_EQUALS(string_constant) \ 
  496   ( localNameLen == static_cast<int>(strlen( string_constant )) && memcmp(pszLocalName, string_constant, localNameLen) == 0 ) 
  498 void QgsGmlStreamingParser::startElement( 
const XML_Char *el, 
const XML_Char **attr )
 
  500   const int elLen = 
static_cast<int>( strlen( el ) );
 
  502   const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
 
  503   const int nsLen = ( pszSep ) ? ( 
int )( pszSep - el ) : 0;
 
  504   const int localNameLen = ( pszSep ) ? ( 
int )( elLen - nsLen ) - 1 : elLen;
 
  505   const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
 
  509   if ( !mGMLNameSpaceURIPtr && pszSep )
 
  523   const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
 
  526   if ( parseMode == Geometry || parseMode == Coordinate || parseMode == PosList ||
 
  527        parseMode == MultiPoint || parseMode == MultiLine || parseMode == MultiPolygon )
 
  529     mGeometryString.append( 
"<", 1 );
 
  530     mGeometryString.append( pszLocalName, localNameLen );
 
  531     mGeometryString.append( 
" ", 1 );
 
  532     for ( 
const XML_Char **attrIter = attr; attrIter && *attrIter; attrIter += 2 )
 
  534       const size_t nAttrLen = strlen( attrIter[0] );
 
  537       if ( nAttrLen > GML32_NAMESPACE_LEN &&
 
  538            attrIter[0][GML32_NAMESPACE_LEN] == 
'?' &&
 
  541         mGeometryString.append( 
"gml:" );
 
  542         mGeometryString.append( attrIter[0] + GML32_NAMESPACE_LEN + 1 );
 
  544       else if ( nAttrLen > GML_NAMESPACE_LEN &&
 
  545                 attrIter[0][GML_NAMESPACE_LEN] == 
'?' &&
 
  546                 memcmp( attrIter[0], 
GML_NAMESPACE, GML_NAMESPACE_LEN ) == 0 )
 
  548         mGeometryString.append( 
"gml:" );
 
  549         mGeometryString.append( attrIter[0] + GML_NAMESPACE_LEN + 1 );
 
  553         mGeometryString.append( attrIter[0] );
 
  555       mGeometryString.append( 
"=\"", 2 );
 
  556       mGeometryString.append( attrIter[1] );
 
  557       mGeometryString.append( 
"\" ", 2 );
 
  560     mGeometryString.append( 
">", 1 );
 
  565     mParseModeStack.push( Coordinate );
 
  566     mCoorMode = QgsGmlStreamingParser::Coordinate;
 
  568     mCoordinateSeparator = readAttribute( QStringLiteral( 
"cs" ), attr );
 
  569     if ( mCoordinateSeparator.isEmpty() )
 
  571       mCoordinateSeparator = 
',';
 
  573     mTupleSeparator = readAttribute( QStringLiteral( 
"ts" ), attr );
 
  574     if ( mTupleSeparator.isEmpty() )
 
  576       mTupleSeparator = 
' ';
 
  582     mParseModeStack.push( QgsGmlStreamingParser::PosList );
 
  583     mCoorMode = QgsGmlStreamingParser::PosList;
 
  585     if ( elDimension == 0 )
 
  587       const QString srsDimension = readAttribute( QStringLiteral( 
"srsDimension" ), attr );
 
  589       const int dimension = srsDimension.toInt( &ok );
 
  592         elDimension = dimension;
 
  596   else if ( ( parseMode == Feature || parseMode == FeatureTuple ) &&
 
  598             localNameLen == 
static_cast<int>( mGeometryAttributeUTF8Len ) &&
 
  599             memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
 
  601     mParseModeStack.push( QgsGmlStreamingParser::Geometry );
 
  602     mFoundUnhandledGeometryElement = 
false;
 
  603     mGeometryString.clear();
 
  608     mParseModeStack.push( QgsGmlStreamingParser::BoundingBox );
 
  610     mBoundedByNullFound = 
false;
 
  612   else if ( parseMode == BoundingBox &&
 
  615     mParseModeStack.push( QgsGmlStreamingParser::Null );
 
  616     mBoundedByNullFound = 
true;
 
  618   else if ( parseMode == BoundingBox &&
 
  622     mParseModeStack.push( QgsGmlStreamingParser::Envelope );
 
  624   else if ( parseMode == Envelope &&
 
  627     mParseModeStack.push( QgsGmlStreamingParser::LowerCorner );
 
  630   else if ( parseMode == Envelope &&
 
  633     mParseModeStack.push( QgsGmlStreamingParser::UpperCorner );
 
  636   else if ( parseMode == None && !mTypeNamePtr &&
 
  639     Q_ASSERT( !mCurrentFeature );
 
  640     mCurrentFeature = 
new QgsFeature( mFeatureCount );
 
  642     const QgsAttributes attributes( mThematicAttributes.size() ); 
 
  644     mParseModeStack.push( QgsGmlStreamingParser::Tuple );
 
  645     mCurrentFeatureId.clear();
 
  647   else if ( parseMode == Tuple )
 
  649     const QString currentTypename( QString::fromUtf8( pszLocalName, localNameLen ) );
 
  650     const QMap< QString, LayerProperties >::const_iterator iter = mMapTypeNameToProperties.constFind( currentTypename );
 
  651     if ( iter != mMapTypeNameToProperties.constEnd() )
 
  653       mFeatureTupleDepth = mParseDepth;
 
  654       mCurrentTypename = currentTypename;
 
  655       mGeometryAttribute.clear();
 
  656       if ( mCurrentWKB.
size() == 0 )
 
  658         mGeometryAttribute = iter.value().mGeometryAttribute;
 
  660       mGeometryAttributeBA = mGeometryAttribute.toUtf8();
 
  661       mGeometryAttributePtr = mGeometryAttributeBA.constData();
 
  662       mGeometryAttributeUTF8Len = strlen( mGeometryAttributePtr );
 
  663       mParseModeStack.push( QgsGmlStreamingParser::FeatureTuple );
 
  665       if ( mGMLNameSpaceURI.isEmpty() )
 
  684         id = readAttribute( mGMLNameSpaceURI + 
NS_SEPARATOR + 
"id", attr );
 
  685       if ( !mCurrentFeatureId.isEmpty() )
 
  686         mCurrentFeatureId += 
'|';
 
  687       mCurrentFeatureId += id;
 
  690   else if ( parseMode == None &&
 
  691             localNameLen == 
static_cast<int>( mTypeNameUTF8Len ) &&
 
  692             memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 )
 
  694     Q_ASSERT( !mCurrentFeature );
 
  695     mCurrentFeature = 
new QgsFeature( mFeatureCount );
 
  697     const QgsAttributes attributes( mThematicAttributes.size() ); 
 
  699     mParseModeStack.push( QgsGmlStreamingParser::Feature );
 
  700     mCurrentFeatureId = readAttribute( QStringLiteral( 
"fid" ), attr );
 
  701     if ( mCurrentFeatureId.isEmpty() )
 
  706       if ( mGMLNameSpaceURI.isEmpty() )
 
  709         if ( !mCurrentFeatureId.isEmpty() )
 
  717           if ( !mCurrentFeatureId.isEmpty() )
 
  725         mCurrentFeatureId = readAttribute( mGMLNameSpaceURI + 
NS_SEPARATOR + 
"id", attr );
 
  729   else if ( parseMode == BoundingBox && isGMLNS && 
LOCALNAME_EQUALS( 
"Box" ) )
 
  742             localNameLen == 
static_cast<int>( strlen( 
"Polygon" ) ) && memcmp( pszLocalName, 
"Polygon", localNameLen ) == 0 )
 
  745     mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
 
  750     mParseModeStack.push( QgsGmlStreamingParser::MultiPoint );
 
  752     mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
 
  757     mParseModeStack.push( QgsGmlStreamingParser::MultiLine );
 
  759     mCurrentWKBFragments.push_back( QList<QgsWkbPtr>() );
 
  764     mParseModeStack.push( QgsGmlStreamingParser::MultiPolygon );
 
  766   else if ( parseMode == FeatureTuple )
 
  768     const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
 
  769     if ( mThematicAttributes.contains( mCurrentTypename + 
'|' + localName ) )
 
  771       mParseModeStack.push( QgsGmlStreamingParser::AttributeTuple );
 
  772       mAttributeName = mCurrentTypename + 
'|' + localName;
 
  776   else if ( parseMode == Feature )
 
  778     const QString localName( QString::fromUtf8( pszLocalName, localNameLen ) );
 
  779     if ( mThematicAttributes.contains( localName ) )
 
  781       mParseModeStack.push( QgsGmlStreamingParser::Attribute );
 
  782       mAttributeName = localName;
 
  789       if ( localName.compare( QLatin1String( 
"attribute" ), Qt::CaseInsensitive ) == 0 )
 
  791         const QString name = readAttribute( QStringLiteral( 
"name" ), attr );
 
  792         if ( mThematicAttributes.contains( name ) )
 
  794           const QString value = readAttribute( QStringLiteral( 
"value" ), attr );
 
  795           setAttribute( name, value );
 
  802     QString 
numberReturned = readAttribute( QStringLiteral( 
"numberReturned" ), attr ); 
 
  804       numberReturned = readAttribute( QStringLiteral( 
"numberOfFeatures" ), attr ); 
 
  808       mNumberReturned = -1;
 
  810     const QString 
numberMatched = readAttribute( QStringLiteral( 
"numberMatched" ), attr ); 
 
  818     mParseModeStack.push( QgsGmlStreamingParser::ExceptionReport );
 
  823     mParseModeStack.push( QgsGmlStreamingParser::ExceptionText );
 
  828     mTruncatedResponse = 
true;
 
  830   else if ( !mGeometryString.empty() &&
 
  846     mFoundUnhandledGeometryElement = 
true;
 
  849   if ( !mGeometryString.empty() )
 
  852   if ( elDimension == 0 && isGeom )
 
  856     const QString srsDimension = readAttribute( QStringLiteral( 
"srsDimension" ), attr );
 
  858     const int dimension = srsDimension.toInt( &ok );
 
  861       elDimension = dimension;
 
  865   if ( elDimension != 0 || mDimensionStack.isEmpty() )
 
  867     mDimensionStack.push( elDimension );
 
  871     mDimensionStack.push( mDimensionStack.back() );
 
  874   if ( mEpsg == 0 && isGeom )
 
  876     if ( readEpsgFromAttribute( mEpsg, attr ) != 0 )
 
  878       QgsDebugMsg( QStringLiteral( 
"error, could not get epsg id" ) );
 
  889 void QgsGmlStreamingParser::endElement( 
const XML_Char *el )
 
  893   const int elLen = 
static_cast<int>( strlen( el ) );
 
  895   const char *pszLocalName = ( pszSep ) ? pszSep + 1 : el;
 
  896   const int nsLen = ( pszSep ) ? ( 
int )( pszSep - el ) : 0;
 
  897   const int localNameLen = ( pszSep ) ? ( 
int )( elLen - nsLen ) - 1 : elLen;
 
  898   const ParseMode parseMode( mParseModeStack.isEmpty() ? None : mParseModeStack.top() );
 
  900   const int lastDimension = mDimensionStack.isEmpty() ? 0 : mDimensionStack.pop();
 
  902   const bool isGMLNS = ( nsLen == mGMLNameSpaceURI.size() && mGMLNameSpaceURIPtr && memcmp( el, mGMLNameSpaceURIPtr, nsLen ) == 0 );
 
  904   if ( parseMode == Coordinate && isGMLNS && 
LOCALNAME_EQUALS( 
"coordinates" ) )
 
  906     mParseModeStack.pop();
 
  908   else if ( parseMode == PosList && isGMLNS &&
 
  911     mDimension = lastDimension;
 
  912     mParseModeStack.pop();
 
  914   else if ( parseMode == AttributeTuple &&
 
  915             mCurrentTypename + 
'|' + QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName ) 
 
  917     mParseModeStack.pop();
 
  919     setAttribute( mAttributeName, mStringCash );
 
  921   else if ( parseMode == Attribute && QString::fromUtf8( pszLocalName, localNameLen ) == mAttributeName ) 
 
  923     mParseModeStack.pop();
 
  925     setAttribute( mAttributeName, mStringCash );
 
  927   else if ( parseMode == Geometry &&
 
  928             localNameLen == 
static_cast<int>( mGeometryAttributeUTF8Len ) &&
 
  929             memcmp( pszLocalName, mGeometryAttributePtr, localNameLen ) == 0 )
 
  931     mParseModeStack.pop();
 
  932     if ( mFoundUnhandledGeometryElement )
 
  938         const int wkbSize = OGR_G_WkbSize( hGeom.get() );
 
  939         unsigned char *pabyBuffer = 
new unsigned char[ wkbSize ];
 
  940         OGR_G_ExportToIsoWkb( hGeom.get(), wkbNDR, pabyBuffer );
 
  942         g.
fromWkb( pabyBuffer, wkbSize );
 
  943         if ( mInvertAxisOrientation )
 
  945           g.
transform( QTransform( 0, 1, 1, 0, 0, 0 ) );
 
  947         Q_ASSERT( mCurrentFeature );
 
  951     mGeometryString.clear();
 
  953   else if ( parseMode == BoundingBox && isGMLNS && 
LOCALNAME_EQUALS( 
"boundedBy" ) )
 
  956     if ( mCurrentExtent.
isNull() &&
 
  957          !mBoundedByNullFound &&
 
  958          !createBBoxFromCoordinateString( mCurrentExtent, mStringCash ) )
 
  960       QgsDebugMsg( QStringLiteral( 
"creation of bounding box failed" ) );
 
  962     if ( !mCurrentExtent.
isNull() && mLayerExtent.
isNull() &&
 
  963          !mCurrentFeature && mFeatureCount == 0 )
 
  965       mLayerExtent = mCurrentExtent;
 
  969     mParseModeStack.pop();
 
  973     mParseModeStack.pop();
 
  975   else if ( parseMode == Envelope && isGMLNS && 
LOCALNAME_EQUALS( 
"Envelope" ) )
 
  977     mParseModeStack.pop();
 
  979   else if ( parseMode == LowerCorner && isGMLNS && 
LOCALNAME_EQUALS( 
"lowerCorner" ) )
 
  981     QList<QgsPointXY> points;
 
  982     pointsFromPosListString( points, mStringCash, 2 );
 
  983     if ( points.size() == 1 )
 
  988     mParseModeStack.pop();
 
  990   else if ( parseMode == UpperCorner && isGMLNS && 
LOCALNAME_EQUALS( 
"upperCorner" ) )
 
  992     QList<QgsPointXY> points;
 
  993     pointsFromPosListString( points, mStringCash, 2 );
 
  994     if ( points.size() == 1 )
 
  999     mParseModeStack.pop();
 
 1001   else if ( parseMode == FeatureTuple && mParseDepth == mFeatureTupleDepth )
 
 1003     mParseModeStack.pop();
 
 1004     mFeatureTupleDepth = 0;
 
 1006   else if ( ( parseMode == Tuple && !mTypeNamePtr &&
 
 1008             ( parseMode == Feature &&
 
 1009               localNameLen == 
static_cast<int>( mTypeNameUTF8Len ) &&
 
 1010               memcmp( pszLocalName, mTypeNamePtr, mTypeNameUTF8Len ) == 0 ) )
 
 1012     Q_ASSERT( mCurrentFeature );
 
 1015       if ( mCurrentWKB.
size() > 0 )
 
 1022       else if ( !mCurrentExtent.
isEmpty() )
 
 1031     mCurrentFeature = 
nullptr;
 
 1033     mParseModeStack.pop();
 
 1037     QList<QgsPointXY> pointList;
 
 1038     if ( pointsFromString( pointList, mStringCash ) != 0 )
 
 1043     if ( pointList.isEmpty() )
 
 1046     if ( parseMode == QgsGmlStreamingParser::Geometry )
 
 1049       if ( getPointWKB( mCurrentWKB, *( pointList.constBegin() ) ) != 0 )
 
 1062       if ( getPointWKB( wkbPtr, *( pointList.constBegin() ) ) != 0 )
 
 1066       if ( !mCurrentWKBFragments.isEmpty() )
 
 1068         mCurrentWKBFragments.last().push_back( wkbPtr );
 
 1072         QgsDebugMsg( QStringLiteral( 
"No wkb fragments" ) );
 
 1081     QList<QgsPointXY> pointList;
 
 1082     if ( pointsFromString( pointList, mStringCash ) != 0 )
 
 1086     if ( parseMode == QgsGmlStreamingParser::Geometry )
 
 1088       if ( getLineWKB( mCurrentWKB, pointList ) != 0 )
 
 1101       if ( getLineWKB( wkbPtr, pointList ) != 0 )
 
 1105       if ( !mCurrentWKBFragments.isEmpty() )
 
 1107         mCurrentWKBFragments.last().push_back( wkbPtr );
 
 1111         QgsDebugMsg( QStringLiteral( 
"no wkb fragments" ) );
 
 1116   else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) &&
 
 1119     QList<QgsPointXY> pointList;
 
 1120     if ( pointsFromString( pointList, mStringCash ) != 0 )
 
 1126     if ( getRingWKB( wkbPtr, pointList ) != 0 )
 
 1131     if ( !mCurrentWKBFragments.isEmpty() )
 
 1133       mCurrentWKBFragments.last().push_back( wkbPtr );
 
 1138       QgsDebugMsg( QStringLiteral( 
"no wkb fragments" ) );
 
 1141   else if ( ( parseMode == Geometry || parseMode == MultiPolygon ) && isGMLNS &&
 
 1149     if ( parseMode == Geometry )
 
 1151       createPolygonFromFragments();
 
 1154   else if ( parseMode == MultiPoint &&  isGMLNS &&
 
 1158     mParseModeStack.pop();
 
 1159     createMultiPointFromFragments();
 
 1161   else if ( parseMode == MultiLine && isGMLNS &&
 
 1165     mParseModeStack.pop();
 
 1166     createMultiLineFromFragments();
 
 1168   else if ( parseMode == MultiPolygon && isGMLNS &&
 
 1172     mParseModeStack.pop();
 
 1173     createMultiPolygonFromFragments();
 
 1177     mParseModeStack.pop();
 
 1179   else if ( parseMode == ExceptionText && 
LOCALNAME_EQUALS( 
"ExceptionText" ) )
 
 1181     mExceptionText = mStringCash;
 
 1182     mParseModeStack.pop();
 
 1185   if ( !mGeometryString.empty() )
 
 1187     mGeometryString.append( 
"</", 2 );
 
 1188     mGeometryString.append( pszLocalName, localNameLen );
 
 1189     mGeometryString.append( 
">", 1 );
 
 1194 void QgsGmlStreamingParser::characters( 
const XML_Char *chars, 
int len )
 
 1197   if ( mParseModeStack.isEmpty() )
 
 1202   if ( !mGeometryString.empty() )
 
 1204     mGeometryString.append( chars, len );
 
 1207   const QgsGmlStreamingParser::ParseMode parseMode = mParseModeStack.top();
 
 1208   if ( parseMode == QgsGmlStreamingParser::Attribute ||
 
 1209        parseMode == QgsGmlStreamingParser::AttributeTuple ||
 
 1210        parseMode == QgsGmlStreamingParser::Coordinate ||
 
 1211        parseMode == QgsGmlStreamingParser::PosList ||
 
 1212        parseMode == QgsGmlStreamingParser::LowerCorner ||
 
 1213        parseMode == QgsGmlStreamingParser::UpperCorner ||
 
 1214        parseMode == QgsGmlStreamingParser::ExceptionText )
 
 1216     mStringCash.append( QString::fromUtf8( chars, len ) );
 
 1220 void QgsGmlStreamingParser::setAttribute( 
const QString &name, 
const QString &value )
 
 1223   const QMap<QString, QPair<int, QgsField> >::const_iterator att_it = mThematicAttributes.constFind( name );
 
 1224   bool conversionOk = 
true;
 
 1225   if ( att_it != mThematicAttributes.constEnd() )
 
 1228     switch ( att_it.value().second.type() )
 
 1230       case QVariant::Double:
 
 1231         var = QVariant( value.toDouble( &conversionOk ) );
 
 1234         var = QVariant( value.toInt( &conversionOk ) );
 
 1236       case QVariant::LongLong:
 
 1237         var = QVariant( value.toLongLong( &conversionOk ) );
 
 1239       case QVariant::DateTime:
 
 1240         var = QVariant( QDateTime::fromString( value, Qt::ISODate ) );
 
 1243         var = QVariant( value );
 
 1246     if ( ! conversionOk )  
 
 1250     Q_ASSERT( mCurrentFeature );
 
 1251     mCurrentFeature->
setAttribute( att_it.value().first, var );
 
 1255 int QgsGmlStreamingParser::readEpsgFromAttribute( 
int &epsgNr, 
const XML_Char **attr )
 
 1260     if ( strcmp( attr[i], 
"srsName" ) == 0 )
 
 1262       const QString epsgString( attr[i + 1] );
 
 1263       QString epsgNrString;
 
 1264       bool bIsUrn = 
false;
 
 1265       if ( epsgString.startsWith( QLatin1String( 
"http://www.opengis.net/gml/srs/" ) ) ) 
 
 1267         epsgNrString = epsgString.section( 
'#', 1, 1 );
 
 1270       else if ( epsgString.startsWith( QLatin1String( 
"urn:ogc:def:crs:EPSG:" ) ) ||
 
 1271                 epsgString.startsWith( QLatin1String( 
"urn:x-ogc:def:crs:EPSG:" ) ) )
 
 1274         epsgNrString = epsgString.split( 
':' ).last();
 
 1276       else if ( epsgString.startsWith( QLatin1String( 
"http://www.opengis.net/def/crs/EPSG/" ) ) ) 
 
 1279         epsgNrString = epsgString.split( 
'/' ).last();
 
 1283         epsgNrString = epsgString.section( 
':', 1, 1 );
 
 1286       const int eNr = epsgNrString.toInt( &conversionOk );
 
 1287       if ( !conversionOk )
 
 1292       mSrsName = epsgString;
 
 1300           mInvertAxisOrientation = !mInvertAxisOrientationRequest;
 
 1311 QString QgsGmlStreamingParser::readAttribute( 
const QString &attributeName, 
const XML_Char **attr )
 const 
 1316     if ( attributeName.compare( attr[i] ) == 0 )
 
 1318       return QString::fromUtf8( attr[i + 1] );
 
 1325 bool QgsGmlStreamingParser::createBBoxFromCoordinateString( 
QgsRectangle &r, 
const QString &coordString )
 const 
 1327   QList<QgsPointXY> points;
 
 1328   if ( pointsFromCoordinateString( points, coordString ) != 0 )
 
 1333   if ( points.size() < 2 )
 
 1338   r.
set( points[0], points[1] );
 
 1343 int QgsGmlStreamingParser::pointsFromCoordinateString( QList<QgsPointXY> &points, 
const QString &coordString )
 const 
 1346 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
 1347   QStringList tuples = coordString.split( mTupleSeparator, QString::SkipEmptyParts );
 
 1349   const QStringList tuples = coordString.split( mTupleSeparator, Qt::SkipEmptyParts );
 
 1351   QStringList tuples_coordinates;
 
 1353   bool conversionSuccess;
 
 1355   QStringList::const_iterator tupleIterator;
 
 1356   for ( tupleIterator = tuples.constBegin(); tupleIterator != tuples.constEnd(); ++tupleIterator )
 
 1358 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
 1359     tuples_coordinates = tupleIterator->split( mCoordinateSeparator, QString::SkipEmptyParts );
 
 1361     tuples_coordinates = tupleIterator->split( mCoordinateSeparator, Qt::SkipEmptyParts );
 
 1363     if ( tuples_coordinates.size() < 2 )
 
 1367     x = tuples_coordinates.at( 0 ).toDouble( &conversionSuccess );
 
 1368     if ( !conversionSuccess )
 
 1372     y = tuples_coordinates.at( 1 ).toDouble( &conversionSuccess );
 
 1373     if ( !conversionSuccess )
 
 1382 int QgsGmlStreamingParser::pointsFromPosListString( QList<QgsPointXY> &points, 
const QString &coordString, 
int dimension )
 const 
 1385 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 
 1386   QStringList coordinates = coordString.split( 
' ', QString::SkipEmptyParts );
 
 1388   const QStringList coordinates = coordString.split( 
' ', Qt::SkipEmptyParts );
 
 1391   if ( coordinates.size() % dimension != 0 )
 
 1393     QgsDebugMsg( QStringLiteral( 
"Wrong number of coordinates" ) );
 
 1396   const int ncoor = coordinates.size() / dimension;
 
 1397   for ( 
int i = 0; i < ncoor; i++ )
 
 1399     bool conversionSuccess;
 
 1400     const double x = coordinates.value( i * dimension ).toDouble( &conversionSuccess );
 
 1401     if ( !conversionSuccess )
 
 1405     const double y = coordinates.value( i * dimension + 1 ).toDouble( &conversionSuccess );
 
 1406     if ( !conversionSuccess )
 
 1415 int QgsGmlStreamingParser::pointsFromString( QList<QgsPointXY> &points, 
const QString &coordString )
 const 
 1417   if ( mCoorMode == QgsGmlStreamingParser::Coordinate )
 
 1419     return pointsFromCoordinateString( points, coordString );
 
 1421   else if ( mCoorMode == QgsGmlStreamingParser::PosList )
 
 1423     return pointsFromPosListString( points, coordString, mDimension ? mDimension : 2 );
 
 1428 int QgsGmlStreamingParser::getPointWKB( 
QgsWkbPtr &wkbPtr, 
const QgsPointXY &point )
 const 
 1430   const int wkbSize = 1 + 
sizeof( int ) + 2 * 
sizeof( 
double );
 
 1431   wkbPtr = 
QgsWkbPtr( 
new unsigned char[wkbSize], wkbSize );
 
 1439 int QgsGmlStreamingParser::getLineWKB( 
QgsWkbPtr &wkbPtr, 
const QList<QgsPointXY> &lineCoordinates )
 const 
 1441   const int wkbSize = 1 + 2 * 
sizeof( int ) + lineCoordinates.size() * 2 * 
sizeof( double );
 
 1442   wkbPtr = 
QgsWkbPtr( 
new unsigned char[wkbSize], wkbSize );
 
 1448   QList<QgsPointXY>::const_iterator iter;
 
 1449   for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
 
 1451     fillPtr << iter->x() << iter->y();
 
 1457 int QgsGmlStreamingParser::getRingWKB( 
QgsWkbPtr &wkbPtr, 
const QList<QgsPointXY> &ringCoordinates )
 const 
 1459   const int wkbSize = 
sizeof( int ) + ringCoordinates.size() * 2 * 
sizeof( double );
 
 1460   wkbPtr = 
QgsWkbPtr( 
new unsigned char[wkbSize], wkbSize );
 
 1464   fillPtr << ringCoordinates.size();
 
 1466   QList<QgsPointXY>::const_iterator iter;
 
 1467   for ( iter = ringCoordinates.constBegin(); iter != ringCoordinates.constEnd(); ++iter )
 
 1469     fillPtr << iter->x() << iter->y();
 
 1475 int QgsGmlStreamingParser::createMultiLineFromFragments()
 
 1477   const int size = 1 + 2 * 
sizeof( int ) + totalWKBFragmentSize();
 
 1478   mCurrentWKB = 
QgsWkbPtr( 
new unsigned char[size], size );
 
 1485   QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
 
 1486   for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
 
 1488     memcpy( wkbPtr, *wkbIt, wkbIt->size() );
 
 1489     wkbPtr += wkbIt->
size();
 
 1493   mCurrentWKBFragments.clear();
 
 1498 int QgsGmlStreamingParser::createMultiPointFromFragments()
 
 1500   const int size = 1 + 2 * 
sizeof( int ) + totalWKBFragmentSize();
 
 1501   mCurrentWKB = 
QgsWkbPtr( 
new unsigned char[size], size );
 
 1506   QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
 
 1507   for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
 
 1509     memcpy( wkbPtr, *wkbIt, wkbIt->size() );
 
 1510     wkbPtr += wkbIt->
size();
 
 1514   mCurrentWKBFragments.clear();
 
 1520 int QgsGmlStreamingParser::createPolygonFromFragments()
 
 1522   const int size = 1 + 2 * 
sizeof( int ) + totalWKBFragmentSize();
 
 1523   mCurrentWKB = 
QgsWkbPtr( 
new unsigned char[size], size );
 
 1528   QList<QgsWkbPtr>::const_iterator wkbIt = mCurrentWKBFragments.constBegin()->constBegin();
 
 1529   for ( ; wkbIt != mCurrentWKBFragments.constBegin()->constEnd(); ++wkbIt )
 
 1531     memcpy( wkbPtr, *wkbIt, wkbIt->size() );
 
 1532     wkbPtr += wkbIt->
size();
 
 1536   mCurrentWKBFragments.clear();
 
 1541 int QgsGmlStreamingParser::createMultiPolygonFromFragments()
 
 1544   size += 1 + 2 * 
sizeof( int );
 
 1545   size += totalWKBFragmentSize();
 
 1546   size += mCurrentWKBFragments.size() * ( 1 + 2 * 
sizeof( int ) ); 
 
 1548   mCurrentWKB = 
QgsWkbPtr( 
new unsigned char[size], size );
 
 1554   QList< QList<QgsWkbPtr> >::const_iterator outerWkbIt = mCurrentWKBFragments.constBegin();
 
 1556   for ( ; outerWkbIt != mCurrentWKBFragments.constEnd(); ++outerWkbIt )
 
 1561     QList<QgsWkbPtr>::const_iterator innerWkbIt = outerWkbIt->constBegin();
 
 1562     for ( ; innerWkbIt != outerWkbIt->constEnd(); ++innerWkbIt )
 
 1564       memcpy( wkbPtr, *innerWkbIt, innerWkbIt->size() );
 
 1565       wkbPtr += innerWkbIt->
size();
 
 1566       delete[] *innerWkbIt;
 
 1570   mCurrentWKBFragments.clear();
 
 1575 int QgsGmlStreamingParser::totalWKBFragmentSize()
 const 
 1578   const auto constMCurrentWKBFragments = mCurrentWKBFragments;
 
 1579   for ( 
const QList<QgsWkbPtr> &list : constMCurrentWKBFragments )
 
 1581     const auto constList = list;
 
 1590 void QgsGmlStreamingParser::createParser( 
const QByteArray &encoding )
 
 1592   Q_ASSERT( !mParser );
 
 1594   mParser = XML_ParserCreateNS( encoding.isEmpty() ? 
nullptr : encoding.data(), 
NS_SEPARATOR );
 
 1595   XML_SetUserData( mParser, 
this );
 
 1596   XML_SetElementHandler( mParser, QgsGmlStreamingParser::start, QgsGmlStreamingParser::end );
 
 1597   XML_SetCharacterDataHandler( mParser, QgsGmlStreamingParser::chars );
 
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static endian_t endian()
Returns whether this machine uses big or little endian.
This class represents a coordinate reference system (CRS).
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool hasAxisInverted() const
Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assigns a field map with the feature to allow attribute access by attribute name.
void setValid(bool validity)
Sets the validity of the feature.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Container of fields for a vector layer.
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
A geometry is the spatial representation of a feature.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QgsWkbTypes::Type wkbType() const
Returns the geometry type.
QPair< QgsFeature *, QString > QgsGmlFeaturePtrGmlIdPair
int numberReturned() const
Returns WFS 2.0 "numberReturned" or WFS 1.1 "numberOfFeatures" attribute, or -1 if invalid/not found.
AxisOrientationLogic
Axis orientation logic.
@ Honour_EPSG
Honour EPSG axis order.
@ Honour_EPSG_if_urn
Honour EPSG axis order only if srsName is of the form urn:ogc:def:crs:EPSG:
int numberMatched() const
Returns WFS 2.0 "numberMatched" attribute, or -1 if invalid/not found.
QgsGmlStreamingParser(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields, AxisOrientationLogic axisOrientationLogic=Honour_EPSG_if_urn, bool invertAxisOrientation=false)
Constructor.
bool processData(const QByteArray &data, bool atEnd, QString &errorMsg)
Process a new chunk of data.
int getEPSGCode() const
Returns the EPSG code, or 0 if unknown.
QVector< QgsGmlFeaturePtrGmlIdPair > getAndStealReadyFeatures()
Returns the list of features that have been completely parsed.
int getFeatures(const QString &uri, QgsWkbTypes::Type *wkbType, QgsRectangle *extent=nullptr, const QString &userName=QString(), const QString &password=QString(), const QString &authcfg=QString())
Does the Http GET request to the wfs server.
void totalStepsUpdate(int totalSteps)
void dataReadProgress(int progress)
QgsGml(const QString &typeName, const QString &geometryAttribute, const QgsFields &fields)
QgsCoordinateReferenceSystem crs() const
Returns features spatial reference system.
void dataProgressAndSteps(int progress, int totalSteps)
Also emit signal with progress and totalSteps together (this is better for the status message)
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).
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
A class to represent a 2D point.
A rectangle specified with double values.
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
void set(const QgsPointXY &p1, const QgsPointXY &p2, bool normalize=true)
Sets the rectangle from two QgsPoints.
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
bool isEmpty() const
Returns true if the rectangle is empty.
Handles storage of information regarding WKB types and their properties.
Type
The WKB type describes the number of dimensions a geometry has.
std::unique_ptr< std::remove_pointer< OGRGeometryH >::type, OGRGeometryDeleter > ogr_geometry_unique_ptr
Scoped OGR geometry.
#define LOCALNAME_EQUALS(string_constant)
#define QgsDebugMsgLevel(str, level)
#define QgsSetRequestInitiatorClass(request, _class)
const QgsCoordinateReferenceSystem & crs