24 #include "qgsogrprovider.h" 
   42 #include <cpl_error.h> 
   43 #include <QJsonDocument> 
   46 #include <QTextStream> 
   47 #include <QDataStream> 
   48 #include <QRegularExpression> 
   50 #include "ogr_srs_api.h" 
   55   OGR_DS_Destroy( source );
 
   61   OGR_G_DestroyGeometry( geometry );
 
   66   OGR_Fld_Destroy( definition );
 
   71   OGR_F_Destroy( feature );
 
   88   CPLPushErrorHandler( CPLQuietErrorHandler );
 
   89   GDALDeleteDataset( driver, path.toUtf8().constData() );
 
  101   GDALDestroyWarpOptions( options );
 
  106   if ( !value || OGR_RawField_IsUnset( value ) || OGR_RawField_IsNull( value ) )
 
  112       return value->Integer;
 
  115       return value->Integer64;
 
  122       return QString::fromUtf8( value->String );
 
  125       return QDate( value->Date.Year, value->Date.Month, value->Date.Day );
 
  129       float secondsPart = 0;
 
  130       float millisecondPart = std::modf( value->Date.Second, &secondsPart );
 
  131       return QTime( value->Date.Hour, value->Date.Minute, 
static_cast< int >( secondsPart ), 
static_cast< int >( 1000 * millisecondPart ) );
 
  136       float secondsPart = 0;
 
  137       float millisecondPart = std::modf( value->Date.Second, &secondsPart );
 
  138       return QDateTime( QDate( value->Date.Year, value->Date.Month, value->Date.Day ),
 
  139                         QTime( value->Date.Hour, value->Date.Minute, 
static_cast< int >( secondsPart ), 
static_cast< int >( 1000 * millisecondPart ) ) );
 
  144       Q_ASSERT_X( 
false, 
"QgsOgrUtils::OGRFieldtoVariant", 
"OFTBinary type not supported" );
 
  150       res.reserve( value->IntegerList.nCount );
 
  151       for ( 
int i = 0; i < value->IntegerList.nCount; ++i )
 
  152         res << value->IntegerList.paList[ i ];
 
  156     case OFTInteger64List:
 
  159       res.reserve( value->Integer64List.nCount );
 
  160       for ( 
int i = 0; i < value->Integer64List.nCount; ++i )
 
  161         res << value->Integer64List.paList[ i ];
 
  168       res.reserve( value->RealList.nCount );
 
  169       for ( 
int i = 0; i < value->RealList.nCount; ++i )
 
  170         res << value->RealList.paList[ i ];
 
  175     case OFTWideStringList:
 
  178       res.reserve( value->StringList.nCount );
 
  179       for ( 
int i = 0; i < value->StringList.nCount; ++i )
 
  180         res << QString::fromUtf8( value->StringList.paList[ i ] );
 
  189   std::unique_ptr< OGRField > res = std::make_unique< OGRField >();
 
  191   switch ( value.type() )
 
  193     case QVariant::Invalid:
 
  194       OGR_RawField_SetUnset( res.get() );
 
  197       res->Integer = value.toBool() ? 1 : 0;
 
  200       res->Integer = value.toInt();
 
  202     case QVariant::LongLong:
 
  203       res->Integer64 = value.toLongLong();
 
  205     case QVariant::Double:
 
  206       res->Real = value.toDouble();
 
  209     case QVariant::String:
 
  210       res->String = CPLStrdup( value.toString().toUtf8().constData() );
 
  214       const QDate date = value.toDate();
 
  215       res->Date.Day = date.day();
 
  216       res->Date.Month = date.month();
 
  217       res->Date.Year = date.year();
 
  218       res->Date.TZFlag = 0;
 
  223       const QTime time = value.toTime();
 
  224       res->Date.Hour = time.hour();
 
  225       res->Date.Minute = time.minute();
 
  226       res->Date.Second = time.second() + 
static_cast< double >( time.msec() ) / 1000;
 
  227       res->Date.TZFlag = 0;
 
  230     case QVariant::DateTime:
 
  232       const QDateTime dateTime = value.toDateTime();
 
  233       res->Date.Day = dateTime.date().day();
 
  234       res->Date.Month = dateTime.date().month();
 
  235       res->Date.Year = dateTime.date().year();
 
  236       res->Date.Hour = dateTime.time().hour();
 
  237       res->Date.Minute = dateTime.time().minute();
 
  238       res->Date.Second = dateTime.time().second() + 
static_cast< double >( dateTime.time().msec() ) / 1000;
 
  239       res->Date.TZFlag = 0;
 
  244       QgsDebugMsg( 
"Unhandled variant type in variantToOGRField" );
 
  245       OGR_RawField_SetUnset( res.get() );
 
  261   feature.
