Skip to content
Permalink
Browse files

Use metadata method to retrieve Shapefile encoding on GDAL 3.1+ builds

Avoids code duplication, correct behavior with vsi* sources
  • Loading branch information
nyalldawson committed Feb 12, 2020
1 parent 5c84d7f commit 54eba4a1b0b7a2312ff70a7cd2096f89fb9f7a74
@@ -75,26 +75,19 @@ void QgsShapefileEncodingInfoAlgorithm::initAlgorithm( const QVariantMap & )
bool QgsShapefileEncodingInfoAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
const QString path = parameterAsFile( parameters, QStringLiteral( "INPUT" ), context );
if ( !QFile::exists( path ) )
{
feedback->reportError( QObject::tr( "Input Shapefile %1 does not exist" ).arg( path ) );
return false;
}

mCpgEncoding = QgsOgrUtils::readShapefileEncodingFromCpg( path );
if ( mCpgEncoding.isEmpty() )
feedback->pushInfo( QObject::tr( "No encoding information present in CPG file" ) );
else
feedback->pushInfo( QObject::tr( "Detected encoding from CPG file: %1" ).arg( mCpgEncoding ) );

mLdidEncoding = QgsOgrUtils::readShapefileEncodingFromLdid( path );
if ( mLdidEncoding.isEmpty() )
feedback->pushInfo( QObject::tr( "No encoding information present in DBF LDID header" ) );
else
{
mCpgEncoding = QgsOgrUtils::readShapefileEncodingFromCpg( path );
if ( mCpgEncoding.isEmpty() )
feedback->pushInfo( QObject::tr( "No encoding information present in CPG file" ) );
else
feedback->pushInfo( QObject::tr( "Detected encoding from CPG file: %1" ).arg( mCpgEncoding ) );

mLdidEncoding = QgsOgrUtils::readShapefileEncodingFromLdid( path );
if ( mLdidEncoding.isEmpty() )
feedback->pushInfo( QObject::tr( "No encoding information present in DBF LDID header" ) );
else
feedback->pushInfo( QObject::tr( "Detected encoding from DBF LDID header: %1" ).arg( mLdidEncoding ) );

}
feedback->pushInfo( QObject::tr( "Detected encoding from DBF LDID header: %1" ).arg( mLdidEncoding ) );

return true;
}

@@ -4537,7 +4537,15 @@ void QgsOgrProvider::open( OpenMode mode )
if ( mode == OpenModeInitial && mGDALDriverName == QLatin1String( "ESRI Shapefile" ) )
{
// determine encoding from shapefile cpg or LDID information, if possible
const QString shpEncoding = QgsOgrUtils::readShapefileEncoding( mFilePath );
QString shpEncoding;
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,1,0)
shpEncoding = mOgrLayer->GetMetadataItem( QStringLiteral( "ENCODING_FROM_CPG" ), QStringLiteral( "SHAPEFILE" ) );
if ( shpEncoding.isEmpty() )
shpEncoding = mOgrLayer->GetMetadataItem( QStringLiteral( "ENCODING_FROM_LDID" ), QStringLiteral( "SHAPEFILE" ) );
#else
shpEncoding = QgsOgrUtils::readShapefileEncoding( mFilePath );
#endif

if ( !shpEncoding.isEmpty() )
setEncoding( shpEncoding );
else
@@ -21,6 +21,7 @@
#include "qgslinestring.h"
#include "qgsmultipoint.h"
#include "qgsmultilinestring.h"
#include "qgsogrprovider.h"
#include <QTextCodec>
#include <QUuid>
#include <cpl_error.h>
@@ -760,8 +761,11 @@ QString QgsOgrUtils::readShapefileEncoding( const QString &path )

QString QgsOgrUtils::readShapefileEncodingFromCpg( const QString &path )
{
// unfortunately OGR's routines for calculating the shapefile encoding aren't exposed anywhere in the GDAL c api, so
// re-implement them here...
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,1,0)
QString errCause;
QgsOgrLayerUniquePtr layer = QgsOgrProviderUtils::getLayer( path, false, QStringList(), 0, errCause, false );
return layer ? layer->GetMetadataItem( QStringLiteral( "ENCODING_FROM_CPG" ), QStringLiteral( "SHAPEFILE" ) ) : QString();
#else
if ( !QFileInfo::exists( path ) )
return QString();

@@ -806,15 +810,17 @@ QString QgsOgrUtils::readShapefileEncodingFromCpg( const QString &path )
}
}
}

#endif
return QString();
}

QString QgsOgrUtils::readShapefileEncodingFromLdid( const QString &path )
{
// unfortunately OGR's routines for calculating the shapefile encoding aren't exposed anywhere in the GDAL c api, so
// re-implement them here...

#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,1,0)
QString errCause;
QgsOgrLayerUniquePtr layer = QgsOgrProviderUtils::getLayer( path, false, QStringList(), 0, errCause, false );
return layer ? layer->GetMetadataItem( QStringLiteral( "ENCODING_FROM_LDID" ), QStringLiteral( "SHAPEFILE" ) ) : QString();
#else
// from OGRShapeLayer::ConvertCodePage
// https://github.com/OSGeo/gdal/blob/master/gdal/ogr/ogrsf_frmts/shape/ogrshapelayer.cpp#L342

@@ -917,4 +923,5 @@ QString QgsOgrUtils::readShapefileEncodingFromLdid( const QString &path )
}
}
return QString();
#endif
}
@@ -2069,7 +2069,6 @@ void TestQgsProcessingAlgs::shapefileEncoding()

QVariantMap results;
results = alg->run( parameters, *context, &feedback, &ok );
QVERIFY( !ok );

parameters.insert( QStringLiteral( "INPUT" ), QStringLiteral( TEST_DATA_DIR ) + "/shapefile/iso-8859-1.shp" );
results = alg->run( parameters, *context, &feedback, &ok );
@@ -662,6 +662,12 @@ def testEncoding(self):
self.assertEqual(vl.dataProvider().encoding(), 'windows-1252')
self.assertEqual(next(vl.getFeatures())[1], 'äöü')

file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'windows-1252.zip')
vl = QgsVectorLayer('/vsizip/{}'.format(file_path))
self.assertTrue(vl.isValid())
self.assertEqual(vl.dataProvider().encoding(), 'windows-1252')
self.assertEqual(next(vl.getFeatures())[1], 'äöü')

file_path = os.path.join(TEST_DATA_DIR, 'shapefile', 'system_encoding.shp')
vl = QgsVectorLayer(file_path)
self.assertTrue(vl.isValid())
Binary file not shown.

0 comments on commit 54eba4a

Please sign in to comment.
You can’t perform that action at this time.