QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsogrutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsogrutils.cpp
3  ---------------
4  begin : February 2016
5  copyright : (C) 2016 Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsogrutils.h"
17 #include "qgsapplication.h"
18 #include "qgslogger.h"
19 #include "qgsgeometry.h"
20 #include "qgsfields.h"
21 #include "qgslinestring.h"
22 #include <QTextCodec>
23 #include <QUuid>
24 #include <cpl_error.h>
25 #include <QJsonDocument>
26 
27 // Starting with GDAL 2.2, there are 2 concepts: unset fields and null fields
28 // whereas previously there was only unset fields. For QGIS purposes, both
29 // states (unset/null) are equivalent.
30 #ifndef OGRNullMarker
31 #define OGR_F_IsFieldSetAndNotNull OGR_F_IsFieldSet
32 #endif
33 
34 
35 
36 void gdal::OGRDataSourceDeleter::operator()( OGRDataSourceH source )
37 {
38  OGR_DS_Destroy( source );
39 }
40 
41 
42 void gdal::OGRGeometryDeleter::operator()( OGRGeometryH geometry )
43 {
44  OGR_G_DestroyGeometry( geometry );
45 }
46 
47 void gdal::OGRFldDeleter::operator()( OGRFieldDefnH definition )
48 {
49  OGR_Fld_Destroy( definition );
50 }
51 
52 void gdal::OGRFeatureDeleter::operator()( OGRFeatureH feature )
53 {
54  OGR_F_Destroy( feature );
55 }
56 
58 {
59  GDALClose( dataset );
60 }
61 
62 void gdal::fast_delete_and_close( gdal::dataset_unique_ptr &dataset, GDALDriverH driver, const QString &path )
63 {
64  // see https://github.com/qgis/QGIS/commit/d024910490a39e65e671f2055c5b6543e06c7042#commitcomment-25194282
65  // faster if we close the handle AFTER delete, but doesn't work for windows
66 #ifdef Q_OS_WIN
67  // close dataset handle
68  dataset.reset();
69 #endif
70 
71  CPLPushErrorHandler( CPLQuietErrorHandler );
72  GDALDeleteDataset( driver, path.toUtf8().constData() );
73  CPLPopErrorHandler();
74 
75 #ifndef Q_OS_WIN
76  // close dataset handle
77  dataset.reset();
78 #endif
79 }
80 
81 
82 void gdal::GDALWarpOptionsDeleter::operator()( GDALWarpOptions *options )
83 {
84  GDALDestroyWarpOptions( options );
85 }
86 
87 QgsFeature QgsOgrUtils::readOgrFeature( OGRFeatureH ogrFet, const QgsFields &fields, QTextCodec *encoding )
88 {
89  QgsFeature feature;
90  if ( !ogrFet )
91  {
92  feature.setValid( false );
93  return feature;
94  }
95 
96  feature.setId( OGR_F_GetFID( ogrFet ) );
97  feature.setValid( true );
98 
99  if ( !readOgrFeatureGeometry( ogrFet, feature ) )
100  {
101  feature.setValid( false );
102  }
103 
104  if ( !readOgrFeatureAttributes( ogrFet, fields, feature, encoding ) )
105  {
106  feature.setValid( false );
107  }
108 
109  return feature;
110 }
111 
112 QgsFields QgsOgrUtils::readOgrFields( OGRFeatureH ogrFet, QTextCodec *encoding )
113 {
114  QgsFields fields;
115 
116  if ( !ogrFet )
117  return fields;
118 
119  int fieldCount = OGR_F_GetFieldCount( ogrFet );
120  for ( int i = 0; i < fieldCount; ++i )
121  {
122  OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, i );
123  if ( !fldDef )
124  {
125  fields.append( QgsField() );
126  continue;
127  }
128 
129  QString name = encoding ? encoding->toUnicode( OGR_Fld_GetNameRef( fldDef ) ) : QString::fromUtf8( OGR_Fld_GetNameRef( fldDef ) );
130  QVariant::Type varType;
131  switch ( OGR_Fld_GetType( fldDef ) )
132  {
133  case OFTInteger:
134  if ( OGR_Fld_GetSubType( fldDef ) == OFSTBoolean )
135  varType = QVariant::Bool;
136  else
137  varType = QVariant::Int;
138  break;
139  case OFTInteger64:
140  varType = QVariant::LongLong;
141  break;
142  case OFTReal:
143  varType = QVariant::Double;
144  break;
145  case OFTDate:
146  varType = QVariant::Date;
147  break;
148  case OFTTime:
149  varType = QVariant::Time;
150  break;
151  case OFTDateTime:
152  varType = QVariant::DateTime;
153  break;
154  case OFTString:
155 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(2,4,0)
156  if ( OGR_Fld_GetSubType( fldDef ) == OFSTJSON )
157  varType = QVariant::Map;
158  else
159  varType = QVariant::String;
160  break;
161 #endif
162  default:
163  varType = QVariant::String; // other unsupported, leave it as a string
164  }
165  fields.append( QgsField( name, varType ) );
166  }
167  return fields;
168 }
169 
170 QVariant QgsOgrUtils::getOgrFeatureAttribute( OGRFeatureH ogrFet, const QgsFields &fields, int attIndex, QTextCodec *encoding, bool *ok )
171 {
172  if ( !ogrFet || attIndex < 0 || attIndex >= fields.count() )
173  {
174  if ( ok )
175  *ok = false;
176  return QVariant();
177  }
178 
179  OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attIndex );
180 
181  if ( ! fldDef )
182  {
183  if ( ok )
184  *ok = false;
185 
186  QgsDebugMsg( QStringLiteral( "ogrFet->GetFieldDefnRef(attindex) returns NULL" ) );
187  return QVariant();
188  }
189 
190  QVariant value;
191 
192  if ( ok )
193  *ok = true;
194 
195  if ( OGR_F_IsFieldSetAndNotNull( ogrFet, attIndex ) )
196  {
197  switch ( fields.at( attIndex ).type() )
198  {
199  case QVariant::String:
200  {
201  if ( encoding )
202  value = QVariant( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
203  else
204  value = QVariant( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ) );
205  break;
206  }
207  case QVariant::Int:
208  value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) );
209  break;
210  case QVariant::Bool:
211  value = QVariant( bool( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) ) );
212  break;
213  case QVariant::LongLong:
214  value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attIndex ) );
215  break;
216  case QVariant::Double:
217  value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attIndex ) );
218  break;
219  case QVariant::Date:
220  case QVariant::DateTime:
221  case QVariant::Time:
222  {
223  int year, month, day, hour, minute, second, tzf;
224 
225  OGR_F_GetFieldAsDateTime( ogrFet, attIndex, &year, &month, &day, &hour, &minute, &second, &tzf );
226  if ( fields.at( attIndex ).type() == QVariant::Date )
227  value = QDate( year, month, day );
228  else if ( fields.at( attIndex ).type() == QVariant::Time )
229  value = QTime( hour, minute, second );
230  else
231  value = QDateTime( QDate( year, month, day ), QTime( hour, minute, second ) );
232  }
233  break;
234 
235  case QVariant::ByteArray:
236  {
237  int size = 0;
238  const GByte *b = OGR_F_GetFieldAsBinary( ogrFet, attIndex, &size );
239 
240  // QByteArray::fromRawData is funny. It doesn't take ownership of the data, so we have to explicitly call
241  // detach on it to force a copy which owns the data
242  QByteArray ba = QByteArray::fromRawData( reinterpret_cast<const char *>( b ), size );
243  ba.detach();
244 
245  value = ba;
246  break;
247  }
248 
249  case QVariant::List:
250  {
251  if ( fields.at( attIndex ).subType() == QVariant::String )
252  {
253  QStringList list;
254  char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
255  const int count = CSLCount( lst );
256  if ( count > 0 )
257  {
258  for ( int i = 0; i < count; i++ )
259  {
260  if ( encoding )
261  list << encoding->toUnicode( lst[i] );
262  else
263  list << QString::fromUtf8( lst[i] );
264  }
265  }
266  value = list;
267  }
268  else
269  {
270  Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" );
271  if ( ok )
272  *ok = false;
273  }
274  break;
275  }
276 
277  case QVariant::Map:
278  {
279  //it has to be JSON
280  //it's null if no json format
281  if ( encoding )
282  value = QJsonDocument::fromJson( encoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
283  else
284  value = QJsonDocument::fromJson( QString::fromUtf8( OGR_F_GetFieldAsString( ogrFet, attIndex ) ).toUtf8() ).toVariant();
285  break;
286  }
287  default:
288  Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" );
289  if ( ok )
290  *ok = false;
291  }
292  }
293  else
294  {
295  value = QVariant( QString() );
296  }
297 
298  return value;
299 }
300 
301 bool QgsOgrUtils::readOgrFeatureAttributes( OGRFeatureH ogrFet, const QgsFields &fields, QgsFeature &feature, QTextCodec *encoding )
302 {
303  // read all attributes
304  feature.initAttributes( fields.count() );
305  feature.setFields( fields );
306 
307  if ( !ogrFet )
308  return false;
309 
310  bool ok = false;
311  for ( int idx = 0; idx < fields.count(); ++idx )
312  {
313  QVariant value = getOgrFeatureAttribute( ogrFet, fields, idx, encoding, &ok );
314  if ( ok )
315  {
316  feature.setAttribute( idx, value );
317  }
318  }
319  return true;
320 }
321 
322 bool QgsOgrUtils::readOgrFeatureGeometry( OGRFeatureH ogrFet, QgsFeature &feature )
323 {
324  if ( !ogrFet )
325  return false;
326 
327  OGRGeometryH geom = OGR_F_GetGeometryRef( ogrFet );
328  if ( !geom )
329  feature.clearGeometry();
330  else
331  feature.setGeometry( ogrGeometryToQgsGeometry( geom ) );
332 
333  return true;
334 }
335 
336 std::unique_ptr< QgsPoint > ogrGeometryToQgsPoint( OGRGeometryH geom )
337 {
338  QgsWkbTypes::Type wkbType = static_cast<QgsWkbTypes::Type>( OGR_G_GetGeometryType( geom ) );
339 
340  double x, y, z, m;
341  OGR_G_GetPointZM( geom, 0, &x, &y, &z, &m );
342  return qgis::make_unique< QgsPoint >( wkbType, x, y, z, m );
343 }
344 
345 std::unique_ptr< QgsLineString > ogrGeometryToQgsLineString( OGRGeometryH geom )
346 {
347  QgsWkbTypes::Type wkbType = static_cast<QgsWkbTypes::Type>( OGR_G_GetGeometryType( geom ) );
348 
349  int count = OGR_G_GetPointCount( geom );
350  QVector< double > x( count );
351  QVector< double > y( count );
352  QVector< double > z;
353  double *pz = nullptr;
354  if ( QgsWkbTypes::hasZ( wkbType ) )
355  {
356  z.resize( count );
357  pz = z.data();
358  }
359  double *pm = nullptr;
360  QVector< double > m;
361  if ( QgsWkbTypes::hasM( wkbType ) )
362  {
363  m.resize( count );
364  pm = m.data();
365  }
366  OGR_G_GetPointsZM( geom, x.data(), sizeof( double ), y.data(), sizeof( double ), pz, sizeof( double ), pm, sizeof( double ) );
367 
368  return qgis::make_unique< QgsLineString>( x, y, z, m, wkbType == QgsWkbTypes::LineString25D );
369 }
370 
372 {
373  switch ( ogrGeomType )
374  {
375  case wkbUnknown: return QgsWkbTypes::Type::Unknown;
376  case wkbPoint: return QgsWkbTypes::Type::Point;
377  case wkbLineString: return QgsWkbTypes::Type::LineString;
378  case wkbPolygon: return QgsWkbTypes::Type::Polygon;
379  case wkbMultiPoint: return QgsWkbTypes::Type::MultiPoint;
380  case wkbMultiLineString: return QgsWkbTypes::Type::MultiLineString;
381  case wkbMultiPolygon: return QgsWkbTypes::Type::MultiPolygon;
382  case wkbGeometryCollection: return QgsWkbTypes::Type::GeometryCollection;
383  case wkbCircularString: return QgsWkbTypes::Type::CircularString;
384  case wkbCompoundCurve: return QgsWkbTypes::Type::CompoundCurve;
385  case wkbCurvePolygon: return QgsWkbTypes::Type::CurvePolygon;
386  case wkbMultiCurve: return QgsWkbTypes::Type::MultiCurve;
387  case wkbMultiSurface: return QgsWkbTypes::Type::MultiSurface;
388  case wkbCurve: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
389  case wkbSurface: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
390  case wkbPolyhedralSurface: return QgsWkbTypes::Type::Unknown; // no actual matching
391  case wkbTIN: return QgsWkbTypes::Type::Unknown; // no actual matching
392  case wkbTriangle: return QgsWkbTypes::Type::Triangle;
393 
394  case wkbNone: return QgsWkbTypes::Type::NoGeometry;
395  case wkbLinearRing: return QgsWkbTypes::Type::LineString; // approximate match
396 
397  case wkbCircularStringZ: return QgsWkbTypes::Type::CircularStringZ;
398  case wkbCompoundCurveZ: return QgsWkbTypes::Type::CompoundCurveZ;
399  case wkbCurvePolygonZ: return QgsWkbTypes::Type::CurvePolygonZ;
400  case wkbMultiCurveZ: return QgsWkbTypes::Type::MultiCurveZ;
401  case wkbMultiSurfaceZ: return QgsWkbTypes::Type::MultiSurfaceZ;
402  case wkbCurveZ: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
403  case wkbSurfaceZ: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
404  case wkbPolyhedralSurfaceZ: return QgsWkbTypes::Type::Unknown; // no actual matching
405  case wkbTINZ: return QgsWkbTypes::Type::Unknown; // no actual matching
406  case wkbTriangleZ: return QgsWkbTypes::Type::TriangleZ;
407 
408  case wkbPointM: return QgsWkbTypes::Type::PointM;
409  case wkbLineStringM: return QgsWkbTypes::Type::LineStringM;
410  case wkbPolygonM: return QgsWkbTypes::Type::PolygonM;
411  case wkbMultiPointM: return QgsWkbTypes::Type::MultiPointM;
412  case wkbMultiLineStringM: return QgsWkbTypes::Type::MultiLineStringM;
413  case wkbMultiPolygonM: return QgsWkbTypes::Type::MultiPolygonM;
414  case wkbGeometryCollectionM: return QgsWkbTypes::Type::GeometryCollectionM;
415  case wkbCircularStringM: return QgsWkbTypes::Type::CircularStringM;
416  case wkbCompoundCurveM: return QgsWkbTypes::Type::CompoundCurveM;
417  case wkbCurvePolygonM: return QgsWkbTypes::Type::CurvePolygonM;
418  case wkbMultiCurveM: return QgsWkbTypes::Type::MultiCurveM;
419  case wkbMultiSurfaceM: return QgsWkbTypes::Type::MultiSurfaceM;
420  case wkbCurveM: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
421  case wkbSurfaceM: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
422  case wkbPolyhedralSurfaceM: return QgsWkbTypes::Type::Unknown; // no actual matching
423  case wkbTINM: return QgsWkbTypes::Type::Unknown; // no actual matching
424  case wkbTriangleM: return QgsWkbTypes::Type::TriangleM;
425 
426  case wkbPointZM: return QgsWkbTypes::Type::PointZM;
427  case wkbLineStringZM: return QgsWkbTypes::Type::LineStringZM;
428  case wkbPolygonZM: return QgsWkbTypes::Type::PolygonZM;
429  case wkbMultiPointZM: return QgsWkbTypes::Type::MultiPointZM;
430  case wkbMultiLineStringZM: return QgsWkbTypes::Type::MultiLineStringZM;
431  case wkbMultiPolygonZM: return QgsWkbTypes::Type::MultiPolygonZM;
432  case wkbGeometryCollectionZM: return QgsWkbTypes::Type::GeometryCollectionZM;
433  case wkbCircularStringZM: return QgsWkbTypes::Type::CircularStringZM;
434  case wkbCompoundCurveZM: return QgsWkbTypes::Type::CompoundCurveZM;
435  case wkbCurvePolygonZM: return QgsWkbTypes::Type::CurvePolygonZM;
436  case wkbMultiCurveZM: return QgsWkbTypes::Type::MultiCurveZM;
437  case wkbMultiSurfaceZM: return QgsWkbTypes::Type::MultiSurfaceZM;
438  case wkbCurveZM: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
439  case wkbSurfaceZM: return QgsWkbTypes::Type::Unknown; // not an actual concrete type
440  case wkbPolyhedralSurfaceZM: return QgsWkbTypes::Type::Unknown; // no actual matching
441  case wkbTINZM: return QgsWkbTypes::Type::Unknown; // no actual matching
442  case wkbTriangleZM: return QgsWkbTypes::Type::TriangleZM;
443 
444  case wkbPoint25D: return QgsWkbTypes::Type::PointZ;
445  case wkbLineString25D: return QgsWkbTypes::Type::LineStringZ;
446  case wkbPolygon25D: return QgsWkbTypes::Type::PolygonZ;
447  case wkbMultiPoint25D: return QgsWkbTypes::Type::MultiPointZ;
448  case wkbMultiLineString25D: return QgsWkbTypes::Type::MultiLineStringZ;
449  case wkbMultiPolygon25D: return QgsWkbTypes::Type::MultiPolygonZ;
450  case wkbGeometryCollection25D: return QgsWkbTypes::Type::GeometryCollectionZ;
451  }
452 
453  // should not reach that point normally
454  return QgsWkbTypes::Type::Unknown;
455 }
456 
458 {
459  if ( !geom )
460  return QgsGeometry();
461 
462  const auto ogrGeomType = OGR_G_GetGeometryType( geom );
463  QgsWkbTypes::Type wkbType = ogrGeometryTypeToQgsWkbType( ogrGeomType );
464 
465  // optimised case for some geometry classes, avoiding wkb conversion on OGR/QGIS sides
466  // TODO - extend to other classes!
467  switch ( QgsWkbTypes::flatType( wkbType ) )
468  {
469  case QgsWkbTypes::Point:
470  {
471  return QgsGeometry( ogrGeometryToQgsPoint( geom ) );
472  }
473 
475  {
476  // optimised case for line -- avoid wkb conversion
477  return QgsGeometry( ogrGeometryToQgsLineString( geom ) );
478  }
479 
480  default:
481  break;
482  };
483 
484  // Fallback to inefficient WKB conversions
485 
486  if ( wkbFlatten( wkbType ) == wkbGeometryCollection )
487  {
488  // Shapefile MultiPatch can be reported as GeometryCollectionZ of TINZ
489  if ( OGR_G_GetGeometryCount( geom ) >= 1 &&
490  wkbFlatten( OGR_G_GetGeometryType( OGR_G_GetGeometryRef( geom, 0 ) ) ) == wkbTIN )
491  {
492  auto newGeom = OGR_G_ForceToMultiPolygon( OGR_G_Clone( geom ) );
493  auto ret = ogrGeometryToQgsGeometry( newGeom );
494  OGR_G_DestroyGeometry( newGeom );
495  return ret;
496  }
497  }
498 
499  // get the wkb representation
500  int memorySize = OGR_G_WkbSize( geom );
501  unsigned char *wkb = new unsigned char[memorySize];
502  OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
503 
504  // Read original geometry type
505  uint32_t origGeomType;
506  memcpy( &origGeomType, wkb + 1, sizeof( uint32_t ) );
507  bool hasZ = ( origGeomType >= 1000 && origGeomType < 2000 ) || ( origGeomType >= 3000 && origGeomType < 4000 );
508  bool hasM = ( origGeomType >= 2000 && origGeomType < 3000 ) || ( origGeomType >= 3000 && origGeomType < 4000 );
509 
510  // PolyhedralSurface and TINs are not supported, map them to multipolygons...
511  if ( origGeomType % 1000 == 16 ) // is TIN, TINZ, TINM or TINZM
512  {
513  // TIN has the same wkb layout as a multipolygon, just need to overwrite the geom types...
514  int nDims = 2 + hasZ + hasM;
515  uint32_t newMultiType = static_cast<uint32_t>( QgsWkbTypes::zmType( QgsWkbTypes::MultiPolygon, hasZ, hasM ) );
516  uint32_t newSingleType = static_cast<uint32_t>( QgsWkbTypes::zmType( QgsWkbTypes::Polygon, hasZ, hasM ) );
517  unsigned char *wkbptr = wkb;
518 
519  // Endianness
520  wkbptr += 1;
521 
522  // Overwrite geom type
523  memcpy( wkbptr, &newMultiType, sizeof( uint32_t ) );
524  wkbptr += 4;
525 
526  // Geom count
527  uint32_t numGeoms;
528  memcpy( &numGeoms, wkb + 5, sizeof( uint32_t ) );
529  wkbptr += 4;
530 
531  // For each part, overwrite the geometry type to polygon (Z|M)
532  for ( uint32_t i = 0; i < numGeoms; ++i )
533  {
534  // Endianness
535  wkbptr += 1;
536 
537  // Overwrite geom type
538  memcpy( wkbptr, &newSingleType, sizeof( uint32_t ) );
539  wkbptr += sizeof( uint32_t );
540 
541  // skip coordinates
542  uint32_t nRings;
543  memcpy( &nRings, wkbptr, sizeof( uint32_t ) );
544  wkbptr += sizeof( uint32_t );
545 
546  for ( uint32_t j = 0; j < nRings; ++j )
547  {
548  uint32_t nPoints;
549  memcpy( &nPoints, wkbptr, sizeof( uint32_t ) );
550  wkbptr += sizeof( uint32_t ) + sizeof( double ) * nDims * nPoints;
551  }
552  }
553  }
554  else if ( origGeomType % 1000 == 15 ) // PolyhedralSurface, PolyhedralSurfaceZ, PolyhedralSurfaceM or PolyhedralSurfaceZM
555  {
556  // PolyhedralSurface has the same wkb layout as a MultiPolygon, just need to overwrite the geom type...
557  uint32_t newType = static_cast<uint32_t>( QgsWkbTypes::zmType( QgsWkbTypes::MultiPolygon, hasZ, hasM ) );
558  // Overwrite geom type
559  memcpy( wkb + 1, &newType, sizeof( uint32_t ) );
560  }
561 
562  QgsGeometry g;
563  g.fromWkb( wkb, memorySize );
564  return g;
565 }
566 
567 QgsFeatureList QgsOgrUtils::stringToFeatureList( const QString &string, const QgsFields &fields, QTextCodec *encoding )
568 {
569  QgsFeatureList features;
570  if ( string.isEmpty() )
571  return features;
572 
573  QString randomFileName = QStringLiteral( "/vsimem/%1" ).arg( QUuid::createUuid().toString() );
574 
575  // create memory file system object from string buffer
576  QByteArray ba = string.toUtf8();
577  VSIFCloseL( VSIFileFromMemBuffer( randomFileName.toUtf8().constData(), reinterpret_cast< GByte * >( ba.data() ),
578  static_cast< vsi_l_offset >( ba.size() ), FALSE ) );
579 
580  gdal::ogr_datasource_unique_ptr hDS( OGROpen( randomFileName.toUtf8().constData(), false, nullptr ) );
581  if ( !hDS )
582  {
583  VSIUnlink( randomFileName.toUtf8().constData() );
584  return features;
585  }
586 
587  OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS.get(), 0 );
588  if ( !ogrLayer )
589  {
590  hDS.reset();
591  VSIUnlink( randomFileName.toUtf8().constData() );
592  return features;
593  }
594 
596  while ( oFeat.reset( OGR_L_GetNextFeature( ogrLayer ) ), oFeat )
597  {
598  QgsFeature feat = readOgrFeature( oFeat.get(), fields, encoding );
599  if ( feat.isValid() )
600  features << feat;
601  }
602 
603  hDS.reset();
604  VSIUnlink( randomFileName.toUtf8().constData() );
605 
606  return features;
607 }
608 
609 QgsFields QgsOgrUtils::stringToFields( const QString &string, QTextCodec *encoding )
610 {
611  QgsFields fields;
612  if ( string.isEmpty() )
613  return fields;
614 
615  QString randomFileName = QStringLiteral( "/vsimem/%1" ).arg( QUuid::createUuid().toString() );
616 
617  // create memory file system object from buffer
618  QByteArray ba = string.toUtf8();
619  VSIFCloseL( VSIFileFromMemBuffer( randomFileName.toUtf8().constData(), reinterpret_cast< GByte * >( ba.data() ),
620  static_cast< vsi_l_offset >( ba.size() ), FALSE ) );
621 
622  gdal::ogr_datasource_unique_ptr hDS( OGROpen( randomFileName.toUtf8().constData(), false, nullptr ) );
623  if ( !hDS )
624  {
625  VSIUnlink( randomFileName.toUtf8().constData() );
626  return fields;
627  }
628 
629  OGRLayerH ogrLayer = OGR_DS_GetLayer( hDS.get(), 0 );
630  if ( !ogrLayer )
631  {
632  hDS.reset();
633  VSIUnlink( randomFileName.toUtf8().constData() );
634  return fields;
635  }
636 
638  //read in the first feature only
639  if ( oFeat.reset( OGR_L_GetNextFeature( ogrLayer ) ), oFeat )
640  {
641  fields = readOgrFields( oFeat.get(), encoding );
642  }
643 
644  hDS.reset();
645  VSIUnlink( randomFileName.toUtf8().constData() );
646  return fields;
647 }
648 
649 QStringList QgsOgrUtils::cStringListToQStringList( char **stringList )
650 {
651  QStringList strings;
652 
653  // presume null terminated string list
654  for ( qgssize i = 0; stringList[i]; ++i )
655  {
656  strings.append( QString::fromUtf8( stringList[i] ) );
657  }
658 
659  return strings;
660 }
661 
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:183
void CORE_EXPORT operator()(OGRFeatureH feature)
Destroys an OGR feature, using the correct gdal calls.
Definition: qgsogrutils.cpp:52
static bool readOgrFeatureAttributes(OGRFeatureH ogrFet, const QgsFields &fields, QgsFeature &feature, QTextCodec *encoding)
Reads all attributes from an OGR feature into a QgsFeature.
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:162
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer&#39;s length...
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
static bool readOgrFeatureGeometry(OGRFeatureH ogrFet, QgsFeature &feature)
Reads the geometry from an OGR feature into a QgsFeature.
Container of fields for a vector layer.
Definition: qgsfields.h:42
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:211
void CORE_EXPORT operator()(OGRDataSourceH source)
Destroys an OGR data source, using the correct gdal calls.
Definition: qgsogrutils.cpp:36
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
static QgsFields readOgrFields(OGRFeatureH ogrFet, QTextCodec *encoding)
Reads an OGR feature and returns a corresponding fields collection.
#define OGR_F_IsFieldSetAndNotNull
Definition: qgsogrutils.cpp:31
static endian_t endian()
Returns whether this machine uses big or little endian.
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:771
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
std::unique_ptr< QgsPoint > ogrGeometryToQgsPoint(OGRGeometryH geom)
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a string representing a collection of features using OGR.
void CORE_EXPORT fast_delete_and_close(dataset_unique_ptr &dataset, GDALDriverH driver, const QString &path)
Performs a fast close of an unwanted GDAL dataset handle by deleting the underlying data store...
Definition: qgsogrutils.cpp:62
std::unique_ptr< std::remove_pointer< OGRFeatureH >::type, OGRFeatureDeleter > ogr_feature_unique_ptr
Scoped OGR feature.
Definition: qgsogrutils.h:129
void CORE_EXPORT operator()(GDALDatasetH datasource)
Destroys an gdal dataset, using the correct gdal calls.
Definition: qgsogrutils.cpp:57
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:202
static QgsFeature readOgrFeature(OGRFeatureH ogrFet, const QgsFields &fields, QTextCodec *encoding)
Reads an OGR feature and converts it to a QgsFeature.
Definition: qgsogrutils.cpp:87
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false) ...
Definition: qgsfields.cpp:59
static QgsFields stringToFields(const QString &string, QTextCodec *encoding)
Attempts to retrieve the fields from a string representing a collection of features using OGR...
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
void setId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:112
void * GDALDatasetH
static QgsGeometry ogrGeometryToQgsGeometry(OGRGeometryH geom)
Converts an OGR geometry representation to a QgsGeometry object.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition: qgis.h:596
void CORE_EXPORT operator()(GDALWarpOptions *options)
Destroys GDAL warp options, using the correct gdal calls.
Definition: qgsogrutils.cpp:82
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:188
void clearGeometry()
Removes any geometry associated with the feature.
Definition: qgsfeature.cpp:151
static QVariant getOgrFeatureAttribute(OGRFeatureH ogrFet, const QgsFields &fields, int attIndex, QTextCodec *encoding, bool *ok=nullptr)
Retrieves an attribute value from an OGR feature.
std::unique_ptr< QgsLineString > ogrGeometryToQgsLineString(OGRGeometryH geom)
void CORE_EXPORT operator()(OGRGeometryH geometry)
Destroys an OGR geometry, using the correct gdal calls.
Definition: qgsogrutils.cpp:42
void CORE_EXPORT operator()(OGRFieldDefnH definition)
Destroys an OGR field definition, using the correct gdal calls.
Definition: qgsogrutils.cpp:47
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
static QgsWkbTypes::Type ogrGeometryTypeToQgsWkbType(OGRwkbGeometryType ogrGeomType)
Converts a OGRwkbGeometryType to QgsWkbTypes::Type.
static Type zmType(Type type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
Definition: qgswkbtypes.h:529
QVariant::Type subType() const
If the field is a collection, gets its element&#39;s type.
Definition: qgsfield.cpp:100
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:821
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
Definition: qgsogrutils.h:134
std::unique_ptr< std::remove_pointer< OGRDataSourceH >::type, OGRDataSourceDeleter > ogr_datasource_unique_ptr
Scoped OGR data source.
Definition: qgsogrutils.h:114
static QStringList cStringListToQStringList(char **stringList)
Converts a c string list to a QStringList.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:430
QVariant::Type type
Definition: qgsfield.h:56