setId( OGR_F_GetFID( ogrFet ) );
 
  264   if ( !readOgrFeatureGeometry( ogrFet, feature ) )
 
  269   if ( !readOgrFeatureAttributes( ogrFet, fields, feature, encoding ) )
 
  284   int fieldCount = OGR_F_GetFieldCount( ogrFet );
 
  285   for ( 
int i = 0; i < fieldCount; ++i )
 
  287     OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, i );
 
  294     QString name = encoding ? encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) ) : QString::fromUtf8( OGR_Fld_GetNameRef( fldDef ) );
 
  295     QVariant::Type varType;
 
  296     switch ( OGR_Fld_GetType( fldDef ) )
 
  299         if ( OGR_Fld_GetSubType( fldDef ) == OFSTBoolean )
 
  300           varType = QVariant::Bool;
 
  302           varType = QVariant::Int;
 
  305         varType = QVariant::LongLong;
 
  308         varType = QVariant::Double;
 
  311         varType = QVariant::Date;
 
  314         varType = QVariant::Time;
 
  317         varType = QVariant::DateTime;
 
  320         if ( OGR_Fld_GetSubType( fldDef ) == OFSTJSON )
 
  321           varType = QVariant::Map;
 
  323           varType = QVariant::String;
 
  326         varType = QVariant::String; 
 
  336   if ( attIndex < 0 || attIndex >= fields.
count() )
 
  344   return getOgrFeatureAttribute( ogrFet, 
field, attIndex, encoding, ok );
 
  349   if ( !ogrFet || attIndex < 0 )
 
  356   OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attIndex );
 
  363     QgsDebugMsg( QStringLiteral( 
"ogrFet->GetFieldDefnRef(attindex) returns NULL" ) );
 
  372   if ( OGR_F_IsFieldSetAndNotNull( ogrFet, attIndex ) )
 
  376       case QVariant::String:
 
  379           value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
 
  381           value = QVariant( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
 
  386         if ( value.isNull() )
 
  387           value = QVariant( QStringLiteral( 
"" ) ); 
 
  393         value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) );
 
  396         value = QVariant( 
bool( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) ) );
 
  398       case QVariant::LongLong:
 
  399         value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attIndex ) );
 
  401       case QVariant::Double:
 
  402         value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attIndex ) );
 
  405       case QVariant::DateTime:
 
  408         int year, month, day, hour, minute, tzf;
 
  410         float secondsPart = 0;
 
  412         OGR_F_GetFieldAsDateTimeEx( ogrFet, attIndex, &year, &month, &day, &hour, &minute, &second, &tzf );
 
  413         float millisecondPart = std::modf( second, &secondsPart );
 
  416           value = QDate( year, month, day );
 
  417         else if ( 
field.
type() == QVariant::Time )
 
  418           value = QTime( hour, minute, 
static_cast< int >( secondsPart ), 
static_cast< int >( 1000 * millisecondPart ) );
 
  420           value = QDateTime( QDate( year, month, day ),
 
  421                              QTime( hour, minute, 
static_cast< int >( secondsPart ), 
static_cast< int >( 1000 * millisecondPart ) ) );
 
  425       case QVariant::ByteArray:
 
  428         const GByte *b = OGR_F_GetFieldAsBinary( ogrFet, attIndex, &size );
 
  432         QByteArray ba = QByteArray::fromRawData( 
reinterpret_cast<const char *
>( b ), size );
 
  439       case QVariant::StringList:
 
  442         char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
 
  443         const int count = CSLCount( lst );
 
  446           list.reserve( count );
 
  447           for ( 
int i = 0; i < count; i++ )
 
  450               list << encoding->toUnicode( lst[i] );
 
  452               list << QString::fromUtf8( lst[i] );
 
  463           case QVariant::String:
 
  466             char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
 
  467             const int count = CSLCount( lst );
 
  470               list.reserve( count );
 
  471               for ( 
int i = 0; i < count; i++ )
 
  474                   list << encoding->toUnicode( lst[i] );
 
  476                   list << QString::fromUtf8( lst[i] );
 
  487             const int *lst = OGR_F_GetFieldAsIntegerList( ogrFet, attIndex, &count );
 
  490               list.reserve( count );
 
  491               for ( 
int i = 0; i < count; i++ )
 
  500           case QVariant::Double:
 
  504             const double *lst = OGR_F_GetFieldAsDoubleList( ogrFet, attIndex, &count );
 
  507               list.reserve( count );
 
  508               for ( 
int i = 0; i < count; i++ )
 
  517           case QVariant::LongLong:
 
  521             const long long *lst = OGR_F_GetFieldAsInteger64List( ogrFet, attIndex, &count );
 
  524               list.reserve( count );
 
  525               for ( 
int i = 0; i < count; i++ )
 
  536             Q_ASSERT_X( 
false, 
"QgsOgrUtils::getOgrFeatureAttribute", 
"unsupported field type" );
 
  550           value = QJsonDocument::fromJson( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
 
  552           value = QJsonDocument::fromJson( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
 
  556         Q_ASSERT_X( 
false, 
"QgsOgrUtils::getOgrFeatureAttribute", 
"unsupported field type" );
 
  579   for ( 
int idx = 0; idx < fields.
count(); ++idx )
 
  581     QVariant value = getOgrFeatureAttribute( ogrFet, fields, idx, encoding, &ok );
 
  595   OGRGeometryH geom = OGR_F_GetGeometryRef( ogrFet );
 
  599     feature.
setGeometry( ogrGeometryToQgsGeometry( geom ) );
 
  609   OGR_G_GetPointZM( geom, 0, &x, &y, &z, &m );
 
  610   return std::make_unique< QgsPoint >( wkbType, x, y, z, m );
 
  615   std::unique_ptr< QgsMultiPoint > mp = std::make_unique< QgsMultiPoint >();
 
  617   const int count = OGR_G_GetGeometryCount( geom );
 
  618   mp->reserve( count );
 
  619   for ( 
int i = 0; i < count; ++i )
 
  631   int count = OGR_G_GetPointCount( geom );
 
  632   QVector< double > x( count );
 
  633   QVector< double > y( count );
 
  635   double *pz = 
nullptr;
 
  641   double *pm = 
nullptr;
 
  648   OGR_G_GetPointsZM( geom, x.data(), 
sizeof( 
double ), y.data(), 
sizeof( 
double ), pz, 
sizeof( 
double ), pm, 
sizeof( 
double ) );
 
  655   std::unique_ptr< QgsMultiLineString > mp = std::make_unique< QgsMultiLineString >();
 
  657   const int count = OGR_G_GetGeometryCount( geom );
 
  658   mp->reserve( count );
 
  659   for ( 
int i = 0; i < count; ++i )
 
  669   std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
 
  671   const int count = OGR_G_GetGeometryCount( geom );
 
  677   for ( 
int i = 1; i < count; ++i )
 
  687   std::unique_ptr< QgsMultiPolygon > polygon = std::make_unique< QgsMultiPolygon >();
 
  689   const int count = OGR_G_GetGeometryCount( geom );
 
  690   polygon->reserve( count );
 
  691   for ( 
int i = 0; i < count; ++i )
 
  701   switch ( ogrGeomType )
 
  703     case wkbUnknown: 
return QgsWkbTypes::Type::Unknown;
 
  704     case wkbPoint: 
return QgsWkbTypes::Type::Point;
 
  705     case wkbLineString: 
return QgsWkbTypes::Type::LineString;
 
  706     case wkbPolygon: 
return QgsWkbTypes::Type::Polygon;
 
  707     case wkbMultiPoint: 
return QgsWkbTypes::Type::MultiPoint;
 
  708     case wkbMultiLineString: 
return QgsWkbTypes::Type::MultiLineString;
 
  709     case wkbMultiPolygon: 
return QgsWkbTypes::Type::MultiPolygon;
 
  710     case wkbGeometryCollection: 
return QgsWkbTypes::Type::GeometryCollection;
 
  711     case wkbCircularString: 
return QgsWkbTypes::Type::CircularString;
 
  712     case wkbCompoundCurve: 
return QgsWkbTypes::Type::CompoundCurve;
 
  713     case wkbCurvePolygon: 
return QgsWkbTypes::Type::CurvePolygon;
 
  714     case wkbMultiCurve: 
return QgsWkbTypes::Type::MultiCurve;
 
  715     case wkbMultiSurface: 
return QgsWkbTypes::Type::MultiSurface;
 
  716     case wkbCurve: 
return QgsWkbTypes::Type::Unknown; 
 
  717     case wkbSurface: 
return QgsWkbTypes::Type::Unknown; 
 
  718     case wkbPolyhedralSurface: 
return QgsWkbTypes::Type::Unknown; 
 
  719     case wkbTIN: 
return QgsWkbTypes::Type::Unknown; 
 
  720     case wkbTriangle: 
return QgsWkbTypes::Type::Triangle;
 
  722     case wkbNone: 
return QgsWkbTypes::Type::NoGeometry;
 
  723     case wkbLinearRing: 
return QgsWkbTypes::Type::LineString; 
 
  725     case wkbCircularStringZ: 
return QgsWkbTypes::Type::CircularStringZ;
 
  726     case wkbCompoundCurveZ: 
return QgsWkbTypes::Type::CompoundCurveZ;
 
  727     case wkbCurvePolygonZ: 
return QgsWkbTypes::Type::CurvePolygonZ;
 
  728     case wkbMultiCurveZ: 
return QgsWkbTypes::Type::MultiCurveZ;
 
  729     case wkbMultiSurfaceZ: 
return QgsWkbTypes::Type::MultiSurfaceZ;
 
  730     case wkbCurveZ: 
return QgsWkbTypes::Type::Unknown; 
 
  731     case wkbSurfaceZ: 
return QgsWkbTypes::Type::Unknown; 
 
  732     case wkbPolyhedralSurfaceZ: 
return QgsWkbTypes::Type::Unknown; 
 
  733     case wkbTINZ: 
return QgsWkbTypes::Type::Unknown; 
 
  734     case wkbTriangleZ: 
return QgsWkbTypes::Type::TriangleZ;
 
  736     case wkbPointM: 
return QgsWkbTypes::Type::PointM;
 
  737     case wkbLineStringM: 
return QgsWkbTypes::Type::LineStringM;
 
  738     case wkbPolygonM: 
return QgsWkbTypes::Type::PolygonM;
 
  739     case wkbMultiPointM: 
return QgsWkbTypes::Type::MultiPointM;
 
  740     case wkbMultiLineStringM: 
return QgsWkbTypes::Type::MultiLineStringM;
 
  741     case wkbMultiPolygonM: 
return QgsWkbTypes::Type::MultiPolygonM;
 
  742     case wkbGeometryCollectionM: 
return QgsWkbTypes::Type::GeometryCollectionM;
 
  743     case wkbCircularStringM: 
return QgsWkbTypes::Type::CircularStringM;
 
  744     case wkbCompoundCurveM: 
return QgsWkbTypes::Type::CompoundCurveM;
 
  745     case wkbCurvePolygonM: 
return QgsWkbTypes::Type::CurvePolygonM;
 
  746     case wkbMultiCurveM: 
return QgsWkbTypes::Type::MultiCurveM;
 
  747     case wkbMultiSurfaceM: 
return QgsWkbTypes::Type::MultiSurfaceM;
 
  748     case wkbCurveM: 
return QgsWkbTypes::Type::Unknown; 
 
  749     case wkbSurfaceM: 
return QgsWkbTypes::Type::Unknown; 
 
  750     case wkbPolyhedralSurfaceM: 
return QgsWkbTypes::Type::Unknown; 
 
  751     case wkbTINM: 
return QgsWkbTypes::Type::Unknown; 
 
  752     case wkbTriangleM: 
return QgsWkbTypes::Type::TriangleM;
 
  754     case wkbPointZM: 
return QgsWkbTypes::Type::PointZM;
 
  755     case wkbLineStringZM: 
return QgsWkbTypes::Type::LineStringZM;
 
  756     case wkbPolygonZM: 
return QgsWkbTypes::Type::PolygonZM;
 
  757     case wkbMultiPointZM: 
return QgsWkbTypes::Type::MultiPointZM;
 
  758     case wkbMultiLineStringZM: 
return QgsWkbTypes::Type::MultiLineStringZM;
 
  759     case wkbMultiPolygonZM: 
return QgsWkbTypes::Type::MultiPolygonZM;
 
  760     case wkbGeometryCollectionZM: 
return QgsWkbTypes::Type::GeometryCollectionZM;
 
  761     case wkbCircularStringZM: 
return QgsWkbTypes::Type::CircularStringZM;
 
  762     case wkbCompoundCurveZM: 
return QgsWkbTypes::Type::CompoundCurveZM;
 
  763     case wkbCurvePolygonZM: 
return QgsWkbTypes::Type::CurvePolygonZM;
 
  764     case wkbMultiCurveZM: 
return QgsWkbTypes::Type::MultiCurveZM;
 
  765     case wkbMultiSurfaceZM: 
return QgsWkbTypes::Type::MultiSurfaceZM;
 
  766     case wkbCurveZM: 
return QgsWkbTypes::Type::Unknown; 
 
  767     case wkbSurfaceZM: 
return QgsWkbTypes::Type::Unknown; 
 
  768     case wkbPolyhedralSurfaceZM: 
return QgsWkbTypes::Type::Unknown; 
 
  769     case wkbTINZM: 
return QgsWkbTypes::Type::Unknown; 
 
  770     case wkbTriangleZM: 
return QgsWkbTypes::Type::TriangleZM;
 
  772     case wkbPoint25D: 
return QgsWkbTypes::Type::PointZ;
 
  773     case wkbLineString25D: 
return QgsWkbTypes::Type::LineStringZ;
 
  774     case wkbPolygon25D: 
return QgsWkbTypes::Type::PolygonZ;
 
  775     case wkbMultiPoint25D: 
return QgsWkbTypes::Type::MultiPointZ;
 
  776     case wkbMultiLineString25D: 
return QgsWkbTypes::Type::MultiLineStringZ;
 
  777     case wkbMultiPolygon25D: 
return QgsWkbTypes::Type::MultiPolygonZ;
 
  778     case wkbGeometryCollection25D: 
return QgsWkbTypes::Type::GeometryCollectionZ;
 
  782   return QgsWkbTypes::Type::Unknown;
 
  790   const auto ogrGeomType = OGR_G_GetGeometryType( geom );
 
  833   if ( wkbFlatten( wkbType ) == wkbGeometryCollection )
 
  836     if ( OGR_G_GetGeometryCount( geom ) >= 1 &&
 
  837          wkbFlatten( OGR_G_GetGeometryType( OGR_G_GetGeometryRef( geom, 0 ) ) ) == wkbTIN )
 
  839       auto newGeom = OGR_G_ForceToMultiPolygon( OGR_G_Clone( geom ) );
 
  840       auto ret = ogrGeometryToQgsGeometry( newGeom );
 
  841       OGR_G_DestroyGeometry( newGeom );
 
  847   int memorySize = OGR_G_WkbSize( geom );
 
  848   unsigned char *wkb = 
new unsigned char[memorySize];
 
  852   uint32_t origGeomType;
 
  853   memcpy( &origGeomType, wkb + 1, 
sizeof( uint32_t ) );
 
  854   bool hasZ = ( origGeomType >= 1000 && origGeomType < 2000 ) || ( origGeomType >= 3000 && origGeomType < 4000 );
 
  855   bool hasM = ( origGeomType >= 2000 && origGeomType < 3000 ) || ( origGeomType >= 3000 && origGeomType < 4000 );
 
  858   if ( origGeomType % 1000 == 16 ) 
 
  861     int nDims = 2 + hasZ + hasM;
 
  864     unsigned char *wkbptr = wkb;
 
  870     memcpy( wkbptr, &newMultiType, 
sizeof( uint32_t ) );
 
  875     memcpy( &numGeoms, wkb + 5, 
sizeof( uint32_t ) );
 
  879     for ( uint32_t i = 0; i < numGeoms; ++i )
 
  885       memcpy( wkbptr, &newSingleType, 
sizeof( uint32_t ) );
 
  886       wkbptr += 
sizeof( uint32_t );
 
  890       memcpy( &nRings, wkbptr, 
sizeof( uint32_t ) );
 
  891       wkbptr += 
sizeof( uint32_t );
 
  893       for ( uint32_t j = 0; j < nRings; ++j )
 
  896         memcpy( &nPoints, wkbptr, 
sizeof( uint32_t ) );
 
  897         wkbptr += 
sizeof( uint32_t ) + 
sizeof( 
double ) * nDims * nPoints;
 
  901   else if ( origGeomType % 1000 == 15 ) 
 
  906     memcpy( wkb + 1, &newType, 
sizeof( uint32_t ) );
 
  917   if ( 
string.isEmpty() )
 
  920   QString randomFileName = QStringLiteral( 
"/vsimem/%1" ).arg( QUuid::createUuid().toString() );
 
  923   QByteArray ba = 
string.toUtf8();
 
  924   VSIFCloseL( VSIFileFromMemBuffer( randomFileName.toUtf8().constData(), 
reinterpret_cast< GByte * 
>( ba.data() ),
 
  925                                     static_cast< vsi_l_offset 
>( ba.size() ), FALSE ) );
 
  930     VSIUnlink( randomFileName.toUtf8().constData() );
 
  934   OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS.get(), 0 );
 
  938     VSIUnlink( randomFileName.toUtf8().constData() );
 
  943   while ( oFeat.reset( OGR_L_GetNextFeature( ogrLayer ) ), oFeat )
 
  945     QgsFeature feat = readOgrFeature( oFeat.get(), fields, encoding );
 
  951   VSIUnlink( randomFileName.toUtf8().constData() );
 
  959   if ( 
string.isEmpty() )
 
  962   QString randomFileName = QStringLiteral( 
"/vsimem/%1" ).arg( QUuid::createUuid().toString() );
 
  965   QByteArray ba = 
string.toUtf8();
 
  966   VSIFCloseL( VSIFileFromMemBuffer( randomFileName.toUtf8().constData(), 
reinterpret_cast< GByte * 
>( ba.data() ),
 
  967                                     static_cast< vsi_l_offset 
>( ba.size() ), FALSE ) );
 
  972     VSIUnlink( randomFileName.toUtf8().constData() );
 
  976   OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS.get(), 0 );
 
  980     VSIUnlink( randomFileName.toUtf8().constData() );
 
  986   if ( oFeat.reset( OGR_L_GetNextFeature( ogrLayer ) ), oFeat )
 
  988     fields = readOgrFields( oFeat.get(), encoding );
 
  992   VSIUnlink( randomFileName.toUtf8().constData() );
 
 1001   for ( 
qgssize i = 0; stringList[i]; ++i )
 
 1003     strings.append( QString::fromUtf8( stringList[i] ) );
 
 1014   char *pszWkt = 
