text: #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  #/******************************************************************************
  # * $Id: ogr2ogr.py 24949 2012-09-22 11:12:02Z rouault $
  # *
  # * Project:  OpenGIS Simple Features Reference Implementation
  # * Purpose:  Python port of a simple client for translating between formats.
  # * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  # *
  # * Port from ogr2ogr.cpp whose author is Frank Warmerdam
  # *
  # ******************************************************************************
  # * Copyright (c) 2010, Even Rouault
  # * Copyright (c) 1999, Frank Warmerdam
  # *
  # * Permission is hereby granted, free of charge, to any person obtaining a
  # * copy of this software and associated documentation files (the "Software"),
  # * to deal in the Software without restriction, including without limitation
  # * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  # * and/or sell copies of the Software, and to permit persons to whom the
  # * Software is furnished to do so, subject to the following conditions:
  # *
  # * The above copyright notice and this permission notice shall be included
  # * in all copies or substantial portions of the Software.
  # *
  # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  # * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  # * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  # * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  # * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  # * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  # * DEALINGS IN THE SOFTWARE.
  # ****************************************************************************/
  
  # Note : this is the most direct port of ogr2ogr.cpp possible
  # It could be made much more Python'ish !
  
  import sys
  import os
  import stat
  
  try:
      from osgeo import gdal
      from osgeo import ogr
      from osgeo import osr
  except:
      import gdal
      import ogr
      import osr
  
  ###############################################################################
  
  class ScaledProgressObject:
      def __init__(self, min, max, cbk, cbk_data = None):
          self.min = min
          self.max = max
          self.cbk = cbk
          self.cbk_data = cbk_data
  
  ###############################################################################
  
  def ScaledProgressFunc(pct, msg, data):
      if data.cbk is None:
          return True
      return data.cbk(data.min + pct * (data.max - data.min), msg, data.cbk_data)
  
  ###############################################################################
  
  def EQUAL(a, b):
      return a.lower() == b.lower()
  
  ###############################################################################
  # Redefinition of GDALTermProgress, so that autotest/pyscripts/test_ogr2ogr_py.py
  # can check that the progress bar is displayed
  
  nLastTick = -1
  
  def TermProgress( dfComplete, pszMessage, pProgressArg ):
  
      global nLastTick
      nThisTick = (int) (dfComplete * 40.0)
  
      if nThisTick < 0:
          nThisTick = 0
      if nThisTick > 40:
          nThisTick = 40
  
      # Have we started a new progress run?  
      if nThisTick < nLastTick and nLastTick >= 39:
          nLastTick = -1
  
      if nThisTick <= nLastTick:
          return True
  
      while nThisTick > nLastTick:
          nLastTick = nLastTick + 1
          if (nLastTick % 4) == 0:
              sys.stdout.write('%d' % ((nLastTick / 4) * 10))
          else:
              sys.stdout.write('.')
  
      if nThisTick == 40:
          print(" - done." )
      else:
          sys.stdout.flush()
  
      return True
  
  class TargetLayerInfo:
      def __init__(self):
          self.poDstLayer = None
          self.poCT = None
          #self.papszTransformOptions = None
          self.panMap = None
          self.iSrcZField = None
  
  class AssociatedLayers:
      def __init__(self):
          self.poSrcLayer = None
          self.psInfo = None
  
  #/************************************************************************/
  #/*                                main()                                */
  #/************************************************************************/
  
  bSkipFailures = False
  nGroupTransactions = 200
  bPreserveFID = False
  nFIDToFetch = ogr.NullFID
  
  class Enum(set):
      def __getattr__(self, name):
          if name in self:
              return name
          raise AttributeError
  
  GeomOperation = Enum(["NONE", "SEGMENTIZE", "SIMPLIFY_PRESERVE_TOPOLOGY"])
  
  def main(args = None, progress_func = TermProgress, progress_data = None):
      
      global bSkipFailures
      global nGroupTransactions
      global bPreserveFID
      global nFIDToFetch
      
      pszFormat = "ESRI Shapefile"
      pszDataSource = None
      pszDestDataSource = None
      papszLayers = []
      papszDSCO = []
      papszLCO = []
      bTransform = False
      bAppend = False
      bUpdate = False
      bOverwrite = False
      pszOutputSRSDef = None
      pszSourceSRSDef = None
      poOutputSRS = None
      bNullifyOutputSRS = False
      poSourceSRS = None
      pszNewLayerName = None
      pszWHERE = None
      poSpatialFilter = None
      pszSelect = None
      papszSelFields = None
      pszSQLStatement = None
      eGType = -2
      eGeomOp = GeomOperation.NONE
      dfGeomOpParam = 0
      papszFieldTypesToString = []
      bDisplayProgress = False
      pfnProgress = None
      pProgressArg = None
      bClipSrc = False
      bWrapDateline = False
      poClipSrc = None
      pszClipSrcDS = None
      pszClipSrcSQL = None
      pszClipSrcLayer = None
      pszClipSrcWhere = None
      poClipDst = None
      pszClipDstDS = None
      pszClipDstSQL = None
      pszClipDstLayer = None
      pszClipDstWhere = None
      pszSrcEncoding = None
      pszDstEncoding = None
      bWrapDateline = False
      bExplodeCollections = False
      pszZField = None
      nCoordDim = -1
  
      if args is None:
          args = sys.argv
  
      args = ogr.GeneralCmdLineProcessor( args )
  
  #/* -------------------------------------------------------------------- */
  #/*      Processing command line arguments.                              */
  #/* -------------------------------------------------------------------- */
      if args is None:
          return False
  
      nArgc = len(args)
  
      iArg = 1
      while iArg < nArgc:
          if EQUAL(args[iArg],"-f") and iArg < nArgc-1:
              iArg = iArg + 1
              pszFormat = args[iArg]
  
          elif EQUAL(args[iArg],"-dsco") and iArg < nArgc-1:
              iArg = iArg + 1
              papszDSCO.append(args[iArg] )
  
          elif EQUAL(args[iArg],"-lco") and iArg < nArgc-1:
              iArg = iArg + 1
              papszLCO.append(args[iArg] )
  
          elif EQUAL(args[iArg],"-preserve_fid"):
              bPreserveFID = True
  
          elif len(args[iArg]) >= 5 and EQUAL(args[iArg][0:5], "-skip"):
              bSkipFailures = True
              nGroupTransactions = 1 # /* #2409 */
  
          elif EQUAL(args[iArg],"-append"):
              bAppend = True
              bUpdate = True
  
          elif EQUAL(args[iArg],"-overwrite"):
              bOverwrite = True
              bUpdate = True
  
          elif EQUAL(args[iArg],"-update"):
              bUpdate = True
  
          elif EQUAL(args[iArg],"-fid") and iArg < nArgc-1:
              iArg = iArg + 1
              nFIDToFetch = int(args[iArg])
  
          elif EQUAL(args[iArg],"-sql") and iArg < nArgc-1:
              iArg = iArg + 1
              pszSQLStatement = args[iArg]
  
          elif EQUAL(args[iArg],"-nln") and iArg < nArgc-1:
              iArg = iArg + 1
              pszNewLayerName = args[iArg]
  
          elif EQUAL(args[iArg],"-nlt") and iArg < nArgc-1:
  
              if EQUAL(args[iArg+1],"NONE"):
                  eGType = ogr.wkbNone
              elif EQUAL(args[iArg+1],"GEOMETRY"):
                  eGType = ogr.wkbUnknown
              elif EQUAL(args[iArg+1],"POINT"):
                  eGType = ogr.wkbPoint
              elif EQUAL(args[iArg+1],"LINESTRING"):
                  eGType = ogr.wkbLineString
              elif EQUAL(args[iArg+1],"POLYGON"):
                  eGType = ogr.wkbPolygon
              elif EQUAL(args[iArg+1],"GEOMETRYCOLLECTION"):
                  eGType = ogr.wkbGeometryCollection
              elif EQUAL(args[iArg+1],"MULTIPOINT"):
                  eGType = ogr.wkbMultiPoint
              elif EQUAL(args[iArg+1],"MULTILINESTRING"):
                  eGType = ogr.wkbMultiLineString
              elif EQUAL(args[iArg+1],"MULTIPOLYGON"):
                  eGType = ogr.wkbMultiPolygon
              elif EQUAL(args[iArg+1],"GEOMETRY25D"):
                  eGType = ogr.wkbUnknown | ogr.wkb25DBit
              elif EQUAL(args[iArg+1],"POINT25D"):
                  eGType = ogr.wkbPoint25D
              elif EQUAL(args[iArg+1],"LINESTRING25D"):
                  eGType = ogr.wkbLineString25D
              elif EQUAL(args[iArg+1],"POLYGON25D"):
                  eGType = ogr.wkbPolygon25D
              elif EQUAL(args[iArg+1],"GEOMETRYCOLLECTION25D"):
                  eGType = ogr.wkbGeometryCollection25D
              elif EQUAL(args[iArg+1],"MULTIPOINT25D"):
                  eGType = ogr.wkbMultiPoint25D
              elif EQUAL(args[iArg+1],"MULTILINESTRING25D"):
                  eGType = ogr.wkbMultiLineString25D
              elif EQUAL(args[iArg+1],"MULTIPOLYGON25D"):
                  eGType = ogr.wkbMultiPolygon25D
              else:
                  print("-nlt %s: type not recognised." % args[iArg+1])
                  return False
  
              iArg = iArg + 1
  
          elif EQUAL(args[iArg],"-dim") and iArg < nArgc-1:
  
              nCoordDim = int(args[iArg+1])
              if nCoordDim != 2 and nCoordDim != 3:
                  print("-dim %s: value not handled." % args[iArg+1])
                  return False
              iArg = iArg + 1
  
          elif (EQUAL(args[iArg],"-tg") or \
                  EQUAL(args[iArg],"-gt")) and iArg < nArgc-1:
              iArg = iArg + 1
              nGroupTransactions = int(args[iArg])
  
          elif EQUAL(args[iArg],"-s_srs") and iArg < nArgc-1:
              iArg = iArg + 1
              pszSourceSRSDef = args[iArg]
  
          elif EQUAL(args[iArg],"-a_srs") and iArg < nArgc-1:
              iArg = iArg + 1
              pszOutputSRSDef = args[iArg]
              if EQUAL(pszOutputSRSDef, "NULL") or \
                 EQUAL(pszOutputSRSDef, "NONE"):
                  pszOutputSRSDef = None
                  bNullifyOutputSRS = True
  
          elif EQUAL(args[iArg],"-t_srs") and iArg < nArgc-1:
              iArg = iArg + 1
              pszOutputSRSDef = args[iArg]
              bTransform = True
  
          elif EQUAL(args[iArg],"-spat") and iArg + 4 < nArgc:
              oRing = ogr.Geometry(ogr.wkbLinearRing)
  
              oRing.AddPoint_2D( float(args[iArg+1]), float(args[iArg+2]) )
              oRing.AddPoint_2D( float(args[iArg+1]), float(args[iArg+4]) )
              oRing.AddPoint_2D( float(args[iArg+3]), float(args[iArg+4]) )
              oRing.AddPoint_2D( float(args[iArg+3]), float(args[iArg+2]) )
              oRing.AddPoint_2D( float(args[iArg+1]), float(args[iArg+2]) )
  
              poSpatialFilter = ogr.Geometry(ogr.wkbPolygon)
              poSpatialFilter.AddGeometry(oRing)
              iArg = iArg + 4
  
          elif EQUAL(args[iArg],"-where") and iArg < nArgc-1:
              iArg = iArg + 1
              pszWHERE = args[++iArg]
  
          elif EQUAL(args[iArg],"-select") and iArg < nArgc-1:
              iArg = iArg + 1
              pszSelect = args[iArg]
              if pszSelect.find(',') != -1:
                  papszSelFields = pszSelect.split(',')
              else:
                  papszSelFields = pszSelect.split(' ')
              if papszSelFields[0] == '':
                  papszSelFields = []
  
          elif EQUAL(args[iArg],"-simplify") and iArg < nArgc-1:
              iArg = iArg + 1
              eGeomOp = GeomOperation.SIMPLIFY_PRESERVE_TOPOLOGY
              dfGeomOpParam = float(args[iArg])
  
          elif EQUAL(args[iArg],"-segmentize") and iArg < nArgc-1:
              iArg = iArg + 1
              eGeomOp = GeomOperation.SEGMENTIZE
              dfGeomOpParam = float(args[iArg])
  
          elif EQUAL(args[iArg],"-fieldTypeToString") and iArg < nArgc-1:
              iArg = iArg + 1
              pszFieldTypeToString = args[iArg]
              if pszFieldTypeToString.find(',') != -1:
                  tokens = pszFieldTypeToString.split(',')
              else:
                  tokens = pszFieldTypeToString.split(' ')
  
              for token in tokens:
                  if EQUAL(token,"Integer") or \
                      EQUAL(token,"Real") or \
                      EQUAL(token,"String") or \
                      EQUAL(token,"Date") or \
                      EQUAL(token,"Time") or \
                      EQUAL(token,"DateTime") or \
                      EQUAL(token,"Binary") or \
                      EQUAL(token,"IntegerList") or \
                      EQUAL(token,"RealList") or \
                      EQUAL(token,"StringList"):
  
                      papszFieldTypesToString.append(token)
  
                  elif EQUAL(token,"All"):
                      papszFieldTypesToString = [ 'All' ]
                      break
  
                  else:
                      print("Unhandled type for fieldtypeasstring option : %s " % token)
                      return Usage()
  
          elif EQUAL(args[iArg],"-progress"):
              bDisplayProgress = True
  
          #/*elif EQUAL(args[iArg],"-wrapdateline") )
          #{
          #    bWrapDateline = True;
          #}
          #*/
          elif EQUAL(args[iArg],"-clipsrc") and iArg < nArgc-1:
  
              bClipSrc = True
              if IsNumber(args[iArg+1]) and iArg < nArgc - 4:
                  oRing = ogr.Geometry(ogr.wkbLinearRing)
  
                  oRing.AddPoint_2D( float(args[iArg+1]), float(args[iArg+2]) )
                  oRing.AddPoint_2D( float(args[iArg+1]), float(args[iArg+4]) )
                  oRing.AddPoint_2D( float(args[iArg+3]), float(args[iArg+4]) )
                  oRing.AddPoint_2D( float(args[iArg+3]), float(args[iArg+2]) )
                  oRing.AddPoint_2D( float(args[iArg+1]), float(args[iArg+2]) )
  
                  poClipSrc = ogr.Geometry(ogr.wkbPolygon)
                  poClipSrc.AddGeometry(oRing)
                  iArg = iArg + 4
  
              elif (len(args[iArg+1]) >= 7 and EQUAL(args[iArg+1][0:7],"POLYGON") ) or \
                    (len(args[iArg+1]) >= 12 and EQUAL(args[iArg+1][0:12],"MULTIPOLYGON") ) :
                  poClipSrc = ogr.CreateGeometryFromWkt(args[iArg+1])
                  if poClipSrc is None:
                      print("FAILURE: Invalid geometry. Must be a valid POLYGON or MULTIPOLYGON WKT\n")
                      return Usage()
  
                  iArg = iArg + 1
  
              elif EQUAL(args[iArg+1],"spat_extent"):
                  iArg = iArg + 1
  
              else:
                  pszClipSrcDS = args[iArg+1]
                  iArg = iArg + 1
  
          elif EQUAL(args[iArg],"-clipsrcsql") and iArg < nArgc-1:
              pszClipSrcSQL = args[iArg+1]
              iArg = iArg + 1
  
          elif EQUAL(args[iArg],"-clipsrclayer") and iArg < nArgc-1:
              pszClipSrcLayer = args[iArg+1]
              iArg = iArg + 1
  
          elif EQUAL(args[iArg],"-clipsrcwhere") and iArg < nArgc-1:
              pszClipSrcWhere = args[iArg+1]
              iArg = iArg + 1
  
          elif EQUAL(args[iArg],"-clipdst") and iArg < nArgc-1:
  
              if IsNumber(args[iArg+1]) and iArg < nArgc - 4:
                  oRing = ogr.Geometry(ogr.wkbLinearRing)
  
                  oRing.AddPoint_2D( float(args[iArg+1]), float(args[iArg+2]) )
                  oRing.AddPoint_2D( float(args[iArg+1]), float(args[iArg+4]) )
                  oRing.AddPoint_2D( float(args[iArg+3]), float(args[iArg+4]) )
                  oRing.AddPoint_2D( float(args[iArg+3]), float(args[iArg+2]) )
                  oRing.AddPoint_2D( float(args[iArg+1]), float(args[iArg+2]) )
  
                  poClipDst = ogr.Geometry(ogr.wkbPolygon)
                  poClipDst.AddGeometry(oRing)
                  iArg = iArg + 4
  
              elif (len(args[iArg+1]) >= 7 and EQUAL(args[iArg+1][0:7],"POLYGON") ) or \
                    (len(args[iArg+1]) >= 12 and EQUAL(args[iArg+1][0:12],"MULTIPOLYGON") ) :
                  poClipDst = ogr.CreateGeometryFromWkt(args[iArg+1])
                  if poClipDst is None:
                      print("FAILURE: Invalid geometry. Must be a valid POLYGON or MULTIPOLYGON WKT\n")
                      return Usage()
  
                  iArg = iArg + 1
  
              elif EQUAL(args[iArg+1],"spat_extent"):
                  iArg = iArg + 1
  
              else:
                  pszClipDstDS = args[iArg+1]
                  iArg = iArg + 1
  
          elif EQUAL(args[iArg],"-clipdstsql") and iArg < nArgc-1:
              pszClipDstSQL = args[iArg+1]
              iArg = iArg + 1
  
          elif EQUAL(args[iArg],"-clipdstlayer") and iArg < nArgc-1:
              pszClipDstLayer = args[iArg+1]
              iArg = iArg + 1
  
          elif EQUAL(args[iArg],"-clipdstwhere") and iArg < nArgc-1:
              pszClipDstWhere = args[iArg+1]
              iArg = iArg + 1
  
          elif EQUAL(args[iArg],"-explodecollections"):
              bExplodeCollections = True
  
          elif EQUAL(args[iArg],"-zfield") and iArg < nArgc-1:
              pszZField = args[iArg+1]
              iArg = iArg + 1
  
          elif args[iArg][0] == '-':
              return Usage()
  
          elif pszDestDataSource is None:
              pszDestDataSource = args[iArg]
          elif pszDataSource is None:
              pszDataSource = args[iArg]
          else:
              papszLayers.append (args[iArg] )
  
          iArg = iArg + 1
  
      if pszDataSource is None:
          return Usage()
  
      if bPreserveFID and bExplodeCollections:
          print("FAILURE: cannot use -preserve_fid and -explodecollections at the same time\n\n")
          return Usage()
  
      if bClipSrc and pszClipSrcDS is not None:
          poClipSrc = LoadGeometry(pszClipSrcDS, pszClipSrcSQL, pszClipSrcLayer, pszClipSrcWhere)
          if poClipSrc is None:
              print("FAILURE: cannot load source clip geometry\n" )
              return Usage()
  
      elif bClipSrc and poClipSrc is None:
          if poSpatialFilter is not None:
              poClipSrc = poSpatialFilter.Clone()
          if poClipSrc is None:
              print("FAILURE: -clipsrc must be used with -spat option or a\n" + \
                    "bounding box, WKT string or datasource must be specified\n")
              return Usage()
  
      if pszClipDstDS is not None:
          poClipDst = LoadGeometry(pszClipDstDS, pszClipDstSQL, pszClipDstLayer, pszClipDstWhere)
          if poClipDst is None:
              print("FAILURE: cannot load dest clip geometry\n" )
              return Usage()
  
  #/* -------------------------------------------------------------------- */
  #/*      Open data source.                                               */
  #/* -------------------------------------------------------------------- */
      poDS = ogr.Open( pszDataSource, False )
  
  #/* -------------------------------------------------------------------- */
  #/*      Report failure                                                  */
  #/* -------------------------------------------------------------------- */
      if poDS is None:
          print("FAILURE:\n" + \
                  "Unable to open datasource `%s' with the following drivers." % pszDataSource)
  
          for iDriver in range(ogr.GetDriverCount()):
              print("  ->  " + ogr.GetDriver(iDriver).GetName() )
  
          return False
  
  #/* -------------------------------------------------------------------- */
  #/*      Try opening the output datasource as an existing, writable      */
  #/* -------------------------------------------------------------------- */
      poODS = None
      poDriver = None
  
      if bUpdate:
          poODS = ogr.Open( pszDestDataSource, True )
          if poODS is None:
  
              if bOverwrite or bAppend:
                  poODS = ogr.Open( pszDestDataSource, False )
                  if poODS is None:
                      # /* ok the datasource doesn't exist at all */
                      bUpdate = False
                  else:
                      poODS.delete()
                      poODS = None
  
              if bUpdate:
                  print("FAILURE:\n" +
                          "Unable to open existing output datasource `%s'." % pszDestDataSource)
                  return False
  
          elif len(papszDSCO) > 0:
              print("WARNING: Datasource creation options ignored since an existing datasource\n" + \
                      "         being updated." )
  
          if poODS is not None:
              poDriver = poODS.GetDriver()
  
  #/* -------------------------------------------------------------------- */
  #/*      Find the output driver.                                         */
  #/* -------------------------------------------------------------------- */
      if not bUpdate:
          poDriver = ogr.GetDriverByName(pszFormat)
          if poDriver is None:
              print("Unable to find driver `%s'." % pszFormat)
              print( "The following drivers are available:" )
  
              for iDriver in range(ogr.GetDriverCount()):
                  print("  ->  %s" % ogr.GetDriver(iDriver).GetName() )
  
              return False
  
          if poDriver.TestCapability( ogr.ODrCCreateDataSource ) == False:
              print( "%s driver does not support data source creation." % pszFormat)
              return False
  
  #/* -------------------------------------------------------------------- */
  #/*      Special case to improve user experience when translating        */
  #/*      a datasource with multiple layers into a shapefile. If the      */
  #/*      user gives a target datasource with .shp and it does not exist, */
  #/*      the shapefile driver will try to create a file, but this is not */
  #/*      appropriate because here we have several layers, so create      */
  #/*      a directory instead.                                            */
  #/* -------------------------------------------------------------------- */
          if EQUAL(poDriver.GetName(), "ESRI Shapefile") and \
             pszSQLStatement is None and \
             (len(papszLayers) > 1 or \
              (len(papszLayers) == 0 and poDS.GetLayerCount() > 1)) and \
              pszNewLayerName is None and \
              EQUAL(os.path.splitext(pszDestDataSource)[1], ".SHP") :
  
              try:
                  os.stat(pszDestDataSource)
              except:
                  try:
                      # decimal 493 = octal 0755. Python 3 needs 0o755, but
                      # this syntax is only supported by Python >= 2.6
                      os.mkdir(pszDestDataSource, 493)
                  except:
                      print("Failed to create directory %s\n"
                            "for shapefile datastore.\n" % pszDestDataSource )
                      return False
  
  #/* -------------------------------------------------------------------- */
  #/*      Create the output data source.                                  */
  #/* -------------------------------------------------------------------- */
          poODS = poDriver.CreateDataSource( pszDestDataSource, options = papszDSCO )
          if poODS is None:
              print( "%s driver failed to create %s" % (pszFormat, pszDestDataSource ))
              return False
  
  #/* -------------------------------------------------------------------- */
  #/*      Parse the output SRS definition if possible.                    */
  #/* -------------------------------------------------------------------- */
      if pszOutputSRSDef is not None:
          poOutputSRS = osr.SpatialReference()
          if poOutputSRS.SetFromUserInput( pszOutputSRSDef ) != 0:
              print( "Failed to process SRS definition: %s" % pszOutputSRSDef )
              return False
  
  #/* -------------------------------------------------------------------- */
  #/*      Parse the source SRS definition if possible.                    */
  #/* -------------------------------------------------------------------- */
      if pszSourceSRSDef is not None:
          poSourceSRS = osr.SpatialReference()
          if poSourceSRS.SetFromUserInput( pszSourceSRSDef ) != 0:
              print( "Failed to process SRS definition: %s" % pszSourceSRSDef )
              return False
  
  #/* -------------------------------------------------------------------- */
  #/*      For OSM file.                                                   */
  #/* -------------------------------------------------------------------- */
      bSrcIsOSM = poDS.GetDriver() is not None and \
                               poDS.GetDriver().GetName() == "OSM"
      nSrcFileSize = 0
      if bSrcIsOSM and poDS.GetName() != "/vsistdin/":
          sStat = gdal.VSIStatL(poDS.GetName())
          if sStat is not None:
              nSrcFileSize = sStat.size
  
  #/* -------------------------------------------------------------------- */
  #/*      Special case for -sql clause.  No source layers required.       */
  #/* -------------------------------------------------------------------- */
      if pszSQLStatement is not None:
          if pszWHERE is not None:
              print( "-where clause ignored in combination with -sql." )
          if len(papszLayers) > 0:
              print( "layer names ignored in combination with -sql." )
  
          poResultSet = poDS.ExecuteSQL( pszSQLStatement, poSpatialFilter, \
                                          None )
  
          if poResultSet is not None:
              nCountLayerFeatures = 0
              if bDisplayProgress:
                  if bSrcIsOSM:
                      pfnProgress = progress_func
                      pProgressArg = progress_data
  
                  elif not poResultSet.TestCapability(ogr.OLCFastFeatureCount):
                      print( "Progress turned off as fast feature count is not available.")
                      bDisplayProgress = False
  
                  else:
                      nCountLayerFeatures = poResultSet.GetFeatureCount()
                      pfnProgress = progress_func
                      pProgressArg = progress_data
  
  #/* -------------------------------------------------------------------- */
  #/*      Special case to improve user experience when translating into   */
  #/*      single file shapefile and source has only one layer, and that   */
  #/*      the layer name isn't specified                                  */
  #/* -------------------------------------------------------------------- */
              if EQUAL(poDriver.GetName(), "ESRI Shapefile") and \
                  pszNewLayerName is None:
                  try:
                      mode = os.stat(pszDestDataSource).st_mode
                      if (mode & stat.S_IFDIR) == 0:
                          pszNewLayerName = os.path.splitext(os.path.basename(pszDestDataSource))[0]
                  except:
                      pass
  
  
              psInfo = SetupTargetLayer(  poDS, \
                                          poResultSet,
                                          poODS, \
                                          papszLCO, \
                                          pszNewLayerName, \
                                          bTransform, \
                                          poOutputSRS, \
                                          bNullifyOutputSRS, \
                                          poSourceSRS, \
                                          papszSelFields, \
                                          bAppend, eGType, nCoordDim, bOverwrite, \
                                          papszFieldTypesToString, \
                                          bWrapDateline, \
                                          bExplodeCollections, \
                                          pszZField, \
                                          pszWHERE )
  
              poResultSet.ResetReading()
  
              if psInfo is None or not TranslateLayer( psInfo, poDS, poResultSet, poODS, \
                                  poOutputSRS, bNullifyOutputSRS, \
                                  eGType, nCoordDim, \
                                  eGeomOp, dfGeomOpParam, \
                                  nCountLayerFeatures, \
                                  poClipSrc, poClipDst, \
                                  bExplodeCollections, \
                                  nSrcFileSize, None, \
                                  pfnProgress, pProgressArg ):
                  print(
                          "Terminating translation prematurely after failed\n" + \
                          "translation from sql statement." )
  
                  return False
  
              poDS.ReleaseResultSet( poResultSet )
  
  
  #/* -------------------------------------------------------------------- */
  #/*      Special case for layer interleaving mode.                       */
  #/* -------------------------------------------------------------------- */
      elif bSrcIsOSM and gdal.GetConfigOption("OGR_INTERLEAVED_READING", None) is None:
  
          gdal.SetConfigOption("OGR_INTERLEAVED_READING", "YES")
  
          #if (bSplitListFields)
          #{
          #    fprintf( stderr, "FAILURE: -splitlistfields not supported in this mode\n" );
          #    exit( 1 );
          #}
  
          nSrcLayerCount = poDS.GetLayerCount()
          pasAssocLayers = [ AssociatedLayers() for i in range(nSrcLayerCount) ]
  
  #/* -------------------------------------------------------------------- */
  #/*      Special case to improve user experience when translating into   */
  #/*      single file shapefile and source has only one layer, and that   */
  #/*      the layer name isn't specified                                  */
  #/* -------------------------------------------------------------------- */
  
          if EQUAL(poDriver.GetName(), "ESRI Shapefile") and \
             (len(papszLayers) == 1 or nSrcLayerCount == 1) and pszNewLayerName is None:
              try:
                  mode = os.stat(pszDestDataSource).st_mode
                  if (mode & stat.S_IFDIR) == 0:
                      pszNewLayerName = os.path.splitext(os.path.basename(pszDestDataSource))[0]
              except:
                  pass
  
          if bDisplayProgress and bSrcIsOSM:
              pfnProgress = progress_func
              pProgressArg = progress_data
  
  #/* -------------------------------------------------------------------- */
  #/*      If no target layer specified, use all source layers.            */
  #/* -------------------------------------------------------------------- */
          if len(papszLayers) == 0:
              papszLayers = [ None for i in range(nSrcLayerCount) ]
              for iLayer in range(nSrcLayerCount):
                  poLayer = poDS.GetLayer(iLayer)
                  if poLayer is None:
                      print("FAILURE: Couldn't fetch advertised layer %d!" % iLayer)
                      return False
  
                  papszLayers[iLayer] = poLayer.GetName()
          else:
              if bSrcIsOSM:
                  osInterestLayers = "SET interest_layers ="
                  for iLayer in range(len(papszLayers)):
                      if iLayer != 0:
                          osInterestLayers = osInterestLayers + ","
                      osInterestLayers = osInterestLayers + papszLayers[iLayer]
  
                  poDS.ExecuteSQL(osInterestLayers, None, None)
  
  #/* -------------------------------------------------------------------- */
  #/*      First pass to set filters and create target layers.             */
  #/* -------------------------------------------------------------------- */
          for iLayer in range(nSrcLayerCount):
              poLayer = poDS.GetLayer(iLayer)
              if poLayer is None:
                  print("FAILURE: Couldn't fetch advertised layer %d!" % iLayer)
                  return False
  
              pasAssocLayers[iLayer].poSrcLayer = poLayer
  
              if CSLFindString(papszLayers, poLayer.GetName()) >= 0:
                  if pszWHERE is not None:
                      if poLayer.SetAttributeFilter( pszWHERE ) != 0:
                          print("FAILURE: SetAttributeFilter(%s) on layer '%s' failed.\n" % (pszWHERE, poLayer.GetName()) )
                          if not bSkipFailures:
                              return False
  
                  if poSpatialFilter is not None:
                      poLayer.SetSpatialFilter( poSpatialFilter )
  
                  psInfo = SetupTargetLayer( poDS, \
                                             poLayer, \
                                             poODS, \
                                             papszLCO, \
                                             pszNewLayerName, \
                                             bTransform, \
                                             poOutputSRS, \
                                             bNullifyOutputSRS, \
                                             poSourceSRS, \
                                             papszSelFields, \
                                             bAppend, eGType, nCoordDim, bOverwrite, \
                                             papszFieldTypesToString, \
                                             bWrapDateline, \
                                             bExplodeCollections, \
                                             pszZField, \
                                             pszWHERE )
  
                  if psInfo is None and not bSkipFailures:
                      return False
  
                  pasAssocLayers[iLayer].psInfo = psInfo
              else:
                  pasAssocLayers[iLayer].psInfo = None
  
  #/* -------------------------------------------------------------------- */
  #/*      Second pass to process features in a interleaved layer mode.    */
  #/* -------------------------------------------------------------------- */
          bHasLayersNonEmpty = True
          while bHasLayersNonEmpty:
              bHasLayersNonEmpty = False
  
              for iLayer in range(nSrcLayerCount):
                  poLayer = pasAssocLayers[iLayer].poSrcLayer
                  psInfo = pasAssocLayers[iLayer].psInfo
                  anReadFeatureCount = [0]
  
                  if psInfo is not None:
                      if not TranslateLayer(psInfo, poDS, poLayer, poODS, \
                                          poOutputSRS, bNullifyOutputSRS,  \
                                          eGType, nCoordDim, \
                                          eGeomOp, dfGeomOpParam,  \
                                          0,  \
                                          poClipSrc, poClipDst,  \
                                          bExplodeCollections,  \
                                          nSrcFileSize,  \
                                          anReadFeatureCount, \
                                          pfnProgress, pProgressArg ) \
                          and not bSkipFailures:
                          print(
                                  "Terminating translation prematurely after failed\n" + \
                                  "translation of layer " + poLayer.GetName() + " (use -skipfailures to skip errors)")
  
                          return False
                  else:
                      #/* No matching target layer : just consumes the features */
  
                      poFeature = poLayer.GetNextFeature()
                      while poFeature is not None:
                          anReadFeatureCount[0] = anReadFeatureCount[0] + 1
                          poFeature = poLayer.GetNextFeature()
  
                  if anReadFeatureCount[0] != 0:
                      bHasLayersNonEmpty = True
  
      else:
  
          nLayerCount = 0
          papoLayers = []
  
  #/* -------------------------------------------------------------------- */
  #/*      Process each data source layer.                                 */
  #/* -------------------------------------------------------------------- */
          if len(papszLayers) == 0:
              nLayerCount = poDS.GetLayerCount()
              papoLayers = [None for i in range(nLayerCount)]
              iLayer = 0
  
              for iLayer in range(nLayerCount):
                  poLayer = poDS.GetLayer(iLayer)
  
                  if poLayer is None:
                      print("FAILURE: Couldn't fetch advertised layer %d!" % iLayer)
                      return False
  
                  papoLayers[iLayer] = poLayer
                  iLayer = iLayer + 1
  
  #/* -------------------------------------------------------------------- */
  #/*      Process specified data source layers.                           */
  #/* -------------------------------------------------------------------- */
          else:
              nLayerCount = len(papszLayers)
              papoLayers = [None for i in range(nLayerCount)]
              iLayer = 0
  
              for layername in papszLayers:
                  poLayer = poDS.GetLayerByName(layername)
  
                  if poLayer is None:
                      print("FAILURE: Couldn't fetch advertised layer %s!" % layername)
                      return False
  
                  papoLayers[iLayer] = poLayer
                  iLayer = iLayer + 1
  
          panLayerCountFeatures = [0 for i in range(nLayerCount)]
          nCountLayersFeatures = 0
          nAccCountFeatures = 0
  
          #/* First pass to apply filters and count all features if necessary */
          for iLayer in range(nLayerCount):
              poLayer = papoLayers[iLayer]
  
              if pszWHERE is not None:
                  if poLayer.SetAttributeFilter( pszWHERE ) != 0:
                      print("FAILURE: SetAttributeFilter(%s) failed." % pszWHERE)
                      if not bSkipFailures:
                          return False
  
              if poSpatialFilter is not None:
                  poLayer.SetSpatialFilter( poSpatialFilter )
  
              if bDisplayProgress and not bSrcIsOSM:
                  if not poLayer.TestCapability(ogr.OLCFastFeatureCount):
                      print("Progress turned off as fast feature count is not available.")
                      bDisplayProgress = False
                  else:
                      panLayerCountFeatures[iLayer] = poLayer.GetFeatureCount()
                      nCountLayersFeatures += panLayerCountFeatures[iLayer]
  
          #/* Second pass to do the real job */
          for iLayer in range(nLayerCount):
              poLayer = papoLayers[iLayer]
  
              if bDisplayProgress:
                  if bSrcIsOSM:
                      pfnProgress = progress_func
                      pProgressArg = progress_data
                  else:
                      pfnProgress = ScaledProgressFunc
                      pProgressArg = ScaledProgressObject( \
                              nAccCountFeatures * 1.0 / nCountLayersFeatures, \
                              (nAccCountFeatures + panLayerCountFeatures[iLayer]) * 1.0 / nCountLayersFeatures, \
                              progress_func, progress_data)
  
              nAccCountFeatures += panLayerCountFeatures[iLayer]
  
  #/* -------------------------------------------------------------------- */
  #/*      Special case to improve user experience when translating into   */
  #/*      single file shapefile and source has only one layer, and that   */
  #/*      the layer name isn't specified                                  */
  #/* -------------------------------------------------------------------- */
              if EQUAL(poDriver.GetName(), "ESRI Shapefile") and \
                  nLayerCount == 1 and pszNewLayerName is None:
                  try:
                      mode = os.stat(pszDestDataSource).st_mode
                      if (mode & stat.S_IFDIR) == 0:
                          pszNewLayerName = os.path.splitext(os.path.basename(pszDestDataSource))[0]
                  except:
                      pass
  
  
              psInfo = SetupTargetLayer( poDS, \
                                         poLayer, \
                                         poODS, \
                                         papszLCO, \
                                         pszNewLayerName, \
                                         bTransform, \
                                         poOutputSRS, \
                                         bNullifyOutputSRS, \
                                         poSourceSRS, \
                                         papszSelFields, \
                                         bAppend, eGType, nCoordDim, bOverwrite, \
                                         papszFieldTypesToString, \
                                         bWrapDateline, \
                                         bExplodeCollections, \
                                         pszZField, \
                                         pszWHERE )
  
              poLayer.ResetReading()
  
              if (psInfo is None or \
                  not TranslateLayer( psInfo, poDS, poLayer, poODS, \
                                      poOutputSRS, bNullifyOutputSRS, \
                                      eGType, nCoordDim, \
                                      eGeomOp, dfGeomOpParam, \
                                      panLayerCountFeatures[iLayer], \
                                      poClipSrc, poClipDst, \
                                      bExplodeCollections, \
                                      nSrcFileSize, None, \
                                      pfnProgress, pProgressArg )) \
                  and not bSkipFailures:
                  print(
                          "Terminating translation prematurely after failed\n" + \
                          "translation of layer " + poLayer.GetLayerDefn().GetName() + " (use -skipfailures to skip errors)")
  
                  return False
  
  #/* -------------------------------------------------------------------- */
  #/*      Close down.                                                     */
  #/* -------------------------------------------------------------------- */
      #/* We must explicetely destroy the output dataset in order the file */
      #/* to be properly closed ! */
      poODS.Destroy()
      poDS.Destroy()
  
      return True
  
  #/************************************************************************/
  #/*                               Usage()                                */
  #/************************************************************************/
  
  def Usage():
  
      print( "Usage: ogr2ogr [--help-general] [-skipfailures] [-append] [-update] [-gt n]\n" + \
              "               [-select field_list] [-where restricted_where] \n" + \
              "               [-progress] [-sql <sql statement>] \n" + \
              "               [-spat xmin ymin xmax ymax] [-preserve_fid] [-fid FID]\n" + \
              "               [-a_srs srs_def] [-t_srs srs_def] [-s_srs srs_def]\n" + \
              "               [-f format_name] [-overwrite] [[-dsco NAME=VALUE] ...]\n" + \
              "               [-simplify tolerance]\n" + \
              #// "               [-segmentize max_dist] [-fieldTypeToString All|(type1[,type2]*)]\n" + \
              "               [-fieldTypeToString All|(type1[,type2]*)] [-explodecollections] \n" + \
              "               dst_datasource_name src_datasource_name\n" + \
              "               [-lco NAME=VALUE] [-nln name] [-nlt type] [-dim 2|3] [layer [layer ...]]\n" + \
              "\n" + \
              " -f format_name: output file format name, possible values are:")
  
      for iDriver in range(ogr.GetDriverCount()):
          poDriver = ogr.GetDriver(iDriver)
  
          if poDriver.TestCapability( ogr.ODrCCreateDataSource ):
              print( "     -f \"" + poDriver.GetName() + "\"" )
  
      print( " -append: Append to existing layer instead of creating new if it exists\n" + \
              " -overwrite: delete the output layer and recreate it empty\n" + \
              " -update: Open existing output datasource in update mode\n" + \
              " -progress: Display progress on terminal. Only works if input layers have the \"fast feature count\" capability\n" + \
              " -select field_list: Comma-delimited list of fields from input layer to\n" + \
              "                     copy to the new layer (defaults to all)\n" + \
              " -where restricted_where: Attribute query (like SQL WHERE)\n" + \
              " -sql statement: Execute given SQL statement and save result.\n" + \
              " -skipfailures: skip features or layers that fail to convert\n" + \
              " -gt n: group n features per transaction (default 200)\n" + \
              " -spat xmin ymin xmax ymax: spatial query extents\n" + \
              " -simplify tolerance: distance tolerance for simplification.\n" + \
              #//" -segmentize max_dist: maximum distance between 2 nodes.\n" + \
              #//"                       Used to create intermediate points\n" + \
              " -dsco NAME=VALUE: Dataset creation option (format specific)\n" + \
              " -lco  NAME=VALUE: Layer creation option (format specific)\n" + \
              " -nln name: Assign an alternate name to the new layer\n" + \
              " -nlt type: Force a geometry type for new layer.  One of NONE, GEOMETRY,\n" + \
              "      POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, MULTIPOINT,\n" + \
              "      MULTIPOLYGON, or MULTILINESTRING.  Add \"25D\" for 3D layers.\n" + \
              "      Default is type of source layer.\n" + \
              " -dim dimension: Force the coordinate dimension to the specified value.\n" + \
              " -fieldTypeToString type1,...: Converts fields of specified types to\n" + \
              "      fields of type string in the new layer. Valid types are : \n" + \
              "      Integer, Real, String, Date, Time, DateTime, Binary, IntegerList, RealList,\n" + \
              "      StringList. Special value All can be used to convert all fields to strings.")
  
      print(" -a_srs srs_def: Assign an output SRS\n" + \
          " -t_srs srs_def: Reproject/transform to this SRS on output\n" + \
          " -s_srs srs_def: Override source SRS\n" + \
          "\n" + \
          " Srs_def can be a full WKT definition (hard to escape properly),\n" + \
          " or a well known definition (ie. EPSG:4326) or a file with a WKT\n" + \
          " definition." )
  
      return False
  
  def CSLFindString(v, mystr):
      i = 0
      for strIter in v:
          if EQUAL(strIter, mystr):
              return i
          i = i + 1
      return -1
  
  def IsNumber( pszStr):
      try:
          (float)(pszStr)
          return True
      except:
          return False
  
  def LoadGeometry( pszDS, pszSQL, pszLyr, pszWhere):
      poGeom = None
  
      poDS = ogr.Open( pszDS, False )
      if poDS is None:
          return None
  
      if pszSQL is not None:
          poLyr = poDS.ExecuteSQL( pszSQL, None, None )
      elif pszLyr is not None:
          poLyr = poDS.GetLayerByName(pszLyr)
      else:
          poLyr = poDS.GetLayer(0)
  
      if poLyr is None:
          print("Failed to identify source layer from datasource.")
          poDS.Destroy()
          return None
  
      if pszWhere is not None:
          poLyr.SetAttributeFilter(pszWhere)
  
      poFeat = poLyr.GetNextFeature()
      while poFeat is not None:
          poSrcGeom = poFeat.GetGeometryRef()
          if poSrcGeom is not None:
              eType = wkbFlatten(poSrcGeom.GetGeometryType())
  
              if poGeom is None:
                  poGeom = ogr.Geometry( ogr.wkbMultiPolygon )
  
              if eType == ogr.wkbPolygon:
                  poGeom.AddGeometry( poSrcGeom )
              elif eType == ogr.wkbMultiPolygon:
                  for iGeom in range(poSrcGeom.GetGeometryCount()):
                      poGeom.AddGeometry(poSrcGeom.GetGeometryRef(iGeom) )
  
              else:
                  print("ERROR: Geometry not of polygon type." )
                  if pszSQL is not None:
                      poDS.ReleaseResultSet( poLyr )
                  poDS.Destroy()
                  return None
  
          poFeat = poLyr.GetNextFeature()
  
      if pszSQL is not None:
          poDS.ReleaseResultSet( poLyr )
      poDS.Destroy()
  
      return poGeom
  
  
  def wkbFlatten(x):
      return x & (~ogr.wkb25DBit)
  
  #/************************************************************************/
  #/*                               SetZ()                                 */
  #/************************************************************************/
  
  def SetZ (poGeom, dfZ ):
  
      if poGeom is None:
          return
  
      eGType = wkbFlatten(poGeom.GetGeometryType())
      if eGType == ogr.wkbPoint:
          poGeom.SetPoint(0, poGeom.GetX(), poGeom.GetY(), dfZ)
  
      elif eGType == ogr.wkbLineString or \
           eGType == ogr.wkbLinearRing:
          for i in range(poGeom.GetPointCount()):
              poGeom.SetPoint(i, poGeom.GetX(i), poGeom.GetY(i), dfZ)
  
      elif eGType == ogr.wkbPolygon or \
           eGType == ogr.wkbMultiPoint or \
           eGType == ogr.wkbMultiLineString or \
           eGType == ogr.wkbMultiPolygon or \
           eGType == ogr.wkbGeometryCollection:
          for i in range(poGeom.GetGeometryCount()):
              SetZ(poGeom.GetGeometryRef(i), dfZ)
  
  #/************************************************************************/
  #/*                         SetupTargetLayer()                           */
  #/************************************************************************/
  
  def SetupTargetLayer( poSrcDS, poSrcLayer, poDstDS, papszLCO, pszNewLayerName, \
                      bTransform,  poOutputSRS, bNullifyOutputSRS, poSourceSRS, papszSelFields, \
                      bAppend, eGType, nCoordDim, bOverwrite, \
                      papszFieldTypesToString, bWrapDateline, \
                      bExplodeCollections, pszZField, pszWHERE) :
  
      if pszNewLayerName is None:
          pszNewLayerName = poSrcLayer.GetLayerDefn().GetName()
  
  #/* -------------------------------------------------------------------- */
  #/*      Setup coordinate transformation if we need it.                  */
  #/* -------------------------------------------------------------------- */
      poCT = None
  
      if bTransform:
          if poSourceSRS is None:
              poSourceSRS = poSrcLayer.GetSpatialRef()
  
          if poSourceSRS is None:
              print("Can't transform coordinates, source layer has no\n" + \
                      "coordinate system.  Use -s_srs to set one." )
              return None
  
          poCT = osr.CoordinateTransformation( poSourceSRS, poOutputSRS )
          if gdal.GetLastErrorMsg().find( 'Unable to load PROJ.4 library' ) != -1:
              poCT = None
  
          if poCT is None:
              pszWKT = None
  
              print("Failed to create coordinate transformation between the\n" + \
                  "following coordinate systems.  This may be because they\n" + \
                  "are not transformable, or because projection services\n" + \
                  "(PROJ.4 DLL/.so) could not be loaded." )
  
              pszWKT = poSourceSRS.ExportToPrettyWkt( 0 )
              print( "Source:\n" + pszWKT )
  
              pszWKT = poOutputSRS.ExportToPrettyWkt( 0 )
              print( "Target:\n" + pszWKT )
              return None
  
  #/* -------------------------------------------------------------------- */
  #/*      Get other info.                                                 */
  #/* -------------------------------------------------------------------- */
      poSrcFDefn = poSrcLayer.GetLayerDefn()
  
      if poOutputSRS is None and not bNullifyOutputSRS:
          poOutputSRS = poSrcLayer.GetSpatialRef()
  
  #/* -------------------------------------------------------------------- */
  #/*      Find the layer.                                                 */
  #/* -------------------------------------------------------------------- */
  
      #/* GetLayerByName() can instanciate layers that would have been */
      #*/ 'hidden' otherwise, for example, non-spatial tables in a */
      #*/ Postgis-enabled database, so this apparently useless command is */
      #/* not useless... (#4012) */
      gdal.PushErrorHandler('CPLQuietErrorHandler')
      poDstLayer = poDstDS.GetLayerByName(pszNewLayerName)
      gdal.PopErrorHandler()
      gdal.ErrorReset()
  
      iLayer = -1
      if poDstLayer is not None:
          nLayerCount = poDstDS.GetLayerCount()
          for iLayer in range(nLayerCount):
              poLayer = poDstDS.GetLayer(iLayer)
              # The .cpp version compares on pointers directly, but we cannot
              # do this with swig object, so just compare the names.
              if poLayer is not None \
                  and poLayer.GetName() == poDstLayer.GetName():
                  break
  
          if (iLayer == nLayerCount):
              # /* shouldn't happen with an ideal driver */
              poDstLayer = None
  
  #/* -------------------------------------------------------------------- */
  #/*      If the user requested overwrite, and we have the layer in       */
  #/*      question we need to delete it now so it will get recreated      */
  #/*      (overwritten).                                                  */
  #/* -------------------------------------------------------------------- */
      if poDstLayer is not None and bOverwrite:
          if poDstDS.DeleteLayer( iLayer ) != 0:
              print("DeleteLayer() failed when overwrite requested." )
              return None
  
          poDstLayer = None
  
  #/* -------------------------------------------------------------------- */
  #/*      If the layer does not exist, then create it.                    */
  #/* -------------------------------------------------------------------- */
      if poDstLayer is None:
          if eGType == -2:
              eGType = poSrcFDefn.GetGeomType()
  
              if bExplodeCollections:
                  n25DBit = eGType & ogr.wkb25DBit
                  if wkbFlatten(eGType) == ogr.wkbMultiPoint:
                      eGType = ogr.wkbPoint | n25DBit
                  elif wkbFlatten(eGType) == ogr.wkbMultiLineString:
                      eGType = ogr.wkbLineString | n25DBit
                  elif wkbFlatten(eGType) == ogr.wkbMultiPolygon:
                      eGType = ogr.wkbPolygon | n25DBit
                  elif wkbFlatten(eGType) == ogr.wkbGeometryCollection:
                      eGType = ogr.wkbUnknown | n25DBit
  
              if pszZField is not None:
                  eGType = eGType | ogr.wkb25DBit
  
          if nCoordDim == 2:
              eGType = eGType & ~ogr.wkb25DBit
          elif nCoordDim == 3:
              eGType = eGType | ogr.wkb25DBit
  
          if poDstDS.TestCapability( ogr.ODsCCreateLayer ) == False:
              print("Layer " + pszNewLayerName + "not found, and CreateLayer not supported by driver.")
              return None
  
          gdal.ErrorReset()
  
          poDstLayer = poDstDS.CreateLayer( pszNewLayerName, poOutputSRS, \
                                              eGType, papszLCO )
  
          if poDstLayer is None:
              return None
  
          bAppend = False
  
  #/* -------------------------------------------------------------------- */
  #/*      Otherwise we will append to it, if append was requested.        */
  #/* -------------------------------------------------------------------- */
      elif not bAppend:
          print("FAILED: Layer " + pszNewLayerName + "already exists, and -append not specified.\n" + \
                              "        Consider using -append, or -overwrite.")
          return None
      else:
          if len(papszLCO) > 0:
              print("WARNING: Layer creation options ignored since an existing layer is\n" + \
                      "         being appended to." )
  
  #/* -------------------------------------------------------------------- */
  #/*      Add fields.  Default to copy all field.                         */
  #/*      If only a subset of all fields requested, then output only      */
  #/*      the selected fields, and in the order that they were            */
  #/*      selected.                                                       */
  #/* -------------------------------------------------------------------- */
  
      # Initialize the index-to-index map to -1's
      nSrcFieldCount = poSrcFDefn.GetFieldCount()
      panMap = [ -1 for i in range(nSrcFieldCount) ]
  
      poDstFDefn = poDstLayer.GetLayerDefn()
  
      if papszSelFields is not None and not bAppend:
  
          nDstFieldCount = 0
          if poDstFDefn is not None:
              nDstFieldCount = poDstFDefn.GetFieldCount()
  
          for iField in range(len(papszSelFields)):
  
              iSrcField = poSrcFDefn.GetFieldIndex(papszSelFields[iField])
              if iSrcField >= 0:
                  poSrcFieldDefn = poSrcFDefn.GetFieldDefn(iSrcField)
                  oFieldDefn = ogr.FieldDefn( poSrcFieldDefn.GetNameRef(),
                                              poSrcFieldDefn.GetType() )
                  oFieldDefn.SetWidth( poSrcFieldDefn.GetWidth() )
                  oFieldDefn.SetPrecision( poSrcFieldDefn.GetPrecision() )
  
                  if papszFieldTypesToString is not None and \
                      (CSLFindString(papszFieldTypesToString, "All") != -1 or \
                      CSLFindString(papszFieldTypesToString, \
                                  ogr.GetFieldTypeName(poSrcFieldDefn.GetType())) != -1):
  
                      oFieldDefn.SetType(ogr.OFTString)
  
                  # The field may have been already created at layer creation
                  iDstField = -1
                  if poDstFDefn is not None:
                      iDstField = poDstFDefn.GetFieldIndex(oFieldDefn.GetNameRef())
                  if iDstField >= 0:
                      panMap[iSrcField] = iDstField
                  elif poDstLayer.CreateField( oFieldDefn ) == 0:
                      # now that we've created a field, GetLayerDefn() won't return NULL
                      if poDstFDefn is None:
                          poDstFDefn = poDstLayer.GetLayerDefn()
  
                      #/* Sanity check : if it fails, the driver is buggy */
                      if poDstFDefn is not None and \
                          poDstFDefn.GetFieldCount() != nDstFieldCount + 1:
                          print("The output driver has claimed to have added the %s field, but it did not!" %  oFieldDefn.GetNameRef() )
                      else:
                          panMap[iSrcField] = nDstFieldCount
                          nDstFieldCount = nDstFieldCount + 1
  
              else:
                  print("Field '" + papszSelFields[iField] + "' not found in source layer.")
                  if not bSkipFailures:
                      return None
  
          #/* -------------------------------------------------------------------- */
          #/* Use SetIgnoredFields() on source layer if available                  */
          #/* -------------------------------------------------------------------- */
  
          # Here we differ from the ogr2ogr.cpp implementation since the OGRFeatureQuery
          # isn't mapped to swig. So in that case just don't use SetIgnoredFields()
          # to avoid issue raised in #4015
          if poSrcLayer.TestCapability(ogr.OLCIgnoreFields) and pszWHERE is None:
              papszIgnoredFields = []
              for iSrcField in range(nSrcFieldCount):
                  pszFieldName = poSrcFDefn.GetFieldDefn(iSrcField).GetNameRef()
                  bFieldRequested = False
                  for iField in range(len(papszSelFields)):
                      if EQUAL(pszFieldName, papszSelFields[iField]):
                          bFieldRequested = True
                          break
  
                  if pszZField is not None and EQUAL(pszFieldName, pszZField):
                      bFieldRequested = True
  
                  #/* If source field not requested, add it to ignored files list */
                  if not bFieldRequested:
                      papszIgnoredFields.append(pszFieldName)
  
              poSrcLayer.SetIgnoredFields(papszIgnoredFields)
  
      elif not bAppend:
  
          nDstFieldCount = 0
          if poDstFDefn is not None:
              nDstFieldCount = poDstFDefn.GetFieldCount()
  
          for iField in range(nSrcFieldCount):
  
              poSrcFieldDefn = poSrcFDefn.GetFieldDefn(iField)
              oFieldDefn = ogr.FieldDefn( poSrcFieldDefn.GetNameRef(),
                                          poSrcFieldDefn.GetType() )
              oFieldDefn.SetWidth( poSrcFieldDefn.GetWidth() )
              oFieldDefn.SetPrecision( poSrcFieldDefn.GetPrecision() )
  
              if papszFieldTypesToString is not None and \
                  (CSLFindString(papszFieldTypesToString, "All") != -1 or \
                  CSLFindString(papszFieldTypesToString, \
                              ogr.GetFieldTypeName(poSrcFieldDefn.GetType())) != -1):
  
                  oFieldDefn.SetType(ogr.OFTString)
  
              # The field may have been already created at layer creation
              iDstField = -1
              if poDstFDefn is not None:
                   iDstField = poDstFDefn.GetFieldIndex(oFieldDefn.GetNameRef())
              if iDstField >= 0:
                  panMap[iField] = iDstField
              elif poDstLayer.CreateField( oFieldDefn ) == 0:
                  # now that we've created a field, GetLayerDefn() won't return NULL
                  if poDstFDefn is None:
                      poDstFDefn = poDstLayer.GetLayerDefn()
  
                  #/* Sanity check : if it fails, the driver is buggy */
                  if poDstFDefn is not None and \
                      poDstFDefn.GetFieldCount() != nDstFieldCount + 1:
                      print("The output driver has claimed to have added the %s field, but it did not!" %  oFieldDefn.GetNameRef() )
                  else:
                      panMap[iField] = nDstFieldCount
                      nDstFieldCount = nDstFieldCount + 1
  
      else:
          #/* For an existing layer, build the map by fetching the index in the destination */
          #/* layer for each source field */
          if poDstFDefn is None:
              print( "poDstFDefn == NULL.\n" )
              return None
  
          for iField in range(nSrcFieldCount):
              poSrcFieldDefn = poSrcFDefn.GetFieldDefn(iField)
              iDstField = poDstFDefn.GetFieldIndex(poSrcFieldDefn.GetNameRef())
              if iDstField >= 0:
                  panMap[iField] = iDstField
  
      iSrcZField = -1
      if pszZField is not None:
          iSrcZField = poSrcFDefn.GetFieldIndex(pszZField)
  
      psInfo = TargetLayerInfo()
      psInfo.poDstLayer = poDstLayer
      psInfo.poCT = poCT
      #psInfo.papszTransformOptions = papszTransformOptions
      psInfo.panMap = panMap
      psInfo.iSrcZField = iSrcZField
  
      return psInfo
  
  #/************************************************************************/
  #/*                           TranslateLayer()                           */
  #/************************************************************************/
  
  def TranslateLayer( psInfo, poSrcDS, poSrcLayer, poDstDS,  \
                      poOutputSRS, bNullifyOutputSRS, \
                      eGType, nCoordDim, eGeomOp, dfGeomOpParam, \
                      nCountLayerFeatures, \
                      poClipSrc, poClipDst, bExplodeCollections, nSrcFileSize, \
                      pnReadFeatureCount, pfnProgress, pProgressArg) :
  
      bForceToPolygon = False
      bForceToMultiPolygon = False
      bForceToMultiLineString = False
      
      poDstLayer = psInfo.poDstLayer
      #papszTransformOptions = psInfo.papszTransformOptions
      poCT = psInfo.poCT
      panMap = psInfo.panMap
      iSrcZField = psInfo.iSrcZField
  
      if poOutputSRS is None and not bNullifyOutputSRS:
          poOutputSRS = poSrcLayer.GetSpatialRef()
  
      if wkbFlatten(eGType) == ogr.wkbPolygon:
          bForceToPolygon = True
      elif wkbFlatten(eGType) == ogr.wkbMultiPolygon:
          bForceToMultiPolygon = True
      elif wkbFlatten(eGType) == ogr.wkbMultiLineString:
          bForceToMultiLineString = True
  
  #/* -------------------------------------------------------------------- */
  #/*      Transfer features.                                              */
  #/* -------------------------------------------------------------------- */
      nFeaturesInTransaction = 0
      nCount = 0
  
      if nGroupTransactions > 0:
          poDstLayer.StartTransaction()
  
      while True:
          poDstFeature = None
  
          if nFIDToFetch != ogr.NullFID:
  
              #// Only fetch feature on first pass.
              if nFeaturesInTransaction == 0:
                  poFeature = poSrcLayer.GetFeature(nFIDToFetch)
              else:
                  poFeature = None
  
          else:
              poFeature = poSrcLayer.GetNextFeature()
  
          if poFeature is None:
              break
  
          nParts = 0
          nIters = 1
          if bExplodeCollections:
              poSrcGeometry = poFeature.GetGeometryRef()
              if poSrcGeometry is not None:
                  eSrcType = wkbFlatten(poSrcGeometry.GetGeometryType())
                  if eSrcType == ogr.wkbMultiPoint or \
                     eSrcType == ogr.wkbMultiLineString or \
                     eSrcType == ogr.wkbMultiPolygon or \
                     eSrcType == ogr.wkbGeometryCollection:
                          nParts = poSrcGeometry.GetGeometryCount()
                          nIters = nParts
                          if nIters == 0:
                              nIters = 1
  
          for iPart in range(nIters):
              nFeaturesInTransaction = nFeaturesInTransaction + 1
              if nFeaturesInTransaction == nGroupTransactions:
                  poDstLayer.CommitTransaction()
                  poDstLayer.StartTransaction()
                  nFeaturesInTransaction = 0
  
              gdal.ErrorReset()
              poDstFeature = ogr.Feature( poDstLayer.GetLayerDefn() )
  
              if poDstFeature.SetFromWithMap( poFeature, 1, panMap ) != 0:
  
                  if nGroupTransactions > 0:
                      poDstLayer.CommitTransaction()
  
                  print("Unable to translate feature %d from layer %s" % (poFeature.GetFID() , poSrcLayer.GetName() ))
  
                  return False
  
              if bPreserveFID:
                  poDstFeature.SetFID( poFeature.GetFID() )
  
              poDstGeometry = poDstFeature.GetGeometryRef()
              if poDstGeometry is not None:
  
                  if nParts > 0:
                      # /* For -explodecollections, extract the iPart(th) of the geometry */
                      poPart = poDstGeometry.GetGeometryRef(iPart).Clone()
                      poDstFeature.SetGeometryDirectly(poPart)
                      poDstGeometry = poPart
  
                  if iSrcZField != -1:
                      SetZ(poDstGeometry, poFeature.GetFieldAsDouble(iSrcZField))
                      # /* This will correct the coordinate dimension to 3 */
                      poDupGeometry = poDstGeometry.Clone()
                      poDstFeature.SetGeometryDirectly(poDupGeometry)
                      poDstGeometry = poDupGeometry
  
  
                  if nCoordDim == 2 or nCoordDim == 3:
                      poDstGeometry.SetCoordinateDimension( nCoordDim )
  
                  if eGeomOp == GeomOperation.SEGMENTIZE:
                      pass
                      #/*if (poDstFeature.GetGeometryRef() is not None and dfGeomOpParam > 0)
                      #    poDstFeature.GetGeometryRef().segmentize(dfGeomOpParam);*/
                  elif eGeomOp == GeomOperation.SIMPLIFY_PRESERVE_TOPOLOGY and dfGeomOpParam > 0:
                      poNewGeom = poDstGeometry.SimplifyPreserveTopology(dfGeomOpParam)
                      if poNewGeom is not None:
                          poDstFeature.SetGeometryDirectly(poNewGeom)
                          poDstGeometry = poNewGeom
  
                  if poClipSrc is not None:
                      poClipped = poDstGeometry.Intersection(poClipSrc)
                      if poClipped is None or poClipped.IsEmpty():
                          #/* Report progress */
                          nCount = nCount +1
                          if pfnProgress is not None:
                              pfnProgress(nCount * 1.0 / nCountLayerFeatures, "", pProgressArg)
                          continue
  
                      poDstFeature.SetGeometryDirectly(poClipped)
                      poDstGeometry = poClipped
  
                  if poCT is not None:
                      eErr = poDstGeometry.Transform( poCT )
                      if eErr != 0:
                          if nGroupTransactions > 0:
                              poDstLayer.CommitTransaction()
  
                          print("Failed to reproject feature %d (geometry probably out of source or destination SRS)." % poFeature.GetFID())
                          if not bSkipFailures:
                              return False
  
                  elif poOutputSRS is not None:
                      poDstGeometry.AssignSpatialReference(poOutputSRS)
  
                  if poClipDst is not None:
                      poClipped = poDstGeometry.Intersection(poClipDst)
                      if poClipped is None or poClipped.IsEmpty():
                          continue
  
                      poDstFeature.SetGeometryDirectly(poClipped)
                      poDstGeometry = poClipped
  
                  if bForceToPolygon:
                      poDstFeature.SetGeometryDirectly(ogr.ForceToPolygon(poDstGeometry))
  
                  elif bForceToMultiPolygon:
                      poDstFeature.SetGeometryDirectly(ogr.ForceToMultiPolygon(poDstGeometry))
  
                  elif bForceToMultiLineString:
                      poDstFeature.SetGeometryDirectly(ogr.ForceToMultiLineString(poDstGeometry))
  
              gdal.ErrorReset()
              if poDstLayer.CreateFeature( poDstFeature ) != 0 and not bSkipFailures:
                  if nGroupTransactions > 0:
                      poDstLayer.RollbackTransaction()
  
                  return False
  
          #/* Report progress */
          nCount = nCount  + 1
          if pfnProgress is not None:
              if nSrcFileSize != 0:
                  if (nCount % 1000) == 0:
                      poFCLayer = poSrcDS.ExecuteSQL("GetBytesRead()", None, None)
                      if poFCLayer is not None:
                          poFeat = poFCLayer.GetNextFeature()
                          if poFeat is not None:
                              pszReadSize = poFeat.GetFieldAsString(0)
                              nReadSize = int(pszReadSize)
                              pfnProgress(nReadSize * 1.0 / nSrcFileSize, "", pProgressArg)
                      poSrcDS.ReleaseResultSet(poFCLayer)
              else:
                  pfnProgress(nCount * 1.0 / nCountLayerFeatures, "", pProgressArg)
  
          if pnReadFeatureCount is not None:
              pnReadFeatureCount[0] = nCount
  
      if nGroupTransactions > 0:
          poDstLayer.CommitTransaction()
  
      return True
  
  if __name__ == '__main__':
      version_num = int(gdal.VersionInfo('VERSION_NUM'))
      if version_num < 1800: # because of ogr.GetFieldTypeName
          print('ERROR: Python bindings of GDAL 1.8.0 or later required')
          sys.exit(1)
  
      if not main(sys.argv):
          sys.exit(1)
      else:
          sys.exit(0)
  
  