nullptr;
 
 1015   const QByteArray multiLineOption = QStringLiteral( 
"MULTILINE=NO" ).toLocal8Bit();
 
 1016   const QByteArray formatOption = QStringLiteral( 
"FORMAT=WKT2" ).toLocal8Bit();
 
 1017   const char *
const options[] = {multiLineOption.constData(), formatOption.constData(), 
nullptr};
 
 1018   OSRExportToWktEx( srs, &pszWkt, options );
 
 1020   const QString res( pszWkt );
 
 1027   const QString wkt = OGRSpatialReferenceToWkt( srs );
 
 1028   if ( wkt.isEmpty() )
 
 1031   const char *authorityName = OSRGetAuthorityName( srs, 
nullptr );
 
 1032   const char *authorityCode = OSRGetAuthorityCode( srs, 
nullptr );
 
 1034   if ( authorityName && authorityCode )
 
 1036     QString authId = QString( authorityName ) + 
':' + QString( authorityCode );
 
 1039     if ( OSRSetFromUserInput( ogrSrsTmp, authId.toUtf8().constData() ) != OGRERR_NONE &&
 
 1040          OSRIsSame( srs, ogrSrsTmp ) )
 
 1045     OSRDestroySpatialReference( ogrSrsTmp );
 
 1050 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0) 
 1051   const double coordinateEpoch = OSRGetCoordinateEpoch( srs );
 
 1052   if ( coordinateEpoch > 0 )
 
 1070     if ( !authId.isEmpty() )
 
 1072       ogrSrs = OSRNewSpatialReference( 
nullptr );
 
 1073       if ( OSRSetFromUserInput( ogrSrs, authId.toUtf8().constData() ) == OGRERR_NONE )
 
 1077         if ( ogrSrsFromWkt )
 
 1079           if ( !OSRIsSame( ogrSrs, ogrSrsFromWkt ) )
 
 1081             OSRDestroySpatialReference( ogrSrs );
 
 1082             ogrSrs = ogrSrsFromWkt;
 
 1086             OSRDestroySpatialReference( ogrSrsFromWkt );
 
 1092         OSRDestroySpatialReference( ogrSrs );
 
 1098       ogrSrs = OSRNewSpatialReference( srsWkt.toUtf8().constData() );
 
 1102       OSRSetAxisMappingStrategy( ogrSrs, OAMS_TRADITIONAL_GIS_ORDER );
 
 1103 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0) 
 1118   const QString cpgEncoding = readShapefileEncodingFromCpg( path );
 
 1119   if ( !cpgEncoding.isEmpty() )
 
 1122   return readShapefileEncodingFromLdid( path );
 
 1127 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,1,0) 
 1129   QgsOgrLayerUniquePtr layer = QgsOgrProviderUtils::getLayer( path, 
false, QStringList(), 0, errCause, 
false );
 
 1130   return layer ? layer->GetMetadataItem( QStringLiteral( 
"ENCODING_FROM_CPG" ), QStringLiteral( 
"SHAPEFILE" ) ) : QString();
 
 1132   if ( !QFileInfo::exists( path ) )
 
 1136   const QFileInfo fi( path );
 
 1137   const QString baseName = fi.completeBaseName();
 
 1138   const QString cpgPath = fi.dir().filePath( QStringLiteral( 
"%1.%2" ).arg( baseName, fi.suffix() == QLatin1String( 
"SHP" ) ? QStringLiteral( 
"CPG" ) : QStringLiteral( 
"cpg" ) ) );
 
 1139   if ( QFile::exists( cpgPath ) )
 
 1141     QFile cpgFile( cpgPath );
 
 1142     if ( cpgFile.open( QIODevice::ReadOnly ) )
 
 1144       QTextStream cpgStream( &cpgFile );
 
 1145       const QString cpgString = cpgStream.readLine();
 
 1148       if ( !cpgString.isEmpty() )
 
 1153         int cpgCodePage = cpgString.toInt( &ok );
 
 1154         if ( ok && ( ( cpgCodePage >= 437 && cpgCodePage <= 950 )
 
 1155                      || ( cpgCodePage >= 1250 && cpgCodePage <= 1258 ) ) )
 
 1157           return QStringLiteral( 
"CP%1" ).arg( cpgCodePage );
 
 1159         else if ( cpgString.startsWith( QLatin1String( 
"8859" ) ) )
 
 1161           if ( cpgString.length() > 4 && cpgString.at( 4 ) == 
'-' )
 
 1162             return QStringLiteral( 
"ISO-8859-%1" ).arg( cpgString.mid( 5 ) );
 
 1164             return QStringLiteral( 
"ISO-8859-%1" ).arg( cpgString.mid( 4 ) );
 
 1166         else if ( cpgString.startsWith( QLatin1String( 
"UTF-8" ), Qt::CaseInsensitive ) ||
 
 1167                   cpgString.startsWith( QLatin1String( 
"UTF8" ), Qt::CaseInsensitive ) )
 
 1168           return QStringLiteral( 
"UTF-8" );
 
 1169         else if ( cpgString.startsWith( QLatin1String( 
"ANSI 1251" ), Qt::CaseInsensitive ) )
 
 1170           return QStringLiteral( 
"CP1251" );
 
 1183 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,1,0) 
 1185   QgsOgrLayerUniquePtr layer = QgsOgrProviderUtils::getLayer( path, 
false, QStringList(), 0, errCause, 
false );
 
 1186   return layer ? layer->GetMetadataItem( QStringLiteral( 
"ENCODING_FROM_LDID" ), QStringLiteral( 
"SHAPEFILE" ) ) : QString();
 
 1191   if ( !QFileInfo::exists( path ) )
 
 1195   const QFileInfo fi( path );
 
 1196   const QString baseName = fi.completeBaseName();
 
 1199   const QString dbfPath = fi.dir().filePath( QStringLiteral( 
"%1.%2" ).arg( baseName, fi.suffix() == QLatin1String( 
"SHP" ) ? QStringLiteral( 
"DBF" ) : QStringLiteral( 
"dbf" ) ) );
 
 1200   if ( QFile::exists( dbfPath ) )
 
 1202     QFile dbfFile( dbfPath );
 
 1203     if ( dbfFile.open( QIODevice::ReadOnly ) )
 
 1206       QDataStream dbfIn( &dbfFile );
 
 1207       dbfIn.setByteOrder( QDataStream::LittleEndian );
 
 1217         case 1: nCP = 437;      
break;
 
 1218         case 2: nCP = 850;      
break;
 
 1219         case 3: nCP = 1252;     
break;
 
 1220         case 4: nCP = 10000;    
break;
 
 1221         case 8: nCP = 865;      
break;
 
 1222         case 10: nCP = 850;     
break;
 
 1223         case 11: nCP = 437;     
break;
 
 1224         case 13: nCP = 437;     
break;
 
 1225         case 14: nCP = 850;     
break;
 
 1226         case 15: nCP = 437;     
break;
 
 1227         case 16: nCP = 850;     
break;
 
 1228         case 17: nCP = 437;     
break;
 
 1229         case 18: nCP = 850;     
break;
 
 1230         case 19: nCP = 932;     
break;
 
 1231         case 20: nCP = 850;     
break;
 
 1232         case 21: nCP = 437;     
break;
 
 1233         case 22: nCP = 850;     
break;
 
 1234         case 23: nCP = 865;     
break;
 
 1235         case 24: nCP = 437;     
break;
 
 1236         case 25: nCP = 437;     
break;
 
 1237         case 26: nCP = 850;     
break;
 
 1238         case 27: nCP = 437;     
break;
 
 1239         case 28: nCP = 863;     
break;
 
 1240         case 29: nCP = 850;     
break;
 
 1241         case 31: nCP = 852;     
break;
 
 1242         case 34: nCP = 852;     
break;
 
 1243         case 35: nCP = 852;     
break;
 
 1244         case 36: nCP = 860;     
break;
 
 1245         case 37: nCP = 850;     
break;
 
 1246         case 38: nCP = 866;     
break;
 
 1247         case 55: nCP = 850;     
break;
 
 1248         case 64: nCP = 852;     
break;
 
 1249         case 77: nCP = 936;     
break;
 
 1250         case 78: nCP = 949;     
break;
 
 1251         case 79: nCP = 950;     
break;
 
 1252         case 80: nCP = 874;     
break;
 
 1253         case 87: 
return QStringLiteral( 
"ISO-8859-1" );
 
 1254         case 88: nCP = 1252;     
break;
 
 1255         case 89: nCP = 1252;     
break;
 
 1256         case 100: nCP = 852;     
break;
 
 1257         case 101: nCP = 866;     
break;
 
 1258         case 102: nCP = 865;     
break;
 
 1259         case 103: nCP = 861;     
break;
 
 1260         case 104: nCP = 895;     
break;
 
 1261         case 105: nCP = 620;     
break;
 
 1262         case 106: nCP = 737;     
break;
 
 1263         case 107: nCP = 857;     
break;
 
 1264         case 108: nCP = 863;     
break;
 
 1265         case 120: nCP = 950;     
break;
 
 1266         case 121: nCP = 949;     
break;
 
 1267         case 122: nCP = 936;     
break;
 
 1268         case 123: nCP = 932;     
break;
 
 1269         case 124: nCP = 874;     
break;
 
 1270         case 134: nCP = 737;     
break;
 
 1271         case 135: nCP = 852;     
break;
 
 1272         case 136: nCP = 857;     
break;
 
 1273         case 150: nCP = 10007;   
break;
 
 1274         case 151: nCP = 10029;   
break;
 
 1275         case 200: nCP = 1250;    
break;
 
 1276         case 201: nCP = 1251;    
break;
 
 1277         case 202: nCP = 1254;    
break;
 
 1278         case 203: nCP = 1253;    
break;
 
 1279         case 204: nCP = 1257;    
break;
 
 1285         return QStringLiteral( 
"CP%1" ).arg( nCP );
 
 1297   char **papszStyleString = CSLTokenizeString2( 
string.toUtf8().constData(), 
";",
 
 1299                             | CSLT_PRESERVEQUOTES
 
 1300                             | CSLT_PRESERVEESCAPES );
 
 1301   for ( 
int i = 0; papszStyleString[i] != 
nullptr; ++i )
 
 1307     const thread_local QRegularExpression sToolPartRx( QStringLiteral( 
"^(.*?)\\((.*)\\)$" ) );
 
 1308     const QString stylePart( papszStyleString[i] );
 
 1309     const QRegularExpressionMatch match = sToolPartRx.match( stylePart );
 
 1310     if ( !match.hasMatch() )
 
 1313     const QString tool = match.captured( 1 );
 
 1314     const QString params = match.captured( 2 );
 
 1316     char **papszTokens = CSLTokenizeString2( params.toUtf8().constData(), 
",", CSLT_HONOURSTRINGS
 
 1317                          | CSLT_PRESERVEESCAPES );
 
 1319     QVariantMap toolParts;
 
 1320     const thread_local QRegularExpression sToolParamRx( QStringLiteral( 
"^(.*?):(.*)$" ) );
 
 1321     for ( 
int j = 0; papszTokens[j] != 
nullptr; ++j )
 
 1323       const QString toolPart( papszTokens[j] );
 
 1324       const QRegularExpressionMatch toolMatch = sToolParamRx.match( toolPart );
 
 1325       if ( !match.hasMatch() )
 
 1329       toolParts.insert( toolMatch.captured( 1 ).toLower(), toolMatch.captured( 2 ) );
 
 1331     CSLDestroy( papszTokens );
 
 1334     styles.insert( tool.toLower(), toolParts );
 
 1336   CSLDestroy( papszStyleString );
 
 1342   const QVariantMap styles = parseStyleString( 
string );
 
 1346     const thread_local QRegularExpression sUnitRx = QRegularExpression( QStringLiteral( 
"^([\\d\\.]+)(g|px|pt|mm|cm|in)$" ) );
 
 1347     const QRegularExpressionMatch match = sUnitRx.match( size );
 
 1348     if ( match.hasMatch() )
 
 1350       value = match.captured( 1 ).toDouble();
 
 1351       const QString unitString = match.captured( 2 );
 
 1352       if ( unitString.compare( QLatin1String( 
"px" ), Qt::CaseInsensitive ) == 0 )
 
 1356         static constexpr 
double PT_TO_INCHES_FACTOR = 1 / 72.0;
 
 1357         static constexpr 
double PX_TO_PT_FACTOR = 1 / ( 96.0 * PT_TO_INCHES_FACTOR );
 
 1359         value *= PX_TO_PT_FACTOR;
 
 1362       else if ( unitString.compare( QLatin1String( 
"pt" ), Qt::CaseInsensitive ) == 0 )
 
 1367       else if ( unitString.compare( QLatin1String( 
"mm" ), Qt::CaseInsensitive ) == 0 )
 
 1372       else if ( unitString.compare( QLatin1String( 
"cm" ), Qt::CaseInsensitive ) == 0 )
 
 1378       else if ( unitString.compare( QLatin1String( 
"in" ), Qt::CaseInsensitive ) == 0 )
 
 1383       else if ( unitString.compare( QLatin1String( 
"g" ), Qt::CaseInsensitive ) == 0 )
 
 1388       QgsDebugMsg( QStringLiteral( 
"Unknown unit %1" ).arg( unitString ) );
 
 1392       QgsDebugMsg( QStringLiteral( 
"Could not parse style size %1" ).arg( size ) );
 
 1397   auto convertColor = []( 
const QString & string ) -> QColor
 
 1399     if ( 
string.isEmpty() )
 
 1402     const thread_local QRegularExpression sColorWithAlphaRx = QRegularExpression( QStringLiteral( 
"^#([0-9a-fA-F]{6})([0-9a-fA-F]{2})$" ) );
 
 1403     const QRegularExpressionMatch match = sColorWithAlphaRx.match( 
string );
 
 1404     if ( match.hasMatch() )
 
 1407       return QColor( QStringLiteral( 
"#%1%2" ).arg( match.captured( 2 ), match.captured( 1 ) ) );
 
 1411       return QColor( 
string );
 
 1415   auto convertPen = [&convertColor, &convertSize, string]( 
const QVariantMap & lineStyle ) -> std::unique_ptr< QgsSymbol >
 
 1417     QColor color = convertColor( lineStyle.value( QStringLiteral( 
"c" ), QStringLiteral( 
"#000000" ) ).toString() );
 
 1421     convertSize( lineStyle.value( QStringLiteral( 
"w" ) ).toString(), lineWidth, lineWidthUnit );
 
 1424     const thread_local QRegularExpression sMapInfoId = QRegularExpression( QStringLiteral( 
"mapinfo-pen-(\\d+)" ) );
 
 1425     const QRegularExpressionMatch match = sMapInfoId.match( 
string );
 
 1426     if ( match.hasMatch() )
 
 1428       const int penId = match.captured( 1 ).toInt();
 
 1435     std::unique_ptr< QgsSimpleLineSymbolLayer > simpleLine = std::make_unique< QgsSimpleLineSymbolLayer >( color, lineWidth );
 
 1436     simpleLine->setWidthUnit( lineWidthUnit );
 
 1439     const QString pattern = lineStyle.value( QStringLiteral( 
"p" ) ).toString();
 
 1440     if ( !pattern.isEmpty() )
 
 1442       const thread_local QRegularExpression sPatternUnitRx = QRegularExpression( QStringLiteral( 
"^([\\d\\.\\s]+)(g|px|pt|mm|cm|in)$" ) );
 
 1443       const QRegularExpressionMatch match = sPatternUnitRx.match( pattern );
 
 1444       if ( match.hasMatch() )
 
 1446         const QStringList patternValues = match.captured( 1 ).split( 
' ' );
 
 1447         QVector< qreal > dashPattern;
 
 1449         for ( 
const QString &val : patternValues )
 
 1452           convertSize( val + match.captured( 2 ), length, patternUnits );
 
 1453           dashPattern.push_back( length * lineWidth * 2 );
 
 1456         simpleLine->setCustomDashVector( dashPattern );
 
 1457         simpleLine->setCustomDashPatternUnit( patternUnits );
 
 1458         simpleLine->setUseCustomDashPattern( 
true );
 
 1462     Qt::PenCapStyle capStyle = Qt::FlatCap;
 
 1463     Qt::PenJoinStyle joinStyle = Qt::MiterJoin;
 
 1465     const QString 
id = lineStyle.value( QStringLiteral( 
"id" ) ).toString();
 
 1466     if ( 
id.contains( QLatin1String( 
"mapinfo-pen" ), Qt::CaseInsensitive ) )
 
 1471       capStyle = Qt::RoundCap;
 
 1472       joinStyle = Qt::RoundJoin;
 
 1476     const QString penCap = lineStyle.value( QStringLiteral( 
"cap" ) ).toString();
 
 1477     if ( penCap.compare( QLatin1String( 
"b" ), Qt::CaseInsensitive ) == 0 )
 
 1479       capStyle = Qt::FlatCap;
 
 1481     else if ( penCap.compare( QLatin1String( 
"r" ), Qt::CaseInsensitive ) == 0 )
 
 1483       capStyle = Qt::RoundCap;
 
 1485     else if ( penCap.compare( QLatin1String( 
"p" ), Qt::CaseInsensitive ) == 0 )
 
 1487       capStyle = Qt::SquareCap;
 
 1489     simpleLine->setPenCapStyle( capStyle );
 
 1492     const QString penJoin = lineStyle.value( QStringLiteral( 
"j" ) ).toString();
 
 1493     if ( penJoin.compare( QLatin1String( 
"m" ), Qt::CaseInsensitive ) == 0 )
 
 1495       joinStyle = Qt::MiterJoin;
 
 1497     else if ( penJoin.compare( QLatin1String( 
"r" ), Qt::CaseInsensitive ) == 0 )
 
 1499       joinStyle = Qt::RoundJoin;
 
 1501     else if ( penJoin.compare( QLatin1String( 
"b" ), Qt::CaseInsensitive ) == 0 )
 
 1503       joinStyle = Qt::BevelJoin;
 
 1505     simpleLine->setPenJoinStyle( joinStyle );
 
 1507     const QString priority = lineStyle.value( QStringLiteral( 
"l" ) ).toString();
 
 1508     if ( !priority.isEmpty() )
 
 1510       simpleLine->setRenderingPass( priority.toInt() );
 
 1512     return std::make_unique< QgsLineSymbol >( 
QgsSymbolLayerList() << simpleLine.release() );
 
 1515   auto convertBrush = [&convertColor]( 
const QVariantMap & brushStyle ) -> std::unique_ptr< QgsSymbol >
 
 1517     const QColor foreColor = convertColor( brushStyle.value( QStringLiteral( 
"fc" ), QStringLiteral( 
"#000000" ) ).toString() );
 
 1518     const QColor backColor = convertColor( brushStyle.value( QStringLiteral( 
"bc" ), QString() ).toString() );
 
 1520     const QString 
id = brushStyle.value( QStringLiteral( 
"id" ) ).toString();
 
 1523     const thread_local QRegularExpression sMapInfoId = QRegularExpression( QStringLiteral( 
"mapinfo-brush-(\\d+)" ) );
 
 1524     const QRegularExpressionMatch match = sMapInfoId.match( 
id );
 
 1525     if ( match.hasMatch() )
 
 1527       const int brushId = match.captured( 1 ).toInt();
 
 1534     const thread_local QRegularExpression sOgrId = QRegularExpression( QStringLiteral( 
"ogr-brush-(\\d+)" ) );
 
 1535     const QRegularExpressionMatch ogrMatch = sOgrId.match( 
id );
 
 1537     Qt::BrushStyle style = Qt::SolidPattern;
 
 1538     if ( ogrMatch.hasMatch() )
 
 1540       const int brushId = ogrMatch.captured( 1 ).toInt();
 
 1544           style = Qt::SolidPattern;
 
 1548           style = Qt::NoBrush;
 
 1552           style = Qt::HorPattern;
 
 1556           style = Qt::VerPattern;
 
 1560           style = Qt::FDiagPattern;
 
 1564           style = Qt::BDiagPattern;
 
 1568           style = Qt::CrossPattern;
 
 1572           style = Qt::DiagCrossPattern;
 
 1578     if ( backColor.isValid() && style != Qt::SolidPattern && style != Qt::NoBrush )
 
 1580       std::unique_ptr< QgsSimpleFillSymbolLayer > backgroundFill = std::make_unique< QgsSimpleFillSymbolLayer >( backColor );
 
 1581       backgroundFill->setLocked( 
true );
 
 1582       backgroundFill->setStrokeStyle( Qt::NoPen );
 
 1583       layers << backgroundFill.release();
 
 1586     std::unique_ptr< QgsSimpleFillSymbolLayer > foregroundFill = std::make_unique< QgsSimpleFillSymbolLayer >( foreColor );
 
 1587     foregroundFill->setBrushStyle( style );
 
 1588     foregroundFill->setStrokeStyle( Qt::NoPen );
 
 1590     const QString priority = brushStyle.value( QStringLiteral( 
"l" ) ).toString();
 
 1591     if ( !priority.isEmpty() )
 
 1593       foregroundFill->setRenderingPass( priority.toInt() );
 
 1595     layers << foregroundFill.release();
 
 1596     return std::make_unique< QgsFillSymbol >( layers );
 
 1599   auto convertSymbol = [&convertColor, &convertSize, string]( 
const QVariantMap & symbolStyle ) -> std::unique_ptr< QgsSymbol >
 
 1601     const QColor color = convertColor( symbolStyle.value( QStringLiteral( 
"c" ), QStringLiteral( 
"#000000" ) ).toString() );
 
 1605     convertSize( symbolStyle.value( QStringLiteral( 
"s" ) ).toString(), symbolSize, symbolSizeUnit );
 
 1607     const double angle = symbolStyle.value( QStringLiteral( 
"a" ), QStringLiteral( 
"0" ) ).toDouble();
 
 1609     const QString 
id = symbolStyle.value( QStringLiteral( 
"id" ) ).toString();
 
 1612     const thread_local QRegularExpression sMapInfoId = QRegularExpression( QStringLiteral( 
"mapinfo-sym-(\\d+)" ) );
 
 1613     const QRegularExpressionMatch match = sMapInfoId.match( 
id );
 
 1614     if ( match.hasMatch() )
 
 1616       const int symbolId = match.captured( 1 ).toInt();
 
 1627     std::unique_ptr< QgsMarkerSymbolLayer > markerLayer;
 
 1629     const thread_local QRegularExpression sFontId = QRegularExpression( QStringLiteral( 
"font-sym-(\\d+)" ) );
 
 1630     const QRegularExpressionMatch fontMatch = sFontId.match( 
id );
 
 1631     if ( fontMatch.hasMatch() )
 
 1633       const int symId = fontMatch.captured( 1 ).toInt();
 
 1634       const QStringList families = symbolStyle.value( QStringLiteral( 
"f" ), QString() ).toString().split( 
',' );
 
 1636       bool familyFound = 
false;
 
 1638       for ( 
const QString &family : std::as_const( families ) )
 
 1643           fontFamily = family;
 
 1650         std::unique_ptr< QgsFontMarkerSymbolLayer > fontMarker = std::make_unique< QgsFontMarkerSymbolLayer >( fontFamily, QChar( symId ), symbolSize );
 
 1651         fontMarker->setSizeUnit( symbolSizeUnit );
 
 1652         fontMarker->setAngle( -
angle );
 
 1654         fontMarker->setColor( color );
 
 1656         const QColor strokeColor = convertColor( symbolStyle.value( QStringLiteral( 
"o" ), QString() ).toString() );
 
 1657         if ( strokeColor.isValid() )
 
 1659           fontMarker->setStrokeColor( strokeColor );
 
 1660           fontMarker->setStrokeWidth( 1 );
 
 1665           fontMarker->setStrokeWidth( 0 );
 
 1668         markerLayer = std::move( fontMarker );
 
 1670       else if ( !families.empty() )
 
 1679       const thread_local QRegularExpression sOgrId = QRegularExpression( QStringLiteral( 
"ogr-sym-(\\d+)" ) );
 
 1680       const QRegularExpressionMatch ogrMatch = sOgrId.match( 
id );
 
 1683       bool isFilled = 
true;
 
 1684       if ( ogrMatch.hasMatch() )
 
 1686         const int symId = ogrMatch.captured( 1 ).toInt();
 
 1749       std::unique_ptr< QgsSimpleMarkerSymbolLayer > simpleMarker = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, symbolSize, -
angle );
 
 1750       simpleMarker->setSizeUnit( symbolSizeUnit );
 
 1754         simpleMarker->setColor( color );
 
 1755         simpleMarker->setStrokeStyle( Qt::NoPen );
 
 1759         simpleMarker->setFillColor( QColor( 0, 0, 0, 0 ) );
 
 1760         simpleMarker->setStrokeColor( color );
 
 1763       const QColor strokeColor = convertColor( symbolStyle.value( QStringLiteral( 
"o" ), QString() ).toString() );
 
 1764       if ( strokeColor.isValid() )
 
 1766         simpleMarker->setStrokeColor( strokeColor );
 
 1767         simpleMarker->setStrokeStyle( Qt::SolidLine );
 
 1770       markerLayer = std::move( simpleMarker );
 
 1773     return std::make_unique< QgsMarkerSymbol >( 
QgsSymbolLayerList() << markerLayer.release() );
 
 1779       if ( styles.contains( QStringLiteral( 
"symbol" ) ) )
 
 1781         const QVariantMap symbolStyle = styles.value( QStringLiteral( 
"symbol" ) ).toMap();
 
 1782         return convertSymbol( symbolStyle );
 
 1790       if ( styles.contains( QStringLiteral( 
"pen" ) ) )
 
 1793         const QVariantMap lineStyle = styles.value( QStringLiteral( 
"pen" ) ).toMap();
 
 1794         return convertPen( lineStyle );
 
 1803       std::unique_ptr< QgsSymbol > fillSymbol = std::make_unique< QgsFillSymbol >();
 
 1804       if ( styles.contains( QStringLiteral( 
"brush" ) ) )
 
 1806         const QVariantMap brushStyle = styles.value( QStringLiteral( 
"brush" ) ).toMap();
 
 1807         fillSymbol = convertBrush( brushStyle );
 
 1811         std::unique_ptr< QgsSimpleFillSymbolLayer > emptyFill = std::make_unique< QgsSimpleFillSymbolLayer >();
 
 1812         emptyFill->setBrushStyle( Qt::NoBrush );
 
 1813         fillSymbol = std::make_unique< QgsFillSymbol >( 
QgsSymbolLayerList() << emptyFill.release() );
 
 1816       std::unique_ptr< QgsSymbol > penSymbol;
 
 1817       if ( styles.contains( QStringLiteral( 
"pen" ) ) )
 
 1819         const QVariantMap lineStyle = styles.value( QStringLiteral( 
"pen" ) ).toMap();
 
 1820         penSymbol = convertPen( lineStyle );
 
 1825         const int count = penSymbol->symbolLayerCount();
 
 1835         for ( 
int i = 0; i < count; ++i )
 
 1837           std::unique_ptr< QgsSymbolLayer > layer( penSymbol->takeSymbolLayer( 0 ) );
 
 1838           layer->setLocked( 
true );
 
 1839           fillSymbol->appendSymbolLayer( layer.release() );
 
 1855   variantType = QVariant::Type::Invalid;
 
 1856   variantSubType = QVariant::Type::Invalid;
 
 1861       if ( ogrSubType == OFSTBoolean )
 
 1863         variantType = QVariant::Bool;
 
 1864         ogrSubType = OFSTBoolean;
 
 1867         variantType = QVariant::Int;
 
 1870       variantType = QVariant::LongLong;
 
 1873       variantType = QVariant::Double;
 
 1876       variantType = QVariant::Date;
 
 1879       variantType = QVariant::Time;
 
 1882       variantType = QVariant::DateTime;
 
 1886       variantType = QVariant::ByteArray;
 
 1891       if ( ogrSubType == OFSTJSON )
 
 1893         ogrSubType = OFSTJSON;
 
 1894         variantType = QVariant::Map;
 
 1895         variantSubType = QVariant::String;
 
 1899         variantType = QVariant::String;
 
 1904     case OFTWideStringList:
 
 1905       variantType = QVariant::StringList;
 
 1906       variantSubType = QVariant::String;
 
 1909     case OFTIntegerList:
 
 1910       variantType = QVariant::List;
 
 1911       variantSubType = QVariant::Int;
 
 1915       variantType = QVariant::List;
 
 1916       variantSubType = QVariant::Double;
 
 1919     case OFTInteger64List:
 
 1920       variantType = QVariant::List;
 
 1921       variantSubType = QVariant::LongLong;
 
 1928   ogrSubType = OFSTNone;
 
 1929   switch ( variantType )
 
 1931     case QVariant::Bool:
 
 1932       ogrType = OFTInteger;
 
 1933       ogrSubType = OFSTBoolean;
 
 1937       ogrType = OFTInteger;
 
 1940     case QVariant::LongLong:
 
 1941       ogrType = OFTInteger64;
 
 1944     case QVariant::Double:
 
 1948     case QVariant::Char:
 
 1949       ogrType = OFTString;
 
 1952     case QVariant::String:
 
 1953       ogrType = OFTString;
 
 1956     case QVariant::StringList:
 
 1957       ogrType = OFTStringList;
 
 1960     case QVariant::ByteArray:
 
 1961       ogrType = OFTBinary;
 
 1964     case QVariant::Date:
 
 1968     case QVariant::Time:
 
 1971     case QVariant::DateTime:
 
 1972       ogrType = OFTDateTime;
 
 1976       ogrType = OFTString;
 
 1983   if ( 
string.isEmpty() )
 
 1991       res = 
string.toInt( &ok );
 
 1995       res = 
string.toLongLong( &ok );
 
 1999       res = 
string.toDouble( &ok );
 
 2009       res = QDate::fromString( 
string, Qt::ISODate );
 
 2014       res = QTime::fromString( 
string, Qt::ISODate );
 
 2019       res = QDateTime::fromString( 
string, Qt::ISODate );
 
 2029   return ok ? res : QVariant();
 
 2033 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,3,0) 
 2039   const QString name{ OGR_FldDomain_GetName( domain ) };
 
 2040   const QString description{ OGR_FldDomain_GetDescription( domain ) };
 
 2042   QVariant::Type fieldType = QVariant::Type::Invalid;
 
 2043   QVariant::Type fieldSubType = QVariant::Type::Invalid;
 
 2044   const OGRFieldType domainFieldType = OGR_FldDomain_GetFieldType( domain );
 
 2045   const OGRFieldSubType domainFieldSubType = OGR_FldDomain_GetFieldSubType( domain );
 
 2046   ogrFieldTypeToQVariantType( domainFieldType, domainFieldSubType, fieldType, fieldSubType );
 
 2048   std::unique_ptr< QgsFieldDomain > res;
 
 2049   switch ( OGR_FldDomain_GetDomainType( domain ) )
 
 2053       QList< QgsCodedValue > values;
 
 2054       const OGRCodedValue *codedValue = OGR_CodedFldDomain_GetEnumeration( domain );
 
 2055       while ( codedValue && codedValue->pszCode )
 
 2057         const QString code( codedValue->pszCode );
 
 2062         const QString value( codedValue->pszValue ? codedValue->pszValue : codedValue->pszCode );
 
 2063         values.append( 
QgsCodedValue( stringToVariant( domainFieldType, domainFieldSubType, code ), value ) );
 
 2068       res = std::make_unique< QgsCodedFieldDomain >( name, description, fieldType, values );
 
 2075       bool minIsInclusive = 
false;
 
 2076       if ( 
const OGRField *min = OGR_RangeFldDomain_GetMin( domain, &minIsInclusive ) )
 
 2081       bool maxIsInclusive = 
false;
 
 2082       if ( 
const OGRField *max = OGR_RangeFldDomain_GetMax( domain, &maxIsInclusive ) )
 
 2087       res = std::make_unique< QgsRangeFieldDomain >( name, description, fieldType,
 
 2088             minValue, minIsInclusive,
 
 2089             maxValue, maxIsInclusive );
 
 2094       res = std::make_unique< QgsGlobFieldDomain >( name, description, fieldType,
 
 2095             QString( OGR_GlobFldDomain_GetGlob( domain ) ) );
 
 2099   switch ( OGR_FldDomain_GetMergePolicy( domain ) )
 
 2101     case OFDMP_DEFAULT_VALUE:
 
 2107     case OFDMP_GEOMETRY_WEIGHTED:
 
 2112   switch ( OGR_FldDomain_GetSplitPolicy( domain ) )
 
 2114     case OFDSP_DEFAULT_VALUE:
 
 2117     case OFDSP_DUPLICATE:
 
 2120     case OFDSP_GEOMETRY_RATIO:
 
 2132   OGRFieldType domainFieldType = OFTInteger;
 
 2133   OGRFieldSubType domainFieldSubType = OFSTNone;
 
 2134   variantTypeToOgrFieldType( domain->
fieldType(), domainFieldType, domainFieldSubType );
 
 2136   OGRFieldDomainH res = 
nullptr;
 
 2137   switch ( domain->
type() )
 
 2141       std::vector< OGRCodedValue > enumeration;
 
 2142       const QList< QgsCodedValue> values = qgis::down_cast< const QgsCodedFieldDomain * >( domain )->values();
 
 2143       enumeration.reserve( values.size() );
 
 2146         OGRCodedValue codedValue;
 
 2147         codedValue.pszCode = CPLStrdup( value.code().toString().toUtf8().constData() );
 
 2148         codedValue.pszValue = CPLStrdup( value.value().toUtf8().constData() );
 
 2149         enumeration.push_back( codedValue );
 
 2152       last.pszCode = 
nullptr;
 
 2153       last.pszValue = 
nullptr;
 
 2154       enumeration.push_back( last );
 
 2155       res = OGR_CodedFldDomain_Create(
 
 2156               domain->
name().toUtf8().constData(),
 
 2163       for ( 
const OGRCodedValue &value : std::as_const( enumeration ) )
 
 2165         CPLFree( value.pszCode );
 
 2166         CPLFree( value.pszValue );
 
 2173       std::unique_ptr< OGRField > min = variantToOGRField( qgis::down_cast< const QgsRangeFieldDomain * >( domain )->minimum() );
 
 2174       std::unique_ptr< OGRField > max = variantToOGRField( qgis::down_cast< const QgsRangeFieldDomain * >( domain )->maximum() );
 
 2175       res = OGR_RangeFldDomain_Create(
 
 2176               domain->
name().toUtf8().constData(),
 
 2181               qgis::down_cast< const QgsRangeFieldDomain * >( domain )->minimumIsInclusive(),
 
 2183               qgis::down_cast< const QgsRangeFieldDomain * >( domain )->maximumIsInclusive()
 
 2190       res = OGR_GlobFldDomain_Create(
 
 2191               domain->
name().toUtf8().constData(),
 
 2195               qgis::down_cast< const QgsGlobFieldDomain * >( domain )->glob().toUtf8().constData()
 
 2204       OGR_FldDomain_SetMergePolicy( res, OFDMP_DEFAULT_VALUE );
 
 2207       OGR_FldDomain_SetMergePolicy( res, OFDMP_GEOMETRY_WEIGHTED );
 
 2210       OGR_FldDomain_SetMergePolicy( res, OFDMP_SUM );
 
 2217       OGR_FldDomain_SetSplitPolicy( res, OFDSP_DEFAULT_VALUE );
 
 2220       OGR_FldDomain_SetSplitPolicy( res, OFDSP_GEOMETRY_RATIO );
 
 2223       OGR_FldDomain_SetSplitPolicy( res, OFDSP_DUPLICATE );